Skip to content
Permalink
Browse files

added option to include errors in tweek-api values result (#1132)

* split files

* return all error from jpad calculations

* add option to propagate errors to tweek response

* add e2e-integration .dockerignore file

* add unit test

* move smoke tests to integration tests

* propagate error tests

* added EnsureSuccess method to TweekValuesResult

* rename propagateErrors -> includeErrors

* split to files
  • Loading branch information...
nataly87s committed Apr 7, 2019
1 parent 3c1952a commit 9abc93c60c5e09892c7692f50c0a55cf887eafda
Showing with 534 additions and 386 deletions.
  1. +69 −27 core/Engine/Tweek.Engine.Tests/EngineTests.cs
  2. +1 −1 core/Engine/Tweek.Engine.Tests/TestDrivers/ITestDriver.cs
  3. +1 −1 core/Engine/Tweek.Engine.Tests/TestDrivers/InMemoryTestDriver.cs
  4. +0 −25 core/Engine/Tweek.Engine/FallbackRule.cs
  5. +15 −0 core/Engine/Tweek.Engine/ITweek.cs
  6. +15 −0 core/Engine/Tweek.Engine/Tweek.cs
  7. +4 −61 core/Engine/Tweek.Engine/{Api.cs → TweekExtensions.cs}
  8. +57 −0 core/Engine/Tweek.Engine/TweekRunner.cs
  9. +12 −0 core/Engine/Tweek.Engine/TweekValuesResult.cs
  10. +15 −0 core/Engine/Tweek.Engine/TweekValuesResultExtensions.cs
  11. +1 −0 e2e/integration/.dockerignore
  12. +93 −0 e2e/integration/spec/tweek-api/context.test.js
  13. +0 −28 e2e/integration/spec/tweek-api/delete-context.test.js
  14. +32 −0 e2e/integration/spec/tweek-api/values/hidden-keys.test.js
  15. +31 −0 e2e/integration/spec/tweek-api/values/ignore-key-type.test.js
  16. +96 −0 e2e/integration/spec/tweek-api/values/include-errors.test.js
  17. +2 −2 e2e/ui/.dockerignore
  18. +0 −90 services/api/Tweek.ApiService.SmokeTests/ContextTests.cs
  19. +0 −72 services/api/Tweek.ApiService.SmokeTests/GetConfigurations/HiddenKeysTests.cs
  20. +0 −56 services/api/Tweek.ApiService.SmokeTests/GetConfigurations/IgnoreKeyTypesTests.cs
  21. +22 −8 services/api/Tweek.ApiService/Controllers/KeysController.cs
  22. +22 −9 services/api/Tweek.ApiService/Security/AuthorizationDecider.cs
  23. +12 −6 services/api/Tweek.ApiService/Startup.cs
  24. +18 −0 ...it-service/BareRepository/tests-source/implementations/jpad/integration_tests/include_errors.jpad
  25. +16 −0 services/git-service/BareRepository/tests-source/manifests/integration_tests/include_errors.json
@@ -41,7 +41,7 @@ public EngineTests(TestDriverFixture fixture)

async Task Run(Func<ITweek, IContextDriver, Task> test)
{
var scope = driver.SetTestEnviornment(contexts, paths, rules);
var scope = driver.SetTestEnvironment(contexts, paths, rules);
await scope.Run(test);
}

@@ -58,13 +58,13 @@ public async Task CalculateSingleValue()
await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate("_", NoIdentities, context);
Assert.Equal("SomeValue", val["abc/somepath"].Value.AsString());
Assert.Equal("SomeValue", val.Data["abc/somepath"].Value.AsString());

val = await tweek.GetContextAndCalculate("abc/_", NoIdentities, context);
Assert.Equal( "SomeValue", val["abc/somepath"].Value.AsString());
Assert.Equal( "SomeValue", val.Data["abc/somepath"].Value.AsString());

val = await tweek.GetContextAndCalculate("abc/somepath", NoIdentities, context);
Assert.Equal( "SomeValue", val["abc/somepath"].Value.AsString());
Assert.Equal( "SomeValue", val.Data["abc/somepath"].Value.AsString());
});
}

@@ -78,7 +78,7 @@ public async Task CalculateMultipleValues()

await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate("abc/_", NoIdentities, context);
var val = (await tweek.GetContextAndCalculate("abc/_", NoIdentities, context)).Data;
Assert.Equal(3, val.Count);
Assert.Equal("SomeValue",val["abc/somepath"].Value.AsString());
Assert.Equal("SomeValue",val["abc/otherpath"].Value.AsString());
@@ -96,7 +96,7 @@ public async Task CalculateMultiplePathQueries()

await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate(new List<ConfigurationPath>{"abc/_", "def/_"}, NoIdentities, context);
var val = (await tweek.GetContextAndCalculate(new List<ConfigurationPath>{"abc/_", "def/_"}, NoIdentities, context)).Data;
Assert.Equal(4, val.Count);
Assert.Equal("SomeValue", val["abc/somepath"].Value.AsString());
Assert.Equal("SomeValue", val["abc/otherpath"].Value.AsString());
@@ -115,7 +115,7 @@ public async Task CalculateMultiplePathQueriesWithOverlap()

