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

Commit 3b2d3e3

Browse files
committed
Merge pull request #41 from github/haacked/credential-cache-tests
Add unit tests for CredentialCache
2 parents 416a1b7 + 016abf0 commit 3b2d3e3

File tree

3 files changed

+317
-11
lines changed

3 files changed

+317
-11
lines changed

src/GitHub.App/Caches/CredentialCache.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class CredentialCache : ISecureBlobCache, IObjectBlobCache
1616
public IScheduler Scheduler { get; protected set; }
1717

1818
readonly AsyncSubject<Unit> shutdown = new AsyncSubject<Unit>();
19-
public IObservable<Unit> Shutdown { get { return shutdown; } }
19+
public IObservable<Unit> Shutdown => shutdown;
2020

2121
public IObservable<Unit> Flush()
2222
{
@@ -84,7 +84,7 @@ public IObservable<Unit> Vacuum()
8484
{
8585
if (disposed) return ExceptionHelper.ObservableThrowObjectDisposedException<Unit>("CredentialCache");
8686

87-
Tuple<string, string> values = value as Tuple<string, string>;
87+
var values = value as Tuple<string, string>;
8888
if (values == null)
8989
return ExceptionHelper.ObservableThrowInvalidOperationException<Unit>(key);
9090

@@ -112,9 +112,9 @@ IObservable<Tuple<string, string>> GetTuple(string key)
112112

113113
var keyHost = GetKeyHost(key);
114114
var ret = GetKey(keyHost);
115-
if (ret != null)
116-
return Observable.Return(ret);
117-
return ExceptionHelper.ObservableThrowKeyNotFoundException<Tuple<string, string>>(keyHost);
115+
return ret != null
116+
? Observable.Return(ret)
117+
: ExceptionHelper.ObservableThrowKeyNotFoundException<Tuple<string, string>>(keyHost);
118118
}
119119

120120
public IObservable<IEnumerable<T>> GetAllObjects<T>()
@@ -180,9 +180,7 @@ static bool DeleteKey(string key)
180180
using (var credential = new Credential())
181181
{
182182
credential.Target = key;
183-
if (!credential.Load())
184-
return false;
185-
return credential.Delete();
183+
return credential.Load() && credential.Delete();
186184
}
187185
}
188186

