adb_log_reader_test.dart 5.96 KB
Newer Older
1 2 3 4
// 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.

5 6
// @dart = 2.8

7 8 9
import 'dart:async';

import 'package:flutter_tools/src/android/android_device.dart';
10
import 'package:test/fake.dart';
11 12

import '../../src/common.dart';
13
import '../../src/fake_process_manager.dart';
14 15 16 17

const int kLollipopVersionCode = 21;
const String kLastLogcatTimestamp = '11-27 15:39:04.506';

18 19 20 21 22
/// By default the android log reader accepts lines that match no patterns
/// if the previous line was a match. Include an intentionally non-matching
/// line as the first input to disable this behavior.
const String kDummyLine = 'Contents are not important\n';

23 24 25 26 27 28 29 30
void main() {
  testWithoutContext('AdbLogReader calls adb logcat with expected flags apiVersion 21', () async {
    final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      const FakeCommand(
        command: <String>[
          'adb',
          '-s',
          '1234',
31 32
          'shell',
          '-x',
33 34 35 36
          'logcat',
          '-v',
          'time',
          '-T',
37
          "'$kLastLogcatTimestamp'",
38 39 40 41
        ],
      )
    ]);
    await AdbLogReader.createLogReader(
42
      createFakeDevice(kLollipopVersionCode),
43 44 45
      processManager,
    );

46
    expect(processManager, hasNoRemainingExpectations);
47 48 49 50 51 52 53 54 55
  });

  testWithoutContext('AdbLogReader calls adb logcat with expected flags apiVersion < 21', () async {
    final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      const FakeCommand(
        command: <String>[
          'adb',
          '-s',
          '1234',
56 57
          'shell',
          '-x',
58 59 60 61 62 63 64
          'logcat',
          '-v',
          'time',
        ],
      )
    ]);
    await AdbLogReader.createLogReader(
65
      createFakeDevice(kLollipopVersionCode - 1),
66 67 68
      processManager,
    );

69
    expect(processManager, hasNoRemainingExpectations);
70 71 72 73 74 75 76 77 78
  });

  testWithoutContext('AdbLogReader calls adb logcat with expected flags null apiVersion', () async {
    final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      const FakeCommand(
        command: <String>[
          'adb',
          '-s',
          '1234',
79 80
          'shell',
          '-x',
81 82 83 84 85 86 87
          'logcat',
          '-v',
          'time',
        ],
      )
    ]);
    await AdbLogReader.createLogReader(
88
      createFakeDevice(null),
89 90 91
      processManager,
    );

92
    expect(processManager, hasNoRemainingExpectations);
93 94
  });

95 96 97 98 99 100 101
  testWithoutContext('AdbLogReader calls adb logcat with expected flags when requesting past logs', () async {
    final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      const FakeCommand(
        command: <String>[
          'adb',
          '-s',
          '1234',
102 103
          'shell',
          '-x',
104 105 106 107 108 109 110 111 112
          'logcat',
          '-v',
          'time',
          '-s',
          'flutter',
        ],
      )
    ]);
    await AdbLogReader.createLogReader(
113
      createFakeDevice(null),
114 115 116 117
      processManager,
      includePastLogs: true,
    );

118
    expect(processManager, hasNoRemainingExpectations);
119 120
  });

121 122 123 124 125 126 127
  testWithoutContext('AdbLogReader handles process early exit', () async {
    final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      FakeCommand(
        command: const <String>[
          'adb',
          '-s',
          '1234',
128 129
          'shell',
          '-x',
130 131 132 133 134 135 136 137 138
          'logcat',
          '-v',
          'time',
        ],
        completer: Completer<void>.sync(),
        stdout: 'Hello There\n',
      )
    ]);
    final AdbLogReader logReader = await AdbLogReader.createLogReader(
139
      createFakeDevice(null),
140 141 142 143 144 145 146 147
      processManager,
    );
    final Completer<void> onDone = Completer<void>.sync();
    logReader.logLines.listen((String _) { }, onDone: onDone.complete);

    logReader.dispose();
    await onDone.future;
  });
148 149 150 151 152 153 154 155

  testWithoutContext('AdbLogReader does not filter output from AndroidRuntime crashes', () async {
    final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      FakeCommand(
        command: const <String>[
          'adb',
          '-s',
          '1234',
156 157
          'shell',
          '-x',
158 159 160 161 162
          'logcat',
          '-v',
          'time',
        ],
        completer: Completer<void>.sync(),
163
        // Example stack trace from an incorrectly named application:name in the AndroidManifest.xml
164
        stdout:
165
          '$kDummyLine'
166 167 168 169 170 171 172
          '05-11 12:54:46.665 E/AndroidRuntime(11787): FATAL EXCEPTION: main\n'
          '05-11 12:54:46.665 E/AndroidRuntime(11787): Process: com.example.foobar, PID: 11787\n'
          '05-11 12:54:46.665 java.lang.RuntimeException: Unable to instantiate application '
          'io.flutter.app.FlutterApplication2: java.lang.ClassNotFoundException:\n',
      )
    ]);
    final AdbLogReader logReader = await AdbLogReader.createLogReader(
173
      createFakeDevice(null),
174 175 176 177 178 179 180 181 182 183
      processManager,
    );
    await expectLater(logReader.logLines, emitsInOrder(<String>[
      'E/AndroidRuntime(11787): FATAL EXCEPTION: main',
      'E/AndroidRuntime(11787): Process: com.example.foobar, PID: 11787',
      'java.lang.RuntimeException: Unable to instantiate application io.flutter.app.FlutterApplication2: java.lang.ClassNotFoundException:',
    ]));

    logReader.dispose();
  });
184 185
}

186 187 188 189 190
AndroidDevice createFakeDevice(int sdkLevel) {
  return FakeAndroidDevice(
    sdkLevel.toString(),
    kLastLogcatTimestamp,
  );
191 192
}

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
class FakeAndroidDevice extends Fake implements AndroidDevice {
  FakeAndroidDevice(this._apiVersion, this._lastLogcatTimestamp);

  final String _lastLogcatTimestamp;
  final String _apiVersion;

  @override
  String get name => 'test-device';

  @override
  Future<String> get apiVersion => Future<String>.value(_apiVersion);

  @override
  Future<String> lastLogcatTimestamp() async => _lastLogcatTimestamp;

  @override
  List<String> adbCommandForDevice(List<String> command) {
    return <String>[
      'adb', '-s', '1234', ...command,
    ];
  }
}