#!/usr/bin/env vpython3
# Copyright 2020 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import json
import os
from typing import Any, Dict, Set, Tuple
import unittest
from unittest import mock

# vpython-provided modules.
from pyfakefs import fake_filesystem_unittest  # pylint: disable=import-error

# //testing imports.
from unexpected_passes_common import builders
from unexpected_passes_common import constants
from unexpected_passes_common import data_types
from unexpected_passes_common import unittest_utils

# Protected access is allowed for unittests.
# pylint: disable=protected-access


class FakeFilesystemTestCaseWithFileCreation(fake_filesystem_unittest.TestCase):
  def CreateFile(self, *args, **kwargs):
    # TODO(crbug.com/40160566): Remove this and just use fs.create_file() when
    # Catapult is updated to a newer version of pyfakefs that is compatible with
    # Chromium's version.
    if hasattr(self.fs, 'create_file'):
      self.fs.create_file(*args, **kwargs)
    else:
      self.fs.CreateFile(*args, **kwargs)


class GetCiBuildersUnittest(FakeFilesystemTestCaseWithFileCreation):
  def setUp(self) -> None:
    self._builders_instance = unittest_utils.GenericBuilders(
      suite='webgl_conformance'
    )
    self._isolate_patcher = mock.patch.object(
      self._builders_instance,
      'GetIsolateNames',
      return_value={'telemetry_gpu_integration_test'},
    )
    self._isolate_mock = self._isolate_patcher.start()
    self.addCleanup(self._isolate_patcher.stop)

  def testJsonContentLoaded(self) -> None:
    """Tests that the correct JSON data is loaded in."""
    self.setUpPyfakefs()
    gpu_json = {
      'AAAAA1 AUTOGENERATED FILE DO NOT EDIT': {},
      'Android Release (Nexus 5X)': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
      'GPU Linux Builder': {},
    }
    gpu_fyi_json = {
      'AAAAA1 AUTOGENERATED FILE DO NOT EDIT': {},
      'ANGLE GPU Android Release (Nexus 5X)': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
      'GPU FYI Linux Builder': {},
    }
    ci_infra_config_json = {
      'Infra Config GPU': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
    }
    # Should be ignored.
    tryserver_json = {
      'AAAAA1 AUTOGENERATED FILE DO NOT EDIT': {},
      'Trybot': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
    }
    # Also should be ignored.
    try_infra_config_json = {
      'Infra Config Try': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
    }
    # Also should be ignored.
    not_buildbot_json = {
      'Not buildbot': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
    }

    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'chromium.gpu.json'),
      contents=json.dumps(gpu_json),
    )
    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'chromium.gpu.fyi.json'),
      contents=json.dumps(gpu_fyi_json),
    )
    self.CreateFile(
      os.path.join(
        builders.INFRA_CONFIG_BUILDERS_DIR,
        'ci',
        'Infra Config GPU',
        'targets',
        'infra.gpu.json',
      ),
      contents=json.dumps(ci_infra_config_json),
    )
    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'tryserver.gpu.json'),
      contents=json.dumps(tryserver_json),
    )
    self.CreateFile(
      os.path.join(
        builders.INFRA_CONFIG_BUILDERS_DIR,
        'try',
        'Infra Config Try',
        'targets',
        'infra.gpu.json',
      ),
      contents=json.dumps(try_infra_config_json),
    )
    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'not_buildbot.json'),
      contents=json.dumps(not_buildbot_json),
    )

    gpu_builders = self._builders_instance.GetCiBuilders()
    self.assertEqual(
      gpu_builders,
      set(
        [
          data_types.BuilderEntry(
            'Android Release (Nexus 5X)', constants.BuilderTypes.CI, False
          ),
          data_types.BuilderEntry(
            'ANGLE GPU Android Release (Nexus 5X)',
            constants.BuilderTypes.CI,
            False,
          ),
          data_types.BuilderEntry(
            'Infra Config GPU', constants.BuilderTypes.CI, False
          ),
          data_types.BuilderEntry(
            'GPU Linux Builder', constants.BuilderTypes.CI, False
          ),
          data_types.BuilderEntry(
            'GPU FYI Linux Builder', constants.BuilderTypes.CI, False
          ),
        ]
      ),
    )

  def testPublicInternalBuilders(self) -> None:
    """Tests that public internal builders are treated as internal."""
    self.setUpPyfakefs()
    gpu_json = {
      'AAAAA1 AUTOGENERATED FILE DO NOT EDIT': {},
      'Android Release (Nexus 5X)': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
      'GPU Linux Builder': {},
    }
    gpu_internal_json = {
      'AAAAA1 AUTOGENERATED FILE DO NOT EDIT': {},
      'Android Chrome Release (Nexus 5X)': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
      'GPU Chrome Linux Builder': {},
    }
    internal_json = {
      'AAAAA1 AUTOGENERATED FILE DO NOT EDIT': {},
      'Android Internal Release (Nexus 5X)': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
      'GPU Internal Linux Builder': {},
    }
    internal_infra_config_json = {
      'Infra Config Internal': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
    }

    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'chromium.gpu.json'),
      contents=json.dumps(gpu_json),
    )
    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'chrome.gpu.fyi.json'),
      contents=json.dumps(gpu_internal_json),
    )
    self.CreateFile(
      os.path.join(builders.INTERNAL_TESTING_BUILDBOT_DIR, 'internal.json'),
      contents=json.dumps(internal_json),
    )
    self.CreateFile(
      os.path.join(
        builders.INTERNAL_INFRA_CONFIG_BUILDERS_DIR,
        'ci',
        'Infra Config Internal',
        'targets',
        'infra.config.json',
      ),
      contents=json.dumps(internal_infra_config_json),
    )

    # Dummy file so that pyfakefs doesn't complain when we check for public
    # infra/config files.
    self.CreateFile(
      os.path.join(
        builders.INFRA_CONFIG_BUILDERS_DIR, 'ci', 'Fake', 'targets', 'fake.json'
      ),
      contents=json.dumps({}),
    )

    gpu_builders = self._builders_instance.GetCiBuilders()
    self.assertEqual(
      gpu_builders,
      set(
        [
          data_types.BuilderEntry(
            'Android Release (Nexus 5X)', constants.BuilderTypes.CI, False
          ),
          data_types.BuilderEntry(
            'GPU Linux Builder', constants.BuilderTypes.CI, False
          ),
        ]
      ),
    )

    internal_instance = unittest_utils.GenericBuilders(
      suite='webgl_conformance', include_internal_builders=True
    )
    with mock.patch.object(
      internal_instance,
      'GetIsolateNames',
      return_value={'telemetry_gpu_integration_test'},
    ):
      gpu_builders = internal_instance.GetCiBuilders()
    self.assertEqual(
      gpu_builders,
      set(
        [
          data_types.BuilderEntry(
            'Android Release (Nexus 5X)', constants.BuilderTypes.CI, False
          ),
          data_types.BuilderEntry(
            'Android Chrome Release (Nexus 5X)', constants.BuilderTypes.CI, True
          ),
          data_types.BuilderEntry(
            'Android Internal Release (Nexus 5X)',
            constants.BuilderTypes.CI,
            True,
          ),
          data_types.BuilderEntry(
            'GPU Linux Builder', constants.BuilderTypes.CI, False
          ),
          data_types.BuilderEntry(
            'GPU Chrome Linux Builder', constants.BuilderTypes.CI, True
          ),
          data_types.BuilderEntry(
            'GPU Internal Linux Builder', constants.BuilderTypes.CI, True
          ),
          data_types.BuilderEntry(
            'Infra Config Internal', constants.BuilderTypes.CI, True
          ),
        ]
      ),
    )

  def testFilterBySuite(self) -> None:
    """Tests that only builders that run the given suite are returned."""

    def SideEffect(tm: Dict[str, Any]) -> bool:
      tests = tm.get('isolated_scripts', [])
      for t in tests:
        if t.get('isolate_name') == 'foo_integration_test':
          if 'webgl_conformance' in t.get('args', []):
            return True
      return False

    self.setUpPyfakefs()
    gpu_json = {
      'AAAAA1 AUTOGENERATED FILE DO NOT EDIT': {},
      'Android Tester': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'not_telemetry',
          },
        ],
      },
      'Linux Tester': {
        'isolated_scripts': [
          {
            'args': [
              'not_a_suite',
            ],
            'isolate_name': 'foo_integration_test',
          },
        ],
      },
      'Windows Tester': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'foo_integration_test',
          },
        ],
      },
    }
    matching_infra_config_json = {
      'Matching Infra Config': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'foo_integration_test',
          },
        ],
      },
    }
    not_matching_infra_config_json = {
      'Not Matching Infra Config': {
        'isolated_scripts': [
          {
            'args': [
              'not_a_suite',
            ],
            'isolate_name': 'foo_integration_test',
          },
        ],
      },
    }

    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'chromium.json'),
      contents=json.dumps(gpu_json),
    )
    self.CreateFile(
      os.path.join(
        builders.INFRA_CONFIG_BUILDERS_DIR,
        'ci',
        'Matching Infra Config',
        'targets',
        'infra.config.json',
      ),
      contents=json.dumps(matching_infra_config_json),
    )
    self.CreateFile(
      os.path.join(
        builders.INFRA_CONFIG_BUILDERS_DIR,
        'ci',
        'Not Matching Infra Config',
        'targets',
        'infra.config.json',
      ),
      contents=json.dumps(not_matching_infra_config_json),
    )

    with mock.patch.object(
      self._builders_instance,
      '_BuilderRunsTestOfInterest',
      side_effect=SideEffect,
    ):
      gpu_builders = self._builders_instance.GetCiBuilders()
    self.assertEqual(
      gpu_builders,
      {
        data_types.BuilderEntry(
          'Windows Tester', constants.BuilderTypes.CI, False
        ),
        data_types.BuilderEntry(
          'Matching Infra Config', constants.BuilderTypes.CI, False
        ),
      },
    )

  def testRealContentCanBeLoaded(self) -> None:
    """Tests that *something* from the real JSON files can be loaded."""
    # This directory is not available on swarming, so if it doesn't exist, just
    # skip the test.
    if not os.path.exists(builders.TESTING_BUILDBOT_DIR):
      return
    self.assertNotEqual(len(self._builders_instance.GetCiBuilders()), 0)


