Skip to content
This repository has been archived by the owner on Oct 6, 2022. It is now read-only.

Supports multi feature toggles. Removed etcetera dependency. #4

Merged
merged 3 commits into from
Nov 26, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,5 @@ FakesAssemblies/

!Build/nunit/bin/
!Build/nunit/bin/*

*.userprefs
84 changes: 84 additions & 0 deletions HobknobClientNet.Tests/EtcdClientForTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System;
using System.Net;
using System.Text;

namespace HobknobClientNet.Tests
{
internal class EtcdClientForTests : EtcdClient
{
public EtcdClientForTests(Uri keysUri) : base(keysUri)
{
}

public void Set(Uri relativeKeyUri, string value)
{
byte[] bytes = Encoding.UTF8.GetBytes("value=" + value);

var webRequest = (HttpWebRequest)WebRequest.Create(GetFullUri(relativeKeyUri));
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "PUT";
webRequest.ContentLength = bytes.Length;

using (var dataStream = webRequest.GetRequestStream())
{
dataStream.Write(bytes, 0, bytes.Length);
dataStream.Flush();
using (webRequest.GetResponse())
{
}
}
}

public void DeleteDir(Uri relativeKeyUri)
{
if (!relativeKeyUri.OriginalString.EndsWith("/"))
{
throw new ArgumentException("Use Delete to delete a key, or end the key with a forward slash.to delete a directory.");
}
var fullKeyUriWithQuery = new UriBuilder(GetFullUri(relativeKeyUri)) { Query = "recursive=true" };

var webRequest = (HttpWebRequest)WebRequest.Create(fullKeyUriWithQuery.Uri);
webRequest.Method = "DELETE";

try
{
using (webRequest.GetResponse())
{
}
}
catch (WebException ex)
{
if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.NotFound)
{
return;
}
throw;
}
}

public void Delete(Uri relativeKeyUri)
{
if (relativeKeyUri.OriginalString.EndsWith("/"))
{
throw new ArgumentException("Use DeleteDir to delete a directory, or don't end the key with a forward slash.");
}

var webRequest = (HttpWebRequest)WebRequest.Create(GetFullUri(relativeKeyUri));
webRequest.Method = "DELETE";
try
{
using (webRequest.GetResponse())
{
}
}
catch (WebException ex)
{
if (((HttpWebResponse) ex.Response).StatusCode == HttpStatusCode.NotFound)
{
return;
}
throw;
}
}
}
}
9 changes: 3 additions & 6 deletions HobknobClientNet.Tests/HobknobClientNet.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,14 @@
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="EtcdClientForTests.cs" />
<Compile Include="Scenarios\CacheUpdates.cs" />
<Compile Include="Scenarios\GetOrDefault.cs" />
<Compile Include="Scenarios\Get.cs" />
<Compile Include="Scenarios\GetOrDefault_MultiFeatureToggle.cs" />
<Compile Include="Scenarios\GetOrDefault_SimpleFeature.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Scenarios\TestBase.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\HobknobClientNet.etcetera\HobknobClientNet.etcetera.csproj">
<Project>{fdd68d70-0708-427f-a3f3-7296cdb8cb52}</Project>
<Name>HobknobClientNet.etcetera</Name>
</ProjectReference>
<ProjectReference Include="..\HobknobClientNet\HobknobClientNet.csproj">
<Project>{0aba6365-c6bb-4596-9782-281994eb3256}</Project>
<Name>HobknobClientNet</Name>
Expand Down
37 changes: 19 additions & 18 deletions HobknobClientNet.Tests/Scenarios/CacheUpdates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,64 +7,65 @@
namespace HobknobClientNet.Tests.Scenarios
{
[TestFixture]
public class CacheUpdates : TestBase
internal class CacheUpdates : TestBase
{
private const string ApplicationName = "cacheUpdateTest";
bool? _toggleValue;

[SetUp]
public void SetUp()
{
TearDown();
Set_cache_update_interval(TimeSpan.FromSeconds(1));
Set_application_name("cacheUpdateTest");
Set_application_name(ApplicationName);
_toggleValue = null;
}

[TearDown]
public void TearDown()
{
EtcdClient.DeleteDir("v1/toggles/cacheUpdateTest", true);
EtcdClient.DeleteDir(new Uri("v1/toggles/cacheUpdateTest/", UriKind.Relative));
}

[Test]
public void Cache_is_not_updated_when_update_interval_is_not_passed()
{
Given_a_toggle("cacheUpdateTest", "toggle1", "true");
When_I_get("toggle1", out _toggleValue);
Given_a_toggle(ApplicationName, "feature1", "true");
When_I_get_with_default("feature1", false, out _toggleValue);
Assert.That(_toggleValue, Is.True);

Given_a_toggle("cacheUpdateTest", "toggle1", "false");
Given_a_toggle(ApplicationName, "feature1", "false");

When_I_get_without_initialising_a_new_hobknob_instance("toggle1", out _toggleValue);
When_I_get_with_default_without_initialising_a_new_hobknob_instance("feature1", out _toggleValue);
Assert.That(_toggleValue, Is.True);
}

[Test]
public void Cache_is_updated_when_update_interval_is_passed()
{
Given_a_toggle("cacheUpdateTest", "toggle1", "true");
When_I_get("toggle1", out _toggleValue);
Given_a_toggle(ApplicationName, "feature1", "true");
When_I_get_with_default("feature1", false, out _toggleValue);
Assert.That(_toggleValue, Is.True);

Given_a_toggle("cacheUpdateTest", "toggle1", "false");
Given_a_toggle(ApplicationName, "feature1", "false");
Thread.Sleep(TimeSpan.FromSeconds(1.2));

When_I_get_without_initialising_a_new_hobknob_instance("toggle1", out _toggleValue);
When_I_get_with_default_without_initialising_a_new_hobknob_instance("feature1", out _toggleValue);
Assert.That(_toggleValue, Is.False);
}

[Test]
public void Cache_updated_information_is_correct()
{
Given_a_toggle("cacheUpdateTest", "existingNoChange", "true");
Given_a_toggle("cacheUpdateTest", "existingChange", "true");
Given_a_toggle("cacheUpdateTest", "existingRemoved", "true");
Given_a_toggle(ApplicationName, "existingNoChange", "true");
Given_a_toggle(ApplicationName, "existingChange", "true");
Given_a_toggle(ApplicationName, "existingRemoved", "true");

var hobknobClient = Create_hobknob_client();

Given_a_toggle("cacheUpdateTest", "newToggle", "true");
Given_a_toggle("cacheUpdateTest", "existingChange", "false");
Given_a_toggle_is_removed("cacheUpdateTest", "existingRemoved");
Given_a_toggle(ApplicationName, "newToggle", "true");
Given_a_toggle(ApplicationName, "existingChange", "false");
Given_a_toggle_is_removed(ApplicationName, "existingRemoved");

CacheUpdatedArgs cacheUpdatedArgs = null;
hobknobClient.CacheUpdated += (sender, args) =>
Expand All @@ -88,7 +89,7 @@ public void Cache_updated_information_is_correct()

private void AssertToggleUpdate(Dictionary<string, CacheUpdate> updates, string key, bool? oldValue, bool? newValue)
{
var cacheUpdate = updates[key];
var cacheUpdate = updates["/v1/toggles/" + ApplicationName + "/" + key];
Assert.That(cacheUpdate.OldValue, Is.EqualTo(oldValue));
Assert.That(cacheUpdate.NewValue, Is.EqualTo(newValue));
}
Expand Down
55 changes: 0 additions & 55 deletions HobknobClientNet.Tests/Scenarios/Get.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using NUnit.Framework;

namespace HobknobClientNet.Tests.Scenarios
{
[TestFixture]
internal class GetOrDefault_MultiFeatureToggle : TestBase
{
bool? _toggleValue;

[SetUp]
public void SetUp()
{
Set_application_name("app1");
_toggleValue = null;
}

[Test]
public void Default_not_used_when_fature_and_toggle_exists()
{
Given_a_toggle("app1", "feature1", "toggle1", "true");
When_I_get_with_default("feature1", "toggle1", false, out _toggleValue);
Assert.That(_toggleValue, Is.True);
}

[Test]
public void Default_is_used_when_feature_does_not_exist()
{
Given_a_toggle("app1", "feature1", "toggle1", "true");
When_I_get_with_default("feature3", "toggle1", true, out _toggleValue);
Assert.That(_toggleValue, Is.True);
}

[Test]
public void Default_is_used_when_toggle_does_not_exist()
{
Given_a_toggle("app1", "feature1", "toggle1", "true");
When_I_get_with_default("feature1", "toggle3", true, out _toggleValue);
Assert.That(_toggleValue, Is.True);
}

[Test]
public void Applications_do_not_clash()
{
Given_a_toggle("app1", "feature1", "toggle1", "true");
Given_a_toggle("app2", "feature1", "toggle1", "false");
When_I_get_with_default("feature1", "toggle1", false, out _toggleValue);
Assert.That(_toggleValue, Is.True);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace HobknobClientNet.Tests.Scenarios
{
[TestFixture]
public class GetOrDefault : TestBase
internal class GetOrDefault_SimpleFeature : TestBase
{
bool? _toggleValue;

Expand All @@ -17,24 +17,24 @@ public void SetUp()
[Test]
public void Default_not_used_when_key_exists()
{
Given_a_toggle("app1", "toggle1", "true");
When_I_get_with_default("toggle1", false, out _toggleValue);
Given_a_toggle("app1", "feature1", "true");
When_I_get_with_default("feature1", false, out _toggleValue);
Assert.That(_toggleValue, Is.True);
}

[Test]
public void Default_is_used_when_key_does_not_exist()
{
When_I_get_with_default("toggle3", true, out _toggleValue);
When_I_get_with_default("feature3", true, out _toggleValue);
Assert.That(_toggleValue, Is.True);
}

[Test]
public void Applications_do_not_clash()
{
Given_a_toggle("app1", "toggle1", "true");
Given_a_toggle("app2", "toggle1", "false");
When_I_get_with_default("toggle1", false, out _toggleValue);
Given_a_toggle("app1", "feature1", "true");
Given_a_toggle("app2", "feature1", "false");
When_I_get_with_default("feature1", false, out _toggleValue);
Assert.That(_toggleValue, Is.True);
}
}
Expand Down
Loading