await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate(new List<ConfigurationPath> { "abc/_", "abc/nested/_" }, NoIdentities, context);
var val = (await tweek.GetContextAndCalculate(new List<ConfigurationPath> { "abc/_", "abc/nested/_" }, NoIdentities, context)).Data;
Assert.Equal(3, val.Count);
Assert.Equal("SomeValue", val["abc/somepath"].Value.AsString());
Assert.Equal("SomeValue", val["abc/otherpath"].Value.AsString());
@@ -142,13 +142,13 @@ public async Task CalculateFilterByMatcher()
await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "1") }, context);
Assert.Equal(0, val.Count);
Assert.Equal(0, val.Data.Count);

val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "2") }, context);
Assert.Equal(0, val.Count);
Assert.Equal(0, val.Data.Count);

val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "3") }, context);
Assert.Equal("SomeValue", val["abc/somepath"].Value.AsString());
Assert.Equal("SomeValue", val.Data["abc/somepath"].Value.AsString());
});
}

@@ -171,13 +171,13 @@ public async Task CalculateFilterByMatcherWithMultiIdentities()
await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "1") }, context);
Assert.Equal(0, val.Count);
Assert.Equal(0, val.Data.Count);

val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("user", "1") }, context);
Assert.Equal(0, val.Count);
Assert.Equal(0, val.Data.Count);

val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "1"), new Identity("user", "1") }, context);
Assert.Equal("SomeValue", val["abc/somepath"].Value.AsString());
Assert.Equal("SomeValue", val.Data["abc/somepath"].Value.AsString());
});
}

@@ -196,7 +196,7 @@ public async Task MultipleRules()
await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "1") }, context);
Assert.Equal( "SomeValue", val["abc/somepath"].Value.AsString());
Assert.Equal( "SomeValue", val.Data["abc/somepath"].Value.AsString());
});
}

@@ -222,7 +222,7 @@ public async Task MultipleRulesWithFallback()
await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "1") }, context);
Assert.Equal("SomeValue", val["abc/somepath"].Value.AsString());
Assert.Equal("SomeValue", val.Data["abc/somepath"].Value.AsString());
});
}

@@ -248,12 +248,14 @@ public async Task CalculateWithMultiVariant()
await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { }, context);
Assert.Equal(0, val.Count);
Assert.Equal(0, val.Data.Count);
val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "1")}, context);
Assert.True(val["abc/somepath"].Value.AsString() == "true" || val["abc/somepath"].Value.AsString() == "false");
Assert.True(val.Data["abc/somepath"].Value.AsString() == "true" || val.Data["abc/somepath"].Value.AsString() == "false");
await Task.WhenAll(Enumerable.Range(0, 10).Select(async x =>
{
Assert.Equal((await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "1") }, context))["abc/somepath"].Value, val["abc/somepath"].Value);
var expected = val.Data["abc/somepath"].Value;
val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> {new Identity("device", "1")}, context);
Assert.Equal(val.Data["abc/somepath"].Value, expected);
}));
});
}
@@ -276,7 +278,7 @@ public async Task ContextKeysShouldBeCaseInsensitive()
await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "1") }, context);
Assert.Equal("true", val["abc/somepath"].Value.AsString());
Assert.Equal("true", val.Data["abc/somepath"].Value.AsString());
});
}

@@ -306,10 +308,10 @@ public async Task RuleUsingTimeBasedOperators()
await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "1") }, context);
Assert.Equal("true", val["abc/somepath"].Value.AsString());
Assert.Equal("true", val.Data["abc/somepath"].Value.AsString());

val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "2") }, context);
Assert.Equal("false", val["abc/somepath"].Value.AsString());
Assert.Equal("false", val.Data["abc/somepath"].Value.AsString());

});
}
@@ -334,13 +336,13 @@ public async Task CalculateWithFixedValue()
await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "1") }, context);
Assert.Equal("FixedValue", val["abc/somepath"].Value.AsString());
Assert.Equal("FixedValue", val.Data["abc/somepath"].Value.AsString());

val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "2") }, context);
Assert.Equal("RuleBasedValue", val["abc/somepath"].Value.AsString());
Assert.Equal("RuleBasedValue", val.Data["abc/somepath"].Value.AsString());

val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "3") }, context);
Assert.Equal("FixedValue", val["abc/somepath"].Value.AsString());
Assert.Equal("FixedValue", val.Data["abc/somepath"].Value.AsString());

});
}
@@ -371,11 +373,11 @@ public async Task CalculateWithRecursiveMatcher()

await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "1") }, context);
var val = (await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "1") }, context)).Data;
Assert.Equal(1, val.Count);
Assert.Equal("true", val["abc/dep_path1"].Value.AsString());

