Esempio n. 1
0
        public async Task ExampleUsage2()
        {
            // Get your key from https://console.developers.google.com/apis/credentials
            var apiKey = "AIzaSyCtcFQMgRIUHhSuXggm4BtXT4eZvUrBWN0";
            // See https://docs.google.com/spreadsheets/d/1Hwu4ZtRR0iXD65Wuj_XyJxLw4PN8SE0sRgnBKeVoq3A
            var            sheetId         = "1Hwu4ZtRR0iXD65Wuj_XyJxLw4PN8SE0sRgnBKeVoq3A";
            var            sheetName       = "MySheet1"; // Has to match the sheet name
            IKeyValueStore onlineNewsStore = new GoogleSheetsKeyValueStore(new InMemoryKeyValueStore(), apiKey, sheetId, sheetName);

            IKeyValueStore onDeviceEventsStore = new InMemoryKeyValueStore();
            IKeyValueStore newsStore           = new DualStore(onlineNewsStore, onDeviceEventsStore);

            var         newsLocalDataStore = new InMemoryKeyValueStore().GetTypeAdapter <News.LocalData>();
            NewsManager manager            = new NewsManager(newsLocalDataStore, newsStore.GetTypeAdapter <News>());

            var  title   = "First App Start";
            var  descr   = "You just started the app the first time!";
            var  url     = "https://github.com/cs-util-com/cscore";
            var  urlText = "Show details..";
            News n       = News.NewLocalNewsEvent(title, descr, url, urlText);
            await onDeviceEventsStore.Set(n.key, n);

            IEnumerable <News> allNews = await manager.GetAllNews();

            Assert.Contains(allNews, x => x.title == title);

            Log.d(JsonWriter.AsPrettyString(allNews));

            IEnumerable <News> unreadNews = await manager.GetAllUnreadNews();

            Assert.Contains(unreadNews, x => x.title == title);
        }
Esempio n. 2
0
        public async Task ExampleUsage1()
        {
            // 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));

            // Open https://docs.google.com/spreadsheets/d/1KBamVmgEUX-fyogMJ48TT6h2kAMKyWU1uBL5skCGRBM for these:
            Assert.False(await FeatureFlag.IsEnabled("MyFlag1"));
            Assert.True(await FeatureFlag.IsEnabled("MyFlag2"));

            var          key3  = "MyFlag3";
            IFeatureFlag flag3 = await FeatureFlagManager <FeatureFlag> .instance.GetFeatureFlag(key3);

            Assert.Equal(40, flag3.rolloutPercentage); // Rollout of feature 3 is at 40%

            // The local random value that was chosen determines if the flag is enabled or not:
            if (flag3.localState.randomPercentage <= flag3.rolloutPercentage)
            {
                Assert.True(await FeatureFlag.IsEnabled(key3));
            }
            else
            {
                Assert.False(await FeatureFlag.IsEnabled(key3));
            }
        }
Esempio n. 3
0
        public async Task ExampleUsage1()
        {
            // Get your key from https://console.developers.google.com/apis/credentials
            var exampleApiKey = "AIzaSyCtcFQMgRIUHhSuXggm4BtXT4eZvUrBWN0";
            // See https://docs.google.com/spreadsheets/d/1qZjRA_uLsImX-VHpJ1nnrCIASmU20Tbaakf5Le5Wrs8
            var spreadsheetId = "1qZjRA_uLsImX-VHpJ1nnrCIASmU20Tbaakf5Le5Wrs8";
            var sheetName     = "UpdateEntriesV2"; // Has to match the sheet name
            var cache         = new InMemoryKeyValueStore();
            var store         = new GoogleSheetsKeyValueStore(cache, exampleApiKey, spreadsheetId, sheetName);

            // Use the GoogleSheets store as the source for the update information:
            var updateChecker = new DefaultAppUpdateChecker(store, null);

            var entries = await updateChecker.DownloadAllUpdateEntries();

            Assert.Equal(5, entries.Count());

            // Use the EnvironmentV2.instance.systemInfo values to match against all entries:
            var matchingEntries = await updateChecker.DownloadMatchingUpdateEntries();

            if (matchingEntries.Count > 0)
            {
                Assert.Single(matchingEntries);
                var instructions = matchingEntries.First().GetUpdateInstructions();
                Assert.Equal("https://github.com/cs-util-com/cscore", instructions.url);
                Log.d("instructions: " + JsonWriter.AsPrettyString(instructions));
            }
            else
            {
                Log.e("Test cant be fully done on current system: "
                      + JsonWriter.AsPrettyString(EnvironmentV2.instance.systemInfo));
            }
        }
