blob: bd95e87df0acb182f1d6869112cb60c381c1d502 [file] [log] [blame]
// 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/artifacts.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/ios/devices.dart';
import 'package:flutter_tools/src/ios/mac.dart';
import 'package:mockito/mockito.dart';
import 'package:vm_service/vm_service.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/testbed.dart';
void main() {
FakeProcessManager processManager;
MockArtifacts artifacts;
FakeCache fakeCache;
BufferLogger logger;
setUp(() {
processManager = FakeProcessManager.list(<FakeCommand>[]);
fakeCache = FakeCache();
artifacts = MockArtifacts();
logger = BufferLogger.test();
when(artifacts.getArtifactPath(Artifact.idevicesyslog, platform: TargetPlatform.ios))
.thenReturn('idevice-syslog');
});
testWithoutContext('decodeSyslog decodes a syslog-encoded line', () {
final String decoded = decodeSyslog(
r'I \M-b\M^]\M-$\M-o\M-8\M^O syslog \M-B\M-/\'
r'134_(\M-c\M^C\M^D)_/\M-B\M-/ \M-l\M^F\240!');
expect(decoded, r'I ❤️ syslog ¯\_(ツ)_/¯ 솠!');
});
testWithoutContext('decodeSyslog passes through un-decodeable lines as-is', () {
final String decoded = decodeSyslog(r'I \M-b\M^O syslog!');
expect(decoded, r'I \M-b\M^O syslog!');
});
testWithoutContext('IOSDeviceLogReader suppresses non-Flutter lines from output with syslog', () async {
processManager.addCommand(
const FakeCommand(
command: <String>[
'idevice-syslog', '-u', '1234',
],
stdout: '''
Runner(Flutter)[297] <Notice>: A is for ari
Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt MobileGestaltSupport.m:153: pid 123 (Runner) does not have sandbox access for frZQaeyWLUvLjeuEK43hmg and IS NOT appropriately entitled
Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt MobileGestalt.c:550: no access to InverseDeviceID (see <rdar://problem/11744455>)
Runner(Flutter)[297] <Notice>: I is for ichigo
Runner(UIKit)[297] <Notice>: E is for enpitsu"
'''
),
);
final DeviceLogReader logReader = IOSDeviceLogReader.test(
iMobileDevice: IMobileDevice(
artifacts: artifacts,
processManager: processManager,
cache: fakeCache,
logger: logger,
),
);
final List<String> lines = await logReader.logLines.toList();
expect(lines, <String>['A is for ari', 'I is for ichigo']);
});
testWithoutContext('IOSDeviceLogReader includes multi-line Flutter logs in the output with syslog', () async {
processManager.addCommand(
const FakeCommand(
command: <String>[
'idevice-syslog', '-u', '1234',
],
stdout: '''
Runner(Flutter)[297] <Notice>: This is a multi-line message,
with another Flutter message following it.
Runner(Flutter)[297] <Notice>: This is a multi-line message,
with a non-Flutter log message following it.
Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
'''
),
);
final DeviceLogReader logReader = IOSDeviceLogReader.test(
iMobileDevice: IMobileDevice(
artifacts: artifacts,
processManager: processManager,
cache: fakeCache,
logger: logger,
),
);
final List<String> lines = await logReader.logLines.toList();
expect(lines, <String>[
'This is a multi-line message,',
' with another Flutter message following it.',
'This is a multi-line message,',
' with a non-Flutter log message following it.',
]);
});
testWithoutContext('includes multi-line Flutter logs in the output', () async {
processManager.addCommand(
const FakeCommand(
command: <String>[
'idevice-syslog', '-u', '1234',
],
stdout: '''
Runner(Flutter)[297] <Notice>: This is a multi-line message,
with another Flutter message following it.
Runner(Flutter)[297] <Notice>: This is a multi-line message,
with a non-Flutter log message following it.
Runner(libsystem_asl.dylib)[297] <Notice>: libMobileGestalt
''',
),
);
final DeviceLogReader logReader = IOSDeviceLogReader.test(
iMobileDevice: IMobileDevice(
artifacts: artifacts,
processManager: processManager,
cache: fakeCache,
logger: logger,
),
);
final List<String> lines = await logReader.logLines.toList();
expect(lines, <String>[
'This is a multi-line message,',
' with another Flutter message following it.',
'This is a multi-line message,',
' with a non-Flutter log message following it.',
]);
});
testWithoutContext('IOSDeviceLogReader can listen to VM Service logs', () async {
final MockVmService vmService = MockVmService();
final DeviceLogReader logReader = IOSDeviceLogReader.test(
useSyslog: false,
iMobileDevice: IMobileDevice(
artifacts: artifacts,
processManager: processManager,
cache: fakeCache,
logger: logger,
),
);
final StreamController<Event> stdoutController = StreamController<Event>();
final StreamController<Event> stderController = StreamController<Event>();
final Completer<Success> stdoutCompleter = Completer<Success>();
final Completer<Success> stderrCompleter = Completer<Success>();
when(vmService.streamListen('Stdout')).thenAnswer((Invocation invocation) {
return stdoutCompleter.future;
});
when(vmService.streamListen('Stderr')).thenAnswer((Invocation invocation) {
return stderrCompleter.future;
});
when(vmService.onStdoutEvent).thenAnswer((Invocation invocation) {
return stdoutController.stream;
});
when(vmService.onStderrEvent).thenAnswer((Invocation invocation) {
return stderController.stream;
});
logReader.connectedVMService = vmService;
stdoutCompleter.complete(Success());
stderrCompleter.complete(Success());
stdoutController.add(Event(
kind: 'Stdout',
timestamp: 0,
bytes: base64.encode(utf8.encode(' This is a message ')),
));
stderController.add(Event(
kind: 'Stderr',
timestamp: 0,
bytes: base64.encode(utf8.encode(' And this is an error ')),
));
// Wait for stream listeners to fire.
await expectLater(logReader.logLines, emitsInAnyOrder(<Matcher>[
equals(' This is a message '),
equals(' And this is an error '),
]));
});
}
class MockArtifacts extends Mock implements Artifacts {}
class MockVmService extends Mock implements VmService {}