val = await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "2") }, context);
val = (await tweek.GetContextAndCalculate("abc/_", new HashSet<Identity> { new Identity("device", "2") }, context)).Data;
Assert.Equal(3, val.Count);
Assert.Equal("true", val["abc/dep_path1"].Value.AsString());
Assert.Equal("true", val["abc/dep_path2"].Value.AsString());
@@ -399,9 +401,49 @@ public async Task EmptyFixedKeyIsIgnoredInScan()
await Run(async (tweek, context) =>
{
var val = await tweek.GetContextAndCalculate("_", new HashSet<Identity> { new Identity("device", "1")}, context);
Assert.Equal("SomeValue", val["abc/somepath"].Value.AsString());
Assert.Equal("SomeValue", val.Data["abc/somepath"].Value.AsString());
});
}

[Fact]
public async Task BadKeyShouldReturnError()
{
contexts = ContextCreator.Create("device", "1", Tuple.Create("SomeDeviceProp", JsonValue.NewNumber(3)));

paths = new[] { "abc/bad_path", "abc/good_path" };
rules = new Dictionary<string, RuleDefinition>
{
["abc/bad_path"] = JPadGenerator.New()
.AddSingleVariantRule(JsonConvert.SerializeObject(new MatcherData {["device.SomeDeviceProp"] = new string[]{}}), "BadValue")
.Generate(),
["abc/good_path"] = JPadGenerator.New().AddSingleVariantRule("{}", "SomeValue").Generate()
};

await Run(async (tweek, context) =>
{
var identities = new HashSet<Identity> {new Identity("device", "1")};

var val = await tweek.GetContextAndCalculate("_", identities, context);
Assert.Equal(1, val.Errors.Count);
Assert.True(val.Errors.ContainsKey("abc/bad_path"));
Assert.False(val.Data.ContainsKey("abc/bad_path"));
Assert.Equal("SomeValue", val.Data["abc/good_path"].Value.AsString());

val = await tweek.GetContextAndCalculate("abc/_", identities, context);
Assert.Equal(1, val.Errors.Count);
Assert.True(val.Errors.ContainsKey("abc/bad_path"));
Assert.False(val.Data.ContainsKey("abc/bad_path"));
Assert.Equal( "SomeValue", val.Data["abc/good_path"].Value.AsString());

val = await tweek.GetContextAndCalculate("abc/good_path", identities, context);
Assert.Equal(0, val.Errors.Count);
Assert.Equal( "SomeValue", val.Data["abc/good_path"].Value.AsString());

val = await tweek.GetContextAndCalculate("abc/bad_path", identities, context);
Assert.Equal(1, val.Errors.Count);
Assert.True(val.Errors.ContainsKey("abc/bad_path"));
Assert.Equal(0, val.Data.Count);
});
}
}
}
@@ -9,6 +9,6 @@ namespace Tweek.Engine.Tests.TestDrivers
public interface ITestDriver
{
IContextDriver Context { get; }
TestScope SetTestEnviornment(Dictionary<Identity, Dictionary<string, JsonValue>> contexts, string[] keys, Dictionary<string,RuleDefinition> rules);
TestScope SetTestEnvironment(Dictionary<Identity, Dictionary<string, JsonValue>> contexts, string[] keys, Dictionary<string,RuleDefinition> rules);
}
}
@@ -81,7 +81,7 @@ private async Task InsertContextRows(Dictionary<Identity, Dictionary<string, Jso

private async Task Flush() => dictionary.Clear();

public TestScope SetTestEnviornment(Dictionary<Identity, Dictionary<string, JsonValue>> contexts, string[] keys,
public TestScope SetTestEnvironment(Dictionary<Identity, Dictionary<string, JsonValue>> contexts, string[] keys,
Dictionary<string, RuleDefinition> rules)
{
return new TestScope(rules: new InMemoryRulesRepository(rules), context: Context,

This file was deleted.

Oops, something went wrong.
@@ -0,0 +1,15 @@
using System.Collections.Generic;
using Tweek.Engine.Core.Context;
using Tweek.Engine.DataTypes;
using IdentityHashSet = System.Collections.Generic.HashSet<Tweek.Engine.DataTypes.Identity>;

namespace Tweek.Engine
{
public interface ITweek
{
TweekValuesResult Calculate(
ICollection<ConfigurationPath> pathQuery,
IdentityHashSet identities, GetLoadedContextByIdentityType context,
ConfigurationPath[] includeFixedPaths = null);
}
}
@@ -0,0 +1,15 @@
using System.Threading.Tasks;
using Tweek.Engine.Drivers.Rules;
using Tweek.Engine.Rules.Creation;

namespace Tweek.Engine
{
public static class Tweek
{
public static async Task<ITweek> Create(IRulesRepository rulesRepository, GetRuleParser parserResolver)
{
var rulesLoader = await RulesLoader.Factory(rulesRepository, parserResolver);
return new TweekRunner(rulesLoader);
}
}
}
Oops, something went wrong.

0 comments on commit 9abc93c

Please sign in to comment.
You can’t perform that action at this time.