| // Copyright 2014 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| import 'dart:convert'; | |
| import 'dart:io'; | |
| /// A result of running a single task. | |
| class TaskResult { | |
| TaskResult.buildOnly() | |
| : succeeded = true, | |
| data = null, | |
| detailFiles = null, | |
| benchmarkScoreKeys = null, | |
| message = 'No tests run'; | |
| /// Constructs a successful result. | |
| TaskResult.success(this.data, { | |
| this.benchmarkScoreKeys = const <String>[], | |
| this.detailFiles = const <String>[], | |
| this.message = 'success', | |
| }) | |
| : succeeded = true { | |
| const JsonEncoder prettyJson = JsonEncoder.withIndent(' '); | |
| if (benchmarkScoreKeys != null) { | |
| for (final String key in benchmarkScoreKeys!) { | |
| if (!data!.containsKey(key)) { | |
| throw 'Invalid benchmark score key "$key". It does not exist in task ' | |
| 'result data ${prettyJson.convert(data)}'; | |
| } else if (data![key] is! num) { | |
| throw 'Invalid benchmark score for key "$key". It is expected to be a num ' | |
| 'but was ${(data![key] as Object).runtimeType}: ${prettyJson.convert(data![key])}'; | |
| } | |
| } | |
| } | |
| } | |
| /// Constructs a successful result using JSON data stored in a file. | |
| factory TaskResult.successFromFile(File file, { | |
| List<String> benchmarkScoreKeys = const <String>[], | |
| List<String> detailFiles = const <String>[], | |
| }) { | |
| return TaskResult.success( | |
| json.decode(file.readAsStringSync()) as Map<String, dynamic>?, | |
| benchmarkScoreKeys: benchmarkScoreKeys, | |
| detailFiles: detailFiles, | |
| ); | |
| } | |
| /// Constructs a [TaskResult] from JSON. | |
| factory TaskResult.fromJson(Map<String, dynamic> json) { | |
| final bool success = json['success'] as bool; | |
| if (success) { | |
| final List<String> benchmarkScoreKeys = (json['benchmarkScoreKeys'] as List<dynamic>? ?? <String>[]).cast<String>(); | |
| final List<String> detailFiles = (json['detailFiles'] as List<dynamic>? ?? <String>[]).cast<String>(); | |
| return TaskResult.success(json['data'] as Map<String, dynamic>?, | |
| benchmarkScoreKeys: benchmarkScoreKeys, | |
| detailFiles: detailFiles, | |
| message: json['reason'] as String?, | |
| ); | |
| } | |
| return TaskResult.failure(json['reason'] as String?); | |
| } | |
| /// Constructs an unsuccessful result. | |
| TaskResult.failure(this.message) | |
| : succeeded = false, | |
| data = null, | |
| detailFiles = null, | |
| benchmarkScoreKeys = null; | |
| /// Whether the task succeeded. | |
| final bool succeeded; | |
| /// Task-specific JSON data | |
| final Map<String, dynamic>? data; | |
| /// Files containing detail on the run (e.g. timeline trace files) | |
| final List<String>? detailFiles; | |
| /// Keys in [data] that store scores that will be submitted to Cocoon. | |
| /// | |
| /// Each key is also part of a benchmark's name tracked by Cocoon. | |
| final List<String>? benchmarkScoreKeys; | |
| /// Whether the task failed. | |
| bool get failed => !succeeded; | |
| /// Explains the result in a human-readable format. | |
| final String? message; | |
| /// Serializes this task result to JSON format. | |
| /// | |
| /// The JSON format is as follows: | |
| /// | |
| /// { | |
| /// "success": true|false, | |
| /// "data": arbitrary JSON data valid only for successful results, | |
| /// "detailFiles": list of filenames containing detail on the run | |
| /// "benchmarkScoreKeys": [ | |
| /// contains keys into "data" that represent benchmarks scores, which | |
| /// can be uploaded, for example. to golem, valid only for successful | |
| /// results | |
| /// ], | |
| /// "reason": failure reason string valid only for unsuccessful results | |
| /// } | |
| Map<String, dynamic> toJson() { | |
| final Map<String, dynamic> json = <String, dynamic>{ | |
| 'success': succeeded, | |
| }; | |
| if (succeeded) { | |
| json['data'] = data; | |
| json['detailFiles'] = detailFiles; | |
| json['benchmarkScoreKeys'] = benchmarkScoreKeys; | |
| } | |
| if (message != null || !succeeded) { | |
| json['reason'] = message; | |
| } | |
| return json; | |
| } | |
| @override | |
| String toString() => message ?? ''; | |
| } | |
| class TaskResultCheckProcesses extends TaskResult { | |
| TaskResultCheckProcesses() : super.success(null); | |
| } |