Esempio n. 4
0
        public async Task ExampleUsage1()
        {
            // Get your key from https://console.developers.google.com/apis/credentials
            var apiKey = "AIzaSyCtcFQMgRIUHhSuXggm4BtXT4eZvUrBWN0";
            // See https://docs.google.com/spreadsheets/d/1Hwu4ZtRR0iXD65Wuj_XyJxLw4PN8SE0sRgnBKeVoq3A
            var            sheetId   = "1Hwu4ZtRR0iXD65Wuj_XyJxLw4PN8SE0sRgnBKeVoq3A";
            var            sheetName = "MySheet1"; // Has to match the sheet name
            IKeyValueStore newsStore = new GoogleSheetsKeyValueStore(new InMemoryKeyValueStore(), apiKey, sheetId, sheetName);

            var         newsLocalDataStore = new InMemoryKeyValueStore().GetTypeAdapter <News.LocalData>();
            NewsManager manager            = new NewsManager(newsLocalDataStore, newsStore.GetTypeAdapter <News>());

            IEnumerable <News> allNews = await manager.GetAllNews();

            var news1 = allNews.First();

            Assert.NotNull(news1);
            Assert.Equal("New", news1.type);
            Assert.Equal(News.NewsType.New, news1.GetNewsType());
            Assert.True(news1.GetDate(true).IsUtc());

            // Mark that the user has read the news:
            await manager.MarkNewsAsRead(news1);

            Assert.True(allNews.First().localData.isRead);
            Assert.True((await manager.GetAllNews()).First().localData.isRead);
            Assert.True((await newsLocalDataStore.Get(news1.key, null)).isRead);

            IEnumerable <News> unreadNews = await manager.GetAllUnreadNews();

            Assert.Contains(news1, allNews);
            Assert.DoesNotContain(news1, unreadNews);
        }
Esempio n. 5
0
        public static async Task <ProgressionSystem <FeatureFlag> > SetupWithGSheets(string apiKey, string sheetId, string sheetName)
        {
            var cachedFlags          = FileBasedKeyValueStore.New("FeatureFlags");
            var cachedFlagsLocalData = FileBasedKeyValueStore.New("FeatureFlags_LocalData");
            var googleSheetsStore    = new GoogleSheetsKeyValueStore(cachedFlags, apiKey, sheetId, sheetName);

            return(await Setup(new FeatureFlagStore(cachedFlagsLocalData, googleSheetsStore)));
        }
