analytics_test.dart 6.45 KB
Newer Older
1 2 3 4 5
// 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.

import 'package:args/command_runner.dart';
6 7 8
import 'package:mockito/mockito.dart';
import 'package:quiver/time.dart';

9
import 'package:flutter_tools/src/base/file_system.dart';
10
import 'package:flutter_tools/src/cache.dart';
11
import 'package:flutter_tools/src/commands/build.dart';
12 13
import 'package:flutter_tools/src/commands/config.dart';
import 'package:flutter_tools/src/commands/doctor.dart';
14
import 'package:flutter_tools/src/doctor.dart';
15
import 'package:flutter_tools/src/runner/flutter_command.dart';
16
import 'package:flutter_tools/src/usage.dart';
17
import 'package:flutter_tools/src/version.dart';
18 19 20 21 22 23

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

void main() {
  group('analytics', () {
24
    Directory tempDir;
25

26 27 28 29
    setUpAll(() {
      Cache.disableLocking();
    });

30
    setUp(() {
31
      Cache.flutterRoot = '../..';
32
      tempDir = fs.systemTempDirectory.createTempSync('flutter_tools_analytics_test.');
33 34 35
    });

    tearDown(() {
36
      tryToDelete(tempDir);
37 38 39 40 41 42 43 44
    });

    // Ensure we don't send anything when analytics is disabled.
    testUsingContext('doesn\'t send when disabled', () async {
      int count = 0;
      flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);

      flutterUsage.enabled = false;
45
      await createProject(tempDir);
46 47 48
      expect(count, 0);

      flutterUsage.enabled = true;
49
      await createProject(tempDir);
50 51 52 53
      expect(count, flutterUsage.isFirstRun ? 0 : 2);

      count = 0;
      flutterUsage.enabled = false;
54
      final DoctorCommand doctorCommand = DoctorCommand();
55
      final CommandRunner<void>runner = createTestCommandRunner(doctorCommand);
56
      await runner.run(<String>['doctor']);
57
      expect(count, 0);
58
    }, overrides: <Type, Generator>{
59 60
      FlutterVersion: () => FlutterVersion(const Clock()),
      Usage: () => Usage(configDirOverride: tempDir.path),
61 62
    });

63
    // Ensure we don't send for the 'flutter config' command.
64 65 66 67 68
    testUsingContext('config doesn\'t send', () async {
      int count = 0;
      flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);

      flutterUsage.enabled = false;
69
      final ConfigCommand command = ConfigCommand();
70
      final CommandRunner<void> runner = createTestCommandRunner(command);
71 72 73 74 75 76
      await runner.run(<String>['config']);
      expect(count, 0);

      flutterUsage.enabled = true;
      await runner.run(<String>['config']);
      expect(count, 0);
77
    }, overrides: <Type, Generator>{
78 79
      FlutterVersion: () => FlutterVersion(const Clock()),
      Usage: () => Usage(configDirOverride: tempDir.path),
80 81
    });
  });
82

83 84 85
  group('analytics with mocks', () {
    Usage mockUsage;
    Clock mockClock;
86
    Doctor mockDoctor;
87 88 89
    List<int> mockTimes;

    setUp(() {
90
      mockUsage = MockUsage();
91
      when(mockUsage.isFirstRun).thenReturn(false);
92 93
      mockClock = MockClock();
      mockDoctor = MockDoctor();
94
      when(mockClock.now()).thenAnswer(
95
        (Invocation _) => DateTime.fromMillisecondsSinceEpoch(mockTimes.removeAt(0))
96 97 98 99 100
      );
    });

    testUsingContext('flutter commands send timing events', () async {
      mockTimes = <int>[1000, 2000];
101
      when(mockDoctor.diagnose(androidLicenses: false, verbose: false)).thenAnswer((_) async => true);
102
      final DoctorCommand command = DoctorCommand();
103
      final CommandRunner<void> runner = createTestCommandRunner(command);
104 105 106 107 108
      await runner.run(<String>['doctor']);

      verify(mockClock.now()).called(2);

      expect(
109
        verify(mockUsage.sendTiming(captureAny, captureAny, captureAny, label: captureAnyNamed('label'))).captured,
110
        <dynamic>['flutter', 'doctor', const Duration(milliseconds: 1000), 'success']
111 112 113
      );
    }, overrides: <Type, Generator>{
      Clock: () => mockClock,
114 115 116 117 118 119
      Doctor: () => mockDoctor,
      Usage: () => mockUsage,
    });

    testUsingContext('doctor fail sends warning', () async {
      mockTimes = <int>[1000, 2000];
120
      when(mockDoctor.diagnose(androidLicenses: false, verbose: false)).thenAnswer((_) async => false);
121
      final DoctorCommand command = DoctorCommand();
122
      final CommandRunner<void> runner = createTestCommandRunner(command);
123 124 125 126 127
      await runner.run(<String>['doctor']);

      verify(mockClock.now()).called(2);

      expect(
128
        verify(mockUsage.sendTiming(captureAny, captureAny, captureAny, label: captureAnyNamed('label'))).captured,
129 130 131 132 133
        <dynamic>['flutter', 'doctor', const Duration(milliseconds: 1000), 'warning']
      );
    }, overrides: <Type, Generator>{
      Clock: () => mockClock,
      Doctor: () => mockDoctor,
134 135
      Usage: () => mockUsage,
    });
136 137

    testUsingContext('single command usage path', () async {
138
      final FlutterCommand doctorCommand = DoctorCommand();
139 140 141 142 143 144
      expect(await doctorCommand.usagePath, 'doctor');
    }, overrides: <Type, Generator>{
      Usage: () => mockUsage,
    });

    testUsingContext('compound command usage path', () async {
145
      final BuildCommand buildCommand = BuildCommand();
146 147 148 149 150
      final FlutterCommand buildApkCommand = buildCommand.subcommands['apk'];
      expect(await buildApkCommand.usagePath, 'build/apk');
    }, overrides: <Type, Generator>{
      Usage: () => mockUsage,
    });
151 152
  });

153
  group('analytics bots', () {
154 155
    Directory tempDir;

156
    setUp(() {
157 158 159 160 161
      tempDir = fs.systemTempDirectory.createTempSync('flutter_tools_analytics_bots_test.');
    });

    tearDown(() {
      tryToDelete(tempDir);
162 163
    });

164 165 166 167 168 169
    testUsingContext('don\'t send on bots', () async {
      int count = 0;
      flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);

      await createTestCommandRunner().run(<String>['--version']);
      expect(count, 0);
170
    }, overrides: <Type, Generator>{
171
      Usage: () => Usage(
172 173
        settingsName: 'flutter_bot_test',
        versionOverride: 'dev/unknown',
174
        configDirOverride: tempDir.path,
175 176 177 178 179 180 181 182 183 184 185
      ),
    });

    testUsingContext('don\'t send on bots even when opted in', () async {
      int count = 0;
      flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
      flutterUsage.enabled = true;

      await createTestCommandRunner().run(<String>['--version']);
      expect(count, 0);
    }, overrides: <Type, Generator>{
186
      Usage: () => Usage(
187 188
        settingsName: 'flutter_bot_test',
        versionOverride: 'dev/unknown',
189
        configDirOverride: tempDir.path,
190
      ),
191 192
    });
  });
193
}
194 195

class MockUsage extends Mock implements Usage {}
196 197

class MockDoctor extends Mock implements Doctor {}