@@ -202,9 +200,9 @@ static Tuple<string, string> GetKey(string key)
202200
{
203201
credential.Target = key;
204202
credential.Type = CredentialType.Generic;
205-
if (credential.Load())
206-
return new Tuple<string, string>(credential.Username, credential.Password);
207-
return null;
203+
return credential.Load()
204+
? new Tuple<string, string>(credential.Username, credential.Password)
205+
: null;
208206
}
209207
}
210208

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Reactive.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using GitHub.Caches;
7+
using Xunit;
8+
9+
public class CredentialCacheTests : TestBaseClass
10+
{
11+
public class TheGetObjectMethod
12+
{
13+
[Fact]
14+
public async Task RetrievesValueWithAlternateKeys()
15+
{
16+
const string key = nameof(RetrievesValueWithAlternateKeys);
17+
using (var credentialCache = new CredentialCache())
18+
{
19+
try
20+
{
21+
var credential = Tuple.Create("somebody", "somebody's secret");
22+
await credentialCache.InsertObject(key, credential);
23+
24+
var retrieved = await credentialCache.GetObject<Tuple<string, string>>(key);
25+
26+
Assert.Equal("somebody", retrieved.Item1);
27+
Assert.Equal("somebody's secret", retrieved.Item2);
28+
29+
var retrieved2 = await credentialCache.GetObject<Tuple<string, string>>("git:" + key + "/");
30+
31+
Assert.Equal("somebody", retrieved2.Item1);
32+
Assert.Equal("somebody's secret", retrieved2.Item2);
33+
34+
var retrieved3 = await credentialCache.GetObject<Tuple<string, string>>("login:" + key + "/");
35+
36+
Assert.Equal("somebody", retrieved3.Item1);
37+
Assert.Equal("somebody's secret", retrieved3.Item2);
38+
}
39+
finally
40+
{
41+
await credentialCache.Invalidate(key);
42+
}
43+
}
44+
}
45+
46+
[Fact]
47+
public async Task ThrowsObservableInvalidOperationExceptionWhenRetrievingSomethingNotATuple()
48+
{
49+
using (var credentialCache = new CredentialCache())
50+
{
51+
await Assert.ThrowsAsync<InvalidOperationException>(
52+
async () => await credentialCache.GetObject<string>("_"));
53+
}
54+
}
55+
56+
[Fact]
57+
public async Task ThrowsObjectDisposedExceptionWhenDisposed()
58+
{
59+
using (var credentialCache = new CredentialCache())
60+
{
61+
credentialCache.Dispose();
62+
await Assert.ThrowsAsync<ObjectDisposedException>(
63+
async () => await credentialCache.GetObject<Tuple<string, string>>("_"));
64+
}
65+
}
66+
}
67+
68+
public class TheInsertObjectMethod
69+
{
70+
[Fact]
71+
public async Task StoresCredentialForKeyAndGitKey()
72+
{
73+
using (var credentialCache = new CredentialCache())
74+
{
75+
try
76+
{
77+
var credential = Tuple.Create("somebody", "somebody's secret");
78+
79+
await credentialCache.InsertObject(nameof(StoresCredentialForKeyAndGitKey), credential);
80+
81+
var retrieved = await credentialCache.GetObject<Tuple<string, string>>(nameof(StoresCredentialForKeyAndGitKey));
82+
Assert.Equal("somebody", retrieved.Item1);
83+
Assert.Equal("somebody's secret", retrieved.Item2);
84+
var retrieved2 = await credentialCache.GetObject<Tuple<string, string>>("git:" + nameof(StoresCredentialForKeyAndGitKey));
85+
Assert.Equal("somebody", retrieved2.Item1);
86+
Assert.Equal("somebody's secret", retrieved2.Item2);
87+
}
88+
finally
89+
{
90+
try
91+
{
92+
await credentialCache.Invalidate(nameof(StoresCredentialForKeyAndGitKey));
93+
}
94+
catch (Exception)
95+
{
96+
}
97+
}
98+
}
99+
}
100+
101+
[Fact]
102+
public async Task ThrowsObjectDisposedExceptionWhenDisposed()
103+
{
104+
using (var credentialCache = new CredentialCache())
105+
{
106+
credentialCache.Dispose();
107+
await Assert.ThrowsAsync<ObjectDisposedException>(
108+
async () => await credentialCache.InsertObject("_", new object()));
109+
}
110+
}
111+
}
112+
113+
public class TheInsertMethod
114+
{
115+
[Fact]
116+
public async Task ThrowsInvalidOperationException()
117+
{
118+
using (var credentialCache = new CredentialCache())
119+
{
120+
await Assert.ThrowsAsync<InvalidOperationException>(
121+
async () => await credentialCache.Insert("key", new byte[] {}));
122+
}
123+
}
124+
}
125+
126+
public class TheGetMethod
127+
{
128+
[Fact]
129+
public async Task RetrievesPasswordAsUnicodeBytes()
130+
{
131+
using (var credentialCache = new CredentialCache())
132+
{
133+
try
134+
{
135+
var credential = Tuple.Create("somebody", "somebody's secret");
136+
await credentialCache.InsertObject(nameof(RetrievesPasswordAsUnicodeBytes), credential);
137+
138+
var retrieved = await credentialCache.Get(nameof(RetrievesPasswordAsUnicodeBytes));
139+
140+
Assert.Equal("somebody's secret", Encoding.Unicode.GetString(retrieved));
141+
}
142+
finally
143+
{
144+
await credentialCache.Invalidate(nameof(RetrievesPasswordAsUnicodeBytes));
145+
}
146+
}
147+
}
148+
149+
[Fact]
150+
public async Task ThrowsObservableKeyNotFoundExceptionWhenKeyNotFound()
151+
{
152+
using (var credentialCache = new CredentialCache())
153+
{
154+
await Assert.ThrowsAsync<KeyNotFoundException>(async () => await credentialCache.Get("unknownkey"));
155+
}
156+
}
157+
158+
[Fact]
159+
public async Task ThrowsObjectDisposedExceptionWhenDisposed()
160+
{
161+
using (var credentialCache = new CredentialCache())
162+
{
163+
credentialCache.Dispose();
164+
await Assert.ThrowsAsync<ObjectDisposedException>(
165+
async () => await credentialCache.Get("_"));
166+
}
167+
}
168+
}
169+
170+
public class TheInvalidateMethod
171+
{
172+
[Fact]
173+
public async Task InvalidatesTheCredential()
174+
{
175+
using (var credentialCache = new CredentialCache())
176+
{
177+
try
178+
{
179+
var credential = Tuple.Create("somebody", "somebody's secret");
180+
await credentialCache.InsertObject(nameof(InvalidatesTheCredential), credential);
181+
}
182+
finally
183+
{
184+
await credentialCache.Invalidate(nameof(InvalidatesTheCredential));
185+
}
186+
187+
await Assert.ThrowsAsync<KeyNotFoundException>(async () => await credentialCache.Get("key"));
188+
}
189+
}
190+
191+
[Fact]
192+
public async Task ThrowsKeyNotFoundExceptionWhenKeyNotFound()
193+
{
194+
using (var credentialCache = new CredentialCache())
195+
{
196+
await Assert.ThrowsAsync<KeyNotFoundException>(
197+
async () => await credentialCache.Invalidate("git:_"));
198+
await Assert.ThrowsAsync<KeyNotFoundException>(
199+
async () => await credentialCache.Invalidate("_"));
200+
}
201+
}
202+
203+
[Fact]
204+
public async Task ThrowsObjectDisposedExceptionWhenDisposed()
205+
{
206+
using (var credentialCache = new CredentialCache())
207+
{
208+
credentialCache.Dispose();
209+
await Assert.ThrowsAsync<ObjectDisposedException>(
210+
async () => await credentialCache.Invalidate("_"));
211+
}
212+
}
213+
}
214+
215+
public class TheInvalidateObjectMethod
216+
{
217+
[Fact]
218+
public async Task InvalidatesTheCredential()
219+
{
220+
const string key = nameof(InvalidatesTheCredential);
221+
using (var credentialCache = new CredentialCache())
222+
{
223+
try
224+
{
225+
var credential = Tuple.Create("somebody", "somebody's secret");
226+
await credentialCache.InsertObject(key, credential);
227+
}
228+
finally
229+
{
230+
await credentialCache.InvalidateObject<Tuple<string, string>>(key);
231+
232+
await Assert.ThrowsAsync<KeyNotFoundException>(async () => await credentialCache.Get("unknownkey"));
233+
}
234+
}
235+
}
236+
237+
[Fact]
238+
public async Task ThrowsObjectDisposedExceptionWhenDisposed()
239+
{
240+
using (var credentialCache = new CredentialCache())
241+
{
242+
credentialCache.Dispose();
243+
await Assert.ThrowsAsync<ObjectDisposedException>(
244+
async () => await credentialCache.InvalidateObject<Tuple<string, string>>("_"));
245+
}
246+
}
247+
248+
[Fact]
249+
public async Task ThrowsKeyNotFoundExceptionWhenKeyNotFound()
250+
{
251+
using (var credentialCache = new CredentialCache())
252+
{
253+
await Assert.ThrowsAsync<KeyNotFoundException>(
254+
async () => await credentialCache.InvalidateObject<Tuple<string, string>>("git:_"));
255+
await Assert.ThrowsAsync<KeyNotFoundException>(
256+
async () => await credentialCache.InvalidateObject<Tuple<string, string>>("_"));
257+
}
258+
}
259+
}
260+
261+
public class TheFlushMethod
262+
{
263+
[Fact]
264+
public async Task ThrowsObjectDisposedExceptionWhenDisposed()
265+
{
266+
using (var credentialCache = new CredentialCache())
267+
{
268+
await credentialCache.Flush();
269+
270+
credentialCache.Dispose();
271+
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await credentialCache.Flush());
272+
}
273+
}
274+
}
275+
276+
public class TheDisposeMethod
277+
{
278+
[Fact]
279+
public void SignalsShutdown()
280+
{
281+
bool shutdown = false;
282+
using (var credentialCache = new CredentialCache())
283+
{
284+
credentialCache.Shutdown.Subscribe(_ => shutdown = true);
285+
}
286+
Assert.True(shutdown);
287+
}
288+
}
289+
290+
public class MethodsNotImplementedOnPurpose
291+
{
292+
[Fact]
293+
public void ThrowNotImplementedException()
294+
{
295+
using (var credentialCache = new CredentialCache())
296+
{
297+
Assert.Throws<NotImplementedException>(() => credentialCache.GetAllKeys());
298+
Assert.Throws<NotImplementedException>(() => credentialCache.GetCreatedAt(""));
299+
Assert.Throws<NotImplementedException>(() => credentialCache.InvalidateAll());
300+
Assert.Throws<NotImplementedException>(() => credentialCache.InvalidateAllObjects<object>());
301+
Assert.Throws<NotImplementedException>(() => credentialCache.Vacuum());
302+
Assert.Throws<NotImplementedException>(() => credentialCache.GetAllObjects<object>());
303+
Assert.Throws<NotImplementedException>(() => credentialCache.GetObjectCreatedAt<object>(""));
304+
}
305+
}
306+
}
307+
}

src/UnitTests/UnitTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@
138138
</ItemGroup>
139139
<ItemGroup>
140140
<Compile Include="Args.cs" />
141+
<Compile Include="GitHub.App\Caches\CredentialCacheTests.cs" />
141142
<Compile Include="GitHub.App\Caches\ImageCacheTests.cs" />
142143
<Compile Include="GitHub.App\Models\ModelServiceTests.cs" />
143144
<Compile Include="GitHub.App\Controllers\UIControllerTests.cs" />

0 commit comments

Comments
 (0)