Esempio n. 6
0
        public async Task ExtendedTest1()
        {
            // Get your key from https://console.developers.google.com/apis/credentials
            var apiKey = "AIzaSyCtcFQMgRIUHhSuXggm4BtXT4eZvUrBWN0";
            // See https://docs.google.com/spreadsheets/d/1KBamVmgEUX-fyogMJ48TT6h2kAMKyWU1uBL5skCGRBM
            var sheetId           = "1KBamVmgEUX-fyogMJ48TT6h2kAMKyWU1uBL5skCGRBM";
            var sheetName         = "MySheet1"; // Has to match the sheet name
            var googleSheetsStore = new GoogleSheetsKeyValueStore(new InMemoryKeyValueStore(), apiKey, sheetId, sheetName);


            var localStore = new InMemoryKeyValueStore();
            var testStore  = new FeatureFlagStore(localStore, googleSheetsStore);

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

            var key1 = "MyFlag1";
            var key2 = "MyFlag2";
            var key3 = "MyFlag3";

            Assert.NotNull(await googleSheetsStore.Get <FeatureFlag>(key1, null));
            Assert.NotNull(await googleSheetsStore.Get <FeatureFlag>(key2, null));
            Assert.NotNull(await testStore.Get(key2, null));
            Assert.NotNull(await FeatureFlagManager <FeatureFlag> .instance.GetFeatureFlag(key2));

            Assert.False(await FeatureFlag.IsEnabled(key1));
            Assert.True(await FeatureFlag.IsEnabled(key2));

            var flag3_1 = await FeatureFlagManager <FeatureFlag> .instance.GetFeatureFlag(key3);

            Assert.Equal(40, flag3_1.rolloutPercentage);

            var localState3_1 = await localStore.Get <IFeatureFlagLocalState>(key3, null);

            var percent3_1 = localState3_1.randomPercentage;

            Assert.NotEqual(0, percent3_1);
            if (percent3_1 < flag3_1.rolloutPercentage)
            {
                Assert.True(await FeatureFlag.IsEnabled(key3));
            }
            else
            {
                Assert.False(await FeatureFlag.IsEnabled(key3));
            }
            localState3_1.randomPercentage = flag3_1.rolloutPercentage - 1;
            await localStore.Set(key3, localState3_1);

            var localState3_2 = await localStore.Get <IFeatureFlagLocalState>(key3, null);

            Assert.NotEqual(percent3_1, localState3_2.randomPercentage);

            var flag3_2 = await FeatureFlagManager <FeatureFlag> .instance.GetFeatureFlag(key3);

            Assert.Equal(localState3_2.randomPercentage, flag3_2.localState.randomPercentage);
            Assert.True(await flag3_2.IsEnabled());
            Assert.True(await FeatureFlag.IsEnabled(key3));
        }
Esempio n. 7
0
        public static NewsManager NewManagerViaGSheets(string apiKey, string sheetId, string sheetName)
        {
            var            newsDir            = EnvironmentV2.instance.GetOrAddTempFolder("NewsManagerCache");
            var            gSheetsCache       = new FileBasedKeyValueStore(newsDir.GetChildDir("GSheetsData"));
            var            newsLocalDataCache = new FileBasedKeyValueStore(newsDir.GetChildDir("LocalData"));
            IKeyValueStore newsStore          = new GoogleSheetsKeyValueStore(gSheetsCache, apiKey, sheetId, sheetName);

            return(new NewsManager(newsLocalDataCache.GetTypeAdapter <News.LocalData>(), newsStore.GetTypeAdapter <News>()));
        }
Esempio n. 8
0
        private static async Task <ProgressionSystem <FeatureFlag> > NewInMemoryTestXpSystem(string apiKey, string sheetId, string sheetName)
        {
            var cachedFlags          = new InMemoryKeyValueStore();
            var googleSheetsStore    = new GoogleSheetsKeyValueStore(cachedFlags, apiKey, sheetId, sheetName);
            var cachedFlagsLocalData = new InMemoryKeyValueStore();
            var analytics            = new LocalAnalytics(new InMemoryKeyValueStore());

            analytics.createStoreFor = (_ => new InMemoryKeyValueStore().GetTypeAdapter <AppFlowEvent>());
            var featureFlagStore = new FeatureFlagStore(cachedFlagsLocalData, googleSheetsStore);

            return(await DefaultProgressionSystem.Setup(featureFlagStore, analytics));
        }
Esempio n. 9
0
        public async Task TestGoogleSheetsKeyValueStore()
        {
            // Get your key from https://console.developers.google.com/apis/credentials
            var apiKey = "AIzaSyCtcFQMgRIUHhSuXggm4BtXT4eZvUrBWN0";
            // See https://docs.google.com/spreadsheets/d/13R9y6lnUMgRPC0PinJ23tACC6Flgogxa7h7SVaaLhT0
            var sheetId   = "13R9y6lnUMgRPC0PinJ23tACC6Flgogxa7h7SVaaLhT0";
            var sheetName = "UpdateEntriesV1"; // Has to match the sheet name

            var refreshDelayInMs = 1000;
            // The cache is where the data from the sheet will be locally stored in:
            var cache = new InMemoryKeyValueStore(); // Could also persist to disc here
            var store = new GoogleSheetsKeyValueStore(cache, apiKey, sheetId, sheetName, refreshDelayInMs);

            var download1 = store.dowloadOnlineDataDebounced();
            var download2 = store.dowloadOnlineDataDebounced();
            var download3 = store.dowloadOnlineDataDebounced();

            // After the refresh delay redownload was allowed again:
            await TaskV2.Delay(refreshDelayInMs * 3);

            Assert.True(await download1); // first trigger downloaded the data
            Assert.NotEmpty(store.latestRawSheetData);
            // Triggering it instant a second time will not download the data again:
            Assert.False(await download2); // Second trigger was skipped
            Assert.True(await download3);

            var entry1 = await store.Get <MySheetEntry>("1", null);

            Assert.NotNull(entry1);
            Assert.Equal("a", entry1.myString1);
            Assert.Equal(new List <int>()
            {
                1, 2, 3, 4
            }, entry1.myArray1);
            Assert.Equal("b", entry1.myObj1.a);
            Assert.Equal(5, entry1.myInt1);
            Assert.Equal(1.4, entry1.myDouble1);

            var entry2 = await store.Get <MySheetEntry>("2", null);

            Assert.NotNull(entry2);
            Assert.Null(entry2.myString1);
            Assert.Empty(entry2.myArray1);
            Assert.Null(entry2.myObj1);
            Assert.Equal(0, entry2.myInt1);
            Assert.Equal(0, entry2.myDouble1);
        }