class GetMirroredBuildersForCiBuilderUnittest(unittest.TestCase):
  def setUp(self) -> None:
    self._builders_instance = builders.Builders('suite', False)
    self._bb_patcher = mock.patch.object(
      self._builders_instance, '_GetBuildbucketOutputForCiBuilder'
    )
    self._bb_mock = self._bb_patcher.start()
    self.addCleanup(self._bb_patcher.stop)
    self._fake_ci_patcher = mock.patch.object(
      self._builders_instance, 'GetFakeCiBuilders', return_value={}
    )
    self._fake_ci_mock = self._fake_ci_patcher.start()
    self.addCleanup(self._fake_ci_patcher.stop)
    self._non_chromium_patcher = mock.patch.object(
      self._builders_instance,
      'GetNonChromiumBuilders',
      return_value={'foo_non_chromium'},
    )
    self._non_chromium_mock = self._non_chromium_patcher.start()
    self.addCleanup(self._non_chromium_patcher.stop)

  def testFakeCiBuilder(self) -> None:
    """Tests that a fake CI builder gets properly mapped."""
    self._fake_ci_mock.return_value = {
      data_types.BuilderEntry('foo_ci', constants.BuilderTypes.CI, False): {
        data_types.BuilderEntry('foo_try', constants.BuilderTypes.TRY, False)
      }
    }
    try_builder, found_mirror = (
      self._builders_instance._GetMirroredBuildersForCiBuilder(
        data_types.BuilderEntry('foo_ci', constants.BuilderTypes.CI, False)
      )
    )
    self.assertTrue(found_mirror)
    self.assertEqual(
      try_builder,
      set(
        [data_types.BuilderEntry('foo_try', constants.BuilderTypes.TRY, False)]
      ),
    )
    self._bb_mock.assert_not_called()

  def testNoBuildbucketOutput(self) -> None:
    """Tests that a failure to get Buildbucket output is surfaced."""
    self._bb_mock.return_value = ''
    builder_entry = data_types.BuilderEntry(
      'nonexistent', constants.BuilderTypes.CI, False
    )
    try_builder, found_mirror = (
      self._builders_instance._GetMirroredBuildersForCiBuilder(builder_entry)
    )
    self.assertFalse(found_mirror)
    self.assertEqual(try_builder, set([builder_entry]))

  def testBuildbucketOutput(self):
    """Tests that Buildbucket output is parsed correctly."""
    self._bb_mock.return_value = json.dumps(
      {
        'output': {
          'properties': {
            'mirrored_builders': [
              'try:foo_try',
              'try:bar_try',
            ]
          }
        }
      }
    )
    try_builders, found_mirror = (
      self._builders_instance._GetMirroredBuildersForCiBuilder(
        data_types.BuilderEntry('foo_ci', constants.BuilderTypes.CI, False)
      )
    )
    self.assertTrue(found_mirror)
    self.assertEqual(
      try_builders,
      set(
        [
          data_types.BuilderEntry('foo_try', constants.BuilderTypes.TRY, False),
          data_types.BuilderEntry('bar_try', constants.BuilderTypes.TRY, False),
        ]
      ),
    )

  def testBuildbucketOutputInternal(self) -> None:
    """Tests that internal Buildbucket output is parsed correctly."""
    self._bb_mock.return_value = json.dumps(
      {
        'output': {
          'properties': {
            'mirrored_builders': [
              'try:foo_try',
              'try:bar_try',
            ]
          }
        }
      }
    )
    try_builders, found_mirror = (
      self._builders_instance._GetMirroredBuildersForCiBuilder(
        data_types.BuilderEntry('foo_ci', constants.BuilderTypes.CI, True)
      )
    )
    self.assertTrue(found_mirror)
    self.assertEqual(
      try_builders,
      set(
        [
          data_types.BuilderEntry('foo_try', constants.BuilderTypes.TRY, True),
          data_types.BuilderEntry('bar_try', constants.BuilderTypes.TRY, True),
        ]
      ),
    )


