public async Task ThrowsArgumentNullExceptionIfKeyIsNull() { var blobCache = new InMemoryBlobCache(); var artworkCache = new ArtworkCache(blobCache); await Helpers.ThrowsAsync<ArgumentNullException>(() => artworkCache.Retrieve(null, 100, 100)); }
public async Task RoundTripIntegrationTest() { var cache = new InMemoryBlobCache(); var cachingHandler = new RateLimitedHttpMessageHandler(new HttpClientHandler(), Priority.UserInitiated, cacheResultFunc: async (rq, resp, key, ct) => { var data = await resp.Content.ReadAsByteArrayAsync(); await cache.Insert(key, data); }); var client = new HttpClient(cachingHandler); var origData = await client.GetStringAsync("http://httpbin.org/get"); Assert.True(origData.Contains("origin")); Assert.Equal(1, (await cache.GetAllKeys()).Count()); var offlineHandler = new OfflineHttpMessageHandler(async (rq, key, ct) => { return await cache.Get(key); }); client = new HttpClient(offlineHandler); var newData = await client.GetStringAsync("http://httpbin.org/get"); Assert.Equal(origData, newData); bool shouldDie = true; try { await client.GetStringAsync("http://httpbin.org/gzip"); } catch (Exception ex) { shouldDie = false; Console.WriteLine(ex); } Assert.False(shouldDie); }
public async Task LogsTheUserInSuccessfullyAndCachesRelevantInfo() { var apiClient = Substitute.For<IApiClient>(); apiClient.HostAddress.Returns(HostAddress.GitHubDotComHostAddress); apiClient.GetOrCreateApplicationAuthenticationCode( Args.TwoFactorChallengCallback, Args.String, Args.Boolean) .Returns(Observable.Return(new ApplicationAuthorization("S3CR3TS"))); apiClient.GetUser().Returns(Observable.Return(CreateUserAndScopes("baymax"))); var hostCache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, hostCache, Substitute.For<IAvatarProvider>()); var loginCache = new TestLoginCache(); var usage = Substitute.For<IUsageTracker>(); var host = new RepositoryHost(apiClient, modelService, loginCache, Substitute.For<ITwoFactorChallengeHandler>(), usage); var result = await host.LogIn("baymax", "aPassword"); Assert.Equal(AuthenticationResult.Success, result); var user = await hostCache.GetObject<AccountCacheItem>("user"); Assert.NotNull(user); Assert.Equal("baymax", user.Login); var loginInfo = await loginCache.GetLoginAsync(HostAddress.GitHubDotComHostAddress); Assert.Equal("baymax", loginInfo.UserName); Assert.Equal("S3CR3TS", loginInfo.Password); Assert.True(host.IsLoggedIn); }
public async Task UsesUsernameAndPasswordInsteadOfAuthorizationTokenWhenEnterpriseAndAPIReturns404() { var enterpriseHostAddress = HostAddress.Create("https://enterprise.example.com/"); var apiClient = Substitute.For<IApiClient>(); apiClient.HostAddress.Returns(enterpriseHostAddress); // Throw a 404 on the first try with the new scopes apiClient.GetOrCreateApplicationAuthenticationCode(Args.TwoFactorChallengCallback, null, false, true) .Returns(Observable.Throw<ApplicationAuthorization>(new NotFoundException("Not there", HttpStatusCode.NotFound))); // Throw a 404 on the retry with the old scopes: apiClient.GetOrCreateApplicationAuthenticationCode(Args.TwoFactorChallengCallback, null, true, false) .Returns(Observable.Throw<ApplicationAuthorization>(new NotFoundException("Also not there", HttpStatusCode.NotFound))); apiClient.GetUser().Returns(Observable.Return(CreateOctokitUser("Cthulu"))); var hostCache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, hostCache, Substitute.For<IAvatarProvider>()); var loginCache = new TestLoginCache(); var host = new RepositoryHost(apiClient, modelService, loginCache, Substitute.For<ITwoFactorChallengeHandler>()); var result = await host.LogIn("Cthulu", "aPassword"); Assert.Equal(AuthenticationResult.Success, result); // Only username and password were saved, never an authorization token: var loginInfo = await loginCache.GetLoginAsync(enterpriseHostAddress); Assert.Equal("Cthulu", loginInfo.UserName); Assert.Equal("aPassword", loginInfo.Password); Assert.True(host.IsLoggedIn); }
public async Task SetOrCreateInsertsValueIntoBlobCache() { var cache = new InMemoryBlobCache(); var settings = new SettingsStorageProxy(cache); settings.SetOrCreateProxy(42, "TestNumber"); Assert.Equal(1, await cache.GetAllKeys().Count()); }
public async Task FailedRequestThrowsException() { var fetcher = Substitute.For<IArtworkFetcher>(); fetcher.RetrieveAsync(Arg.Any<string>(), Arg.Any<string>()).Returns(Observable.Throw<Uri>(new ArtworkFetchException(String.Empty, null)).ToTask()); var blobCache = new InMemoryBlobCache(); var fixture = new ArtworkCache(blobCache, fetcher); await Helpers.ThrowsAsync<ArtworkCacheException>(() => fixture.FetchOnline("A", "B")); }
public async Task NullSearchTermDefaultsToEmptyString() { var songs = new[] { new SoundCloudSong { IsStreamable = true, StreamUrl = new Uri("http://blabla.com"), PermaLinkUrl = new Uri("http://blabla") } }; var cache = new InMemoryBlobCache(); cache.InsertObject(BlobCacheKeys.GetKeyForSoundCloudCache(string.Empty), songs); var finder = new SoundCloudSongFinder(cache); var result = await finder.GetSongsAsync(); Assert.Equal(1, result.Count); }
public async Task NullSearchTermDefaultsToEmptyString() { var songs = new[] { new YoutubeSong("http://blabla", TimeSpan.Zero) }; var cache = new InMemoryBlobCache(); cache.InsertObject(BlobCacheKeys.GetKeyForYoutubeCache(string.Empty), songs); var finder = new YoutubeSongFinder(cache); var result = await finder.GetSongsAsync(); Assert.Equal(1, result.Count); }
public async Task NotFoundRequestReturnsNull() { var fetcher = Substitute.For<IArtworkFetcher>(); fetcher.RetrieveAsync(Arg.Any<string>(), Arg.Any<string>()).Returns(Task.FromResult<Uri>(null)); var blobCache = new InMemoryBlobCache(); var fixture = new ArtworkCache(blobCache, fetcher); string returned = await fixture.FetchOnline("A", "B"); Assert.Null(returned); }
public async Task AddsUserToCache() { var apiClient = Substitute.For<IApiClient>(); var cache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, cache, Substitute.For<IAvatarProvider>()); var user = await modelService.InsertUser(new AccountCacheItem(CreateOctokitUser("octocat"))); var cached = await cache.GetObject<AccountCacheItem>("user"); Assert.Equal("octocat", cached.Login); }
public async Task UsesCachedSongsIfAvailable() { const string searchTerm = "Foo"; var songs = new[] { new SoundCloudSong { IsStreamable = true, StreamUrl = new Uri("http://blabla.com"), PermaLinkUrl = new Uri("http://blabla") } }; var cache = new InMemoryBlobCache(); cache.InsertObject(BlobCacheKeys.GetKeyForSoundCloudCache(searchTerm), songs); var finder = new SoundCloudSongFinder(cache); var result = await finder.GetSongsAsync(searchTerm); Assert.Equal(1, result.Count); }
public async Task UsesCachedSongsIfAvailable() { const string searchTerm = "Foo"; var songs = new[] { new YoutubeSong("http://blabla", TimeSpan.Zero) }; var cache = new InMemoryBlobCache(); cache.InsertObject(BlobCacheKeys.GetKeyForYoutubeCache(searchTerm), songs); var finder = new YoutubeSongFinder(cache); var result = await finder.GetSongsAsync(searchTerm); Assert.Equal(1, result.Count); }
public async Task ReturnsCollectionOnlyContainingTheNoneOptionnWhenGitIgnoreEndpointNotFound() { var apiClient = Substitute.For<IApiClient>(); apiClient.GetGitIgnoreTemplates() .Returns(Observable.Throw<string>(new NotFoundException("Not Found", HttpStatusCode.NotFound))); var cache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, cache, Substitute.For<IAvatarProvider>()); var fetched = await modelService.GetGitIgnoreTemplates(); Assert.Equal(1, fetched.Count); Assert.Equal("None", fetched[0].Name); }
public async Task ReturnsCollectionOnlyContainingTheNoneOptionWhenLicenseApiNotFound() { var apiClient = Substitute.For <IApiClient>(); apiClient.GetLicenses() .Returns(Observable.Throw <LicenseMetadata>(new NotFoundException("Not Found", HttpStatusCode.NotFound))); var cache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, cache, Substitute.For <IAvatarProvider>()); var fetched = await modelService.GetLicenses(); Assert.Equal(1, fetched.Count); Assert.Equal("None", fetched[0].Name); }
public async Task NotFoundRequestIsMarked() { var fetcher = Substitute.For<IArtworkFetcher>(); fetcher.RetrieveAsync(Arg.Any<string>(), Arg.Any<string>()).Returns(Task.FromResult<Uri>(null)); var blobCache = new InMemoryBlobCache(); var fixture = new ArtworkCache(blobCache, fetcher); string artist = "A"; string album = "B"; string lookupKey = BlobCacheKeys.GetKeyForOnlineArtwork(artist, album); await fixture.FetchOnline(artist, album); Assert.Equal("FAILED", await blobCache.GetObject<string>(lookupKey)); }
public async Task NotFoundRequestIsMarked() { var fetcher = Substitute.For <IArtworkFetcher>(); fetcher.RetrieveAsync(Arg.Any <string>(), Arg.Any <string>()).Returns(Task.FromResult <Uri>(null)); var blobCache = new InMemoryBlobCache(); var fixture = new ArtworkCache(blobCache, fetcher); string artist = "A"; string album = "B"; string lookupKey = BlobCacheKeys.GetKeyForOnlineArtwork(artist, album); await fixture.FetchOnline(artist, album); Assert.Equal("FAILED", await blobCache.GetObject <string>(lookupKey)); }
public static InMemoryBlobCache RegisterComponentsAndReturnInMemoryBlobCache() { EventListener verboseListener = new StorageFileEventListener("MyListenerVerbose1"); EventListener informationListener = new StorageFileEventListener("MyListenerInformation1"); verboseListener.EnableEvents(KrossEventSource.Log, EventLevel.Error); Locator.CurrentMutable.RegisterConstant(KrossEventSource.Log, typeof(KrossEventSource)); var blobCache = new InMemoryBlobCache(); Locator.CurrentMutable.RegisterConstant(blobCache, typeof(IBlobCache), "UserAccount"); Locator.CurrentMutable.Register(() => new KrossLogger(), typeof(ILogger)); return(blobCache); }
public async Task AddsImageDirectlyToCache() { var singlePixel = Convert.FromBase64String("R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw=="); var cache = new InMemoryBlobCache(); var cacheFactory = Substitute.For <IBlobCacheFactory>(); cacheFactory.CreateBlobCache(Args.String).Returns(cache); var imageCache = new ImageCache(cacheFactory, Substitute.For <IEnvironment>(), new Lazy <IImageDownloader>(() => Substitute.For <IImageDownloader>())); await imageCache.SeedImage(new Uri("https://fake/"), singlePixel, DateTimeOffset.MaxValue); var retrieved = await cache.Get("https://fake/"); Assert.That(singlePixel, Is.EqualTo(retrieved)); }
public async Task RemovesImageFromCache() { var singlePixel = Convert.FromBase64String("R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw=="); var cache = new InMemoryBlobCache(); await cache.Insert("https://fake/", singlePixel); var cacheFactory = Substitute.For <IBlobCacheFactory>(); cacheFactory.CreateBlobCache(Args.String).Returns(cache); var imageCache = new ImageCache(cacheFactory, Substitute.For <IEnvironment>(), new Lazy <IImageDownloader>(() => Substitute.For <IImageDownloader>())); await imageCache.Invalidate(new Uri("https://fake/")); Assert.ThrowsAsync <KeyNotFoundException>(async() => await cache.Get("https://fake/")); }
public async Task PullsSearchesFromCache() { string artist = "A"; string album = "B"; string key = BlobCacheKeys.GetKeyForOnlineArtwork(artist, album); var fetcher = Substitute.For<IArtworkFetcher>(); var blobCache = new InMemoryBlobCache(); await blobCache.InsertObject(key, "TestArtworkKey"); var fixture = new ArtworkCache(blobCache, fetcher); string returned = await fixture.FetchOnline(artist, album); Assert.Equal("TestArtworkKey", returned); fetcher.DidNotReceiveWithAnyArgs().RetrieveAsync(null, null); }
public async Task PullsSearchesFromCache() { string artist = "A"; string album = "B"; string key = BlobCacheKeys.GetKeyForOnlineArtwork(artist, album); var fetcher = Substitute.For <IArtworkFetcher>(); var blobCache = new InMemoryBlobCache(); await blobCache.InsertObject(key, "TestArtworkKey"); var fixture = new ArtworkCache(blobCache, fetcher); string returned = await fixture.FetchOnline(artist, album); Assert.Equal("TestArtworkKey", returned); fetcher.DidNotReceiveWithAnyArgs().RetrieveAsync(null, null); }
public void ThrowsKeyNotFoundExceptionWhenItemNotInCacheAndImageFetchReturnsEmpty() { var imageUri = new Uri("https://example.com/poop.gif"); var cache = new InMemoryBlobCache(); var cacheFactory = Substitute.For <IBlobCacheFactory>(); cacheFactory.CreateBlobCache(Args.String).Returns(cache); var imageDownloader = Substitute.For <IImageDownloader>(); imageDownloader.DownloadImageBytes(imageUri).Returns(Observable.Empty <byte[]>()); var imageCache = new ImageCache(cacheFactory, Substitute.For <IEnvironment>(), new Lazy <IImageDownloader>(() => imageDownloader)); Assert.ThrowsAsync <KeyNotFoundException>(async() => await imageCache.GetImage(imageUri).FirstAsync()); }
public async Task SupportsGistIsFalseWhenGistScopeIsNotPresent() { var apiClient = Substitute.For <IApiClient>(); apiClient.HostAddress.Returns(HostAddress.GitHubDotComHostAddress); apiClient.GetUser().Returns(Observable.Return(CreateUserAndScopes("baymax", new[] { "foo" }))); var hostCache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, hostCache, Substitute.For <IAvatarProvider>()); var loginCache = new TestLoginCache(); var host = new RepositoryHost(apiClient, modelService, loginCache, Substitute.For <ITwoFactorChallengeHandler>()); var result = await host.LogIn("baymax", "aPassword"); Assert.Equal(AuthenticationResult.Success, result); Assert.False(host.SupportsGist); }
public void CanStoreMulipleArtworksIfArtworksExistsInCache() { var blobCache = new InMemoryBlobCache(); var data = new byte[] { 0, 1 }; string key = BlobCacheKeys.GetKeyForArtwork(data); blobCache.Insert(key, data); var fixture = new ArtworkCache(blobCache); Task firstTask = fixture.Store(key, data); Task secondTask = fixture.Store(key, data); Task thrirdTask = fixture.Store(key, data); Assert.True(firstTask.IsCompleted); Assert.True(secondTask.IsCompleted); Assert.True(thrirdTask.IsCompleted); }
public async Task GetsAvatarFromCache() { var expectedImage = AvatarProvider.CreateBitmapImage("pack://*****:*****@test.com&s=140"); var blobCache = new InMemoryBlobCache(); var sharedCache = Substitute.For<ISharedCache>(); sharedCache.LocalMachine.Returns(blobCache); var imageCache = new TestImageCache(); await imageCache.SeedImage(avatarUrl, expectedImage, DateTimeOffset.MaxValue); var avatarProvider = new AvatarProvider(sharedCache, imageCache); var avatarContainer = Substitute.For<IAvatarContainer>(); avatarContainer.AvatarUrl.Returns("https://avatars.githubusercontent.com/u/[email protected]&s=140"); var retrieved = await avatarProvider.GetAvatar(avatarContainer); AssertSameImage(expectedImage, retrieved); }
public async Task RetrievesImageFromCacheAndDoesNotFetchIt() { var singlePixel = Convert.FromBase64String("R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw=="); var cache = new InMemoryBlobCache(); await cache.Insert("https://fake/", singlePixel); var cacheFactory = Substitute.For<IBlobCacheFactory>(); cacheFactory.CreateBlobCache(Args.String).Returns(cache); var imageDownloader = Substitute.For<IImageDownloader>(); imageDownloader.DownloadImageBytes(Args.Uri).Returns(_ => { throw new InvalidOperationException(); }); var imageCache = new ImageCache(cacheFactory, Substitute.For<IEnvironment>(), new Lazy<IImageDownloader>(() => imageDownloader)); var retrieved = await imageCache.GetImage(new Uri("https://fake/")).FirstAsync(); Assert.NotNull(retrieved); Assert.Equal(32, retrieved.PixelWidth); Assert.Equal(32, retrieved.PixelHeight); }
public async Task IncrementsLoginCount() { var apiClient = Substitute.For <IApiClient>(); apiClient.HostAddress.Returns(HostAddress.GitHubDotComHostAddress); var hostCache = new InMemoryBlobCache(); var modelService = Substitute.For <IModelService>(); var loginManager = Substitute.For <ILoginManager>(); loginManager.LoginFromCache(HostAddress.GitHubDotComHostAddress, Arg.Any <IGitHubClient>()).Returns(CreateOctokitUser("baymax")); var loginCache = new TestLoginCache(); var usage = Substitute.For <IUsageTracker>(); var host = new RepositoryHost(apiClient, modelService, loginManager, loginCache, usage); var result = await host.LogInFromCache(); await usage.Received().IncrementLoginCount(); }
public async Task WhenLoadingFromCacheFailsInvalidatesCacheEntry() { var cache = new InMemoryBlobCache(); await cache.Insert("https://fake/", new byte[] { 0, 0, 0 }); var cacheFactory = Substitute.For<IBlobCacheFactory>(); cacheFactory.CreateBlobCache(Args.String).Returns(cache); var imageDownloader = Substitute.For<IImageDownloader>(); imageDownloader.DownloadImageBytes(Args.Uri).Returns(_ => { throw new InvalidOperationException(); }); var imageCache = new ImageCache(cacheFactory, Substitute.For<IEnvironment>(), new Lazy<IImageDownloader>(() => imageDownloader)); var retrieved = await imageCache .GetImage(new Uri("https://fake/")) .Catch(Observable.Return<BitmapSource>(null)) .FirstAsync(); Assert.Null(retrieved); await Assert.ThrowsAsync<KeyNotFoundException>(async () => await cache.Get("https://fake/")); }
protected SharedCache(IBlobCache userAccountCache, IBlobCache localMachineCache, ISecureBlobCache secureCache) { if (secureCache == null) { try { BlobCache.Secure = new CredentialCache(); secureCache = BlobCache.Secure; } catch (Exception e) { log.Error("Failed to set up secure cache.", e); secureCache = new InMemoryBlobCache(); } } UserAccount = userAccountCache ?? GetBlobCacheWithFallback(() => BlobCache.UserAccount, "UserAccount"); LocalMachine = localMachineCache ?? GetBlobCacheWithFallback(() => BlobCache.LocalMachine, "LocalMachine"); Secure = secureCache; }
protected SharedCache(IBlobCache userAccountCache, IBlobCache localMachineCache, ISecureBlobCache secureCache) { if (secureCache == null) { try { BlobCache.Secure = new CredentialCache(); secureCache = BlobCache.Secure; } catch (Exception e) { log.Error(e, "Failed to set up secure cache"); secureCache = new InMemoryBlobCache(); } } UserAccount = userAccountCache ?? GetBlobCacheWithFallback(() => BlobCache.UserAccount, "UserAccount"); LocalMachine = localMachineCache ?? GetBlobCacheWithFallback(() => BlobCache.LocalMachine, "LocalMachine"); Secure = secureCache; }
public async Task InitializeAsyncLoadsValuesIntoCache() { var testCache = new InMemoryBlobCache(); await testCache.InsertObject("Storage:DummyNumber", 16); await testCache.InsertObject("Storage:DummyText", "Random"); var cache = Substitute.For<IBlobCache>(); cache.Get(Arg.Any<string>()).Returns(x => testCache.Get(x.Arg<string>())); var settings = new DummySettingsStorage("Storage", cache); await settings.InitializeAsync(); int number = settings.DummyNumber; string text = settings.DummyText; Assert.Equal(16, number); Assert.Equal("Random", text); cache.ReceivedWithAnyArgs(2).Get(Arg.Any<string>()); }
public async Task DoesNotLogInWhenRetrievingOauthTokenFails() { var apiClient = Substitute.For <IApiClient>(); apiClient.HostAddress.Returns(HostAddress.GitHubDotComHostAddress); var hostCache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, hostCache, Substitute.For <IAvatarProvider>()); var loginManager = Substitute.For <ILoginManager>(); loginManager.Login(HostAddress.GitHubDotComHostAddress, Arg.Any <IGitHubClient>(), "jiminy", "cricket") .Returns <User>(_ => { throw new NotFoundException("", HttpStatusCode.BadGateway); }); var loginCache = new TestLoginCache(); var usage = Substitute.For <IUsageTracker>(); var host = new RepositoryHost(apiClient, modelService, loginManager, loginCache, usage); await Assert.ThrowsAsync <NotFoundException>(async() => await host.LogIn("jiminy", "cricket")); await Assert.ThrowsAsync <KeyNotFoundException>( async() => await hostCache.GetObject <AccountCacheItem>("user")); }
public async Task RetrievesGitHubAvatar() { var expectedImage = AvatarProvider.CreateBitmapImage("pack://*****:*****@test.com&s=140"); var blobCache = new InMemoryBlobCache(); var sharedCache = Substitute.For <ISharedCache>(); sharedCache.LocalMachine.Returns(blobCache); var imageCache = new TestImageCache(); await imageCache.SeedImage(avatarUrl, expectedImage, DateTimeOffset.MaxValue); var avatarProvider = new AvatarProvider(sharedCache, imageCache); var avatarContainer = Substitute.For <IAvatarContainer>(); avatarContainer.AvatarUrl.Returns("https://avatars.githubusercontent.com/u/[email protected]&s=140"); var retrieved = await avatarProvider.GetAvatar(avatarContainer); AssertSameImage(expectedImage, retrieved); }
public async Task RetrievesImageFromCacheAndDoesNotFetchIt() { var singlePixel = Convert.FromBase64String("R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw=="); var cache = new InMemoryBlobCache(); await cache.Insert("https://fake/", singlePixel); var cacheFactory = Substitute.For <IBlobCacheFactory>(); cacheFactory.CreateBlobCache(Args.String).Returns(cache); var imageDownloader = Substitute.For <IImageDownloader>(); imageDownloader.DownloadImageBytes(Args.Uri).Returns(_ => { throw new InvalidOperationException(); }); var imageCache = new ImageCache(cacheFactory, Substitute.For <IEnvironment>(), new Lazy <IImageDownloader>(() => imageDownloader)); var retrieved = await imageCache.GetImage(new Uri("https://fake/")).FirstAsync(); Assert.NotNull(retrieved); Assert.That(32, Is.EqualTo(retrieved.PixelWidth)); Assert.That(32, Is.EqualTo(retrieved.PixelHeight)); }
public async Task CanBeAccessedFromMultipleThreads() { var blobCache = new InMemoryBlobCache(); var sharedCache = Substitute.For<ISharedCache>(); sharedCache.LocalMachine.Returns(blobCache); var imageCache = new TestImageCache(); var avatarProvider = new AvatarProvider(sharedCache, imageCache); var expected = avatarProvider.DefaultUserBitmapImage.ToString(); int mainThreadId = Thread.CurrentThread.ManagedThreadId; int otherThreadId = mainThreadId; var actual = await Task.Run(() => { otherThreadId = Thread.CurrentThread.ManagedThreadId; return avatarProvider.DefaultUserBitmapImage.ToString(); }); Assert.Equal(expected, actual); Assert.NotEqual(mainThreadId, otherThreadId); }
public async Task SupportsGistIsTrueWhenScopesAreNull() { // TODO: Check assumptions here. From my conversation with @shana it seems that the first login // will be done with basic auth and from then on a token will be used. So if it's the first login, // it's from this version and so gists will be supported. However I've been unable to repro this // behavior. var apiClient = Substitute.For <IApiClient>(); apiClient.HostAddress.Returns(HostAddress.GitHubDotComHostAddress); apiClient.GetUser().Returns(Observable.Return(CreateUserAndScopes("baymax"))); var hostCache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, hostCache, Substitute.For <IAvatarProvider>()); var loginCache = new TestLoginCache(); var host = new RepositoryHost(apiClient, modelService, loginCache, Substitute.For <ITwoFactorChallengeHandler>()); var result = await host.LogIn("baymax", "aPassword"); Assert.Equal(AuthenticationResult.Success, result); Assert.True(host.SupportsGist); }
public async Task OnlyRetrievesOneUserEvenIfCacheOrApiReturnsMoreThanOne() { // This should be impossible, but let's pretend it does happen. var users = new[] { CreateUserAndScopes("peppermintpatty"), CreateUserAndScopes("peppermintpatty") }; var apiClient = Substitute.For <IApiClient>(); apiClient.GetUser().Returns(users.ToObservable()); apiClient.GetOrganizations().Returns(Observable.Empty <Organization>()); var cache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, cache, Substitute.For <IAvatarProvider>()); var fetched = await modelService.GetAccounts(); Assert.Equal(1, fetched.Count); Assert.Equal("peppermintpatty", fetched[0].Login); }
public async Task CanRetrieveAndCacheGitIgnores() { var templates = new[] { "dotnet", "peanuts", "bloomcounty" }; var apiClient = Substitute.For<IApiClient>(); apiClient.GetGitIgnoreTemplates().Returns(templates.ToObservable()); var cache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, cache, Substitute.For<IAvatarProvider>()); var fetched = await modelService.GetGitIgnoreTemplates(); Assert.Equal(4, fetched.Count); Assert.Equal("None", fetched[0].Name); Assert.Equal("dotnet", fetched[1].Name); Assert.Equal("peanuts", fetched[2].Name); Assert.Equal("bloomcounty", fetched[3].Name); var cached = await cache.GetObject<IReadOnlyList<string>>("gitignores"); Assert.Equal(3, cached.Count); Assert.Equal("dotnet", cached[0]); Assert.Equal("peanuts", cached[1]); Assert.Equal("bloomcounty", cached[2]); }
public async Task WhenLoadingFromCacheFailsInvalidatesCacheEntry() { var cache = new InMemoryBlobCache(); await cache.Insert("https://fake/", new byte[] { 0, 0, 0 }); var cacheFactory = Substitute.For <IBlobCacheFactory>(); cacheFactory.CreateBlobCache(Args.String).Returns(cache); var imageDownloader = Substitute.For <IImageDownloader>(); imageDownloader.DownloadImageBytes(Args.Uri).Returns(_ => { throw new InvalidOperationException(); }); var imageCache = new ImageCache(cacheFactory, Substitute.For <IEnvironment>(), new Lazy <IImageDownloader>(() => imageDownloader)); var retrieved = await imageCache .GetImage(new Uri("https://fake/")) .Catch(Observable.Return <BitmapSource>(null)) .FirstAsync(); Assert.That(retrieved, Is.Null); Assert.ThrowsAsync <KeyNotFoundException>(async() => await cache.Get("https://fake/")); }
public async Task CanBeAccessedFromMultipleThreads() { var blobCache = new InMemoryBlobCache(); var sharedCache = Substitute.For <ISharedCache>(); sharedCache.LocalMachine.Returns(blobCache); var imageCache = new TestImageCache(); var avatarProvider = new AvatarProvider(sharedCache, imageCache); var expected = avatarProvider.DefaultUserBitmapImage.ToString(); int mainThreadId = Thread.CurrentThread.ManagedThreadId; int otherThreadId = mainThreadId; var actual = await Task.Run(() => { otherThreadId = Thread.CurrentThread.ManagedThreadId; return(avatarProvider.DefaultUserBitmapImage.ToString()); }); Assert.Equal(expected, actual); Assert.NotEqual(mainThreadId, otherThreadId); }
public async Task DoesNotFallBackToOldScopesWhenGitHubAndTwoFactorAuthFailsAndErasesLogin() { var apiClient = Substitute.For <IApiClient>(); apiClient.HostAddress.Returns(HostAddress.GitHubDotComHostAddress); bool received1 = false, received2 = false; apiClient.GetOrCreateApplicationAuthenticationCode(Args.TwoFactorChallengCallback, null, false, true) .Returns(_ => { received1 = true; return(Observable.Throw <ApplicationAuthorization>(new TwoFactorChallengeFailedException())); }); apiClient.GetOrCreateApplicationAuthenticationCode(Args.TwoFactorChallengCallback, Args.String, true, Args.Boolean) .Returns(_ => { received2 = true; return(Observable.Throw <ApplicationAuthorization>(new TwoFactorChallengeFailedException())); }); apiClient.GetUser().Returns(Observable.Return(CreateUserAndScopes("jiminy"))); var hostCache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, hostCache, Substitute.For <IAvatarProvider>()); var loginCache = new TestLoginCache(); var usage = Substitute.For <IUsageTracker>(); var host = new RepositoryHost(apiClient, modelService, loginCache, Substitute.For <ITwoFactorChallengeHandler>(), usage); await host.LogIn("aUsername", "aPassowrd"); Assert.True(received1); Assert.False(received2); Assert.False(host.IsLoggedIn); var loginInfo = await loginCache.GetLoginAsync(HostAddress.GitHubDotComHostAddress); Assert.Equal("", loginInfo.UserName); Assert.Equal("", loginInfo.Password); }
public async Task LogsTheUserInSuccessfullyAndCachesRelevantInfo() { var apiClient = Substitute.For <IApiClient>(); apiClient.HostAddress.Returns(HostAddress.GitHubDotComHostAddress); var hostCache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, hostCache, Substitute.For <IAvatarProvider>()); var loginManager = Substitute.For <ILoginManager>(); loginManager.LoginFromCache(HostAddress.GitHubDotComHostAddress, Arg.Any <IGitHubClient>()).Returns(CreateOctokitUser("baymax")); var loginCache = new TestLoginCache(); var usage = Substitute.For <IUsageTracker>(); var host = new RepositoryHost(apiClient, modelService, loginManager, loginCache, usage); var result = await host.LogInFromCache(); Assert.Equal(AuthenticationResult.Success, result); var user = await hostCache.GetObject <AccountCacheItem>("user"); Assert.NotNull(user); Assert.Equal("baymax", user.Login); }
public async Task DoesNotLogInWhenRetrievingOauthTokenFails() { var apiClient = Substitute.For<IApiClient>(); apiClient.HostAddress.Returns(HostAddress.GitHubDotComHostAddress); apiClient.GetOrCreateApplicationAuthenticationCode( Args.TwoFactorChallengCallback, Args.String, Args.Boolean) .Returns(Observable.Throw<ApplicationAuthorization>(new NotFoundException("", HttpStatusCode.BadGateway))); apiClient.GetUser().Returns(Observable.Return(CreateOctokitUser("jiminy"))); var hostCache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, hostCache, Substitute.For<IAvatarProvider>()); var loginCache = new TestLoginCache(); var host = new RepositoryHost(apiClient, modelService, loginCache, Substitute.For<ITwoFactorChallengeHandler>()); await Assert.ThrowsAsync<NotFoundException>(async () => await host.LogIn("jiminy", "cricket")); await Assert.ThrowsAsync<KeyNotFoundException>( async () => await hostCache.GetObject<AccountCacheItem>("user")); var loginInfo = await loginCache.GetLoginAsync(HostAddress.GitHubDotComHostAddress); Assert.Equal("jiminy", loginInfo.UserName); Assert.Equal("cricket", loginInfo.Password); Assert.False(host.IsLoggedIn); }
public async Task IncrementsLoginCount() { var apiClient = Substitute.For <IApiClient>(); apiClient.HostAddress.Returns(HostAddress.GitHubDotComHostAddress); apiClient.GetOrCreateApplicationAuthenticationCode( Args.TwoFactorChallengCallback, Args.String, Args.Boolean) .Returns(Observable.Return(new ApplicationAuthorization("S3CR3TS"))); apiClient.GetUser().Returns(Observable.Return(CreateOctokitUser("baymax"))); var hostCache = new InMemoryBlobCache(); var modelService = Substitute.For <IModelService>(); var loginManager = Substitute.For <ILoginManager>(); loginManager.Login(HostAddress.GitHubDotComHostAddress, Arg.Any <IGitHubClient>(), "baymax", "aPassword").Returns(CreateOctokitUser("baymax")); var loginCache = new TestLoginCache(); var usage = Substitute.For <IUsageTracker>(); var host = new RepositoryHost(apiClient, modelService, loginManager, loginCache, usage); var result = await host.LogIn("baymax", "aPassword"); await usage.Received().IncrementLoginCount(); }
public async Task CanRetrieveAndCacheGitIgnores() { var data = new[] { "dotnet", "peanuts", "bloomcounty" }; var apiClient = Substitute.For<IApiClient>(); apiClient.GetGitIgnoreTemplates().Returns(data.ToObservable()); var cache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, cache, Substitute.For<IAvatarProvider>()); var fetched = await modelService.GetGitIgnoreTemplates().ToList(); Assert.Equal(3, fetched.Count); for (int i = 0; i < data.Length; i++) Assert.Equal(data[i], fetched[i].Name); var indexKey = CacheIndex.GitIgnoresPrefix; var cached = await cache.GetObject<CacheIndex>(indexKey); Assert.Equal(3, cached.Keys.Count); var items = await cache.GetObjects<GitIgnoreCacheItem>(cached.Keys).Take(1); for (int i = 0; i < data.Length; i++) Assert.Equal(data[i], items[indexKey + "|" + data[i]].Name); }
public async Task IncrementsLoginCount() { var apiClient = Substitute.For <IApiClient>(); apiClient.HostAddress.Returns(HostAddress.GitHubDotComHostAddress); var hostCache = new InMemoryBlobCache(); var modelService = Substitute.For <IModelService>(); var loginManager = Substitute.For <ILoginManager>(); loginManager.LoginFromCache(HostAddress.GitHubDotComHostAddress, Arg.Any <IGitHubClient>()).Returns(CreateOctokitUser("baymax")); var loginCache = new TestLoginCache(); var usage = Substitute.For <IUsageTracker>(); var host = new RepositoryHost(apiClient, modelService, loginManager, loginCache, usage); var result = await host.LogInFromCache(); var model = new UsageModel(); await usage.Received().IncrementCounter( Arg.Is <Expression <Func <UsageModel, int> > >(x => ((MemberExpression)x.Body).Member.Name == nameof(model.NumberOfLogins))); }
public async Task CanRetrieveAndCacheGitIgnores() { var templates = new[] { "dotnet", "peanuts", "bloomcounty" }; var apiClient = Substitute.For <IApiClient>(); apiClient.GetGitIgnoreTemplates().Returns(templates.ToObservable()); var cache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, cache, Substitute.For <IAvatarProvider>()); var fetched = await modelService.GetGitIgnoreTemplates(); Assert.Equal(4, fetched.Count); Assert.Equal("None", fetched[0].Name); Assert.Equal("dotnet", fetched[1].Name); Assert.Equal("peanuts", fetched[2].Name); Assert.Equal("bloomcounty", fetched[3].Name); var cached = await cache.GetObject <IReadOnlyList <string> >("gitignores"); Assert.Equal(3, cached.Count); Assert.Equal("dotnet", cached[0]); Assert.Equal("peanuts", cached[1]); Assert.Equal("bloomcounty", cached[2]); }
public async Task DistinctsFetchedSongsByGuid() { var songs = Helpers.SetupSongs(2); songs[0].Artist = "A"; songs[1].Artist = "B"; var songFetcher = Substitute.For <ISongFetcher <NetworkSong> >(); songFetcher.GetSongsAsync().Returns(Observable.Return(songs).Concat(Observable.Return(songs))); var cache = new InMemoryBlobCache(); var vm = new RemoteArtistsViewModel(songFetcher, cache); vm.Activator.Activate(); var loadResults = vm.LoadCommand.CreateCollection(); await vm.LoadCommand.ExecuteAsync(); Assert.Equal(1, loadResults.Count); }
public async Task InitializeAsyncLoadsValuesIntoCache() { var testCache = new InMemoryBlobCache(); await testCache.InsertObject("Storage:DummyNumber", 16); await testCache.InsertObject("Storage:DummyText", "Random"); var cache = Substitute.For <IBlobCache>(); cache.Get(Arg.Any <string>()).Returns(x => testCache.Get(x.Arg <string>())); var settings = new DummySettingsStorage("Storage", cache); await settings.InitializeAsync(); int number = settings.DummyNumber; string text = settings.DummyText; Assert.Equal(16, number); Assert.Equal("Random", text); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed cache.ReceivedWithAnyArgs(2).Get(Arg.Any <string>()); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed }
public async Task RoundTripIntegrationTest() { var cache = new InMemoryBlobCache(); var cachingHandler = new RateLimitedHttpMessageHandler(new HttpClientHandler(), Priority.UserInitiated, cacheResultFunc: async(rq, resp, key, ct) => { var data = await resp.Content.ReadAsByteArrayAsync().ConfigureAwait(false); await cache.Insert(key, data); }); var client = new HttpClient(cachingHandler); var origData = await client.GetStringAsync(new Uri("http://httpbin.org/get")).ConfigureAwait(false); Assert.True(origData.Contains("origin")); Assert.Equal(1, (await cache.GetAllKeys()).Count()); var offlineHandler = new OfflineHttpMessageHandler(async(rq, key, ct) => await cache.Get(key)); client = new HttpClient(offlineHandler); var newData = await client.GetStringAsync(new Uri("http://httpbin.org/get")).ConfigureAwait(false); Assert.Equal(origData, newData); bool shouldDie = true; try { await client.GetStringAsync(new Uri("http://httpbin.org/gzip")).ConfigureAwait(false); } catch (Exception ex) { shouldDie = false; Console.WriteLine(ex); } Assert.False(shouldDie); }
public async Task CachingTest() { var testScheduler = new TestScheduler(); var cache = new InMemoryBlobCache(testScheduler); var cacheTimeout = TimeSpan.FromSeconds(10); var someApi = new Mock <ISomeApi>(); someApi.Setup(s => s.GetSomeStrings()) .Returns(Task.FromResult("helloworld")).Verifiable(); var apiWrapper = new SomeApiWrapper(someApi.Object, cache, cacheTimeout); var string1 = await apiWrapper.GetSomeStrings(); someApi.Verify(s => s.GetSomeStrings(), Times.Once()); StringAssert.AreEqualIgnoringCase("helloworld", string1); testScheduler.AdvanceToMs(5000); var observer = testScheduler.CreateObserver <string>(); apiWrapper.GetSomeStrings().Subscribe(observer); testScheduler.AdvanceByMs(cacheTimeout.TotalMilliseconds); someApi.Verify(s => s.GetSomeStrings(), Times.Once()); StringAssert.AreEqualIgnoringCase("helloworld", observer.Messages[0].Value.Value); }
public void CanCreateUserSettings() { Logger.Debug("CanCreateUserSettings"); var autoResetEvent = new AutoResetEvent(false); var inMemoryBlobCache = new InMemoryBlobCache(); _autoSub.Provide <IBlobCache>(inMemoryBlobCache); var dataCache = _autoSub.Resolve <DataCache>(); UserSettings userSettings = null; dataCache.GetUserSettings() .Subscribe(settings => { userSettings = settings; autoResetEvent.Set(); }); autoResetEvent.WaitOne(); userSettings.Should().NotBeNull(); }
public async Task RetriesUsingOldScopeWhenAuthenticationFailsAndIsEnterprise() { var enterpriseHostAddress = HostAddress.Create("https://enterprise.example.com/"); var apiClient = Substitute.For <IApiClient>(); apiClient.HostAddress.Returns(enterpriseHostAddress); apiClient.GetOrCreateApplicationAuthenticationCode(Args.TwoFactorChallengCallback, null, false, true) .Returns(Observable.Throw <ApplicationAuthorization>(new ApiException("Bad scopes", (HttpStatusCode)422))); apiClient.GetOrCreateApplicationAuthenticationCode(Args.TwoFactorChallengCallback, null, true, false) .Returns(Observable.Return(new ApplicationAuthorization("T0k3n"))); apiClient.GetUser().Returns(Observable.Return(CreateUserAndScopes("jiminy"))); var hostCache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, hostCache, Substitute.For <IAvatarProvider>()); var loginCache = new TestLoginCache(); var host = new RepositoryHost(apiClient, modelService, loginCache, Substitute.For <ITwoFactorChallengeHandler>()); await host.LogIn("jiminy", "aPassowrd"); Assert.True(host.IsLoggedIn); var loginInfo = await loginCache.GetLoginAsync(enterpriseHostAddress); Assert.Equal("jiminy", loginInfo.UserName); Assert.Equal("T0k3n", loginInfo.Password); }
public async Task ExpiredIndexClearsItems() { var expected = 5; var username = "******"; var reponame = "repo"; var cache = new InMemoryBlobCache(); var apiClient = Substitute.For<IApiClient>(); var modelService = new ModelService(apiClient, cache, Substitute.For<IAvatarProvider>()); var user = CreateOctokitUser(username); apiClient.GetUser().Returns(Observable.Return(user)); apiClient.GetOrganizations().Returns(Observable.Empty<Organization>()); var act = modelService.GetAccounts().ToEnumerable().First().First(); var repo = Substitute.For<ISimpleRepositoryModel>(); repo.Name.Returns(reponame); repo.CloneUrl.Returns(new UriString("https://github.com/" + username + "/" + reponame)); var indexKey = string.Format(CultureInfo.InvariantCulture, "{0}|{1}|pr", user.Login, repo.Name); var prcache = Enumerable.Range(1, expected) .Select(id => CreatePullRequest(user, id, ItemState.Open, "Cache " + id, DateTimeOffset.UtcNow, DateTimeOffset.UtcNow, 0)); // seed the cache prcache .Select(item => new ModelService.PullRequestCacheItem(item)) .Select(item => item.Save<ModelService.PullRequestCacheItem>(cache, indexKey).ToEnumerable().First()) .SelectMany(item => CacheIndex.AddAndSaveToIndex(cache, indexKey, item).ToEnumerable()) .ToList(); // expire the index var indexobj = await cache.GetObject<CacheIndex>(indexKey); indexobj.UpdatedAt = DateTimeOffset.UtcNow - TimeSpan.FromMinutes(6); await cache.InsertObject(indexKey, indexobj); var prlive = Observable.Range(5, expected) .Select(id => CreatePullRequest(user, id, ItemState.Open, "Live " + id, DateTimeOffset.UtcNow, DateTimeOffset.UtcNow, 0)) .DelaySubscription(TimeSpan.FromMilliseconds(10)); apiClient.GetPullRequestsForRepository(user.Login, repo.Name).Returns(prlive); await modelService.InsertUser(new AccountCacheItem(user)); var col = modelService.GetPullRequests(repo); col.ProcessingDelay = TimeSpan.Zero; var count = 0; var evt = new ManualResetEvent(false); col.Subscribe(t => { // we get all the items from the cache (items 1-5), all the items from the live (items 5-9), // and 4 deletions (items 1-4) because the cache expired the items that were not // a part of the live data if (++count == 14) evt.Set(); }, () => { }); evt.WaitOne(); evt.Reset(); Assert.Equal(5, col.Count); Assert.Collection(col, t => { Assert.True(t.Title.StartsWith("Live")); Assert.Equal(5, t.Number); }, t => { Assert.True(t.Title.StartsWith("Live")); Assert.Equal(6, t.Number); }, t => { Assert.True(t.Title.StartsWith("Live")); Assert.Equal(7, t.Number); }, t => { Assert.True(t.Title.StartsWith("Live")); Assert.Equal(8, t.Number); }, t => { Assert.True(t.Title.StartsWith("Live")); Assert.Equal(9, t.Number); } ); }
public async Task NonExpiredIndexReturnsCache() { var expected = 5; var username = "******"; var reponame = "repo"; var cache = new InMemoryBlobCache(); var apiClient = Substitute.For<IApiClient>(); var modelService = new ModelService(apiClient, cache, Substitute.For<IAvatarProvider>()); var user = CreateOctokitUser(username); apiClient.GetUser().Returns(Observable.Return(user)); apiClient.GetOrganizations().Returns(Observable.Empty<Organization>()); var act = modelService.GetAccounts().ToEnumerable().First().First(); var repo = Substitute.For<ISimpleRepositoryModel>(); repo.Name.Returns(reponame); repo.CloneUrl.Returns(new UriString("https://github.com/" + username + "/" + reponame)); var indexKey = string.Format(CultureInfo.InvariantCulture, "{0}|{1}|pr", user.Login, repo.Name); var prcache = Enumerable.Range(1, expected) .Select(id => CreatePullRequest(user, id, ItemState.Open, "Cache " + id, DateTimeOffset.UtcNow, DateTimeOffset.UtcNow, 0)); // seed the cache prcache .Select(item => new ModelService.PullRequestCacheItem(item)) .Select(item => item.Save<ModelService.PullRequestCacheItem>(cache, indexKey).ToEnumerable().First()) .SelectMany(item => CacheIndex.AddAndSaveToIndex(cache, indexKey, item).ToEnumerable()) .ToList(); var prlive = Observable.Range(1, expected) .Select(id => CreatePullRequest(user, id, ItemState.Open, "Live " + id, DateTimeOffset.UtcNow, DateTimeOffset.UtcNow, 0)) .DelaySubscription(TimeSpan.FromMilliseconds(10)); apiClient.GetPullRequestsForRepository(user.Login, repo.Name).Returns(prlive); await modelService.InsertUser(new AccountCacheItem(user)); var col = modelService.GetPullRequests(repo); col.ProcessingDelay = TimeSpan.Zero; var count = 0; var evt = new ManualResetEvent(false); col.Subscribe(t => { if (++count == expected) evt.Set(); }, () => { }); evt.WaitOne(); evt.Reset(); Assert.Collection(col, col.Select(x => new Action<IPullRequestModel>(t => Assert.True(x.Title.StartsWith("Cache")))).ToArray()); }
public async Task InvalidatesTheCache() { var apiClient = Substitute.For<IApiClient>(); var cache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, cache, Substitute.For<IAvatarProvider>()); var user = await modelService.InsertUser(new AccountCacheItem(CreateOctokitUser("octocat"))); Assert.Equal(1, (await cache.GetAllObjects<AccountCacheItem>()).Count()); await modelService.InvalidateAll(); Assert.Equal(0, (await cache.GetAllObjects<AccountCacheItem>()).Count()); }
public async Task CanRetrieveAndCacheRepositoriesForUserAndOrganizations() { var orgs = new[] { CreateOctokitOrganization("github"), CreateOctokitOrganization("octokit") }; var ownedRepos = new[] { CreateRepository("haacked", "seegit"), CreateRepository("haacked", "codehaacks") }; var memberRepos = new[] { CreateRepository("mojombo", "semver"), CreateRepository("ninject", "ninject"), CreateRepository("jabbr", "jabbr"), CreateRepository("fody", "nullguard") }; var githubRepos = new[] { CreateRepository("github", "visualstudio") }; var octokitRepos = new[] { CreateRepository("octokit", "octokit.net"), CreateRepository("octokit", "octokit.rb"), CreateRepository("octokit", "octokit.objc") }; var apiClient = Substitute.For<IApiClient>(); apiClient.GetOrganizations().Returns(orgs.ToObservable()); apiClient.GetUserRepositories(RepositoryType.Owner).Returns(ownedRepos.ToObservable()); apiClient.GetUserRepositories(RepositoryType.Member).Returns(memberRepos.ToObservable()); apiClient.GetRepositoriesForOrganization("github").Returns(githubRepos.ToObservable()); apiClient.GetRepositoriesForOrganization("octokit").Returns(octokitRepos.ToObservable()); var cache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, cache, Substitute.For<IAvatarProvider>()); await modelService.InsertUser(new AccountCacheItem { Login = "******" }); var fetched = await modelService.GetRepositories().ToList(); Assert.Equal(4, fetched.Count); Assert.Equal(2, fetched[0].Count); Assert.Equal(4, fetched[1].Count); Assert.Equal(1, fetched[2].Count); Assert.Equal(3, fetched[3].Count); Assert.Equal("seegit", fetched[0][0].Name); Assert.Equal("codehaacks", fetched[0][1].Name); Assert.Equal("semver", fetched[1][0].Name); Assert.Equal("ninject", fetched[1][1].Name); Assert.Equal("jabbr", fetched[1][2].Name); Assert.Equal("nullguard", fetched[1][3].Name); Assert.Equal("visualstudio", fetched[2][0].Name); Assert.Equal("octokit.net", fetched[3][0].Name); Assert.Equal("octokit.rb", fetched[3][1].Name); Assert.Equal("octokit.objc", fetched[3][2].Name); var cachedOwnerRepositories = await cache.GetObject<IReadOnlyList<ModelService.RepositoryCacheItem>>("opus|Owner:repos"); Assert.Equal(2, cachedOwnerRepositories.Count); Assert.Equal("seegit", cachedOwnerRepositories[0].Name); Assert.Equal("haacked", cachedOwnerRepositories[0].Owner.Login); Assert.Equal("codehaacks", cachedOwnerRepositories[1].Name); Assert.Equal("haacked", cachedOwnerRepositories[1].Owner.Login); var cachedMemberRepositories = await cache.GetObject<IReadOnlyList<ModelService.RepositoryCacheItem>>("opus|Member:repos"); Assert.Equal(4, cachedMemberRepositories.Count); Assert.Equal("semver", cachedMemberRepositories[0].Name); Assert.Equal("mojombo", cachedMemberRepositories[0].Owner.Login); Assert.Equal("ninject", cachedMemberRepositories[1].Name); Assert.Equal("ninject", cachedMemberRepositories[1].Owner.Login); Assert.Equal("jabbr", cachedMemberRepositories[2].Name); Assert.Equal("jabbr", cachedMemberRepositories[2].Owner.Login); Assert.Equal("nullguard", cachedMemberRepositories[3].Name); Assert.Equal("fody", cachedMemberRepositories[3].Owner.Login); var cachedGitHubRepositories = await cache.GetObject<IReadOnlyList<ModelService.RepositoryCacheItem>>("opus|github|repos"); Assert.Equal(1, cachedGitHubRepositories.Count); Assert.Equal("seegit", cachedOwnerRepositories[0].Name); Assert.Equal("haacked", cachedOwnerRepositories[0].Owner.Login); Assert.Equal("codehaacks", cachedOwnerRepositories[1].Name); Assert.Equal("haacked", cachedOwnerRepositories[1].Owner.Login); var cachedOctokitRepositories = await cache.GetObject<IReadOnlyList<ModelService.RepositoryCacheItem>>("opus|octokit|repos"); Assert.Equal("octokit.net", cachedOctokitRepositories[0].Name); Assert.Equal("octokit", cachedOctokitRepositories[0].Owner.Login); Assert.Equal("octokit.rb", cachedOctokitRepositories[1].Name); Assert.Equal("octokit", cachedOctokitRepositories[1].Owner.Login); Assert.Equal("octokit.objc", cachedOctokitRepositories[2].Name); Assert.Equal("octokit", cachedOctokitRepositories[2].Owner.Login); }
public async Task OnlyRetrievesOneUserEvenIfCacheOrApiReturnsMoreThanOne() { // This should be impossible, but let's pretend it does happen. var users = new[] { CreateOctokitUser("peppermintpatty"), CreateOctokitUser("peppermintpatty") }; var apiClient = Substitute.For<IApiClient>(); apiClient.GetUser().Returns(users.ToObservable()); apiClient.GetOrganizations().Returns(Observable.Empty<Organization>()); var cache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, cache, Substitute.For<IAvatarProvider>()); var fetched = await modelService.GetAccounts(); Assert.Equal(1, fetched.Count); Assert.Equal("peppermintpatty", fetched[0].Login); }
public async Task CanRetrieveUserFromCacheAndAccountsFromApi() { var orgs = new[] { CreateOctokitOrganization("github"), CreateOctokitOrganization("fake") }; var apiClient = Substitute.For<IApiClient>(); apiClient.GetOrganizations().Returns(orgs.ToObservable()); var cache = new InMemoryBlobCache(); var modelService = new ModelService(apiClient, cache, Substitute.For<IAvatarProvider>()); await modelService.InsertUser(new AccountCacheItem(CreateOctokitUser("octocat"))); var fetched = await modelService.GetAccounts(); Assert.Equal(3, fetched.Count); Assert.Equal("octocat", fetched[0].Login); Assert.Equal("github", fetched[1].Login); Assert.Equal("fake", fetched[2].Login); var cachedOrgs = await cache.GetObject<IReadOnlyList<AccountCacheItem>>("octocat|orgs"); Assert.Equal(2, cachedOrgs.Count); Assert.Equal("github", cachedOrgs[0].Login); Assert.Equal("fake", cachedOrgs[1].Login); var cachedUser = await cache.GetObject<AccountCacheItem>("user"); Assert.Equal("octocat", cachedUser.Login); }