Esempio n. 10
0
        public async Task TestDefaultProgressionSystemSetup()
        {
            // 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 cachedFlags          = FileBasedKeyValueStore.New("FeatureFlags");
            var cachedFlagsLocalData = FileBasedKeyValueStore.New("FeatureFlags_LocalData");
            var googleSheetsStore    = new GoogleSheetsKeyValueStore(cachedFlags, apiKey, sheetId, sheetName);

            DefaultProgressionSystem.Setup(new TestFeatureFlagStore(cachedFlagsLocalData, googleSheetsStore));

            AppFlow.TrackEvent(EventConsts.catMethod, "Some event");
            Assert.False(await FeatureFlag.IsEnabled("MyFlag4"));
            Log.d("Now take a look at the folders in " + cachedFlags.folderForAllFiles.Parent.GetFullFileSystemPath());
        }
Esempio n. 11
0
        public static Func <string, Task <Dictionary <string, Translation> > > LoadLocaleFromGoogleSheets(
            IKeyValueStore localCache, string apiKey, string sheetId, string initialSheetName = "en-US")
        {
            var translationDatabase = new GoogleSheetsKeyValueStore(localCache, apiKey, sheetId, initialSheetName);

            return(async(string localeName) => {
                if (localeName != translationDatabase.sheetName)
                {
                    translationDatabase.sheetName = localeName;
                }
                var downloadTask = translationDatabase.dowloadOnlineDataDebounced();
                if (downloadTask != null && !await downloadTask)   // Make sure the data is downloaded at least once
                {
                    Log.w($"Could not download {localeName} translation data from sheet {sheetId}, device offline?");
                }
                return await ConvertToDictionary(await translationDatabase.GetAll <Translation>());
            });
        }
Esempio n. 12
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);
        }
Esempio n. 13
0
        public async Task ExampleUsage2()
        {
            // Get your key from https://console.developers.google.com/apis/credentials
            var apiKey = "AIzaSyCtcFQMgRIUHhSuXggm4BtXT4eZvUrBWN0";
            // https://docs.google.com/spreadsheets/d/1rl1vi-LUhOgoY_QrMJsm2UE0SdiL4EbOtLwfNPsavxQ contains the sheetId:
            var sheetId   = "1rl1vi-LUhOgoY_QrMJsm2UE0SdiL4EbOtLwfNPsavxQ";
            var sheetName = "UsageRules1"; // Has to match the sheet name
            var source    = new GoogleSheetsKeyValueStore(new InMemoryKeyValueStore(), apiKey, sheetId, sheetName);
            var store     = source.GetTypeAdapter <UsageRule>();

            var analytics = CreateLocalAnalyticsSystem();
            IEnumerable <UsageRule> rules = await store.GetRulesInitialized(analytics);

            foreach (var rule in rules)
            {
                if (await rule.isTrue())
                {
                    Log.d(JsonWriter.AsPrettyString(rule)); // TODO
                }
            }
            Assert.Single(rules.Filter(r => !r.andRules.IsNullOrEmpty()));
        }
Esempio n. 14
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));
        }