| // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file |
| // for details. 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:io' as io; |
| |
| import 'package:file/file.dart'; |
| import 'package:file/memory.dart'; |
| import 'package:test/test.dart'; |
| import 'package:unified_analytics/src/constants.dart'; |
| import 'package:unified_analytics/src/enums.dart'; |
| import 'package:unified_analytics/src/utils.dart'; |
| import 'package:unified_analytics/unified_analytics.dart'; |
| |
| void main() { |
| late MemoryFileSystem fs; |
| late Directory home; |
| late Directory dartToolDirectory; |
| late File clientIdFile; |
| late File sessionFile; |
| late File configFile; |
| late File logFile; |
| late File dismissedSurveyFile; |
| |
| const homeDirName = 'home'; |
| const initialTool = DashTool.flutterTool; |
| const secondTool = DashTool.dartTool; |
| const toolsMessageVersion = 1; |
| const toolsMessage = 'toolsMessage'; |
| const flutterChannel = 'flutterChannel'; |
| const flutterVersion = 'flutterVersion'; |
| const dartVersion = 'dartVersion'; |
| const platform = DevicePlatform.macos; |
| |
| final testEvent = Event.hotReloadTime(timeMs: 50); |
| |
| setUp(() { |
| // Setup the filesystem with the home directory |
| final fsStyle = |
| io.Platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix; |
| fs = MemoryFileSystem.test(style: fsStyle); |
| home = fs.directory(homeDirName); |
| dartToolDirectory = home.childDirectory(kDartToolDirectoryName); |
| |
| // The 3 files that should have been generated |
| clientIdFile = home |
| .childDirectory(kDartToolDirectoryName) |
| .childFile(kClientIdFileName); |
| sessionFile = |
| home.childDirectory(kDartToolDirectoryName).childFile(kSessionFileName); |
| configFile = |
| home.childDirectory(kDartToolDirectoryName).childFile(kConfigFileName); |
| logFile = |
| home.childDirectory(kDartToolDirectoryName).childFile(kLogFileName); |
| dismissedSurveyFile = home |
| .childDirectory(kDartToolDirectoryName) |
| .childFile(kDismissedSurveyFileName); |
| }); |
| |
| test('Confirm workflow for first run', () { |
| final firstAnalytics = Analytics.fake( |
| tool: initialTool, |
| homeDirectory: home, |
| flutterChannel: flutterChannel, |
| toolsMessageVersion: toolsMessageVersion, |
| toolsMessage: toolsMessage, |
| flutterVersion: flutterVersion, |
| dartVersion: dartVersion, |
| fs: fs, |
| platform: platform, |
| ); |
| |
| expect(firstAnalytics.shouldShowMessage, true); |
| expect(firstAnalytics.okToSend, false); |
| |
| firstAnalytics.clientShowedMessage(); |
| expect(firstAnalytics.shouldShowMessage, false); |
| expect(firstAnalytics.okToSend, false, |
| reason: 'On the first run, we should not be ok ' |
| 'to send any events, even if the user accepts'); |
| }); |
| |
| test('Confirm workflow for updated tools message version + new tool', () { |
| // Helper function to check the state of the instance |
| void checkAnalyticsInstance(Analytics instance) { |
| expect(instance.shouldShowMessage, true); |
| expect(instance.okToSend, false); |
| |
| instance.clientShowedMessage(); |
| expect(instance.shouldShowMessage, false); |
| expect(instance.okToSend, false, |
| reason: 'On the first run, we should not be ok ' |
| 'to send any events, even if the user accepts'); |
| } |
| |
| final firstAnalytics = Analytics.fake( |
| tool: initialTool, |
| homeDirectory: home, |
| flutterChannel: flutterChannel, |
| toolsMessageVersion: toolsMessageVersion, |
| toolsMessage: toolsMessage, |
| flutterVersion: flutterVersion, |
| dartVersion: dartVersion, |
| fs: fs, |
| platform: platform, |
| ); |
| |
| checkAnalyticsInstance(firstAnalytics); |
| |
| // Instance where we increment the version of the message |
| final secondAnalytics = Analytics.fake( |
| tool: initialTool, |
| homeDirectory: home, |
| flutterChannel: flutterChannel, |
| toolsMessageVersion: toolsMessageVersion + 1, // Incrementing version |
| toolsMessage: toolsMessage, |
| flutterVersion: flutterVersion, |
| dartVersion: dartVersion, |
| fs: fs, |
| platform: platform, |
| ); |
| |
| // Running the same checks for the second instance, it should |
| // behave the same as if it was a first run |
| checkAnalyticsInstance(secondAnalytics); |
| |
| // Instance for a different tool with the incremented version |
| final thirdAnalytics = Analytics.fake( |
| tool: secondTool, // Different tool |
| homeDirectory: home, |
| flutterChannel: flutterChannel, |
| toolsMessageVersion: toolsMessageVersion + 1, // Incrementing version |
| toolsMessage: toolsMessage, |
| flutterVersion: flutterVersion, |
| dartVersion: dartVersion, |
| fs: fs, |
| platform: platform, |
| ); |
| |
| // The instance with a new tool getting onboarded should be |
| // treated the same as the 2 previous instances |
| checkAnalyticsInstance(thirdAnalytics); |
| }); |
| |
| test('Confirm workflow for checking tools into the config file', () { |
| final firstAnalytics = Analytics.fake( |
| tool: initialTool, |
| homeDirectory: home, |
| flutterChannel: flutterChannel, |
| toolsMessageVersion: toolsMessageVersion, |
| toolsMessage: toolsMessage, |
| flutterVersion: flutterVersion, |
| dartVersion: dartVersion, |
| fs: fs, |
| platform: platform, |
| ); |
| |
| // Host of assertions to ensure all required artifacts |
| // are created |
| expect(dartToolDirectory.existsSync(), true, |
| reason: 'The directory should have been created'); |
| expect(clientIdFile.existsSync(), true, |
| reason: 'The $kClientIdFileName file was not found'); |
| expect(sessionFile.existsSync(), true, |
| reason: 'The $kSessionFileName file was not found'); |
| expect(configFile.existsSync(), true, |
| reason: 'The $kConfigFileName was not found'); |
| expect(logFile.existsSync(), true, |
| reason: 'The $kLogFileName file was not found'); |
| expect(dismissedSurveyFile.existsSync(), true, |
| reason: 'The $dismissedSurveyFile file was not found'); |
| expect( |
| dartToolDirectory.listSync().length, |
| equals(5), |
| reason: 'There should only be 5 files in the $kDartToolDirectoryName ' |
| 'directory', |
| ); |
| expect(configFile.readAsStringSync(), kConfigString); |
| |
| expect(firstAnalytics.shouldShowMessage, true); |
| |
| // Attempting to send a message with this instance should be |
| // blocked because it has not invoked `clientShowedMessage()` |
| // and it is the first run |
| // |
| // Even after invoking the method, it should be prevented from |
| // sending a message because it is the first time the tool was |
| // run in this instance |
| firstAnalytics.send(testEvent); |
| expect(logFile.readAsLinesSync().length, 0); |
| firstAnalytics.clientShowedMessage(); |
| |
| // Attempt to send two events, both should be blocked because it is |
| // part of the first instance |
| firstAnalytics.send(testEvent); |
| firstAnalytics.send(testEvent); |
| expect(logFile.readAsLinesSync().length, 0); |
| |
| // Creating a second analytics instance from the same tool now should |
| // allow for events to be sent |
| final secondAnalytics = Analytics.fake( |
| tool: initialTool, |
| homeDirectory: home, |
| flutterChannel: flutterChannel, |
| toolsMessageVersion: toolsMessageVersion, |
| toolsMessage: toolsMessage, |
| flutterVersion: flutterVersion, |
| dartVersion: dartVersion, |
| fs: fs, |
| platform: platform, |
| ); |
| |
| expect(secondAnalytics.shouldShowMessage, false); |
| secondAnalytics.send(testEvent); |
| expect(logFile.readAsLinesSync().length, 1, |
| reason: 'Events will be blocked until invoking method ' |
| 'ensuring client has seen message'); |
| |
| secondAnalytics.send(testEvent); |
| secondAnalytics.send(testEvent); |
| expect(logFile.readAsLinesSync().length, 3); |
| |
| // Next, we will want to confirm that the message should be showing when |
| // a new analytics instance has been created with a newer version for |
| // message that should be shown |
| // |
| // In this case, it should be treated as a new tool being added for the |
| // first time and all events should be blocked |
| |
| // Delete the log file to reset the counter of events sent |
| logFile.deleteSync(); |
| final thirdAnalytics = Analytics.fake( |
| tool: initialTool, |
| homeDirectory: home, |
| flutterChannel: flutterChannel, |
| toolsMessageVersion: toolsMessageVersion + 1, // Incrementing version |
| toolsMessage: toolsMessage, |
| flutterVersion: flutterVersion, |
| dartVersion: dartVersion, |
| fs: fs, |
| platform: platform, |
| ); |
| |
| expect(logFile.existsSync(), true, |
| reason: 'The $kLogFileName file was not found'); |
| expect(thirdAnalytics.shouldShowMessage, true, |
| reason: 'New version number should require showing message'); |
| thirdAnalytics.send(testEvent); |
| expect(logFile.readAsLinesSync().length, 0); |
| thirdAnalytics.clientShowedMessage(); |
| |
| // Attempt to send two events, both should be blocked because it is |
| // part of the third instance which has a new version for the consent |
| // message which will be treated as a new tool being onboarded |
| thirdAnalytics.send(testEvent); |
| thirdAnalytics.send(testEvent); |
| expect(logFile.readAsLinesSync().length, 0); |
| |
| // The fourth instance of the analytics class with the consent message |
| // version incremented should now be able to send messages |
| final fourthAnalytics = Analytics.fake( |
| tool: initialTool, |
| homeDirectory: home, |
| flutterChannel: flutterChannel, |
| toolsMessageVersion: toolsMessageVersion + 1, // Incrementing version |
| toolsMessage: toolsMessage, |
| flutterVersion: flutterVersion, |
| dartVersion: dartVersion, |
| fs: fs, |
| platform: platform, |
| ); |
| |
| expect(fourthAnalytics.shouldShowMessage, false); |
| fourthAnalytics.send(testEvent); |
| expect(logFile.readAsLinesSync().length, 1, |
| reason: 'Events will be blocked until invoking method ' |
| 'ensuring client has seen message'); |
| |
| fourthAnalytics.send(testEvent); |
| fourthAnalytics.send(testEvent); |
| expect(logFile.readAsLinesSync().length, 3); |
| }); |
| |
| test('Disable second instance if first one did not show message', () { |
| final firstAnalytics = Analytics.fake( |
| tool: initialTool, |
| homeDirectory: home, |
| flutterChannel: flutterChannel, |
| toolsMessageVersion: toolsMessageVersion, |
| toolsMessage: toolsMessage, |
| flutterVersion: flutterVersion, |
| dartVersion: dartVersion, |
| fs: fs, |
| platform: platform, |
| ); |
| |
| expect(firstAnalytics.shouldShowMessage, true); |
| |
| final secondAnalytics = Analytics.fake( |
| tool: initialTool, |
| homeDirectory: home, |
| flutterChannel: flutterChannel, |
| toolsMessageVersion: toolsMessageVersion, |
| toolsMessage: toolsMessage, |
| flutterVersion: flutterVersion, |
| dartVersion: dartVersion, |
| fs: fs, |
| platform: platform, |
| ); |
| |
| expect(secondAnalytics.shouldShowMessage, true); |
| |
| secondAnalytics.clientShowedMessage(); |
| |
| final thirdAnalytics = Analytics.fake( |
| tool: initialTool, |
| homeDirectory: home, |
| flutterChannel: flutterChannel, |
| toolsMessageVersion: toolsMessageVersion, |
| toolsMessage: toolsMessage, |
| flutterVersion: flutterVersion, |
| dartVersion: dartVersion, |
| fs: fs, |
| platform: platform, |
| ); |
| |
| expect(thirdAnalytics.shouldShowMessage, false); |
| }); |
| |
| test('Passing large version number gets logged in config', () { |
| final firstVersion = toolsMessageVersion + 3; |
| final secondAnalytics = Analytics.fake( |
| tool: secondTool, |
| homeDirectory: home, |
| flutterChannel: flutterChannel, |
| toolsMessageVersion: firstVersion, |
| toolsMessage: toolsMessage, |
| flutterVersion: 'Flutter 3.6.0-7.0.pre.47', |
| dartVersion: 'Dart 2.19.0', |
| fs: fs, |
| platform: platform, |
| ); |
| secondAnalytics.clientShowedMessage(); |
| |
| expect( |
| configFile |
| .readAsStringSync() |
| .endsWith('${secondTool.label}=$dateStamp,$firstVersion\n'), |
| true); |
| |
| // Create a new instane of the secondTool with an even |
| // bigger version |
| final secondVersion = firstVersion + 3; |
| final thirdAnalytics = Analytics.fake( |
| tool: secondTool, |
| homeDirectory: home, |
| flutterChannel: flutterChannel, |
| toolsMessageVersion: secondVersion, |
| toolsMessage: toolsMessage, |
| flutterVersion: 'Flutter 3.6.0-7.0.pre.47', |
| dartVersion: 'Dart 2.19.0', |
| fs: fs, |
| platform: platform, |
| ); |
| |
| expect( |
| configFile |
| .readAsStringSync() |
| .endsWith('${secondTool.label}=$dateStamp,$firstVersion\n'), |
| true); |
| |
| // After invoking this method, it will get updated |
| // in the config with the next version |
| thirdAnalytics.clientShowedMessage(); |
| |
| expect( |
| configFile |
| .readAsStringSync() |
| .endsWith('${secondTool.label}=$dateStamp,$secondVersion\n'), |
| true); |
| }); |
| } |