Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit 8096a8e

Browse files
committed
Merge pull request #38 from github/haacked/add-unit-tests
SimpleApiClient Unit Tests
2 parents ad6a715 + b1e012a commit 8096a8e

File tree

5 files changed

+231
-33
lines changed

5 files changed

+231
-33
lines changed

src/GitHub.Api/SimpleApiClient.cs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class SimpleApiClient : ISimpleApiClient
1313
public HostAddress HostAddress { get; }
1414
public UriString OriginalUrl { get; }
1515

16-
readonly GitHubClient client;
16+
readonly IGitHubClient client;
1717
readonly Lazy<IEnterpriseProbeTask> enterpriseProbe;
1818
readonly Lazy<IWikiProbe> wikiProbe;
1919
static readonly SemaphoreSlim sem = new SemaphoreSlim(1);
@@ -23,7 +23,7 @@ public class SimpleApiClient : ISimpleApiClient
2323
bool? isEnterprise;
2424
bool? hasWiki;
2525

26-
internal SimpleApiClient(HostAddress hostAddress, UriString repoUrl, GitHubClient githubClient,
26+
public SimpleApiClient(HostAddress hostAddress, UriString repoUrl, IGitHubClient githubClient,
2727
Lazy<IEnterpriseProbeTask> enterpriseProbe, Lazy<IWikiProbe> wikiProbe)
2828
{
2929
HostAddress = hostAddress;
@@ -78,16 +78,12 @@ async Task<Repository> GetRepositoryInternal()
7878

7979
public bool HasWiki()
8080
{
81-
if (hasWiki.HasValue)
82-
return hasWiki.Value;
83-
return false;
81+
return hasWiki.HasValue && hasWiki.Value;
8482
}
8583

8684
public bool IsEnterprise()
8785
{
88-
if (isEnterprise.HasValue)
89-
return isEnterprise.Value;
90-
return false;
86+
return isEnterprise.HasValue && isEnterprise.Value;
9187
}
9288

9389
async Task<bool> HasWikiInternal(Repository repo)
@@ -108,8 +104,6 @@ async Task<bool> HasWikiInternal(Repository repo)
108104
return false;
109105
#endif
110106
var ret = await probe.ProbeAsync(repo);
111-
if (ret == WikiProbeResult.Failed)
112-
return false;
113107
return (ret == WikiProbeResult.Ok);
114108
}
115109

@@ -122,8 +116,6 @@ async Task<bool> IsEnterpriseInternal()
122116
return false;
123117
#endif
124118
var ret = await probe.ProbeAsync(HostAddress.WebUri);
125-
if (ret == EnterpriseProbeResult.Failed)
126-
return false;
127119
return (ret == EnterpriseProbeResult.Ok);
128120
}
129121
}
Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.ComponentModel.Composition;
34
using GitHub.Models;
45
using GitHub.Primitives;
56
using GitHub.Services;
67
using Octokit;
7-
using System.Collections.Generic;
8+
using System.Collections.Concurrent;
89

