예제 #1
0
        public async Task TestDefaultAppFlowImplementation()
        {
            var tracker = new MyAppFlowTracker2(new InMemoryKeyValueStore().GetTypeAdapter <AppFlowEvent>());

            AppFlow.AddAppFlowTracker(tracker);
            Log.MethodEntered(); // This will internally notify the AppFlow instance
            Assert.NotEmpty(await tracker.store.GetAllKeys());

            var s = StopwatchV2.StartNewV2();

            for (int i = 0; i < 20; i++)
            {
                await TaskV2.Delay(500);

                if ((await tracker.store.GetAllKeys()).Count() == 0)
                {
                    break;
                }
            }
            Assert.True(s.ElapsedMilliseconds < 5000, "s.ElapsedMilliseconds=" + s.ElapsedMilliseconds);

            Assert.Empty(await tracker.store.GetAllKeys());
            // Make sure the DefaultAppFlowImpl itself does not create more events while sending the existing ones:
            for (int i = 0; i < 10; i++)
            {
                await TaskV2.Delay(100);

                var c1 = tracker.eventsThatWereSent.Count;
                await TaskV2.Delay(100);

                var c2 = tracker.eventsThatWereSent.Count;
                Assert.Equal(c1, c2);
            }
        }
예제 #2
0
        public void TestAppFlowTracking()
        {
            AppFlow.AddAppFlowTracker(new MyAppFlowTracker1());
            Log.MethodEntered(); // This will internally notify the AppFlow instance
            MyAppFlowTracker1 t = AppFlow.GetAllOfType <MyAppFlowTracker1>().First();

            Assert.True(t.wasCalledByTestAppFlowTrackingTest);
        }
예제 #3
0
        private static LocalAnalytics CreateLocalAnalyticsSystem()
        {
            LocalAnalytics analytics = new LocalAnalytics(new InMemoryKeyValueStore());

            analytics.createStoreFor = (_) => new InMemoryKeyValueStore().GetTypeAdapter <AppFlowEvent>();
            // Setup the AppFlow logic to use the LocalAnalytics system:
            AppFlow.AddAppFlowTracker(new AppFlowToStore(analytics));
            return(analytics);
        }
예제 #4
0
        public static void Setup(DefaultFeatureFlagStore featureFlagStore)
        {
            IoC.inject.SetSingleton(new FeatureFlagManager(featureFlagStore));
            LocalAnalytics analytics = new LocalAnalytics();

            AppFlow.AddAppFlowTracker(new AppFlowToStore(analytics));
            var xpSystem = new DefaultProgressionSystem(analytics);

            IoC.inject.SetSingleton <ProgressionSystem>(xpSystem);
        }
예제 #5
0
        [Fact] // Event tracking should by default not interrupt the normal application flow:
        public void TestErrorInTrackEvent()
        {
            var tracker = new AppFlowThatThrowsErrors();

            AppFlow.AddAppFlowTracker(tracker);
            // Even though TrackEvent does not work correctly the application flow is not interrupted:
            AppFlow.TrackEvent("category 1", "action 1");
            IoC.inject.Get <IAppFlow>(this).TrackEvent("category 1", "action 2");
            // Directly using the tracker would not protect against the inner exception:
            Assert.Throws <InvalidOperationException>(() => tracker.TrackEvent("category 1", "action 3"));
        }
예제 #6
0
        public override IEnumerator RunTest()
        {
            AppFlow.AddAppFlowTracker(new AppFlowToLog().WithAllTrackingActive());

            var links = gameObject.GetLinkMap();

            links.Get <Button>("OptionsButton").SetOnClickAction(delegate {
                gameObject.GetViewStack().ShowView("ExampleUi2_OptionsScreen", gameObject);
            });
            links.Get <Button>("UserDetailsButton").SetOnClickAction(ShowUserUi);
            yield return(null);
        }
예제 #7
0
        public static async Task <ProgressionSystem <FeatureFlag> > Setup(KeyValueStoreTypeAdapter <FeatureFlag> featureFlagStore, LocalAnalytics analytics)
        {
            var ffm = new FeatureFlagManager <FeatureFlag>(featureFlagStore);

            IoC.inject.SetSingleton(ffm);
            AppFlow.AddAppFlowTracker(new AppFlowToStore(analytics).WithBasicTrackingActive());
            var xpSystem = new ProgressionSystem <FeatureFlag>(analytics, ffm);

            IoC.inject.SetSingleton <IProgressionSystem <FeatureFlag> >(xpSystem);
            await xpSystem.UpdateCurrentCategoryCounts();

            return(xpSystem);
        }
