adb_log_reader_test.dart 5.89 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// 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:async';

import 'package:flutter_tools/src/android/android_device.dart';
import 'package:mockito/mockito.dart';

import '../../src/common.dart';
import '../../src/context.dart';

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

16 17 18 19 20
/// 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';

21 22 23 24 25 26 27 28
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',
29 30
          'shell',
          '-x',
31 32 33 34
          'logcat',
          '-v',
          'time',
          '-T',
35
          '\'$kLastLogcatTimestamp\'',
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
        ],
      )
    ]);
    await AdbLogReader.createLogReader(
      createMockDevice(kLollipopVersionCode),
      processManager,
    );

    expect(processManager.hasRemainingExpectations, false);
  });

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

    expect(processManager.hasRemainingExpectations, false);
  });

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

    expect(processManager.hasRemainingExpectations, false);
  });

93 94 95 96 97 98 99
  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',
100 101
          'shell',
          '-x',
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
          'logcat',
          '-v',
          'time',
          '-s',
          'flutter',
        ],
      )
    ]);
    await AdbLogReader.createLogReader(
      createMockDevice(null),
      processManager,
      includePastLogs: true,
    );

    expect(processManager.hasRemainingExpectations, false);
  });

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

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

  testWithoutContext('AdbLogReader does not filter output from AndroidRuntime crashes', () async {
    final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      FakeCommand(
        command: const <String>[
          'adb',
          '-s',
          '1234',
154 155
          'shell',
          '-x',
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
          'logcat',
          '-v',
          'time',
        ],
        completer: Completer<void>.sync(),
        // Example stack trace from an incorrectly named application:name in the AndroidManfiest.xml
        stdout:
          kDummyLine +
          '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(
      createMockDevice(null),
      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();
  });
182 183 184 185 186 187
}

MockAndroidDevice createMockDevice(int sdkLevel) {
  final MockAndroidDevice mockAndroidDevice = MockAndroidDevice();
  when(mockAndroidDevice.apiVersion)
    .thenAnswer((Invocation invocation) async => sdkLevel.toString());
188
  when(mockAndroidDevice.lastLogcatTimestamp()).thenAnswer((Invocation _) async => kLastLogcatTimestamp);
189 190 191 192 193 194 195 196
  when(mockAndroidDevice.adbCommandForDevice(any))
    .thenAnswer((Invocation invocation) => <String>[
      'adb', '-s', '1234', ...invocation.positionalArguments.first as List<String>
    ]);
  return mockAndroidDevice;
}

class MockAndroidDevice extends Mock implements AndroidDevice {}