Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Unified Diff: tools/testing/dart/test_runner.dart

Issue 2957703002: Refactor dependency_graph.dart. (Closed)
Patch Set: Update dependency graph test. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/testing/dart/dependency_graph.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/testing/dart/test_runner.dart
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index fd5598bf3dff4afff9261211f9e5c30bf1865c4d..0a32721152a041d7025b4a00f8da1369259a5b8b 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -22,7 +22,7 @@ import 'browser_controller.dart';
import 'command.dart';
import 'command_output.dart';
import 'configuration.dart';
-import 'dependency_graph.dart' as dgraph;
+import 'dependency_graph.dart';
import 'expectation.dart';
import 'runtime_configuration.dart';
import 'test_progress.dart';
@@ -818,56 +818,56 @@ class BatchRunnerProcess {
* on them, so we can safely use them as keys in Map/Set objects.
*/
class TestCaseEnqueuer {
- final dgraph.Graph graph;
+ final Graph<Command> graph;
final Function _onTestCaseAdded;
- final command2node = new Map<Command, dgraph.Node>();
- final command2testCases = new Map<Command, List<TestCase>>();
+ final command2node = <Command, Node<Command>>{};
+ final command2testCases = <Command, List<TestCase>>{};
final remainingTestCases = new Set<TestCase>();
TestCaseEnqueuer(this.graph, this._onTestCaseAdded);
void enqueueTestSuites(List<TestSuite> testSuites) {
- void newTest(TestCase testCase) {
- remainingTestCases.add(testCase);
-
- dgraph.Node lastNode;
- for (var command in testCase.commands) {
- // Make exactly *one* node in the dependency graph for every command.
- // This ensures that we never have two commands c1 and c2 in the graph
- // with "c1 == c2".
- var node = command2node[command];
- if (node == null) {
- var requiredNodes = (lastNode != null) ? [lastNode] : <dgraph.Node>[];
- node = graph.newNode(command, requiredNodes);
- command2node[command] = node;
- command2testCases[command] = <TestCase>[];
- }
- // Keep mapping from command to all testCases that refer to it
- command2testCases[command].add(testCase);
-
- lastNode = node;
- }
- _onTestCaseAdded(testCase);
- }
-
// Cache information about test cases per test suite. For multiple
// configurations there is no need to repeatedly search the file
// system, generate tests, and search test files for options.
- var testCache = new Map<String, List<TestInformation>>();
+ var testCache = <String, List<TestInformation>>{};
- Iterator<TestSuite> iterator = testSuites.iterator;
+ var iterator = testSuites.iterator;
void enqueueNextSuite() {
if (!iterator.moveNext()) {
// We're finished with building the dependency graph.
- graph.sealGraph();
+ graph.seal();
} else {
- iterator.current.forEachTest(newTest, testCache, enqueueNextSuite);
+ iterator.current.forEachTest(_newTest, testCache, enqueueNextSuite);
}
}
enqueueNextSuite();
}
+
+ void _newTest(TestCase testCase) {
+ remainingTestCases.add(testCase);
+
+ Node<Command> lastNode;
+ for (var command in testCase.commands) {
+ // Make exactly *one* node in the dependency graph for every command.
+ // This ensures that we never have two commands c1 and c2 in the graph
+ // with "c1 == c2".
+ var node = command2node[command];
+ if (node == null) {
+ var requiredNodes = (lastNode != null) ? [lastNode] : <Node<Command>>[];
+ node = graph.add(command, requiredNodes);
+ command2node[command] = node;
+ command2testCases[command] = <TestCase>[];
+ }
+ // Keep mapping from command to all testCases that refer to it
+ command2testCases[command].add(testCase);
+
+ lastNode = node;
+ }
+ _onTestCaseAdded(testCase);
+ }
}
/*
@@ -878,31 +878,23 @@ class TestCaseEnqueuer {
* have a state of NodeState.Failed/NodeState.UnableToRun.
*/
class CommandEnqueuer {
- static final INIT_STATES = [
- dgraph.NodeState.Initialized,
- dgraph.NodeState.Waiting
- ];
- static final FINISHED_STATES = [
- dgraph.NodeState.Successful,
- dgraph.NodeState.Failed,
- dgraph.NodeState.UnableToRun
+ static const _initStates = const [NodeState.initialized, NodeState.waiting];
+
+ static const _finishedStates = const [
+ NodeState.successful,
+ NodeState.failed,
+ NodeState.unableToRun
];
- final dgraph.Graph _graph;
- CommandEnqueuer(this._graph) {
- var eventCondition = _graph.events.where;
+ final Graph<Command> _graph;
- eventCondition((e) => e is dgraph.NodeAddedEvent).listen((e) {
- var event = e as dgraph.NodeAddedEvent;
- dgraph.Node node = event.node;
- _changeNodeStateIfNecessary(node);
- });
+ CommandEnqueuer(this._graph) {
+ _graph.added.listen(_changeNodeStateIfNecessary);
- eventCondition((e) => e is dgraph.StateChangedEvent).listen((e) {
- var event = e as dgraph.StateChangedEvent;
- if ([dgraph.NodeState.Waiting, dgraph.NodeState.Processing]
- .contains(event.from)) {
- if (FINISHED_STATES.contains(event.to)) {
+ _graph.changed.listen((event) {
+ if (event.from == NodeState.waiting ||
+ event.from == NodeState.processing) {
+ if (_finishedStates.contains(event.to)) {
for (var dependendNode in event.node.neededFor) {
_changeNodeStateIfNecessary(dependendNode);
}
@@ -913,22 +905,20 @@ class CommandEnqueuer {
// Called when either a new node was added or if one of it's dependencies
// changed it's state.
- void _changeNodeStateIfNecessary(dgraph.Node node) {
- if (INIT_STATES.contains(node.state)) {
- bool anyDependenciesUnsuccessful = node.dependencies.any((dep) => [
- dgraph.NodeState.Failed,
- dgraph.NodeState.UnableToRun
- ].contains(dep.state));
-
- var newState = dgraph.NodeState.Waiting;
+ void _changeNodeStateIfNecessary(Node<Command> node) {
+ if (_initStates.contains(node.state)) {
+ bool anyDependenciesUnsuccessful = node.dependencies.any((dep) =>
+ [NodeState.failed, NodeState.unableToRun].contains(dep.state));
+
+ var newState = NodeState.waiting;
if (anyDependenciesUnsuccessful) {
- newState = dgraph.NodeState.UnableToRun;
+ newState = NodeState.unableToRun;
} else {
- bool allDependenciesSuccessful = node.dependencies
- .every((dep) => dep.state == dgraph.NodeState.Successful);
+ bool allDependenciesSuccessful =
+ node.dependencies.every((dep) => dep.state == NodeState.successful);
if (allDependenciesSuccessful) {
- newState = dgraph.NodeState.Enqueuing;
+ newState = NodeState.enqueuing;
}
}
if (node.state != newState) {
@@ -952,7 +942,7 @@ class CommandEnqueuer {
* and the [executor] has cleaned up it's resources.
*/
class CommandQueue {
- final dgraph.Graph graph;
+ final Graph<Command> graph;
final CommandExecutor executor;
final TestCaseEnqueuer enqueuer;
@@ -969,34 +959,29 @@ class CommandQueue {
CommandQueue(this.graph, this.enqueuer, this.executor, this._maxProcesses,
this._maxBrowserProcesses, this._verbose) {
- var eventCondition = graph.events.where;
- eventCondition((e) => e is dgraph.StateChangedEvent).listen((e) {
- var event = e as dgraph.StateChangedEvent;
- if (event.to == dgraph.NodeState.Enqueuing) {
- assert(event.from == dgraph.NodeState.Initialized ||
- event.from == dgraph.NodeState.Waiting);
- graph.changeState(event.node, dgraph.NodeState.Processing);
- var command = event.node.userData as Command;
- if (event.node.dependencies.length > 0) {
+ graph.changed.listen((event) {
+ if (event.to == NodeState.enqueuing) {
+ assert(event.from == NodeState.initialized ||
+ event.from == NodeState.waiting);
+ graph.changeState(event.node, NodeState.processing);
+ var command = event.node.data;
+ if (event.node.dependencies.isNotEmpty) {
_runQueue.addFirst(command);
} else {
_runQueue.add(command);
}
Timer.run(() => _tryRunNextCommand());
+ } else if (event.to == NodeState.unableToRun) {
+ _checkDone();
}
});
+
// We're finished if the graph is sealed and all nodes are in a finished
// state (Successful, Failed or UnableToRun).
// So we're calling '_checkDone()' to check whether that condition is met
// and we can cleanup.
- graph.events.listen((dgraph.GraphEvent event) {
- if (event is dgraph.GraphSealedEvent) {
- _checkDone();
- } else if (event is dgraph.StateChangedEvent) {
- if (event.to == dgraph.NodeState.UnableToRun) {
- _checkDone();
- }
- }
+ graph.sealed.listen((event) {
+ _checkDone();
});
}
@@ -1039,9 +1024,9 @@ class CommandQueue {
_commandOutputStream.add(output);
if (output.canRunDependendCommands) {
- graph.changeState(node, dgraph.NodeState.Successful);
+ graph.changeState(node, NodeState.successful);
} else {
- graph.changeState(node, dgraph.NodeState.Failed);
+ graph.changeState(node, NodeState.failed);
}
_numProcesses--;
@@ -1058,10 +1043,10 @@ class CommandQueue {
_runQueue.isEmpty &&
_numProcesses == 0 &&
graph.isSealed &&
- graph.stateCount(dgraph.NodeState.Initialized) == 0 &&
- graph.stateCount(dgraph.NodeState.Waiting) == 0 &&
- graph.stateCount(dgraph.NodeState.Enqueuing) == 0 &&
- graph.stateCount(dgraph.NodeState.Processing) == 0) {
+ graph.stateCount(NodeState.initialized) == 0 &&
+ graph.stateCount(NodeState.waiting) == 0 &&
+ graph.stateCount(NodeState.enqueuing) == 0 &&
+ graph.stateCount(NodeState.processing) == 0) {
_finishing = true;
executor.cleanup().then((_) {
_completer.complete();
@@ -1099,7 +1084,7 @@ abstract class CommandExecutor {
Future cleanup();
// TODO(kustermann): The [timeout] parameter should be a property of Command
Future<CommandOutput> runCommand(
- dgraph.Node node, covariant Command command, int timeout);
+ Node<Command> node, covariant Command command, int timeout);
}
class CommandExecutorImpl implements CommandExecutor {
@@ -1401,53 +1386,51 @@ bool shouldRetryCommand(CommandOutput output) {
* closed.
*/
class TestCaseCompleter {
- static final COMPLETED_STATES = [
- dgraph.NodeState.Failed,
- dgraph.NodeState.Successful
+ static const _completedStates = const [
+ NodeState.failed,
+ NodeState.successful
];
- final dgraph.Graph graph;
- final TestCaseEnqueuer enqueuer;
- final CommandQueue commandQueue;
- Map<Command, CommandOutput> _outputs = new Map<Command, CommandOutput>();
+ final Graph<Command> _graph;
+ final TestCaseEnqueuer _enqueuer;
+ final CommandQueue _commandQueue;
+
+ final Map<Command, CommandOutput> _outputs = {};
+ final StreamController<TestCase> _controller = new StreamController();
bool _closed = false;
- StreamController<TestCase> _controller = new StreamController<TestCase>();
- TestCaseCompleter(this.graph, this.enqueuer, this.commandQueue) {
- var eventCondition = graph.events.where;
- bool finishedRemainingTestCases = false;
+ TestCaseCompleter(this._graph, this._enqueuer, this._commandQueue) {
+ var finishedRemainingTestCases = false;
// Store all the command outputs -- they will be delivered synchronously
// (i.e. before state changes in the graph)
- commandQueue.completedCommands.listen((CommandOutput output) {
+ _commandQueue.completedCommands.listen((CommandOutput output) {
_outputs[output.command] = output;
}, onDone: () {
- _completeTestCasesIfPossible(new List.from(enqueuer.remainingTestCases));
+ _completeTestCasesIfPossible(new List.from(_enqueuer.remainingTestCases));
finishedRemainingTestCases = true;
- assert(enqueuer.remainingTestCases.isEmpty);
+ assert(_enqueuer.remainingTestCases.isEmpty);
_checkDone();
});
// Listen for NodeState.Processing -> NodeState.{Successful,Failed}
// changes.
- eventCondition((event) => event is dgraph.StateChangedEvent).listen((e) {
- var event = e as dgraph.StateChangedEvent;
- if (event.from == dgraph.NodeState.Processing &&
- !finishedRemainingTestCases) {
- var command = event.node.userData;
+ _graph.changed.listen((event) {
+ if (event.from == NodeState.processing && !finishedRemainingTestCases) {
+ var command = event.node.data;
- assert(COMPLETED_STATES.contains(event.to));
+ assert(_completedStates.contains(event.to));
assert(_outputs[command] != null);
- _completeTestCasesIfPossible(enqueuer.command2testCases[command]);
+ _completeTestCasesIfPossible(_enqueuer.command2testCases[command]);
_checkDone();
}
});
- // Listen also for GraphSealedEvent's. If there is not a single node in the
+ // Listen also for GraphSealedEvents. If there is not a single node in the
// graph, we still want to finish after the graph was sealed.
- eventCondition((event) => event is dgraph.GraphSealedEvent).listen((_) {
- if (!_closed && enqueuer.remainingTestCases.isEmpty) {
+ _graph.sealed.listen((_) {
+ if (!_closed && _enqueuer.remainingTestCases.isEmpty) {
_controller.close();
_closed = true;
}
@@ -1457,7 +1440,7 @@ class TestCaseCompleter {
Stream<TestCase> get finishedTestCases => _controller.stream;
void _checkDone() {
- if (!_closed && graph.isSealed && enqueuer.remainingTestCases.isEmpty) {
+ if (!_closed && _graph.isSealed && _enqueuer.remainingTestCases.isEmpty) {
_controller.close();
_closed = true;
}
@@ -1475,9 +1458,9 @@ class TestCaseCompleter {
}
void completeTestCase(TestCase testCase) {
- if (enqueuer.remainingTestCases.contains(testCase)) {
+ if (_enqueuer.remainingTestCases.contains(testCase)) {
_controller.add(testCase);
- enqueuer.remainingTestCases.remove(testCase);
+ _enqueuer.remainingTestCases.remove(testCase);
} else {
DebugLogger.error("${testCase.displayName} would be finished twice");
}
@@ -1498,7 +1481,7 @@ class ProcessQueue {
Configuration _globalConfiguration;
Function _allDone;
- final dgraph.Graph _graph = new dgraph.Graph();
+ final Graph<Command> _graph = new Graph();
List<EventListener> _eventListener;
ProcessQueue(
@@ -1512,9 +1495,7 @@ class ProcessQueue {
[bool verbose = false,
AdbDevicePool adbDevicePool]) {
void setupForListing(TestCaseEnqueuer testCaseEnqueuer) {
- _graph.events
- .where((event) => event is dgraph.GraphSealedEvent)
- .listen((_) {
+ _graph.sealed.listen((_) {
var testCases = testCaseEnqueuer.remainingTestCases.toList();
testCases.sort((a, b) => a.displayName.compareTo(b.displayName));
@@ -1553,13 +1534,13 @@ class ProcessQueue {
print("");
print("Graph is sealed: ${_graph.isSealed}");
print("");
- _graph.DumpCounts();
+ _graph.dumpCounts();
print("");
var unfinishedNodeStates = [
- dgraph.NodeState.Initialized,
- dgraph.NodeState.Waiting,
- dgraph.NodeState.Enqueuing,
- dgraph.NodeState.Processing
+ NodeState.initialized,
+ NodeState.waiting,
+ NodeState.enqueuing,
+ NodeState.processing
];
for (var nodeState in unfinishedNodeStates) {
@@ -1569,7 +1550,7 @@ class ProcessQueue {
print("");
for (var node in _graph.nodes) {
if (node.state == nodeState) {
- var command = node.userData;
+ var command = node.data;
var testCases = testCaseEnqueuer.command2testCases[command];
print(" Command: $command");
for (var testCase in testCases) {
@@ -1591,9 +1572,7 @@ class ProcessQueue {
}
// When the graph building is finished, notify event listeners.
- _graph.events
- .where((event) => event is dgraph.GraphSealedEvent)
- .listen((event) {
+ _graph.sealed.listen((_) {
eventAllTestsKnown();
});
« no previous file with comments | « tools/testing/dart/dependency_graph.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698