예제 #8
0
        public async Task TestDefaultProgressionSystem()
        {
            // Get your key from https://console.developers.google.com/apis/credentials
            var apiKey = "AIzaSyCtcFQMgRIUHhSuXggm4BtXT4eZvUrBWN0";
            // https://docs.google.com/spreadsheets/d/1KBamVmgEUX-fyogMJ48TT6h2kAMKyWU1uBL5skCGRBM contains the sheetId:
            var sheetId           = "1KBamVmgEUX-fyogMJ48TT6h2kAMKyWU1uBL5skCGRBM";
            var sheetName         = "MySheet1"; // Has to match the sheet name
            var googleSheetsStore = new GoogleSheetsKeyValueStore(new InMemoryKeyValueStore(), apiKey, sheetId, sheetName);
            var ffm = new FeatureFlagManager <FeatureFlag>(new FeatureFlagStore(new InMemoryKeyValueStore(), googleSheetsStore));

            IoC.inject.SetSingleton <FeatureFlagManager <FeatureFlag> >(ffm);

            LocalAnalytics analytics = new LocalAnalytics();

            AppFlow.AddAppFlowTracker(new AppFlowToStore(analytics));
            var xpSystem = new ProgressionSystem <FeatureFlag>(analytics, ffm);

            IoC.inject.SetSingleton <IProgressionSystem <FeatureFlag> >(xpSystem);

            await CleanupFilesFromTest(analytics, xpSystem);

            // Simulate User progression by causing analytics events:
            var eventCount = 1000;

            for (int i = 0; i < eventCount; i++)
            {
                AppFlow.TrackEvent(EventConsts.catMutation, "User did mutation nr " + i);
            }

            var flagId4 = "MyFlag4";
            var flag4   = await FeatureFlagManager <FeatureFlag> .instance.GetFeatureFlag(flagId4);

            Assert.Equal(1000, flag4.requiredXp); // The user needs >= 1000 XP for the feature

            // Now that the user has 1000 XP the condition of the TestXpSystem is met:
            Assert.True(await FeatureFlag.IsEnabled(flagId4));

            // The number of mutation events:
            Assert.Equal(eventCount, xpSystem.cachedCategoryCounts[EventConsts.catMutation]);
            // Since there are only mutation events the XP is equal to the factor*event count:
            Assert.Equal(await xpSystem.GetLatestXp(), eventCount * xpSystem.xpFactors[EventConsts.catMutation]);

            await CleanupFilesFromTest(analytics, xpSystem);
        }
예제 #9
0
        public override IEnumerator RunTest()
        {
            var testTracker = new TestAppFlowTracker();

            testTracker.WithAllTrackingActive();
            AppFlow.AddAppFlowTracker(testTracker);

            setupImmutableDatastore();
            // In setupImmutableDatastore() Log.MethodEntered is used, so there must be a recorded method:
            AssertV2.AreEqual(1, testTracker.recordedEvents.Count(x => x.category == EventConsts.catMethod));
            // In setupImmutableDatastore() the datastore will be set as a singleton:
            AssertV2.AreEqual(1, testTracker.recordedEvents.Count(x => x.action.Contains("DataStore")));

            var store = MyDataModel.GetStore();

            AssertV2.IsNotNull(store, "store");
            store.Dispatch(new ActionSetBool1()
            {
                newB = true
            });
            store.Dispatch(new ActionSetString1 {
                newS = "abc"
            });
            AssertV2.AreEqual(true, store.GetState().subSection1.bool1);
            AssertV2.AreEqual("abc", store.GetState().subSection1.string1);
            // After the 2 mutations, there should be 2 mutation AppFlow events recorded:
            AssertV2.AreEqual(2, testTracker.recordedEvents.Count(x => x.category == EventConsts.catMutation));

            var presenter = new MyDataModelPresenter();

            presenter.targetView = gameObject;
            yield return(presenter.LoadModelIntoView(store).AsCoroutine());

            // After the presenter loaded the UI there should be a load start and load end event recorded:
            AssertV2.AreEqual(2, testTracker.recordedEvents.Count(x => x.category == EventConsts.catPresenter));
            // The MyDataModelPresenter uses a GetLinkMap() when connecting to the view:
            AssertV2.AreEqual(1, testTracker.recordedEvents.Count(x => x.category == EventConsts.catLinked));

            yield return(new WaitForSeconds(1));
        }
