def testListSummaries_stateFilter(self): # Helper to fetch test runs filtered by state def FetchTestRuns(*args): state_filters = '&'.join(['state=' + str(state) for state in args]) res = self.app.get('/_ah/api/mtt/v1/test_runs?' + state_filters) self.assertEqual('200 OK', res.status) return protojson.decode_message(messages.TestRunSummaryList, res.body).test_runs test = self._createMockTest(name='foo') pending_run = self._createMockTestRunSummaries( test=test, state=ndb_models.TestRunState.PENDING) pending_msg = messages.Convert(pending_run[0], messages.TestRunSummary) completed_run_1 = self._createMockTestRunSummaries( test=test, state=ndb_models.TestRunState.COMPLETED) completed_msg_1 = messages.Convert(completed_run_1[0], messages.TestRunSummary) completed_run_2 = self._createMockTestRunSummaries( test=test, state=ndb_models.TestRunState.COMPLETED) completed_msg_2 = messages.Convert(completed_run_2[0], messages.TestRunSummary) # Can search for multiple states self.assertEqual([completed_msg_2, completed_msg_1, pending_msg], FetchTestRuns(ndb_models.TestRunState.PENDING, ndb_models.TestRunState.COMPLETED)) # Can search for a single state self.assertEqual([pending_msg], FetchTestRuns(ndb_models.TestRunState.PENDING)) self.assertEqual([completed_msg_2, completed_msg_1], FetchTestRuns(ndb_models.TestRunState.COMPLETED)) # Can search for a state with no runs self.assertEqual([], FetchTestRuns(ndb_models.TestRunState.ERROR))
def testGetMetadata_ancestry(self, mock_get_request): mock_get_request.return_value = mock.MagicMock() test = self._createMockTest() # create hierarchy of test_runs child, parent, grandparent = self._createMockTestRuns(test=test, count=3) child.prev_test_run_key = parent.key child.prev_test_context = ndb_models.TestContextObj() child.put() parent.prev_test_run_key = grandparent.key parent.prev_test_context = ndb_models.TestContextObj() parent.put() res = self.app.get('/_ah/api/mtt/v1/test_runs/%s/metadata' % child.key.id()) # metadata is sent back w/ ordered ancestry information metadata = protojson.decode_message(messages.TestRunMetadataList, res.body) expected = messages.TestRunMetadataList( test_runs=[ messages.TestRunMetadata( test_run=messages.Convert(child, messages.TestRun)), messages.TestRunMetadata( test_run=messages.Convert(parent, messages.TestRun)), messages.TestRunMetadata( test_run=messages.Convert(grandparent, messages.TestRun)) ], server_version=env.VERSION) self.assertEqual(expected, metadata)
def New(self, request): """Creates a new test run. Body: Test run request data """ labels = request.labels test_run_config = mtt_messages.Convert(request.test_run_config, ndb_models.TestRunConfig) if not test_run_config.device_specs: if not test_run_config.run_target: raise endpoints.BadRequestException( 'test_run_config.(device_specs or run_target) must be set') # For old run targets are one or more device serials. Convert them to # device specs for backward compatibility test_run_config.device_specs = mtt_messages.ConvertToDeviceSpecs( test_run_config.run_target) test_run_config.run_target = None # start test run test_run = test_kicker.CreateTestRun( labels=labels, test_run_config=test_run_config, rerun_context=request.rerun_context, rerun_configs=mtt_messages.ConvertList(request.rerun_configs, ndb_models.TestRunConfig)) return mtt_messages.Convert(test_run, mtt_messages.TestRun)
def testGetMetadata_remoteAncestry(self, mock_open_file): # create hierarchy of test_runs test = self._createMockTest() child, parent = self._createMockTestRuns(test=test, count=2) with tempfile.NamedTemporaryFile(suffix='.zip') as tmp_stream: # write parent metadata to a temporary zip file with zipfile.ZipFile(tmp_stream, 'w') as context_file: res = self.app.get('/_ah/api/mtt/v1/test_runs/%s/metadata' % parent.key.id()) context_file.writestr('mtt.json', res.body) tmp_stream.seek(0) mock_open_file.return_value = tmp_stream # mark child as a remote return child.prev_test_context = ndb_models.TestContextObj(test_resources=[ ndb_models.TestResourceObj(name='mtt.json', url='url') ]) child.put() res = self.app.get('/_ah/api/mtt/v1/test_runs/%s/metadata' % child.key.id()) # metadata is sent back w/ ordered ancestry information metadata = protojson.decode_message(messages.TestRunMetadataList, res.body) expected = messages.TestRunMetadataList( test_runs=[ messages.TestRunMetadata( test_run=messages.Convert(child, messages.TestRun)), messages.TestRunMetadata( test_run=messages.Convert(parent, messages.TestRun)) ], server_version=env.VERSION) self.assertEqual(expected, metadata)
def testListSummaries_filterReruns(self): test = self._createMockTest() test_run = self._createMockTestRunSummaries(test=test)[0] res = self.app.get('/_ah/api/mtt/v1/test_runs?prev_test_run_id=%s' % test_run.key.id()) self.assertEqual('200 OK', res.status) test_run_msg = protojson.decode_message(messages.TestRunSummaryList, res.body).test_runs self.assertEqual(test_run_msg, []) test_run_key = messages.ConvertToKey(ndb_models.TestRun, test_run.key.id()) retry_run = self._createMockTestRunSummaries( test=test, prev_test_run_key=test_run_key)[0] retry_run_msg = messages.Convert(retry_run, messages.TestRunSummary) separate_retry = self._createMockTestRunSummaries( test=test, prev_test_run_key=test_run_key)[0] separate_retry_msg = messages.Convert(separate_retry, messages.TestRunSummary) res = self.app.get('/_ah/api/mtt/v1/test_runs?prev_test_run_id=%s' % test_run.key.id()) test_run_msg = protojson.decode_message(messages.TestRunSummaryList, res.body).test_runs self.assertEqual(test_run_msg[0].id, separate_retry_msg.id) self.assertEqual(test_run_msg[1].id, retry_run_msg.id)
def testConvert_TestResourceDef(self): obj = ndb_models.TestResourceDef( name='foo', default_download_url='bar', decompress=True, decompress_dir='dir', params=ndb_models.TestResourceParameters( decompress_files=['file'])) msg = messages.TestResourceDef( name='foo', default_download_url='bar', decompress=True, decompress_dir='dir', params=messages.TestResourceParameters(decompress_files=['file'])) self.assertSameTestResourceDef( obj, messages.Convert(obj, messages.TestResourceDef)) self.assertSameTestResourceDef( messages.Convert(msg, ndb_models.TestResourceDef), msg) obj = ndb_models.TestResourceDef(name='foo') msg = messages.TestResourceDef(name='foo') self.assertSameTestResourceDef( obj, messages.Convert(obj, messages.TestResourceDef)) self.assertSameTestResourceDef( messages.Convert(msg, ndb_models.TestResourceDef), msg)
def Update(self, request): """Updates the server's node configuration. Body: Node configuration data """ node_config = messages.Convert(request, ndb_models.NodeConfig, messages.NodeConfig) node_config.put() return messages.Convert(node_config, messages.NodeConfig)
def Create(self, request): """Creates a test suite. Body: Test suite data """ test = mtt_messages.Convert(request, ndb_models.Test, from_cls=mtt_messages.Test) test.put() return mtt_messages.Convert(test, mtt_messages.Test)
def _ConfigSetConverter(obj): return _ConfigSetMessage( node_config=messages.Convert(obj.node_config, messages.NodeConfig), build_channels=messages.ConvertList(obj.build_channels, messages.BuildChannelConfig), device_actions=messages.ConvertList(obj.device_actions, messages.DeviceAction), test_run_actions=messages.ConvertList(obj.test_run_actions, messages.TestRunAction), tests=messages.ConvertList(obj.tests, messages.Test), info=messages.Convert(obj.info, messages.ConfigSetInfo))
def _ConfigSetMessageConverter(msg): return ConfigSet( node_config=messages.Convert(msg.node_config, ndb_models.NodeConfig), build_channels=messages.ConvertList(msg.build_channels, ndb_models.BuildChannelConfig), device_actions=messages.ConvertList(msg.device_actions, ndb_models.DeviceAction), test_run_actions=messages.ConvertList(msg.test_run_actions, ndb_models.TestRunAction), tests=messages.ConvertList(msg.tests, ndb_models.Test), info=messages.Convert(msg.info, ndb_models.ConfigSetInfo))
def Update(self, request): """Updates the server's private node configuration. Body: Private node configuration data """ private_node_config = messages.Convert(request, ndb_models.PrivateNodeConfig, messages.PrivateNodeConfig) private_node_config.put() return messages.Convert(private_node_config, messages.PrivateNodeConfig)
def Create(self, request): """Creates a device action. Body: Device action data """ device_action = mtt_messages.Convert( request, ndb_models.DeviceAction, from_cls=mtt_messages.DeviceAction) device_action.put() return mtt_messages.Convert(device_action, mtt_messages.DeviceAction)
def Create(self, request): """Creates a test plan. Body: Test plan data """ test_plan = mtt_messages.Convert(request, ndb_models.TestPlan, from_cls=mtt_messages.TestPlan) _ValidateTestPlan(test_plan) test_plan.key = None test_plan.put() test_scheduler.ScheduleTestPlanCronJob(test_plan.key.id()) return mtt_messages.Convert(test_plan, mtt_messages.TestPlan)
def testGetMetadata_returnsCompletedAttempts(self, mock_get_request): # request w/ RUNNING and COMPLETED attempts mock_request = mock.MagicMock() mock_get_request.return_value = mock_request running_attempt = self._createAttempt(CommandState.RUNNING) completed_attempt = self._createAttempt(CommandState.COMPLETED) mock_request.command_attempts = [running_attempt, completed_attempt] test = self._createMockTest() test_run = self._createMockTestRuns(test=test)[0] test_run.request_id = 'request' test_run.put() res = self.app.get( '/_ah/api/mtt/v1/test_runs/%s/metadata' % test_run.key.id()) # metadata is sent back w/ only COMPLETED attempts metadata = protojson.decode_message(messages.TestRunMetadataList, res.body) expected = messages.TestRunMetadataList( test_runs=[ messages.TestRunMetadata( test_run=messages.Convert(test_run, messages.TestRun), command_attempts=[completed_attempt]) ], server_version=env.VERSION) self.assertEqual(expected, metadata)
def testGet(self): """Tests test_plans.get API.""" test_plan = _CreateMockTestPlan('foo') res = self.app.get('/_ah/api/mtt/v1/test_plans/%s' % test_plan.key.id()) msg = protojson.decode_message(messages.TestPlan, res.body) self.assertEqual(messages.Convert(test_plan, messages.TestPlan), msg)
def testList(self): device_actions = [self._CreateDeviceAction()] res = self.app.get('/_ah/api/mtt/v1/device_actions') res_msg = protojson.decode_message(messages.DeviceActionList, res.body) for obj, msg in zip(device_actions, res_msg.device_actions): self.assertEqual(messages.Convert(obj, messages.DeviceAction), msg)
def testNew_withRunTarget(self, mock_run_test): test = self._createMockTest() request = { 'labels': ['label'], 'test_run_config': { 'test_id': str(test.key.id()), 'cluster': 'cluster', 'device_specs': ['foo', 'bar'], 'run_count': 10, 'shard_count': 100, 'max_retry_on_test_failures': 1000, 'test_resource_objs': [ { 'name': 'bar', 'url': 'bar_url' }, { 'name': 'zzz', 'url': 'zzz_url' }, ], }, } test_run = ndb_models.TestRun( test=test, labels=['label'], test_run_config=ndb_models.TestRunConfig( test_key=test.key, cluster='cluster', device_specs=['foo', 'bar'], run_count=10, shard_count=100, max_retry_on_test_failures=1000)) test_run.put() mock_run_test.return_value = test_run res = self.app.post_json('/_ah/api/mtt/v1/test_runs', request) mock_run_test.assert_called_with( labels=['label'], test_run_config=ndb_models.TestRunConfig( test_key=test.key, cluster='cluster', device_specs=['foo', 'bar'], run_count=10, shard_count=100, max_retry_on_test_failures=1000, test_resource_objs=[ ndb_models.TestResourceObj(name='bar', url='bar_url'), ndb_models.TestResourceObj(name='zzz', url='zzz_url'), ]), rerun_context=None, rerun_configs=[] ) self.assertEqual('200 OK', res.status) test_run_msg = protojson.decode_message(messages.TestRun, res.body) self.assertEqual( messages.Convert(test_run, messages.TestRun), test_run_msg)
def Get(self, request): """Fetches a build channel. Parameters: build_channel_id: Build channel ID """ build_channel = self._GetBuildChannel(request.build_channel_id) return mtt_messages.Convert(build_channel.config, mtt_messages.BuildChannelConfig)
def Update(self, request): """Updates a test suite. Body: Test suite data Parameters: test_id: Test ID """ test = mtt_messages.ConvertToKey(ndb_models.Test, request.test_id).get() if not test: raise endpoints.NotFoundException('no test found for ID %s' % request.test_id) request.id = request.test_id test = mtt_messages.Convert(request, ndb_models.Test, mtt_messages.Test) test.put() return mtt_messages.Convert(test, mtt_messages.Test)
def Update(self, request): """Updates an existing device action. Body: Device action data Parameters: device_action_id: Device action ID """ device_action = mtt_messages.ConvertToKey( ndb_models.DeviceAction, request.device_action_id).get() if not device_action: raise endpoints.NotFoundException( 'no device action found for ID %s' % request.device_action_id) request.id = request.device_action_id device_action = mtt_messages.Convert(request, ndb_models.DeviceAction, mtt_messages.DeviceAction) device_action.put() return mtt_messages.Convert(device_action, mtt_messages.DeviceAction)
def testListSummaries_filter(self): # Helper to fetch filtered test runs and verify/parse response. def FetchTestRuns(*args): filters = '&'.join(['filter_query=' + query for query in args]) res = self.app.get('/_ah/api/mtt/v1/test_runs?' + filters) self.assertEqual('200 OK', res.status) return protojson.decode_message(messages.TestRunSummaryList, res.body).test_runs # Create placeholder test runs with a variety of property values runs1 = self._createMockTestRunSummaries( test=self._createMockTest(name='foo'), labels=['bar'], device_specs=['baz']) msg1 = messages.Convert(runs1[0], messages.TestRunSummary) runs2 = self._createMockTestRunSummaries( test=self._createMockTest(), labels=['common'], test_devices=[ ndb_models.TestDeviceInfo(build_id='qux', product='spam') ]) msg2 = messages.Convert(runs2[0], messages.TestRunSummary) runs3 = self._createMockTestRunSummaries( test=self._createMockTest(name='common'), test_package_info=ndb_models.TestPackageInfo( name='ham', version='eggs')) msg3 = messages.Convert(runs3[0], messages.TestRunSummary) # Can search using individual properties self.assertEqual([], FetchTestRuns('unknown')) self.assertEqual([msg1], FetchTestRuns('foo')) # test name self.assertEqual([msg1], FetchTestRuns('bar')) # label self.assertEqual([msg1], FetchTestRuns('baz')) # run target self.assertEqual([msg2], FetchTestRuns('qux')) # device build ID self.assertEqual([msg2], FetchTestRuns('spam')) # device product self.assertEqual([msg3], FetchTestRuns('ham')) # test package name self.assertEqual([msg3], FetchTestRuns('eggs')) # test package version self.assertEqual([msg3, msg2], FetchTestRuns('common')) # Can search for union of multiple values self.assertEqual([msg1], FetchTestRuns('foo', 'bar', 'baz')) self.assertEqual([msg2], FetchTestRuns('common', 'qux', 'spam')) self.assertEqual([msg3], FetchTestRuns('common', 'ham', 'eggs')) self.assertEqual([], FetchTestRuns('foo', 'common'))
def Encode(config_set): """Serializes MTT configuration. Args: config_set: MTT configuration set Returns: Configuration set serialized as a YAML string """ msg = messages.Convert(config_set, _ConfigSetMessage) return _JsonToYaml(protojson.encode_message(msg)) # pytype: disable=module-attr
def testGet(self): device_action = self._CreateDeviceAction() device_action_id = str(device_action.key.id()) res = self.app.get('/_ah/api/mtt/v1/device_actions/%s' % device_action_id) msg = protojson.decode_message(messages.DeviceAction, res.body) self.assertEqual( messages.Convert(device_action, messages.DeviceAction), msg)
def Get(self, request): """Fetches a test run. Parameters: test_run_id: Test run ID """ test_run = ndb_models.TestRun.get_by_id(request.test_run_id) if not test_run: raise endpoints.NotFoundException('no test run found for ID %s' % request.test_run_id) return mtt_messages.Convert(test_run, mtt_messages.TestRun)
def Update(self, request): """Updates a test plan. Body: Test plan data Parameters: test_plan_id: Test plan ID """ test_plan_key = mtt_messages.ConvertToKey(ndb_models.TestPlan, request.test_plan_id) if not test_plan_key.get(): raise endpoints.NotFoundException() test_plan = mtt_messages.Convert(request, ndb_models.TestPlan, from_cls=mtt_messages.TestPlan) _ValidateTestPlan(test_plan) test_plan.key = test_plan_key test_plan.put() test_scheduler.ScheduleTestPlanCronJob(test_plan.key.id()) return mtt_messages.Convert(test_plan, mtt_messages.TestPlan)
def testUpdate(self): device_action = self._CreateDeviceAction() device_action_id = str(device_action.key.id()) data = {'id': device_action_id, 'name': 'bar'} res = self.app.put_json( '/_ah/api/mtt/v1/device_actions/%s' % device_action_id, data) device_action = device_action.key.get() msg = protojson.decode_message(messages.DeviceAction, res.body) self.assertEqual( messages.Convert(device_action, messages.DeviceAction), msg) self.assertEqual(data['name'], device_action.name)
def _GetMetadata(self, test_run): """Get the metadata for a test run.""" completed_attempts = [] if test_run.request_id: request = tfc_client.GetRequest(test_run.request_id) attempts = request.command_attempts or [] completed_attempts = [ attempt for attempt in attempts if IsFinalCommandState(attempt.state) ] return mtt_messages.TestRunMetadata( test_run=mtt_messages.Convert(test_run, mtt_messages.TestRun), command_attempts=completed_attempts)
def GetLocalConfigSetInfos(): """Get list of config infos imported to the current MTT instance. Returns: A list of mtt_messages.ConfigSetInfo """ query = ndb_models.ConfigSetInfo.query().order( ndb_models.ConfigSetInfo.name) infos = query.fetch() info_messages = [] for info in infos: info_message = mtt_messages.Convert(info, mtt_messages.ConfigSetInfo) info_message.status = ndb_models.ConfigSetStatus.IMPORTED info_messages.append(info_message) return info_messages
def Get(self, request): """Fetches a device action. Parameters: device_action_id: Device action ID """ if request.device_action_id == '0': device_action = ndb_models.DeviceAction(name='') else: device_action = mtt_messages.ConvertToKey( ndb_models.DeviceAction, request.device_action_id).get() if not device_action: raise endpoints.NotFoundException('No device action with ID %s' % request.device_action_id) return mtt_messages.Convert(device_action, mtt_messages.DeviceAction)
def testConvert_Test(self): obj = ndb_models.Test( name='name', test_resource_defs=[ ndb_models.TestResourceDef(name='foo', default_download_url='bar') ], command='command', env_vars=[ ndb_models.NameValuePair(name='name', value='value'), ], output_file_patterns=['pattern_1', 'pattern_2'], setup_scripts=['script_1', 'script_2', 'script_3']) msg = messages.Convert(obj, messages.Test) self.assertIsInstance(msg, messages.Test) self.assertSameTest(obj, msg)