From 96f1abdacaa494743b1ec39cb77cb6bdd2642104 Mon Sep 17 00:00:00 2001 From: Karl Klose Date: Mon, 23 Sep 2019 07:57:39 +0000 Subject: [PATCH] [pkg/testing] Replace top-level logging functions with an interface. Change-Id: Id896436ab869d52c6e9befff885494b87690a342 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/118382 Reviewed-by: Johnni Winther Commit-Queue: Karl Klose --- pkg/testing/lib/src/chain.dart | 33 ++--- pkg/testing/lib/src/log.dart | 204 ++++++++++++++++----------- pkg/testing/lib/src/run.dart | 19 ++- pkg/testing/lib/src/run_tests.dart | 20 ++- pkg/testing/lib/src/zone_helper.dart | 4 +- 5 files changed, 157 insertions(+), 123 deletions(-) diff --git a/pkg/testing/lib/src/chain.dart b/pkg/testing/lib/src/chain.dart index 83380731820..803f10f87c6 100644 --- a/pkg/testing/lib/src/chain.dart +++ b/pkg/testing/lib/src/chain.dart @@ -21,15 +21,7 @@ import 'zone_helper.dart' show runGuarded; import 'error_handling.dart' show withErrorHandling; -import 'log.dart' - show - logMessage, - logStepComplete, - logStepStart, - logSuiteComplete, - logTestComplete, - logUnexpectedResult, - splitLines; +import 'log.dart' show Logger, StdoutLogger, splitLines; import 'multitest.dart' show MultitestTransformer, isError; @@ -112,7 +104,9 @@ abstract class ChainContext { ExpectationSet get expectationSet => ExpectationSet.Default; Future run(Chain suite, Set selectors, - {int shards = 1, int shard = 0}) async { + {int shards = 1, + int shard = 0, + Logger logger: const StdoutLogger()}) async { assert(shards >= 1, "Invalid shards count: $shards"); assert(0 <= shard && shard < shards, "Invalid shard index: $shard, not in range [0,$shards[."); @@ -182,8 +176,8 @@ abstract class ChainContext { Step step = iterator.current; lastStepRun = step; isAsync = step.isAsync; - logStepStart(completed, unexpectedResults.length, descriptions.length, - suite, description, step); + logger.logStepStart(completed, unexpectedResults.length, + descriptions.length, suite, description, step); // TODO(ahe): It's important to share the zone error reporting zone // between all the tasks. Otherwise, if a future completes with an // error in one zone, and gets stored, it becomes an uncaught error @@ -201,7 +195,7 @@ abstract class ChainContext { future = future.then((_currentResult) async { Result currentResult = _currentResult; if (currentResult != null) { - logStepComplete(completed, unexpectedResults.length, + logger.logStepComplete(completed, unexpectedResults.length, descriptions.length, suite, description, lastStepRun); result = currentResult; if (currentResult.outcome == Expectation.Pass) { @@ -217,12 +211,13 @@ abstract class ChainContext { result.addLog("$sb"); unexpectedResults[description] = result; unexpectedOutcomes[description] = expectedOutcomes; - logUnexpectedResult(suite, description, result, expectedOutcomes); + logger.logUnexpectedResult( + suite, description, result, expectedOutcomes); exitCode = 1; } else { - logMessage(sb); + logger.logMessage(sb); } - logTestComplete(++completed, unexpectedResults.length, + logger.logTestComplete(++completed, unexpectedResults.length, descriptions.length, suite, description); }); if (isAsync) { @@ -233,14 +228,16 @@ abstract class ChainContext { } } + logger.logTestStart(completed, unexpectedResults.length, + descriptions.length, suite, description); // The input of the first step is [description]. await doStep(description); } await Future.wait(futures); - logSuiteComplete(); + logger.logSuiteComplete(); if (unexpectedResults.isNotEmpty) { unexpectedResults.forEach((TestDescription description, Result result) { - logUnexpectedResult( + logger.logUnexpectedResult( suite, description, result, unexpectedOutcomes[description]); }); print("${unexpectedResults.length} failed:"); diff --git a/pkg/testing/lib/src/log.dart b/pkg/testing/lib/src/log.dart index edd366384db..b15de1466e6 100644 --- a/pkg/testing/lib/src/log.dart +++ b/pkg/testing/lib/src/log.dart @@ -38,106 +38,146 @@ void enableVerboseOutput() { _isVerbose = true; } -void logTestComplete(int completed, int failed, int total, Suite suite, - TestDescription description) { - String message = formatProgress(completed, failed, total); - if (suite != null) { - message += ": ${formatTestDescription(suite, description)}"; - } - logProgress(message); +abstract class Logger { + void logTestStart(int completed, int failed, int total, Suite suite, + TestDescription description); + + void logTestComplete(int completed, int failed, int total, Suite suite, + TestDescription description); + + void logStepStart(int completed, int failed, int total, Suite suite, + TestDescription description, Step step); + + void logStepComplete(int completed, int failed, int total, Suite suite, + TestDescription description, Step step); + + void logProgress(String message); + + void logMessage(Object message); + + void logNumberedLines(String text); + + void logExpectedResult(Suite suite, TestDescription description, + Result result, Set expectedOutcomes); + + void logUnexpectedResult(Suite suite, TestDescription description, + Result result, Set expectedOutcomes); + + void logSuiteComplete(); + + void logUncaughtError(error, StackTrace stackTrace); } -void logStepStart(int completed, int failed, int total, Suite suite, - TestDescription description, Step step) { - String message = formatProgress(completed, failed, total); - if (suite != null) { - message += ": ${formatTestDescription(suite, description)} ${step.name}"; - if (step.isAsync) { - message += "..."; +class StdoutLogger implements Logger { + const StdoutLogger(); + + void logTestStart(int completed, int failed, int total, Suite suite, + TestDescription description) {} + + void logTestComplete(int completed, int failed, int total, Suite suite, + TestDescription description) { + String message = formatProgress(completed, failed, total); + if (suite != null) { + message += ": ${formatTestDescription(suite, description)}"; } + logProgress(message); } - logProgress(message); -} -void logStepComplete(int completed, int failed, int total, Suite suite, - TestDescription description, Step step) { - if (!step.isAsync) return; - String message = formatProgress(completed, failed, total); - if (suite != null) { - message += ": ${formatTestDescription(suite, description)} ${step.name}!"; + void logStepStart(int completed, int failed, int total, Suite suite, + TestDescription description, Step step) { + String message = formatProgress(completed, failed, total); + if (suite != null) { + message += ": ${formatTestDescription(suite, description)} ${step.name}"; + if (step.isAsync) { + message += "..."; + } + } + logProgress(message); } - logProgress(message); -} -void logProgress(String message) { - if (isVerbose) { - print(message); - } else { - print("$eraseLine$message$cursorUp"); + void logStepComplete(int completed, int failed, int total, Suite suite, + TestDescription description, Step step) { + if (!step.isAsync) return; + String message = formatProgress(completed, failed, total); + if (suite != null) { + message += ": ${formatTestDescription(suite, description)} ${step.name}!"; + } + logProgress(message); } -} -String formatProgress(int completed, int failed, int total) { - Duration elapsed = wallclock.elapsed; - String percent = pad((completed / total * 100.0).toStringAsFixed(1), 5); - String good = pad(completed - failed, 5); - String bad = pad(failed, 5); - String minutes = pad(elapsed.inMinutes, 2, filler: "0"); - String seconds = pad(elapsed.inSeconds % 60, 2, filler: "0"); - return "[ $minutes:$seconds | $percent% | +$good | -$bad ]"; -} - -String formatTestDescription(Suite suite, TestDescription description) { - return "${suite.name}/${description.shortName}"; -} - -void logMessage(Object message) { - if (isVerbose) { - print("$message"); - } -} - -void logNumberedLines(String text) { - if (isVerbose) { - print(numberedLines(text)); - } -} - -void logUnexpectedResult(Suite suite, TestDescription description, - Result result, Set expectedOutcomes) { - print("${eraseLine}UNEXPECTED: ${suite.name}/${description.shortName}"); - Uri statusFile = suite.statusFile; - if (statusFile != null) { - String path = statusFile.toFilePath(); - if (result.outcome == Expectation.Pass) { - print("The test unexpectedly passed, please update $path."); + void logProgress(String message) { + if (isVerbose) { + print(message); } else { - print("The test had the outcome ${result.outcome}, but the status file " - "($path) allows these outcomes: ${expectedOutcomes.join(' ')}"); + print("$eraseLine$message$cursorUp"); } } - String log = result.log; - if (log.isNotEmpty) { - print(log); + + String formatProgress(int completed, int failed, int total) { + Duration elapsed = wallclock.elapsed; + String percent = pad((completed / total * 100.0).toStringAsFixed(1), 5); + String good = pad(completed - failed, 5); + String bad = pad(failed, 5); + String minutes = pad(elapsed.inMinutes, 2, filler: "0"); + String seconds = pad(elapsed.inSeconds % 60, 2, filler: "0"); + return "[ $minutes:$seconds | $percent% | +$good | -$bad ]"; } - if (result.error != null) { - print(result.error); - if (result.trace != null) { - print(result.trace); + + String formatTestDescription(Suite suite, TestDescription description) { + return "${suite.name}/${description.shortName}"; + } + + void logMessage(Object message) { + if (isVerbose) { + print("$message"); } } -} -void logSuiteComplete() { - if (!isVerbose) { - print(""); + void logNumberedLines(String text) { + if (isVerbose) { + print(numberedLines(text)); + } } -} -void logUncaughtError(error, StackTrace stackTrace) { - logMessage(error); - if (stackTrace != null) { - logMessage(stackTrace); + void logExpectedResult(Suite suite, TestDescription description, + Result result, Set expectedOutcomes) {} + + void logUnexpectedResult(Suite suite, TestDescription description, + Result result, Set expectedOutcomes) { + print("${eraseLine}UNEXPECTED: ${suite.name}/${description.shortName}"); + Uri statusFile = suite.statusFile; + if (statusFile != null) { + String path = statusFile.toFilePath(); + if (result.outcome == Expectation.Pass) { + print("The test unexpectedly passed, please update $path."); + } else { + print("The test had the outcome ${result.outcome}, but the status file " + "($path) allows these outcomes: ${expectedOutcomes.join(' ')}"); + } + } + String log = result.log; + if (log.isNotEmpty) { + print(log); + } + if (result.error != null) { + print(result.error); + if (result.trace != null) { + print(result.trace); + } + } + } + + void logSuiteComplete() { + if (!isVerbose) { + print(""); + } + } + + void logUncaughtError(error, StackTrace stackTrace) { + logMessage(error); + if (stackTrace != null) { + logMessage(stackTrace); + } } } diff --git a/pkg/testing/lib/src/run.dart b/pkg/testing/lib/src/run.dart index d16cf30034f..12305bad32a 100644 --- a/pkg/testing/lib/src/run.dart +++ b/pkg/testing/lib/src/run.dart @@ -24,12 +24,7 @@ import '../testing.dart' import 'analyze.dart' show Analyze; import 'log.dart' - show - enableVerboseOutput, - isVerbose, - logMessage, - logNumberedLines, - splitLines; + show enableVerboseOutput, isVerbose, Logger, splitLines, StdoutLogger; import 'suite.dart' show Dart, Suite; @@ -55,7 +50,11 @@ Future computeTestRoot(String configurationPath, Uri base) { /// `testing.json` isn't located in the current working directory and is a path /// relative to [me] which defaults to `Platform.script`. Future runMe(List arguments, CreateContext f, - {String configurationPath, Uri me, int shards = 1, int shard = 0}) { + {String configurationPath, + Uri me, + int shards = 1, + int shard = 0, + Logger logger: const StdoutLogger()}) { me ??= Platform.script; return withErrorHandling(() async { TestRoot testRoot = await computeTestRoot(configurationPath, me); @@ -66,7 +65,7 @@ Future runMe(List arguments, CreateContext f, print("Running suite ${suite.name}..."); ChainContext context = await f(suite, cl.environment); await context.run(suite, new Set.from(cl.selectors), - shards: shards, shard: shard); + shards: shards, shard: shard, logger: logger); } } }); @@ -117,8 +116,8 @@ Future run(List arguments, List suiteNames, } Future runProgram(String program, Uri packages) async { - logMessage("Running:"); - logNumberedLines(program); + const StdoutLogger().logMessage("Running:"); + const StdoutLogger().logNumberedLines(program); Uri dataUri = new Uri.dataFromString(program); ReceivePort exitPort = new ReceivePort(); Isolate isolate = await Isolate.spawnUri(dataUri, [], null, diff --git a/pkg/testing/lib/src/run_tests.dart b/pkg/testing/lib/src/run_tests.dart index 5d6e27d2ddf..ecb28d436f3 100644 --- a/pkg/testing/lib/src/run_tests.dart +++ b/pkg/testing/lib/src/run_tests.dart @@ -18,13 +18,7 @@ import 'test_root.dart' show TestRoot; import 'zone_helper.dart' show runGuarded; -import 'log.dart' - show - enableVerboseOutput, - isVerbose, - logMessage, - logSuiteComplete, - logTestComplete; +import 'log.dart' show enableVerboseOutput, isVerbose, StdoutLogger; import 'run.dart' show SuiteRunner, runProgram; @@ -115,7 +109,8 @@ class CommandLine { } } } - logMessage("Reading configuration file '$configurationPath'."); + const StdoutLogger() + .logMessage("Reading configuration file '$configurationPath'."); Uri configuration = await Isolate.resolvePackageUri(Uri.base.resolve(configurationPath)); if (configuration == null || @@ -177,18 +172,21 @@ Future runTests(Map tests) => withErrorHandling(() async { int completed = 0; for (String name in tests.keys) { + const StdoutLogger() + .logTestStart(completed, 0, tests.length, null, null); StringBuffer sb = new StringBuffer(); try { await runGuarded(() { print("Running test $name"); return tests[name](); }, printLineOnStdout: sb.writeln); - logMessage(sb); + const StdoutLogger().logMessage(sb); } catch (e) { print(sb); rethrow; } - logTestComplete(++completed, 0, tests.length, null, null); + const StdoutLogger() + .logTestComplete(++completed, 0, tests.length, null, null); } - logSuiteComplete(); + const StdoutLogger().logSuiteComplete(); }); diff --git a/pkg/testing/lib/src/zone_helper.dart b/pkg/testing/lib/src/zone_helper.dart index 5359c2ef4fc..e2d106d80f3 100644 --- a/pkg/testing/lib/src/zone_helper.dart +++ b/pkg/testing/lib/src/zone_helper.dart @@ -11,7 +11,7 @@ import 'dart:io' show exit, stderr; import 'dart:isolate' show Capability, Isolate, ReceivePort; -import 'log.dart' show logUncaughtError; +import 'log.dart' show StdoutLogger; Future runGuarded(Future f(), {void printLineOnStdout(line), @@ -26,7 +26,7 @@ Future runGuarded(Future f(), Completer completer = new Completer(); handleUncaughtError(error, StackTrace stackTrace) { - logUncaughtError(error, stackTrace); + StdoutLogger().logUncaughtError(error, stackTrace); if (!completer.isCompleted) { completer.completeError(error, stackTrace); } else if (handleLateError != null) {