예제 #10
0
        public async Task TestAppFlowToGoogleAnalytics()
        {
            var tracker = new GoogleAnalytics(TEST_APP_KEY, NewInMemoryStore());

            AppFlow.AddAppFlowTracker(tracker);

            var t = Log.MethodEntered(); // This will internally notify the AppFlow instance
            await TaskV2.Delay(100);

            Log.MethodDone(t);

            // Check that in the store of the tracker there are now events waiting to be sent:
            var count1 = (await tracker.store.GetAllKeys()).Count();

            Assert.True(count1 > 0);

            await TaskV2.Delay(3000);

            // Check that the events are no longer in the store (sent to Google Analytics):
            var count2 = (await tracker.store.GetAllKeys()).Count();

            Assert.True(count2 < count1, "count2=" + count2 + ", count1=" + count1);
        }
예제 #11
0
        public async Task TestProgressiveDisclosure()
        {
            // Get your key from https://console.developers.google.com/apis/credentials
            var apiKey = "AIzaSyCtcFQMgRIUHhSuXggm4BtXT4eZvUrBWN0";
            // https://docs.google.com/spreadsheets/d/1KBamVmgEUX-fyogMJ48TT6h2kAMKyWU1uBL5skCGRBM contains the sheetId:
            var sheetId           = "1KBamVmgEUX-fyogMJ48TT6h2kAMKyWU1uBL5skCGRBM";
            var sheetName         = "MySheet1"; // Has to match the sheet name
            var googleSheetsStore = new GoogleSheetsKeyValueStore(new InMemoryKeyValueStore(), apiKey, sheetId, sheetName);
            var testStore         = new FeatureFlagStore(new InMemoryKeyValueStore(), googleSheetsStore);

            IoC.inject.SetSingleton <FeatureFlagManager <FeatureFlag> >(new FeatureFlagManager <FeatureFlag>(testStore));

            // Make sure user would normally be included in the rollout:
            var flagId4 = "MyFlag4";
            var flag4   = await FeatureFlagManager <FeatureFlag> .instance.GetFeatureFlag(flagId4);

            Assert.Equal(flagId4, flag4.id);
            Assert.Equal(100, flag4.rolloutPercentage);

            // There is no user progression system setup so the requiredXp value of the feature flag is ignored:
            Assert.True(await FeatureFlag.IsEnabled(flagId4));
            Assert.True(await flag4.IsFeatureUnlocked());

            // Setup progression system and check again:
            var xpSystem = new TestXpSystem();

            IoC.inject.SetSingleton <IProgressionSystem <FeatureFlag> >(xpSystem);
            // Now that there is a progression system
            Assert.False(await flag4.IsFeatureUnlocked());
            Assert.False(await FeatureFlag.IsEnabled(flagId4));

            var eventCount = 1000;

            var store = new MutationObserverKeyValueStore().WithFallbackStore(new InMemoryKeyValueStore());

            // Lets assume the users xp correlates with the number of triggered local analytics events:
            store.onSet = delegate {
                xpSystem.currentXp++;
                return(Task.FromResult(true));
            };

            // Set the store to be the target of the local analytics so that whenever any
            LocalAnalytics analytics = new LocalAnalytics(store);

            analytics.createStoreFor = (_) => new InMemoryKeyValueStore().GetTypeAdapter <AppFlowEvent>();

            // Setup the AppFlow logic to use LocalAnalytics:
            AppFlow.AddAppFlowTracker(new AppFlowToStore(analytics));

            // Simulate User progression by causing analytics events:
            for (int i = 0; i < eventCount; i++)
            {
                AppFlow.TrackEvent(EventConsts.catMutation, "User did mutation nr " + i);
            }

            // Get the analtics store for category "Mutations":
            var mutationStore = await analytics.GetStoreForCategory(EventConsts.catMutation).GetAll();

            Assert.Equal(eventCount, mutationStore.Count()); // All events so far were mutations
            Assert.True(eventCount <= xpSystem.currentXp);   // The user received xp for each mutation

            Assert.Equal(1000, flag4.requiredXp);            // The user needs >= 1000 xp for the feature

            // Now that the user has more than 1000 xp the condition of the TestXpSystem is met:
            Assert.True(await flag4.IsFeatureUnlocked());
            Assert.True(await FeatureFlag.IsEnabled(flagId4));
        }