task_result.dart 3.89 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
// 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 {
  /// Constructs a successful result.
  TaskResult.success(this.data, {
    this.benchmarkScoreKeys = const <String>[],
13
    this.detailFiles = const <String>[],
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
  })
      : succeeded = true,
        message = 'success' {
    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].runtimeType}: ${prettyJson.convert(data[key])}';
        }
      }
    }
  }

  /// Constructs a successful result using JSON data stored in a file.
32 33 34 35
  factory TaskResult.successFromFile(File file, {
    List<String> benchmarkScoreKeys = const <String>[],
    List<String> detailFiles = const <String>[],
  }) {
36 37 38
    return TaskResult.success(
      json.decode(file.readAsStringSync()) as Map<String, dynamic>,
      benchmarkScoreKeys: benchmarkScoreKeys,
39
      detailFiles: detailFiles,
40 41 42 43 44 45 46 47
    );
  }

  /// 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>();
48
      final List<String> detailFiles = (json['detailFiles'] as List<dynamic> ?? <String>[]).cast<String>();
49
      return TaskResult.success(json['data'] as Map<String, dynamic>,
50 51 52
        benchmarkScoreKeys: benchmarkScoreKeys,
        detailFiles: detailFiles,
      );
53 54 55 56 57 58 59 60 61 62
    }

    return TaskResult.failure(json['reason'] as String);
  }

  /// Constructs an unsuccessful result.
  TaskResult.failure(this.message)
      : succeeded = false,
        data = null,
        detailFiles = null,
63
        benchmarkScoreKeys = null;
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106

  /// 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;
107
      json['detailFiles'] = detailFiles;
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
      json['benchmarkScoreKeys'] = benchmarkScoreKeys;
    } else {
      json['reason'] = message;
    }

    return json;
  }

  @override
  String toString() => message;
}

class TaskResultCheckProcesses extends TaskResult {
  TaskResultCheckProcesses() : super.success(null);
}