예제 #1
0
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)
예제 #2
0
class TestRunSummary(ndb.Model):
    """Partial test run information.

  Attributes:
    prev_test_run_key: ID of the previous (parent) test run.
    labels: list of strings users can use to categorize test runs.
    test_name: name of the Test to run.
    device_specs: device specs.
    run_target: run target.
    state: a test run state.
    test_package_info: a test package information
    test_devices: a list of TestDeviceInfo of DUTs
    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.
  """
    prev_test_run_key = ndb.KeyProperty(kind='TestRun')
    labels = ndb.StringProperty(repeated=True)
    test_name = ndb.StringProperty()
    device_specs = ndb.StringProperty(repeated=True)
    run_target = ndb.StringProperty()
    state = ndb.EnumProperty(TestRunState, default=TestRunState.UNKNOWN)
    test_package_info = ndb.StructuredProperty(TestPackageInfo)
    test_devices = ndb.StructuredProperty(TestDeviceInfo, repeated=True)
    total_test_count = ndb.IntegerProperty()
    failed_test_count = ndb.IntegerProperty()
    failed_test_run_count = ndb.IntegerProperty()
    create_time = ndb.DateTimeProperty()
    update_time = ndb.DateTimeProperty()
예제 #3
0
class TestPlanStatus(ndb.Model):
    """A test plan status."""
    last_run_time = ndb.DateTimeProperty()
    last_run_keys = ndb.KeyProperty(kind='TestRun', repeated=True)
    last_run_error = ndb.StringProperty()
    next_run_time = ndb.DateTimeProperty()
    next_run_task_name = ndb.StringProperty()
예제 #4
0
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()
예제 #5
0
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
예제 #6
0
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