| Index: dashboard/dashboard/pinpoint/models/quest/run_test.py
|
| diff --git a/dashboard/dashboard/pinpoint/models/quest/run_test.py b/dashboard/dashboard/pinpoint/models/quest/run_test.py
|
| index 8ee61cce3b77401cd6f3303e1af261fc14e95eb3..996a289cc1d7b47f0f4e5bb63034412b17aa6e64 100644
|
| --- a/dashboard/dashboard/pinpoint/models/quest/run_test.py
|
| +++ b/dashboard/dashboard/pinpoint/models/quest/run_test.py
|
| @@ -8,6 +8,8 @@ This is the only Quest/Execution where the Execution has a reference back to
|
| modify the Quest.
|
| """
|
|
|
| +import collections
|
| +
|
| from dashboard.pinpoint.models.quest import execution as execution_module
|
| from dashboard.pinpoint.models.quest import quest
|
| from dashboard.services import swarming_service
|
| @@ -53,25 +55,32 @@ class RunTest(quest.Quest):
|
| self._extra_args = extra_args
|
|
|
| # We want subsequent executions use the same bot as the first one.
|
| - self._first_execution = None
|
| + self._canonical_executions = []
|
| + self._execution_counts = collections.defaultdict(int)
|
|
|
| def __eq__(self, other):
|
| return (isinstance(other, type(self)) and
|
| self._dimensions == other._dimensions and
|
| self._extra_args == other._extra_args and
|
| - self._first_execution == other._first_execution)
|
| + self._canonical_executions == other._canonical_executions and
|
| + self._execution_counts == other._execution_counts)
|
|
|
|
|
| def __str__(self):
|
| return 'Test'
|
|
|
| - def Start(self, isolate_hash):
|
| - execution = _RunTestExecution(
|
| - self._dimensions, self._extra_args, isolate_hash,
|
| - first_execution=self._first_execution)
|
| + def Start(self, change, isolate_hash):
|
| + index = self._execution_counts[change]
|
| + self._execution_counts[change] += 1
|
|
|
| - if not self._first_execution:
|
| - self._first_execution = execution
|
| + if len(self._canonical_executions) <= index:
|
| + execution = _RunTestExecution(
|
| + self._dimensions, self._extra_args, isolate_hash)
|
| + self._canonical_executions.append(execution)
|
| + else:
|
| + execution = _RunTestExecution(
|
| + self._dimensions, self._extra_args, isolate_hash,
|
| + previous_execution=self._canonical_executions[index])
|
|
|
| return execution
|
|
|
| @@ -79,62 +88,59 @@ class RunTest(quest.Quest):
|
| class _RunTestExecution(execution_module.Execution):
|
|
|
| def __init__(self, dimensions, extra_args, isolate_hash,
|
| - first_execution=None):
|
| + previous_execution=None):
|
| super(_RunTestExecution, self).__init__()
|
| self._dimensions = dimensions
|
| self._extra_args = extra_args
|
| self._isolate_hash = isolate_hash
|
| - self._first_execution = first_execution
|
| + self._previous_execution = previous_execution
|
|
|
| - self._task_ids = []
|
| - self._bot_ids = []
|
| + self._task_id = None
|
| + self._bot_id = None
|
|
|
| @property
|
| - def bot_ids(self):
|
| - return tuple(self._bot_ids)
|
| + def bot_id(self):
|
| + return self._bot_id
|
|
|
| def _AsDict(self):
|
| return {
|
| - 'bot_ids': self._bot_ids,
|
| - 'task_ids': self._task_ids,
|
| + 'bot_id': self._bot_id,
|
| + 'task_id': self._task_id,
|
| 'input_isolate_hash': self._isolate_hash,
|
| }
|
|
|
| def _Poll(self):
|
| - if not self._task_ids:
|
| + if not self._task_id:
|
| self._StartTask()
|
| return
|
|
|
| - self._bot_ids = []
|
| - isolate_hashes = []
|
| - for task_id in self._task_ids:
|
| - result = swarming_service.Task(task_id).Result()
|
| + result = swarming_service.Task(self._task_id).Result()
|
|
|
| - if 'bot_id' in result:
|
| - # Set bot_id to pass the info back to the Quest.
|
| - self._bot_ids.append(result['bot_id'])
|
| + if 'bot_id' in result:
|
| + # Set bot_id to pass the info back to the Quest.
|
| + self._bot_id = result['bot_id']
|
|
|
| - if result['state'] == 'PENDING' or result['state'] == 'RUNNING':
|
| - return
|
| + if result['state'] == 'PENDING' or result['state'] == 'RUNNING':
|
| + return
|
|
|
| - if result['state'] != 'COMPLETED':
|
| - raise SwarmingTaskError(task_id, result['state'])
|
| + if result['state'] != 'COMPLETED':
|
| + raise SwarmingTaskError(self._task_id, result['state'])
|
|
|
| - if result['failure']:
|
| - raise SwarmingTestError(task_id, result['exit_code'])
|
| + if result['failure']:
|
| + raise SwarmingTestError(self._task_id, result['exit_code'])
|
|
|
| - isolate_hashes.append(result['outputs_ref']['isolated'])
|
| + isolate_hash = result['outputs_ref']['isolated']
|
|
|
| - result_arguments = {'isolate_hashes': tuple(isolate_hashes)}
|
| + result_arguments = {'isolate_hash': isolate_hash}
|
| self._Complete(result_arguments=result_arguments)
|
|
|
|
|
| def _StartTask(self):
|
| """Kick off a Swarming task to run a test."""
|
| - if self._first_execution and not self._first_execution.bot_ids:
|
| - if self._first_execution.failed:
|
| - # If the first Execution fails before it gets a bot ID, it's likely it
|
| - # couldn't find any device to run on. Subsequent Executions probably
|
| + if self._previous_execution and not self._previous_execution.bot_id:
|
| + if self._previous_execution.failed:
|
| + # If the previous Execution fails before it gets a bot ID, it's likely
|
| + # it couldn't find any device to run on. Subsequent Executions probably
|
| # wouldn't have any better luck, and failing fast is less complex than
|
| # handling retries.
|
| raise RunTestError('There are no bots available to run the test.')
|
| @@ -142,11 +148,10 @@ class _RunTestExecution(execution_module.Execution):
|
| return
|
|
|
| dimensions = [{'key': 'pool', 'value': 'Chrome-perf-pinpoint'}]
|
| - if self._first_execution:
|
| + if self._previous_execution:
|
| dimensions.append({
|
| 'key': 'id',
|
| - # TODO: Use all the bot ids.
|
| - 'value': self._first_execution.bot_ids[0]
|
| + 'value': self._previous_execution.bot_id
|
| })
|
| else:
|
| dimensions += self._dimensions
|
| @@ -166,4 +171,4 @@ class _RunTestExecution(execution_module.Execution):
|
| }
|
| response = swarming_service.Tasks().New(body)
|
|
|
| - self._task_ids.append(response['task_id'])
|
| + self._task_id = response['task_id']
|
|
|