def testPerformStageSuccessVarientBoard(self): """Test that SignerResultsStage works with varient boards. Varient boards need some name conversion. Make sure that's okay. """ self._current_board = 'x86-alex_he' with patch(release_stages.parallel, 'BackgroundTaskRunner') as background: queue = background().__enter__() # This patch is only required for external builds with no config data. with patch(paygen_build_lib, 'ValidateBoardConfig'): stage = self.ConstructStage() with patch(stage, '_WaitForPushImage') as wait_push: with patch(stage, '_WaitForSigningResults') as wait_signing: wait_push.return_value = self.INSNS_URLS_PER_CHANNEL wait_signing.side_effect = self.generateNotifyCalls(('stable', 'beta')) stage.PerformStage() # Verify that we queue up work self.assertEqual( queue.put.call_args_list, [mock.call(('stable', 'x86-alex-he', '0.0.1', False, False, False)), mock.call(('beta', 'x86-alex-he', '0.0.1', False, False, False))])
def testPerformStageTrybot(self): """Test the PerformStage alternate behavior for trybot runs.""" with patch(release_stages.parallel, 'BackgroundTaskRunner') as background: queue = background().__enter__() # This patch is only required for external builds with no config data. with patch(paygen_build_lib, 'ValidateBoardConfig'): # The stage is constructed differently for trybots, so don't use # ConstructStage. stage = release_stages.PaygenStage( self._run, self._current_board, archive_stage=None, channels=['foo', 'bar']) with patch(stage, '_WaitForPushImage') as wait_push: with patch(stage, '_WaitForSigningResults') as wait_signing: stage.PerformStage() # Make sure we don't wait on push_image or signing in this case. self.assertEqual(wait_push.mock_calls, []) self.assertEqual(wait_signing.mock_calls, []) # Notice that we didn't put anything in _wait_for_channel_signing, but # still got results right away. self.assertEqual( queue.put.call_args_list, [mock.call(('foo', 'x86-mario', '0.0.1', False, False, False)), mock.call(('bar', 'x86-mario', '0.0.1', False, False, False))])
def testCheckForResultsPartialComplete(self): """Verify _CheckForResults handles partial signing results.""" def catChan2Success(url): if url.startswith('chan2'): return self.SIGNER_RESULT else: raise release_stages.gs.GSNoSuchKey() with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value mock_gs_ctx.Cat.side_effect = catChan2Success notifier = mock.Mock() stage = self.ConstructStage() self.assertFalse( stage._CheckForResults(mock_gs_ctx, self.INSNS_URLS_PER_CHANNEL, notifier)) self.assertEqual(stage.signing_results, { 'chan1': {}, 'chan2': { 'chan2_uri1.json': { 'board': 'link', 'channel': 'stable', 'keyset': 'link-mp-v4', 'status': {'status': 'passed'}, 'type': 'recovery' } } }) self.assertEqual(notifier.mock_calls, [mock.call('chan2')])
def testPerformStageBackgroundFail(self): """Test that exception from background processes are properly handled.""" with patch(paygen_build_lib, 'CreatePayloads') as create_payloads: create_payloads.side_effect = failures_lib.TestLabFailure stage = self.ConstructStage(channels=['foo', 'bar']) with patch(stage, '_HandleExceptionAsWarning') as warning_handler: warning_handler.return_value = (results_lib.Results.FORGIVEN, 'description', 0) stage.Run() # This proves the exception was turned into a warning. self.assertTrue(warning_handler.called)
def testPerformStageSigningFailed(self): """Test that PaygenStage works when signing works.""" with patch(release_stages.parallel, 'BackgroundTaskRunner') as background: queue = background().__enter__() stage = self.ConstructStage() with patch(stage, '_WaitForPushImage') as wait_push: with patch(stage, '_WaitForSigningResults') as wait_signing: wait_push.return_value = self.INSNS_URLS_PER_CHANNEL wait_signing.side_effect = release_stages.SignerFailure self.assertRaises(release_stages.SignerFailure, stage.PerformStage) # Ensure no work was queued up. self.assertFalse(queue.put.called)
def testPerformStageBackgroundFail(self): """Test that exception from background processes are properly handled.""" with patch(paygen_build_lib, 'CreatePayloads') as create_payloads: create_payloads.side_effect = failures_lib.TestLabFailure # This patch is only required for external builds with no config data. with patch(paygen_build_lib, 'ValidateBoardConfig'): stage = release_stages.PaygenStage( self._run, self._current_board, archive_stage=None, channels=['foo', 'bar']) with patch(stage, '_HandleExceptionAsWarning') as warning_handler: warning_handler.return_value = (results_lib.Results.FORGIVEN, 'description', 0) stage.Run() # This proves the exception was turned into a warning. self.assertTrue(warning_handler.called)
def testPerformStageNoChannels(self): """Test that PaygenStage works when signing works.""" with patch(release_stages.parallel, 'BackgroundTaskRunner') as background: queue = background().__enter__() stage = self.ConstructStage(channels=[]) stage.PerformStage() # Verify that we queue up work self.assertEqual(queue.put.call_args_list, [])
def testPerformStageSuccess(self): """Test that PaygenStage works when signing works.""" with patch(release_stages.parallel, 'BackgroundTaskRunner') as background: queue = background().__enter__() stage = self.ConstructStage() with patch(stage, '_WaitForPushImage') as wait_push: with patch(stage, '_WaitForSigningResults') as wait_signing: wait_push.return_value = self.INSNS_URLS_PER_CHANNEL wait_signing.side_effect = self.generateNotifyCalls(('stable', 'beta')) stage.PerformStage() # Verify that we queue up work self.assertEqual( queue.put.call_args_list, [mock.call(('stable', 'x86-mario', '0.0.1', False, False, False)), mock.call(('beta', 'x86-mario', '0.0.1', False, False, False))])
def testWaitForSigningResultsSuccessNothingSigned(self): """Test _WaitForSigningResults when there are no signed images.""" with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value mock_gs_ctx.Cat.return_value = self.SIGNER_RESULT notifier = mock.Mock() stage = self.ConstructStage() stage._WaitForSigningResults({}, notifier) self.assertEqual(notifier.mock_calls, []) self.assertEqual(mock_gs_ctx.Cat.mock_calls, [])
def testWaitForSigningResultsTimeout(self): """Test that _WaitForSigningResults reports timeouts correctly.""" with patch(release_stages.timeout_util, 'WaitForSuccess') as mock_wait: mock_wait.side_effect = timeout_util.TimeoutError notifier = mock.Mock() stage = self.ConstructStage() self.assertRaises(release_stages.SignerResultsTimeout, stage._WaitForSigningResults, {'chan1': ['chan1_uri1']}, notifier) self.assertEqual(notifier.mock_calls, [])
def testWaitForSigningResultsSuccessNoNotifier(self): """Test that _WaitForSigningResults works when signing works.""" results = ['chan1_uri1.json', 'chan1_uri2.json', 'chan2_uri1.json'] with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value mock_gs_ctx.Cat.return_value = self.SIGNER_RESULT stage = self.ConstructStage() stage._WaitForSigningResults(self.INSNS_URLS_PER_CHANNEL, None) for result in results: mock_gs_ctx.Cat.assert_any_call(result)
def testCheckForResultsMalformedJson(self): """Verify _CheckForResults handles unexpected Json values.""" with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value mock_gs_ctx.Cat.return_value = '{' notifier = mock.Mock() stage = self.ConstructStage() self.assertFalse( stage._CheckForResults(mock_gs_ctx, self.INSNS_URLS_PER_CHANNEL, notifier)) self.assertEqual(stage.signing_results, {'chan1': {}, 'chan2': {}}) self.assertEqual(notifier.mock_calls, [])
def testPerformStageUnknownBoard(self): """Test that PaygenStage exits when an unknown board is specified.""" self._current_board = 'unknown-board-name' badBoardException = paygen_build_lib.BoardNotConfigured(self._current_board) # This patch is only required for external builds with no config data. with patch(paygen_build_lib, 'ValidateBoardConfig') as validate_boards: validate_boards.side_effect = badBoardException stage = self.ConstructStage() self.assertRaises(release_stages.PaygenNoPaygenConfigForBoard, stage.PerformStage)
def testCheckForResultsSuccessNoChannels(self): """Test that _CheckForResults works when there is nothing to check for.""" with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value notifier = mock.Mock() stage = self.ConstructStage() # Ensure we find that we are ready if there are no channels to look for. self.assertTrue(stage._CheckForResults(mock_gs_ctx, {}, notifier)) # Ensure we didn't contact GS while checking for no channels. self.assertFalse(mock_gs_ctx.Cat.called) self.assertEqual(notifier.mock_calls, [])
def testCheckForResultsSuccess(self): """Test that _CheckForResults works when signing works.""" with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value mock_gs_ctx.Cat.return_value = self.SIGNER_RESULT notifier = mock.Mock() stage = self.ConstructStage() self.assertTrue( stage._CheckForResults(mock_gs_ctx, self.INSNS_URLS_PER_CHANNEL, notifier)) self.assertEqual( notifier.mock_calls, [mock.call('chan1'), mock.call('chan2')])
def testCheckForResultsSuccess(self): """Test that _CheckForResults works when signing works.""" with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value mock_gs_ctx.Cat.return_value = self.SIGNER_RESULT notifier = mock.Mock() stage = self.ConstructStage() self.assertTrue( stage._CheckForResults(mock_gs_ctx, self.INSNS_URLS_PER_CHANNEL, notifier)) self.assertEqual(notifier.mock_calls, [mock.call('chan1'), mock.call('chan2')])
def testCheckForResultsMalformedJson(self): """Verify _CheckForResults handles unexpected Json values.""" with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value mock_gs_ctx.Cat.return_value = '{' notifier = mock.Mock() stage = self.ConstructStage() self.assertFalse( stage._CheckForResults(mock_gs_ctx, self.INSNS_URLS_PER_CHANNEL, notifier)) self.assertEqual(stage.signing_results, { 'chan1': {}, 'chan2': {} }) self.assertEqual(notifier.mock_calls, [])
def testCheckForResultsFailed(self): """Verify _CheckForResults handles missing signer results.""" with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value mock_gs_ctx.Cat.side_effect = release_stages.gs.GSNoSuchKey notifier = mock.Mock() stage = self.ConstructStage() self.assertFalse( stage._CheckForResults(mock_gs_ctx, self.INSNS_URLS_PER_CHANNEL, notifier)) self.assertEqual(stage.signing_results, { 'chan1': {}, 'chan2': {} }) self.assertEqual(notifier.mock_calls, [])
def testPerformStageSuccess(self): """Test that PaygenStage works when signing works.""" with patch(release_stages.parallel, 'BackgroundTaskRunner') as background: queue = background().__enter__() stage = self.ConstructStage(channels=['stable', 'beta']) stage.PerformStage() # Verify that we queue up work self.assertEqual( queue.put.call_args_list, [mock.call(('stable', 'x86-alex-he', '0.0.1', False, False, False, True)), mock.call(('beta', 'x86-alex-he', '0.0.1', False, False, False, True))])
def testPerformStageTrybot(self): """Test the PerformStage alternate behavior for trybot runs.""" with patch(release_stages.parallel, 'BackgroundTaskRunner') as background: queue = background().__enter__() # The stage is constructed differently for trybots, so don't use # ConstructStage. stage = self.ConstructStage(channels=['foo', 'bar']) stage.PerformStage() # Notice that we didn't put anything in _wait_for_channel_signing, but # still got results right away. self.assertEqual(queue.put.call_args_list, [ mock.call(('foo', 'auron-yuna', '0.0.1', False, False, False, True)), mock.call(('bar', 'auron-yuna', '0.0.1', False, False, False, True)) ])
def testWaitForSigningResultsMalformedJson(self): """Test _WaitForSigningResults when invalid Json is received..""" with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value mock_gs_ctx.Cat.return_value.output = "{" notifier = mock.Mock() stage = self.ConstructStage() self.assertRaises(release_stages.MalformedResultsException, stage._WaitForSigningResults, self.INSNS_URLS_PER_CHANNEL, notifier) self.assertEqual(notifier.mock_calls, []) self.assertEqual(mock_gs_ctx.Cat.mock_calls, [mock.call('chan1_uri1.json')])
def testPerformStageSuccess(self): """Test that PaygenStage works when signing works.""" with patch(release_stages.parallel, 'BackgroundTaskRunner') as background: queue = background().__enter__() stage = self.ConstructStage(channels=['stable', 'beta']) stage.PerformStage() # Verify that we queue up work self.assertEqual(queue.put.call_args_list, [ mock.call(('stable', 'x86-alex-he', '0.0.1', False, False, False, True)), mock.call(('beta', 'x86-alex-he', '0.0.1', False, False, False, True)) ])
def testWaitForSigningResultsSuccess(self): """Test that _WaitForSigningResults works when signing works.""" results = ['chan1_uri1.json', 'chan1_uri2.json', 'chan2_uri1.json'] with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value mock_gs_ctx.Cat.return_value = self.SIGNER_RESULT notifier = mock.Mock() stage = self.ConstructStage() stage._WaitForSigningResults(self.INSNS_URLS_PER_CHANNEL, notifier) self.assertEqual( notifier.mock_calls, [mock.call('chan1'), mock.call('chan2')]) for result in results: mock_gs_ctx.Cat.assert_any_call(result)
def testWaitForSigningResultsSuccess(self): """Test that _WaitForSigningResults works when signing works.""" results = ['chan1_uri1.json', 'chan1_uri2.json', 'chan2_uri1.json'] with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value mock_gs_ctx.Cat.return_value.output = self.SIGNER_RESULT notifier = mock.Mock() stage = self.ConstructStage() stage._WaitForSigningResults(self.INSNS_URLS_PER_CHANNEL, notifier) self.assertEqual(notifier.mock_calls, [mock.call('chan1'), mock.call('chan2')]) for result in results: mock_gs_ctx.Cat.assert_any_call(result)
def testPerformStageTrybot(self): """Test the PerformStage alternate behavior for trybot runs.""" with patch(release_stages.parallel, 'BackgroundTaskRunner') as background: queue = background().__enter__() # The stage is constructed differently for trybots, so don't use # ConstructStage. stage = self.ConstructStage(channels=['foo', 'bar']) stage.PerformStage() # Notice that we didn't put anything in _wait_for_channel_signing, but # still got results right away. self.assertEqual( queue.put.call_args_list, [mock.call(('foo', 'x86-alex-he', '0.0.1', False, False, False, True)), mock.call(('bar', 'x86-alex-he', '0.0.1', False, False, False, True))])
def testRunPaygenInParallelWithUnifiedBuild(self): self._run.config.models = [ config_lib.ModelTestConfig('model1', 'model1', ['au']), config_lib.ModelTestConfig('model2', 'model1', ['au']) ] # Have to patch and verify that the PaygenTestStage is created. stage = self.ConstructStage() with patch(parallel, 'RunParallelSteps') as parallel_tests: stage._RunPaygenInProcess('foo', 'foo-board', 'foo-version', True, False, False, skip_duts_check=False) parallel_tests.assert_called_once_with([mock.ANY, mock.ANY])
def testRunPaygenInProcess(self): """Test that _RunPaygenInProcess works in the simple case.""" with patch(paygen_build_lib, 'CreatePayloads') as create_payloads: # Call the method under test. stage = self.ConstructStage() stage._RunPaygenInProcess('foo', 'foo-board', 'foo-version', False, False, False) # Ensure arguments are properly converted and passed along. create_payloads.assert_called_with(gspaths.Build(version='foo-version', board='foo-board', channel='foo-channel'), dry_run=False, work_dir=mock.ANY, run_parallel=True, run_on_builder=True, skip_delta_payloads=False, disable_tests=False)
def testCollectLLVMMetadataRaisesOnAnInvalidVersionString(self): stage = self.ConstructStage() def equery_uses(): return ' - + llvm_pgo_generate :' def clang_version(): valid_version_lines = self._VALID_CLANG_VERSION_STRING.splitlines() valid_version_lines[0] = 'clang version 8.0.1\n' return ''.join(valid_version_lines) with patch(cros_build_lib, 'run') as run_command: run_command.side_effect = self._MetadataMultiDispatch( equery_uses_fn=equery_uses, clang_version_fn=clang_version) with self.assertRaises(ValueError) as raised: stage._CollectLLVMMetadata() self.assertIn('version string', str(raised.exception))
def testWaitForSigningResultsFailure(self): """Test _WaitForSigningResults when the signers report an error.""" with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value mock_gs_ctx.Cat.return_value.output = """ { "status": { "status": "failed" }, "board": "link", "keyset": "link-mp-v4", "type": "recovery", "channel": "stable" } """ notifier = mock.Mock() stage = self.ConstructStage() self.assertRaises(release_stages.SignerFailure, stage._WaitForSigningResults, {'chan1': ['chan1_uri1']}, notifier) self.assertEqual(notifier.mock_calls, []) self.assertEqual(mock_gs_ctx.Cat.mock_calls, [mock.call('chan1_uri1.json')])
def testRunPaygenInProcessComplex(self): """Test that _RunPaygenInProcess with arguments that are more unusual.""" with patch(paygen_build_lib, 'CreatePayloads') as create_payloads: # Call the method under test. # Use release tools channel naming, and a board name including a variant. stage = self.ConstructStage() stage._RunPaygenInProcess('foo-channel', 'foo-board-variant', 'foo-version', True, True, True) # Ensure arguments are properly converted and passed along. create_payloads.assert_called_with( gspaths.Build(version='foo-version', board='foo-board-variant', channel='foo-channel'), dry_run=True, work_dir=mock.ANY, run_parallel=True, run_on_builder=True, skip_delta_payloads=True, disable_tests=True)
def testWaitForSigningResultsFailure(self): """Test _WaitForSigningResults when the signers report an error.""" with patch(release_stages.gs, 'GSContext') as mock_gs_ctx_init: mock_gs_ctx = mock_gs_ctx_init.return_value mock_gs_ctx.Cat.return_value = """ { "status": { "status": "failed" }, "board": "link", "keyset": "link-mp-v4", "type": "recovery", "channel": "stable" } """ notifier = mock.Mock() stage = self.ConstructStage() self.assertRaisesStringifyable(release_stages.SignerFailure, stage._WaitForSigningResults, {'chan1': ['chan1_uri1']}, notifier) # Ensure we didn't notify anyone of success. self.assertEqual(notifier.mock_calls, []) self.assertEqual(mock_gs_ctx.Cat.mock_calls, [mock.call('chan1_uri1.json')])
def testCollectLLVMMetadataRaisesIfClangIsntPGOGenerated(self): stage = self.ConstructStage() def clang_version(): return self._VALID_CLANG_VERSION_STRING with patch(cros_build_lib, 'run') as run_command: for uses in ['', ' - - llvm_pgo_generate :']: def equery_uses(): # We're using a loop var on purpose; this function should die by the # end of the current iteration. # pylint: disable=cell-var-from-loop return uses run_command.side_effect = self._MetadataMultiDispatch( equery_uses_fn=equery_uses, clang_version_fn=clang_version) with self.assertRaises(ValueError) as raised: stage._CollectLLVMMetadata() self.assertIn('pgo_generate flag', str(raised.exception))
def testRunPaygenInProcess(self): """Test that _RunPaygenInProcess works in the simple case.""" # Have to patch and verify that the PaygenTestStage is created. stage = self.ConstructStage() with patch(paygen_build_lib, 'ScheduleAutotestTests') as sched_tests: # Call the method under test. stage._RunPaygenInProcess( 'foo', 'foo-board', 'foo-version', True, False, False, skip_duts_check=False) # Ensure that PaygenTestStage is created and schedules the test suite # with the correct arguments. sched_tests.assert_called_once_with( 'foo-suite-name', 'foo-archive-board', None, 'foo-archive-build', False, True, [], constants.ENV_AUTOTEST, job_keyvals=mock.ANY) # Ensure arguments are properly converted and passed along. self.paygenBuildMock.assert_called_with( gspaths.Build( version='foo-version', board='foo-board', channel='foo-channel', bucket=gspaths.ChromeosReleases.BUCKET), mock.ANY, work_dir=mock.ANY, site_config=stage._run.site_config, dry_run=True, skip_delta_payloads=False, skip_duts_check=False)
def testRunPaygenInParallelWithUnifiedBuild(self): # payload_config1 defines applicable_models as model1 and model3. # model3 does not have au enabled but gets scheduled since it has type FSI. # payload_config2 has type OMAHA so gets scheduled on model1 and model2 # (all models with au enabled). So we should get 4 parallel runs total. self._run.config.models = [ config_lib.ModelTestConfig('model1', 'model1', ['au']), config_lib.ModelTestConfig('model2', 'model1', ['au']), config_lib.ModelTestConfig('model3', 'model1') ] # Have to patch and verify that the PaygenTestStage is created. stage = self.ConstructStage() with patch(parallel, 'RunParallelSteps') as parallel_tests: stage._RunPaygenInProcess('foo', 'foo-board', 'foo-version', True, False, False, skip_duts_check=False) parallel_tests.assert_called_once_with( [mock.ANY, mock.ANY, mock.ANY, mock.ANY])
def testPerformStageSuccess(self): """Test that PaygenStage works when signing works.""" with patch(release_stages.parallel, 'BackgroundTaskRunner') as background: queue = background().__enter__() channels = ['stable', 'beta'] stage = self.ConstructStage(channels=channels) stage.PerformStage() metadata_channels = self._run.attrs.metadata.GetValue('channels') self.assertEqual(','.join(channels), metadata_channels) # Verify that we validate with the board name in release name space. self.assertEqual(self.validateMock.call_args_list, [mock.call('auron-yuna')]) # Verify that we queue up work self.assertEqual(queue.put.call_args_list, [ mock.call(('stable', 'auron-yuna', '0.0.1', False, False, False, True)), mock.call( ('beta', 'auron-yuna', '0.0.1', False, False, False, True)) ])
def _BuildImages(self, *args, **kwargs): with patches(patch(os, 'symlink'), patch(os, 'readlink', return_value='foo.txt')): self.backup['_BuildImages'](*args, **kwargs)
def BuildAutotestTarballs(self, *args, **kwargs): with patches( patch(commands, 'BuildTarball'), patch(commands, 'FindFilesWithPattern', return_value=['foo.txt'])): self.backup['BuildAutotestTarballs'](*args, **kwargs)
def _Run(self, dir_exists): """Helper for running the build.""" with patch(os.path, 'isdir', return_value=dir_exists): self.RunStage()
def BuildTastTarball(self, *args, **kwargs): with patch(commands, 'BuildTarball'): self.backup['BuildTastTarball'](*args, **kwargs)
def _GenerateAuZip(self, *args, **kwargs): with patch(path_util, 'ToChrootPath', return_value='/chroot/path'): self.backup['_GenerateAuZip'](*args, **kwargs)
def UploadArtifact(self, *args, **kwargs): with patch(commands, 'ArchiveFile', return_value='foo.txt'): with patch(commands, 'UploadArchivedFile'): self.backup['UploadArtifact'](*args, **kwargs)
def _BuildImages(self, *args, **kwargs): with patches( patch(os, 'symlink'), patch(os, 'readlink', return_value='foo.txt')): self.backup['_BuildImages'](*args, **kwargs)