class GetTryBuildersUnittest(FakeFilesystemTestCaseWithFileCreation):
  def setUp(self) -> None:
    self._builders_instance = builders.Builders('suite', False)
    self._get_patcher = mock.patch.object(
      self._builders_instance, '_GetMirroredBuildersForCiBuilder'
    )
    self._get_mock = self._get_patcher.start()
    self.addCleanup(self._get_patcher.stop)
    self._runs_test_patcher = mock.patch.object(
      self._builders_instance, '_BuilderRunsTestOfInterest'
    )
    self._runs_test_mock = self._runs_test_patcher.start()
    self.addCleanup(self._runs_test_patcher.stop)

    self.setUpPyfakefs()
    # Make sure the directory exists.
    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'placeholder.txt')
    )

  def testMirrorNoOutputCausesFailure(self) -> None:
    """Tests that a failure to get Buildbot output raises an exception."""
    # Create a dummy file so that pyfakefs does not complain about a directory
    # not existing.
    self.CreateFile(
      os.path.join(
        builders.INFRA_CONFIG_BUILDERS_DIR,
        'try',
        'Fake',
        'targets',
        'fake.json',
      ),
      contents=json.dumps({}),
    )
    builder = data_types.BuilderEntry(
      'foo_ci', constants.BuilderTypes.CI, False
    )
    self._get_mock.return_value = (set([builder]), False)
    self._runs_test_mock.return_value = True
    with self.assertRaises(RuntimeError):
      self._builders_instance.GetTryBuilders([builder])

  def testMirrorOutputReturned(self) -> None:
    """Tests that parsed, mirrored builders get returned on success."""

    def SideEffect(
      ci_builder: data_types.BuilderEntry,
    ) -> Tuple[Set[data_types.BuilderEntry], bool]:
      b = [
        data_types.BuilderEntry(
          ci_builder.name.replace('ci', 'try'),
          constants.BuilderTypes.TRY,
          False,
        ),
        data_types.BuilderEntry(
          ci_builder.name.replace('ci', 'try2'),
          constants.BuilderTypes.TRY,
          False,
        ),
      ]
      return set(b), True

    # Create a dummy file so that pyfakefs does not complain about a directory
    # not existing.
    self.CreateFile(
      os.path.join(
        builders.INFRA_CONFIG_BUILDERS_DIR,
        'try',
        'Fake',
        'targets',
        'fake.json',
      ),
      contents=json.dumps({}),
    )

    self._get_mock.side_effect = SideEffect
    self._runs_test_mock.return_value = False
    mirrored_builders = self._builders_instance.GetTryBuilders(
      [
        data_types.BuilderEntry('foo_ci', constants.BuilderTypes.CI, False),
        data_types.BuilderEntry('bar_ci', constants.BuilderTypes.CI, False),
      ]
    )
    self.assertEqual(
      mirrored_builders,
      set(
        [
          data_types.BuilderEntry('foo_try', constants.BuilderTypes.TRY, False),
          data_types.BuilderEntry(
            'foo_try2', constants.BuilderTypes.TRY, False
          ),
          data_types.BuilderEntry('bar_try', constants.BuilderTypes.TRY, False),
          data_types.BuilderEntry(
            'bar_try2', constants.BuilderTypes.TRY, False
          ),
        ]
      ),
    )

  def testDedicatedJsonContentLoaded(self) -> None:
    """Tests that tryserver JSON content is loaded."""

    def SideEffect(test_spec: Dict[str, Any]) -> bool:
      # Treat non-empty test specs as valid.
      return bool(test_spec)

    self._runs_test_mock.side_effect = SideEffect
    # Should be ignored.
    gpu_json = {
      'AAAAA1 AUTOGENERATED FILE DO NOT EDIT': {},
      'Android Release (Nexus 5X)': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
      'GPU Linux Builder': {},
    }
    # Should be ignored.
    gpu_fyi_json = {
      'AAAAA1 AUTOGENERATED FILE DO NOT EDIT': {},
      'ANGLE GPU Android Release (Nexus 5X)': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
      'GPU FYI Linux Builder': {},
    }
    # Also should be ignored.
    ci_infra_config_json = {
      'CI Infra Config': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
    }
    tryserver_json = {
      'AAAAA1 AUTOGENERATED FILE DO NOT EDIT': {},
      'Trybot': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
      'Trybot Empty': {},
    }
    try_infra_config_json = {
      'Mirrored CI Infra Config': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
    }
    # Also should be ignored.
    not_buildbot_json = {
      'Not buildbot': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
    }

    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'chromium.gpu.json'),
      contents=json.dumps(gpu_json),
    )
    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'chromium.gpu.fyi.json'),
      contents=json.dumps(gpu_fyi_json),
    )
    self.CreateFile(
      os.path.join(
        builders.INFRA_CONFIG_BUILDERS_DIR,
        'ci',
        'CI Infra Config',
        'targets',
        'infra.config.json',
      ),
      contents=json.dumps(ci_infra_config_json),
    )
    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'tryserver.gpu.json'),
      contents=json.dumps(tryserver_json),
    )
    self.CreateFile(
      os.path.join(
        builders.INFRA_CONFIG_BUILDERS_DIR,
        'try',
        'Try Infra Config',
        'targets',
        'infra.config.json',
      ),
      contents=json.dumps(try_infra_config_json),
    )
    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'not_buildbot.json'),
      contents=json.dumps(not_buildbot_json),
    )

    gpu_builders = self._builders_instance.GetTryBuilders({})
    self.assertEqual(
      gpu_builders,
      {
        data_types.BuilderEntry('Trybot', constants.BuilderTypes.TRY, False),
        data_types.BuilderEntry(
          'Try Infra Config', constants.BuilderTypes.TRY, False
        ),
      },
    )

  def testDedicatedFilterBySuite(self) -> None:
    """Tests that only builders that run the given suite are returned."""

    def SideEffect(tm: Dict[str, Any]) -> bool:
      tests = tm.get('isolated_scripts', [])
      for t in tests:
        if t.get('isolate_name') == 'foo_integration_test':
          if 'webgl_conformance' in t.get('args', []):
            return True
      return False

    self._runs_test_mock.side_effect = SideEffect
    gpu_json = {
      'AAAAA1 AUTOGENERATED FILE DO NOT EDIT': {},
      'Android Tester': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'not_telemetry',
          },
        ],
      },
      'Linux Tester': {
        'isolated_scripts': [
          {
            'args': [
              'not_a_suite',
            ],
            'isolate_name': 'foo_integration_test',
          },
        ],
      },
      'Windows Tester': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'foo_integration_test',
          },
        ],
      },
    }
    matching_infra_config_json = {
      'Matching Infra Config Mirrored CI': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'foo_integration_test',
          },
        ],
      },
    }
    not_matching_infra_config_json = {
      'Not Matching Infra Config': {
        'isolated_scripts': [
          {
            'args': [
              'not_a_suite',
            ],
            'isolate_name': 'foo_integration_test',
          },
        ],
      },
    }

    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'tryserver.chromium.json'),
      contents=json.dumps(gpu_json),
    )
    self.CreateFile(
      os.path.join(
        builders.INFRA_CONFIG_BUILDERS_DIR,
        'try',
        'Matching Infra Config',
        'targets',
        'infra.config.json',
      ),
      contents=json.dumps(matching_infra_config_json),
    )
    self.CreateFile(
      os.path.join(
        builders.INFRA_CONFIG_BUILDERS_DIR,
        'try',
        'Not Matching Infra Config',
        'targets',
        'infra.config.json',
      ),
      contents=json.dumps(not_matching_infra_config_json),
    )

    gpu_builders = self._builders_instance.GetTryBuilders({})
    self.assertEqual(
      gpu_builders,
      {
        data_types.BuilderEntry(
          'Windows Tester', constants.BuilderTypes.TRY, False
        ),
        data_types.BuilderEntry(
          'Matching Infra Config', constants.BuilderTypes.TRY, False
        ),
      },
    )

  def testDedicatedAndMirroredCombined(self) -> None:
    """Tests that both dedicated and mirrored trybots are returned."""

    def SideEffect(_: Any) -> Tuple[Set[data_types.BuilderEntry], bool]:
      return set(
        {
          data_types.BuilderEntry(
            'mirrored_trybot', constants.BuilderTypes.TRY, False
          )
        }
      ), True

    self._get_mock.side_effect = SideEffect
    self._runs_test_mock.return_value = True
    tryserver_json = {
      'AAAAA1 AUTOGENERATED FILE DO NOT EDIT': {},
      'Trybot': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
    }
    infra_config_json = {
      'Infra Config Mirrored CI': {
        'isolated_scripts': [
          {
            'args': [
              'webgl_conformance',
            ],
            'isolate_name': 'telemetry_gpu_integration_test',
          }
        ],
      },
    }

    self.CreateFile(
      os.path.join(builders.TESTING_BUILDBOT_DIR, 'tryserver.chromium.json'),
      contents=json.dumps(tryserver_json),
    )
    self.CreateFile(
      os.path.join(
        builders.INFRA_CONFIG_BUILDERS_DIR,
        'try',
        'Infra Config',
        'targets',
        'infra.config.json',
      ),
      contents=json.dumps(infra_config_json),
    )

    try_builders = self._builders_instance.GetTryBuilders(
      {data_types.BuilderEntry('ci_builder', constants.BuilderTypes.CI, False)}
    )
    self.assertEqual(
      try_builders,
      {
        data_types.BuilderEntry(
          'mirrored_trybot', constants.BuilderTypes.TRY, False
        ),
        data_types.BuilderEntry('Trybot', constants.BuilderTypes.TRY, False),
        data_types.BuilderEntry(
          'Infra Config', constants.BuilderTypes.TRY, False
        ),
      },
    )


if __name__ == '__main__':
  unittest.main(verbosity=2)
