class TestPlan(ndb.Model): """A test plan. Attributes: name: a test resource name. labels: list of strings users can use to categorize test runs and plans. cron_exp: a CRON expression. cron_exp_timezone: timezone to use when processing cron expression. test_run_configs: a list of test run configs. test_resource_pipes: a list of test resource pipes. before_device_action_keys: common before device actions for tests. test_run_action_refs: common test run actions to execute during tests. """ name = ndb.StringProperty(required=True) labels = ndb.StringProperty(repeated=True) cron_exp = ndb.StringProperty() cron_exp_timezone = ndb.StringProperty(default='UTC') test_run_configs = ndb.LocalStructuredProperty(TestRunConfig, repeated=True) test_resource_pipes = ndb.LocalStructuredProperty( TestResourcePipe, repeated=True) # TODO: Deprecated before_device_action_keys = ndb.KeyProperty( DeviceAction, repeated=True) # TODO: Deprecated test_run_action_refs = ndb.LocalStructuredProperty(TestRunActionRef, repeated=True) @classmethod def _post_delete_hook(cls, key, future): status = TestPlanStatus.query(ancestor=key).get() if status: status.key.delete()
class NodeConfig(ndb.Model): """A MTT node configuration. Attributes: env_vars: default environment vars. test_resource_default_download_urls: default download URLs for test resources. """ env_vars = ndb.LocalStructuredProperty(NameValuePair, repeated=True) test_resource_default_download_urls = ndb.LocalStructuredProperty( NameValuePair, repeated=True)
class TestRunConfig(ndb.Model): """A test run config. Attributes: test_key: a Test key. cluster: a cluster to run a test in. command: the command to run the test suite retry_command: the command to retry this test run device_specs: device requirements expressed in space-separated list of key-value pairs (e.g. "product:bramble sim_state:LOADED"). run_target: (deprecated) a run target. Only used when device_specs is empty. run_count: a run count. shard_count: a shard count. sharding_mode: a sharding mode. extra_args: a string containing extra arguments. retry_extra_args: extra arguments used when retrying. max_retry_on_test_failures: the max number of retry on test failure. queue_timeout_seconds: how long a test run can stay in QUEUED state before being cancelled invocation_timeout_seconds: the maximum time for each invocation to run. If an invocation(attempt) runs longer than a given timeout, it would be force stopped. output_idle_timeout_seconds: how long a test run's output can be idle before attempting recovery before_device_action_keys: device actions to execute before running a test. test_run_action_refs: test run actions to execute during a test. test_resource_objs: path to the files to use for test resources. use_parallel_setup: a flag on whether to setup devices in parallel. """ test_key = ndb.KeyProperty(kind=Test, required=True) cluster = ndb.StringProperty(required=True) command = ndb.StringProperty(required=True, default='') retry_command = ndb.StringProperty(required=True, default='') device_specs = ndb.StringProperty(repeated=True) run_target = ndb.StringProperty() run_count = ndb.IntegerProperty(required=True, default=1) shard_count = ndb.IntegerProperty(required=True, default=1) sharding_mode = ndb.EnumProperty(ShardingMode, default=ShardingMode.RUNNER) extra_args = ndb.StringProperty() # TODO: Deprecated retry_extra_args = ndb.StringProperty() # TODO: Deprecated max_retry_on_test_failures = ndb.IntegerProperty() queue_timeout_seconds = ndb.IntegerProperty( required=True, default=env.DEFAULT_QUEUE_TIMEOUT_SECONDS) invocation_timeout_seconds = ndb.IntegerProperty( default=env.DEFAULT_INVOCATION_TIMEOUT_SECONDS) output_idle_timeout_seconds = ndb.IntegerProperty( default=env.DEFAULT_OUTPUT_IDLE_TIMEOUT_SECONDS) before_device_action_keys = ndb.KeyProperty(DeviceAction, repeated=True) test_run_action_refs = ndb.LocalStructuredProperty(TestRunActionRef, repeated=True) test_resource_objs = ndb.LocalStructuredProperty(TestResourceObj, repeated=True) use_parallel_setup = ndb.BooleanProperty(default=True)
class TestContextObj(ndb.Model): """A test context object. The "Obj" suffix was added to avoid name collision with TFC TestContext. Attributes: command_line: a command line. env_vars: environment variables. test_resources: a list of TestResourceObj objects. """ command_line = ndb.StringProperty() env_vars = ndb.LocalStructuredProperty(NameValuePair, repeated=True) test_resources = ndb.LocalStructuredProperty(TestResourceObj, repeated=True)
class TestResourceDef(ndb.Model): """A test resource definition. Attributes: name: a test resource name. default_download_url: a default download URL. test_resource_type: a test resource type. decompress: whether the host should decompress the downloaded file. decompress_dir: the directory where the host decompresses the file. mount_zip: whether to mount zip file. params: test resource parameters. """ name = ndb.StringProperty(required=True) default_download_url = ndb.StringProperty() test_resource_type = ndb.EnumProperty(TestResourceType) decompress = ndb.BooleanProperty() decompress_dir = ndb.StringProperty() mount_zip = ndb.BooleanProperty() params = ndb.LocalStructuredProperty(TestResourceParameters) def ToTestResourceObj(self): """Create a TestResourceObj from this definition.""" return TestResourceObj(name=self.name, url=self.default_download_url, test_resource_type=self.test_resource_type, decompress=self.decompress or False, decompress_dir=self.decompress_dir or '', mount_zip=self.mount_zip or False, params=TestResourceParameters.Clone( self.params))
class TradefedConfigObject(ndb.Model): """A Tradefed object and its options. Attributes: class_name: a Tradefed config class name. option_values: a list of option name and value pairs. """ class_name = ndb.StringProperty(required=True) option_values = ndb.LocalStructuredProperty(NameMultiValuePair, repeated=True)
class TestRunAction(ndb.Model): """Test run action, describes a specific hook execution. Attributes: name: action name. description: action description. hook_class_name: run hook class identifier. phases: phases during which hook should be triggered. options: key-value pairs to use when configuring the hook. tradefed_result_reporters: list of TF result reporters. credentials: stored OAuth2 credentials. """ name = ndb.StringProperty(required=True) description = ndb.StringProperty() hook_class_name = ndb.StringProperty(required=True) phases = ndb.EnumProperty(TestRunPhase, repeated=True) options = ndb.LocalStructuredProperty(NameValuePair, repeated=True) tradefed_result_reporters = ndb.LocalStructuredProperty( TradefedConfigObject, repeated=True) credentials = oauth2_util.CredentialsProperty()
class DeviceAction(ndb.Model): """A device action. Attributes: name: a device action name. description: a description. test_resource_defs: a list of test resource definitions. tradefed_target_preparers: a list of Tradefed target preparers. device_type: the type of the devices that require the device action. tradefed_options: key-value pairs to be added to Tradefed configuration. """ name = ndb.StringProperty(required=True) description = ndb.StringProperty() test_resource_defs = ndb.LocalStructuredProperty(TestResourceDef, repeated=True) tradefed_target_preparers = ndb.LocalStructuredProperty( TradefedConfigObject, repeated=True) device_type = ndb.StringProperty() tradefed_options = ndb.LocalStructuredProperty(NameMultiValuePair, repeated=True)
class TestRunSequence(ndb.Model): """A list of test run configs to be scheduled as retries. Attributes: state: completion state for this sequence test_run_configs: remaining retries to schedule finished_test_run_ids: list of completed runs scheduled for this sequence """ state = ndb.EnumProperty(TestRunSequenceState, required=True) test_run_configs = ndb.LocalStructuredProperty(TestRunConfig, repeated=True) finished_test_run_ids = ndb.StringProperty(repeated=True)
class TestRunActionRef(ndb.Model): """Test run action reference, with additional overridden options. Attributes: action_key: test run action to execute. options: additional key-value pairs to use when configuring the hook. """ action_key = ndb.KeyProperty(TestRunAction, required=True) options = ndb.LocalStructuredProperty(NameValuePair, repeated=True) def ToAction(self): """Converts this ref into a test run action.""" action = self.action_key.get() if not action: raise ValueError('Test run action %s not found' % self.action_key) options = NameValuePair.ToDict(action.options or []) options.update(NameValuePair.ToDict(self.options or [])) action.options = NameValuePair.FromDict(options) return action
class Test(ndb.Model): """A test. Attributes: name: a test name. description: user-friendly string that describes the test suite. test_resource_defs: a list of test resource definitions. command: a TF command line. env_vars: a dict of environment variables to set before running a test. output_file_patterns: a list of file patterns to collect after a test run. result_file: XML result file path. setup_scripts: a list of scripts to run before running a test. jvm_options: a list of JVM options to be passed to TF. java_properties: a dict of Java properties to be passed to TF. context_file_dir: directory where the context file which needs to be passed across attempts is located. context_file_pattern: a regex pattern for the filename of the context file which needs to be passed across attempts. retry_command_line: a command line to use in retry invocations. attempts. runner_sharding_args: extra args to enable runner sharding. It can contain a reference to a desired shard count (e.g. ${TF_SHARD_COUNT}) default_test_run_parameters: default test run parameters. module_config_pattern: a regex pattern for module config files. module_execution_args: extra args to run a specific module. """ name = ndb.StringProperty(required=True) description = ndb.StringProperty() test_resource_defs = ndb.StructuredProperty(TestResourceDef, repeated=True) command = ndb.StringProperty(required=True) env_vars = ndb.StructuredProperty(NameValuePair, repeated=True) output_file_patterns = ndb.StringProperty(repeated=True) result_file = ndb.StringProperty() setup_scripts = ndb.StringProperty(repeated=True) jvm_options = ndb.StringProperty(repeated=True) java_properties = ndb.StructuredProperty(NameValuePair, repeated=True) context_file_dir = ndb.StringProperty() context_file_pattern = ndb.StringProperty() retry_command_line = ndb.StringProperty() runner_sharding_args = ndb.StringProperty() default_test_run_parameters = ndb.LocalStructuredProperty(TestRunParameter) module_config_pattern = ndb.StringProperty() module_execution_args = ndb.StringProperty()
class TestResourceObj(ndb.Model): """A test resource object. The "Obj" suffix was added to avoid name collistion with TFC TestResource. Attributes: name: a test resource name. url: a URL. cache_url: a URL for a cached copy. test_resource_type: a test resource type. decompress: whether the host should decompress the downloaded file. decompress_dir: the directory where the host decompresses the file. mount_zip: whether to mount a zip file. params: test resource parameters. """ name = ndb.StringProperty(required=True) url = ndb.StringProperty() cache_url = ndb.StringProperty() test_resource_type = ndb.EnumProperty(TestResourceType) decompress = ndb.BooleanProperty() decompress_dir = ndb.StringProperty() mount_zip = ndb.BooleanProperty() params = ndb.LocalStructuredProperty(TestResourceParameters)
class TestRun(ndb.Model): """A test run. Attributes: prev_test_run_key: previous (parent) test run key. user: a user who scheduled a test run. labels: list of strings users can use to categorize test runs. test_plan_key: a test plan key. test: a Test object copy made at the test run schedule time. test_run_config: a TestRunConfig object. test_resources: a list of TestResourceObj objects. state: a test run state. is_finalized: True if post-run handlers were executed. output_path: a path to store test outputs to. output_url: a test output URL. prev_test_context: a previous test context object. next_test_context: a test context object from this test run. test_package_info: a test package information test_devices: a list of TestDeviceInfo of DUTs request_id: a TFC request ID. sequence_id: a TestRunSequence ID. total_test_count: the number of total test cases. failed_test_count: the number of failed test cases. failed_test_run_count: the number of test modules that failed to execute. create_time: time a test run is created. update_time: time a test run is last updated. before_device_actions: device actions used during the run. test_run_actions: test run actions executed during the run. hook_data: additional data used by hooks cancel_reason: cancellation reason error_reason: error reason """ prev_test_run_key = ndb.KeyProperty(kind='TestRun') user = ndb.StringProperty() labels = ndb.StringProperty(repeated=True) test_plan_key = ndb.KeyProperty(TestPlan) test = ndb.StructuredProperty(Test) test_run_config = ndb.StructuredProperty(TestRunConfig) test_resources = ndb.StructuredProperty(TestResourceObj, repeated=True) state = ndb.EnumProperty(TestRunState, default=TestRunState.UNKNOWN) is_finalized = ndb.BooleanProperty() output_path = ndb.StringProperty() output_url = ndb.StringProperty() prev_test_context = ndb.LocalStructuredProperty(TestContextObj) next_test_context = ndb.LocalStructuredProperty(TestContextObj) test_package_info = ndb.StructuredProperty(TestPackageInfo) test_devices = ndb.StructuredProperty(TestDeviceInfo, repeated=True) request_id = ndb.StringProperty() sequence_id = ndb.StringProperty() total_test_count = ndb.IntegerProperty() failed_test_count = ndb.IntegerProperty() failed_test_run_count = ndb.IntegerProperty() create_time = ndb.DateTimeProperty(auto_now_add=True) update_time = ndb.DateTimeProperty(auto_now_add=True) # TODO improve action versioning # Snapshot of the actions executed by the run before_device_actions = ndb.LocalStructuredProperty(DeviceAction, repeated=True) test_run_actions = ndb.LocalStructuredProperty(TestRunAction, repeated=True) hook_data = ndb.JsonProperty(default={}) cancel_reason = ndb.EnumProperty(common.CancelReason) error_reason = ndb.StringProperty() @classmethod def get_by_id(cls, id_, **kwargs): try: # support numeric (legacy) and uuid identifiers id_ = int(id_) except ValueError: pass return TestRun._get_by_id(id_, **kwargs) def _post_put_hook(self, future): self.ToSummary().put() @classmethod def _post_delete_hook(cls, key, future): ndb.delete_multi(ndb.Query(ancestor=key).iter(keys_only=True)) def ToSummary(self): return TestRunSummary(parent=self.key, id=self.key.id(), prev_test_run_key=self.prev_test_run_key, labels=self.labels, test_name=self.test.name if self.test else None, device_specs=(self.test_run_config.device_specs if self.test_run_config else []), run_target=(self.test_run_config.run_target if self.test_run_config else None), state=self.state, test_package_info=self.test_package_info, test_devices=self.test_devices, total_test_count=self.total_test_count, failed_test_count=self.failed_test_count, failed_test_run_count=self.failed_test_run_count, create_time=self.create_time, update_time=self.update_time) def IsFinal(self): """Returns whether a test run is in a final state. Returns: True if a test run is in a final state. Otherwise false. """ return self.state in FINAL_TEST_RUN_STATES def IsRerun(self): """Checks whether this is a rerun of another test run.""" return self.prev_test_context is not None def IsLocalRerun(self): """Checks whether this is a rerun using a local test run ID.""" return self.prev_test_run_key is not None def IsRemoteRerun(self): """Checks whether this is a rerun using an uploaded context file.""" return self.IsRerun() and not self.IsLocalRerun() def GetRerunContextFile(self): """Fetches the rerun context file if it exists.""" if not self.prev_test_context or not self.prev_test_context.test_resources: return None return self.prev_test_context.test_resources[0] def GetContext(self): """Returns a test run context dictionary.""" ctx = { 'MTT_USER': env.USER, 'MTT_HOSTNAME': env.HOSTNAME, 'MTT_VERSION': env.VERSION, 'MTT_TEST_RUN_ID': self.key.id(), 'MTT_TEST_ID': self.test_run_config.test_key.id(), 'MTT_TEST_NAME': self.test.name, 'MTT_TEST_PLAN_NAME': (self.test_plan_key.get().name if self.test_plan_key else ''), 'MTT_TEST_RUN_CREATE_TIMESTAMP': ToTimestamp(self.create_time), 'MTT_TEST_RUN_CREATE_TIMESTAMP_MILLIS': ToTimestamp(self.create_time) * 1000, } test_resource_map = {} for r in self.test_resources: m = re.match(r'mtt:///android_ci/(\S+)/(\S+)/(\S+)/.*', r.url) if m: test_resource_map[r.test_resource_type] = [ r.url, m.group(1), m.group(2), m.group(3) ] else: test_resource_map[r.test_resource_type] = [ r.url, None, None, None ] for t in TestResourceType: if t == TestResourceType.UNKNOWN: continue url, branch, target, build_id = test_resource_map.get( t, [None, None, None, None]) ctx['MTT_%s_URL' % t.name] = url or '' ctx['MTT_%s_BRANCH' % t.name] = branch or '' ctx['MTT_%s_BUILD_ID' % t.name] = build_id or '' ctx['MTT_%s_TARGET' % t.name] = target or '' return ctx