910
namespace GitHub.Api
1011
{
@@ -16,7 +17,7 @@ public class SimpleApiClientFactory : ISimpleApiClientFactory
1617
readonly Lazy<IEnterpriseProbeTask> lazyEnterpriseProbe;
1718
readonly Lazy<IWikiProbe> lazyWikiProbe;
1819

19-
static readonly Dictionary<UriString, ISimpleApiClient> cache = new Dictionary<UriString, ISimpleApiClient>();
20+
static readonly ConcurrentDictionary<UriString, ISimpleApiClient> cache = new ConcurrentDictionary<UriString, ISimpleApiClient>();
2021

2122
[ImportingConstructor]
2223
public SimpleApiClientFactory(IProgram program, Lazy<IEnterpriseProbeTask> enterpriseProbe, Lazy<IWikiProbe> wikiProbe)
@@ -28,29 +29,16 @@ public SimpleApiClientFactory(IProgram program, Lazy<IEnterpriseProbeTask> enter
2829

2930
public ISimpleApiClient Create(UriString repositoryUrl)
3031
{
31-
var contains = cache.ContainsKey(repositoryUrl);
32-
if (contains)
33-
return cache[repositoryUrl];
34-
35-
lock (cache)
36-
{
37-
if (!cache.ContainsKey(repositoryUrl))
38-
{
39-
var hostAddress = HostAddress.Create(repositoryUrl);
40-
var apiBaseUri = hostAddress.ApiUri;
41-
cache.Add(repositoryUrl, new SimpleApiClient(hostAddress, repositoryUrl, new GitHubClient(productHeader, new SimpleCredentialStore(hostAddress), apiBaseUri), lazyEnterpriseProbe, lazyWikiProbe));
42-
}
43-
return cache[repositoryUrl];
44-
}
32+
var hostAddress = HostAddress.Create(repositoryUrl);
33+
return cache.GetOrAdd(repositoryUrl, new SimpleApiClient(hostAddress, repositoryUrl,
34+
new GitHubClient(productHeader, new SimpleCredentialStore(hostAddress), hostAddress.ApiUri),
35+
lazyEnterpriseProbe, lazyWikiProbe));
4536
}
4637

4738
public void ClearFromCache(ISimpleApiClient client)
4839
{
49-
lock (cache)
50-
{
51-
if (cache.ContainsKey(client.OriginalUrl))
52-
cache.Remove(client.OriginalUrl);
53-
}
40+
ISimpleApiClient c;
41+
cache.TryRemove(client.OriginalUrl, out c);
5442
}
5543
}
5644
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using System;
2+
using GitHub.Api;
3+
using GitHub.Primitives;
4+
using GitHub.Services;
5+
using GitHub.VisualStudio;
6+
using NSubstitute;
7+
using Xunit;
8+
9+
public class SimpleApiClientFactoryTests
10+
{
11+
public class TheCreateMethod
12+
{
13+
[Fact]
14+
public void CreatesNewInstanceOfSimpleApiClient()
15+
{
16+
var program = new Program();
17+
var enterpriseProbe = Substitute.For<IEnterpriseProbeTask>();
18+
var wikiProbe = Substitute.For<IWikiProbe>();
19+
var factory = new SimpleApiClientFactory(
20+
program,
21+
new Lazy<IEnterpriseProbeTask>(() => enterpriseProbe),
22+
new Lazy<IWikiProbe>(() => wikiProbe));
23+
24+
var client = factory.Create("https://github.com/github/visualstudio");
25+
26+
Assert.Equal("https://github.com/github/visualstudio", client.OriginalUrl);
27+
Assert.Equal(HostAddress.GitHubDotComHostAddress, client.HostAddress);
28+
Assert.Same(client, factory.Create("https://github.com/github/visualstudio")); // Tests caching.
29+
}
30+
}
31+
32+
public class TheClearFromCacheMethod
33+
{
34+
[Fact]
35+
public void RemovesClientFromCache()
36+
{
37+
var program = new Program();
38+
var enterpriseProbe = Substitute.For<IEnterpriseProbeTask>();
39+
var wikiProbe = Substitute.For<IWikiProbe>();
40+
var factory = new SimpleApiClientFactory(
41+
program,
42+
new Lazy<IEnterpriseProbeTask>(() => enterpriseProbe),
43+
new Lazy<IWikiProbe>(() => wikiProbe));
44+
45+
var client = factory.Create("https://github.com/github/visualstudio");
46+
factory.ClearFromCache(client);
47+
48+
Assert.NotSame(client, factory.Create("https://github.com/github/visualstudio"));
49+
}
50+
}
51+
}
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using GitHub.Api;
4+
using GitHub.Primitives;
5+
using GitHub.Services;
6+
using NSubstitute;
7+
using Octokit;
8+
using Xunit;
9+
10+
public class SimpleApiClientTests
11+
{
12+
public class TheGetRepositoryMethod
13+
{
14+
[Fact]
15+
public async Task RetrievesRepositoryFromWeb()
16+
{
17+
var gitHubHost = HostAddress.GitHubDotComHostAddress;
18+
var gitHubClient = Substitute.For<IGitHubClient>();
19+
var repository = new Repository(42);
20+
gitHubClient.Repository.Get("github", "visualstudio").Returns(Task.FromResult(repository));
21+
var enterpriseProbe = Substitute.For<IEnterpriseProbeTask>();
22+
var wikiProbe = Substitute.For<IWikiProbe>();
23+
var client = new SimpleApiClient(
24+
gitHubHost,
25+
"https://github.com/github/visualstudio",
26+
gitHubClient,
27+
new Lazy<IEnterpriseProbeTask>(() => enterpriseProbe),
28+
new Lazy<IWikiProbe>(() => wikiProbe));
29+
30+
var result = await client.GetRepository();
31+
32+
Assert.Equal(42, result.Id);
33+
}
34+
35+
[Fact]
36+
public async Task RetrievesCachedRepositoryForSubsequentCalls()
37+
{
38+
var gitHubHost = HostAddress.GitHubDotComHostAddress;
39+
var gitHubClient = Substitute.For<IGitHubClient>();
40+
var repository = new Repository(42);
41+
gitHubClient.Repository.Get("github", "visualstudio")
42+
.Returns(_ => Task.FromResult(repository), _ => { throw new Exception("Should only be called once."); });
43+
var enterpriseProbe = Substitute.For<IEnterpriseProbeTask>();
44+
var wikiProbe = Substitute.For<IWikiProbe>();
45+
var client = new SimpleApiClient(
46+
gitHubHost,
47+
"https://github.com/github/visualstudio",
48+
gitHubClient,
49+
new Lazy<IEnterpriseProbeTask>(() => enterpriseProbe),
50+
new Lazy<IWikiProbe>(() => wikiProbe));
51+
await client.GetRepository();
52+
53+
var result = await client.GetRepository();
54+
55+
Assert.Equal(42, result.Id);
56+
}
57+
}
58+
59+
public class TheHasWikiMethod
60+
{
61+
[Theory]
62+
[InlineData(WikiProbeResult.Ok, true)]
63+
[InlineData(WikiProbeResult.Failed, false)]
64+
[InlineData(WikiProbeResult.NotFound, false)]
65+
public async Task ReturnsTrueWhenWikiProbeReturnsOk(WikiProbeResult probeResult, bool expected)
66+
{
67+
var gitHubHost = HostAddress.GitHubDotComHostAddress;
68+
var gitHubClient = Substitute.For<IGitHubClient>();
69+
var repository = CreateRepository(42, true);
70+
gitHubClient.Repository.Get("github", "visualstudio").Returns(Task.FromResult(repository));
71+
var enterpriseProbe = Substitute.For<IEnterpriseProbeTask>();
72+
var wikiProbe = Substitute.For<IWikiProbe>();
73+
wikiProbe.ProbeAsync(repository)
74+
.Returns(_ => Task.FromResult(probeResult), _ => { throw new Exception("Only call it once"); });
75+
var client = new SimpleApiClient(
76+
gitHubHost,
77+
"https://github.com/github/visualstudio",
78+
gitHubClient,
79+
new Lazy<IEnterpriseProbeTask>(() => enterpriseProbe),
80+
new Lazy<IWikiProbe>(() => wikiProbe));
81+
await client.GetRepository();
82+
83+
var result = client.HasWiki();
84+
85+
Assert.Equal(expected, result);
86+
Assert.Equal(expected, client.HasWiki());
87+
}
88+
89+
[Fact]
90+
public void ReturnsFalseWhenWeHaveNotRequestedRepository()
91+
{
92+
var gitHubHost = HostAddress.GitHubDotComHostAddress;
93+
var gitHubClient = Substitute.For<IGitHubClient>();
94+
var enterpriseProbe = Substitute.For<IEnterpriseProbeTask>();
95+
var wikiProbe = Substitute.For<IWikiProbe>();
96+
var client = new SimpleApiClient(
97+
gitHubHost,
98+
"https://github.com/github/visualstudio",
99+
gitHubClient,
100+
new Lazy<IEnterpriseProbeTask>(() => enterpriseProbe),
101+
new Lazy<IWikiProbe>(() => wikiProbe));
102+
103+
var result = client.HasWiki();
104+
105+
Assert.False(result);
106+
}
107+
}
108+
109+
public class TheIsEnterpriseMethod
110+
{
111+
[Theory]
112+
[InlineData(EnterpriseProbeResult.Ok, true)]
113+
[InlineData(EnterpriseProbeResult.Failed, false)]
114+
[InlineData(EnterpriseProbeResult.NotFound, false)]
115+
public async Task ReturnsTrueWhenEnterpriseProbeReturnsOk(EnterpriseProbeResult probeResult, bool expected)
116+
{
117+
var gitHubHost = HostAddress.GitHubDotComHostAddress;
118+
var gitHubClient = Substitute.For<IGitHubClient>();
119+
var repository = CreateRepository(42, true);
120+
gitHubClient.Repository.Get("github", "visualstudio").Returns(Task.FromResult(repository));
121+
var enterpriseProbe = Substitute.For<IEnterpriseProbeTask>();
122+
enterpriseProbe.ProbeAsync(Args.Uri)
123+
.Returns(_ => Task.FromResult(probeResult), _ => { throw new Exception("Only call it once"); });
124+
var wikiProbe = Substitute.For<IWikiProbe>();
125+
var client = new SimpleApiClient(
126+
gitHubHost,
127+
"https://github.com/github/visualstudio",
128+
gitHubClient,
129+
new Lazy<IEnterpriseProbeTask>(() => enterpriseProbe),
130+
new Lazy<IWikiProbe>(() => wikiProbe));
131+
await client.GetRepository();
132+
133+
var result = client.IsEnterprise();
134+
135+
Assert.Equal(expected, result);
136+
Assert.Equal(expected, client.IsEnterprise());
137+
}
138+
139+
[Fact]
140+
public void ReturnsFalseWhenWeHaveNotRequestedRepository()
141+
{
142+
var gitHubHost = HostAddress.GitHubDotComHostAddress;
143+
var gitHubClient = Substitute.For<IGitHubClient>();
144+
var enterpriseProbe = Substitute.For<IEnterpriseProbeTask>();
145+
var wikiProbe = Substitute.For<IWikiProbe>();
146+
var client = new SimpleApiClient(
147+
gitHubHost,
148+
"https://github.com/github/visualstudio",
149+
gitHubClient,
150+
new Lazy<IEnterpriseProbeTask>(() => enterpriseProbe),
151+
new Lazy<IWikiProbe>(() => wikiProbe));
152+
153+
var result = client.IsEnterprise();
154+
155+
Assert.False(result);
156+
}
157+
}
158+
159+
private static Repository CreateRepository(int id, bool hasWiki)
160+
{
161+
return new Repository("", "", "", "", "", "", "", id, new User(), "", "", "", "", "", false, false, 0, 0, 0, "",
162+
0, null, DateTimeOffset.Now, DateTimeOffset.Now, new RepositoryPermissions(), new User(), null, null, false,
163+
hasWiki, false);
164+
}
165+
}

src/UnitTests/UnitTests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@
138138
</ItemGroup>
139139
<ItemGroup>
140140
<Compile Include="Args.cs" />
141+
<Compile Include="GitHub.Api\SimpleApiClientFactoryTests.cs" />
142+
<Compile Include="GitHub.Api\SimpleApiClientTests.cs" />
141143
<Compile Include="GitHub.App\Caches\CredentialCacheTests.cs" />
142144
<Compile Include="GitHub.App\Caches\ImageCacheTests.cs" />
143145
<Compile Include="GitHub.App\Models\ModelServiceTests.cs" />

0 commit comments

Comments
 (0)