drive_test.dart 9.78 KB
Newer Older
yjbanov's avatar
yjbanov committed
1 2 3 4
// Copyright 2016 The Chromium 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
import 'dart:async';

7
import 'package:file/memory.dart';
8
import 'package:flutter_tools/src/android/android_device.dart';
9
import 'package:flutter_tools/src/base/common.dart';
yjbanov's avatar
yjbanov committed
10
import 'package:flutter_tools/src/base/file_system.dart';
11
import 'package:flutter_tools/src/base/io.dart';
12
import 'package:flutter_tools/src/base/platform.dart';
13
import 'package:flutter_tools/src/cache.dart';
14 15
import 'package:flutter_tools/src/commands/drive.dart';
import 'package:flutter_tools/src/device.dart';
16
import 'package:mockito/mockito.dart';
yjbanov's avatar
yjbanov committed
17 18
import 'package:test/test.dart';

19 20 21
import '../src/common.dart';
import '../src/context.dart';
import '../src/mocks.dart';
yjbanov's avatar
yjbanov committed
22

23
void main() {
yjbanov's avatar
yjbanov committed
24
  group('drive', () {
25 26
    DriveCommand command;
    Device mockDevice;
27 28
    MemoryFileSystem fs;
    Directory cwd;
29 30 31 32 33 34 35

    void withMockDevice([Device mock]) {
      mockDevice = mock ?? new MockDevice();
      targetDeviceFinder = () async => mockDevice;
      testDeviceManager.addDevice(mockDevice);
    }

36 37 38 39
    setUpAll(() {
      Cache.disableLocking();
    });

yjbanov's avatar
yjbanov committed
40
    setUp(() {
41 42
      command = new DriveCommand();
      applyMocksToCommand(command);
43 44 45 46 47 48 49
      fs = new MemoryFileSystem();
      cwd = fs.systemTempDirectory.createTempSync('some_app_');
      fs.currentDirectory = cwd;
      fs.directory('test').createSync();
      fs.directory('test_driver').createSync();
      fs.file('pubspec.yaml')..createSync();
      fs.file('.packages').createSync();
50
      setExitFunctionForTests();
51 52 53
      targetDeviceFinder = () {
        throw 'Unexpected call to targetDeviceFinder';
      };
54
      appStarter = (DriveCommand command) {
55 56
        throw 'Unexpected call to appStarter';
      };
57
      testRunner = (List<String> testArgs, String observatoryUri, bool previewDart2) {
58 59
        throw 'Unexpected call to testRunner';
      };
60
      appStopper = (DriveCommand command) {
61 62
        throw 'Unexpected call to appStopper';
      };
yjbanov's avatar
yjbanov committed
63 64 65
    });

    tearDown(() {
66
      command = null;
67
      restoreExitFunction();
68 69 70 71
      restoreAppStarter();
      restoreAppStopper();
      restoreTestRunner();
      restoreTargetDeviceFinder();
yjbanov's avatar
yjbanov committed
72 73
    });

74
    testUsingContext('returns 1 when test file is not found', () async {
75
      withMockDevice();
76

77 78
      final String testApp = fs.path.join(cwd.path, 'test', 'e2e.dart');
      final String testFile = fs.path.join(cwd.path, 'test_driver', 'e2e_test.dart');
79
      fs.file(testApp).createSync(recursive: true);
80

81
      final List<String> args = <String>[
yjbanov's avatar
yjbanov committed
82
        'drive',
83
        '--target=$testApp',
yjbanov's avatar
yjbanov committed
84
      ];
85 86 87 88 89
      try {
        await createTestCommandRunner(command).run(args);
        fail('Expect exception');
      } on ToolExit catch (e) {
        expect(e.exitCode ?? 1, 1);
90
        expect(e.message, contains('Test file not found: $testFile'));
91
      }
92
    }, overrides: <Type, Generator>{
93
      FileSystem: () => fs,
yjbanov's avatar
yjbanov committed
94 95 96
    });

    testUsingContext('returns 1 when app fails to run', () async {
97
      withMockDevice();
98
      appStarter = expectAsync1((DriveCommand command) async => null);
yjbanov's avatar
yjbanov committed
99

100 101
      final String testApp = fs.path.join(cwd.path, 'test_driver', 'e2e.dart');
      final String testFile = fs.path.join(cwd.path, 'test_driver', 'e2e_test.dart');
yjbanov's avatar
yjbanov committed
102

103
      final MemoryFileSystem memFs = fs;
104 105
      await memFs.file(testApp).writeAsString('main() { }');
      await memFs.file(testFile).writeAsString('main() { }');
yjbanov's avatar
yjbanov committed
106

107
      final List<String> args = <String>[
yjbanov's avatar
yjbanov committed
108 109 110
        'drive',
        '--target=$testApp',
      ];
111 112 113 114 115
      try {
        await createTestCommandRunner(command).run(args);
        fail('Expect exception');
      } on ToolExit catch (e) {
        expect(e.exitCode, 1);
116
        expect(e.message, contains('Application failed to start. Will not run test. Quitting.'));
117
      }
118
    }, overrides: <Type, Generator>{
119
      FileSystem: () => fs,
yjbanov's avatar
yjbanov committed
120 121
    });

122
    testUsingContext('returns 1 when app file is outside package', () async {
123
      final String appFile = fs.path.join(cwd.dirname, 'other_app', 'app.dart');
124
      fs.file(appFile).createSync(recursive: true);
125
      final List<String> args = <String>[
126 127 128
        'drive',
        '--target=$appFile',
      ];
129 130 131 132 133 134
      try {
        await createTestCommandRunner(command).run(args);
        fail('Expect exception');
      } on ToolExit catch (e) {
        expect(e.exitCode ?? 1, 1);
        expect(testLogger.errorText, contains(
135
            'Application file $appFile is outside the package directory ${cwd.path}',
136
        ));
137
      }
138
    }, overrides: <Type, Generator>{
139
      FileSystem: () => fs,
140 141 142
    });

    testUsingContext('returns 1 when app file is in the root dir', () async {
143
      final String appFile = fs.path.join(cwd.path, 'main.dart');
144
      fs.file(appFile).createSync(recursive: true);
145
      final List<String> args = <String>[
146 147 148
        'drive',
        '--target=$appFile',
      ];
149 150 151 152 153 154
      try {
        await createTestCommandRunner(command).run(args);
        fail('Expect exception');
      } on ToolExit catch (e) {
        expect(e.exitCode ?? 1, 1);
        expect(testLogger.errorText, contains(
155 156
            'Application file main.dart must reside in one of the '
            'sub-directories of the package structure, not in the root directory.',
157
        ));
158
      }
159
    }, overrides: <Type, Generator>{
160
      FileSystem: () => fs,
161 162
    });

yjbanov's avatar
yjbanov committed
163
    testUsingContext('returns 0 when test ends successfully', () async {
164 165
      withMockDevice();

166 167
      final String testApp = fs.path.join(cwd.path, 'test', 'e2e.dart');
      final String testFile = fs.path.join(cwd.path, 'test_driver', 'e2e_test.dart');
yjbanov's avatar
yjbanov committed
168

169
      appStarter = expectAsync1((DriveCommand command) async {
170
        return new LaunchResult.succeeded();
171
      });
172
      testRunner = expectAsync3((List<String> testArgs, String observatoryUri, bool previewDart2) async {
173
        expect(testArgs, <String>[testFile]);
174
        return null;
175
      });
176
      appStopper = expectAsync1((DriveCommand command) async {
177
        return true;
178
      });
yjbanov's avatar
yjbanov committed
179

180
      final MemoryFileSystem memFs = fs;
yjbanov's avatar
yjbanov committed
181 182 183
      await memFs.file(testApp).writeAsString('main() {}');
      await memFs.file(testFile).writeAsString('main() {}');

184
      final List<String> args = <String>[
yjbanov's avatar
yjbanov committed
185 186 187
        'drive',
        '--target=$testApp',
      ];
188 189
      await createTestCommandRunner(command).run(args);
      expect(testLogger.errorText, isEmpty);
190
    }, overrides: <Type, Generator>{
191
      FileSystem: () => fs,
yjbanov's avatar
yjbanov committed
192
    });
193

194 195 196
    testUsingContext('returns exitCode set by test runner', () async {
      withMockDevice();

197 198
      final String testApp = fs.path.join(cwd.path, 'test', 'e2e.dart');
      final String testFile = fs.path.join(cwd.path, 'test_driver', 'e2e_test.dart');
199

200
      appStarter = expectAsync1((DriveCommand command) async {
201
        return new LaunchResult.succeeded();
202
      });
203
      testRunner = (List<String> testArgs, String observatoryUri, bool previewDart2) async {
204 205
        throwToolExit(null, exitCode: 123);
      };
206
      appStopper = expectAsync1((DriveCommand command) async {
207
        return true;
208 209
      });

210
      final MemoryFileSystem memFs = fs;
211 212 213
      await memFs.file(testApp).writeAsString('main() {}');
      await memFs.file(testFile).writeAsString('main() {}');

214
      final List<String> args = <String>[
215 216 217
        'drive',
        '--target=$testApp',
      ];
218 219 220 221 222 223 224
      try {
        await createTestCommandRunner(command).run(args);
        fail('Expect exception');
      } on ToolExit catch (e) {
        expect(e.exitCode ?? 1, 123);
        expect(e.message, isNull);
      }
225
    }, overrides: <Type, Generator>{
226
      FileSystem: () => fs,
227 228
    });

229 230 231 232 233 234 235
    group('findTargetDevice', () {
      testUsingContext('uses specified device', () async {
        testDeviceManager.specifiedDeviceId = '123';
        withMockDevice();
        when(mockDevice.name).thenReturn('specified-device');
        when(mockDevice.id).thenReturn('123');

236
        final Device device = await findTargetDevice();
237
        expect(device.name, 'specified-device');
238
      }, overrides: <Type, Generator>{
239
        FileSystem: () => fs,
240 241 242
      });
    });

243 244
    void findTargetDeviceOnOperatingSystem(String operatingSystem) {
      Platform platform() => new FakePlatform(operatingSystem: operatingSystem);
245 246 247

      testUsingContext('returns null if no devices found', () async {
        expect(await findTargetDevice(), isNull);
248
      }, overrides: <Type, Generator>{
249
        FileSystem: () => fs,
250
        Platform: platform,
251 252 253 254 255 256 257
      });

      testUsingContext('uses existing Android device', () async {
        mockDevice = new MockAndroidDevice();
        when(mockDevice.name).thenReturn('mock-android-device');
        withMockDevice(mockDevice);

258
        final Device device = await findTargetDevice();
259
        expect(device.name, 'mock-android-device');
260
      }, overrides: <Type, Generator>{
261
        FileSystem: () => fs,
262
        Platform: platform,
263
      });
264 265 266
    }

    group('findTargetDevice on Linux', () {
267
      findTargetDeviceOnOperatingSystem('linux');
268 269 270
    });

    group('findTargetDevice on Windows', () {
271
      findTargetDeviceOnOperatingSystem('windows');
272
    });
273 274 275 276 277 278 279 280 281

    group('findTargetDevice on macOS', () {
      findTargetDeviceOnOperatingSystem('macos');

      Platform macOsPlatform() => new FakePlatform(operatingSystem: 'macos');

      testUsingContext('uses existing simulator', () async {
        withMockDevice();
        when(mockDevice.name).thenReturn('mock-simulator');
282 283
        when(mockDevice.isLocalEmulator)
            .thenAnswer((Invocation invocation) => new Future<bool>.value(true));
284 285 286 287 288 289 290 291

        final Device device = await findTargetDevice();
        expect(device.name, 'mock-simulator');
      }, overrides: <Type, Generator>{
        FileSystem: () => fs,
        Platform: macOsPlatform,
      });
    });
292
  });
yjbanov's avatar
yjbanov committed
293
}
294 295 296

class MockDevice extends Mock implements Device {
  MockDevice() {
297
    when(isSupported()).thenReturn(true);
298 299 300 301
  }
}

class MockAndroidDevice extends Mock implements AndroidDevice { }