Skip to content

Commit

Permalink
Merge pull request #16 from open-feature/feat/add-spec-complaint-tests
Browse files Browse the repository at this point in the history
Add spec compliant test suite
  • Loading branch information
benjiro authored Jul 13, 2022
2 parents 1e48ab7 + 9274056 commit 05de4b5
Show file tree
Hide file tree
Showing 27 changed files with 905 additions and 333 deletions.
1 change: 1 addition & 0 deletions build/Common.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<Project>
<PropertyGroup>
<LangVersion>7.3</LangVersion>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup>

Expand Down
12 changes: 0 additions & 12 deletions src/OpenFeature/Constant/Error.cs

This file was deleted.

19 changes: 19 additions & 0 deletions src/OpenFeature/Constant/ErrorType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.ComponentModel;

namespace OpenFeature.Constant
{
public enum ErrorType
{
None,
[Description("PROVIDER_NOT_READY")]
ProviderNotReady,
[Description("FLAG_NOT_FOUND")]
FlagNotFound,
[Description("PARSE_ERROR")]
ParseError,
[Description("TYPE_MISMATCH")]
TypeMismatch,
[Description("GENERAL")]
General
}
}
1 change: 1 addition & 0 deletions src/OpenFeature/Constant/NoOpProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ public static class NoOpProvider
{
public const string NoOpProviderName = "No-op Provider";
public const string ReasonNoOp = "No-op";
public const string Variant = "No-op";
}
}
19 changes: 19 additions & 0 deletions src/OpenFeature/Error/FeatureProviderException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using OpenFeature.Constant;
using OpenFeature.Extention;

namespace OpenFeature.Error
{
public class FeatureProviderException : Exception
{
public ErrorType ErrorType { get; }
public string ErrorTypeDescription { get; }

public FeatureProviderException(ErrorType errorType, Exception innerException)
: base(null, innerException)
{
this.ErrorType = errorType;
this.ErrorTypeDescription = errorType.GetDescription();
}
}
}
16 changes: 16 additions & 0 deletions src/OpenFeature/Extension/EnumExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.ComponentModel;
using System.Linq;

namespace OpenFeature.Extention
{
public static class EnumExtensions
{
public static string GetDescription(this Enum value)
{
var field = value.GetType().GetField(value.ToString());
var attribute = field.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault() as DescriptionAttribute;
return attribute?.Description ?? value.ToString();
}
}
}
2 changes: 1 addition & 1 deletion src/OpenFeature/Extension/ResolutionDetailsExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public static class ResolutionDetailsExtensions
{
public static FlagEvaluationDetails<T> ToFlagEvaluationDetails<T>(this ResolutionDetails<T> details)
{
return new FlagEvaluationDetails<T>(details.FlagKey, details.Value, details.ErrorCode, details.Reason, details.Variant);
return new FlagEvaluationDetails<T>(details.FlagKey, details.Value, details.ErrorType, details.Reason, details.Variant);
}
}
}
2 changes: 2 additions & 0 deletions src/OpenFeature/Hook.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;

namespace OpenFeature.Model
{

internal interface IHook
{
Task<EvaluationContext> Before<T>(HookContext<T> context, IReadOnlyDictionary<string, object> hints = null);
Expand Down
2 changes: 1 addition & 1 deletion src/OpenFeature/Model/ClientMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public class ClientMetadata : Metadata

public ClientMetadata(string name, string version) : base(name)
{
Version = version;
this.Version = version;
}
}
}
27 changes: 13 additions & 14 deletions src/OpenFeature/Model/EvaluationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,55 @@

namespace OpenFeature.Model
{
public class EvaluationContext : IEnumerable<object>
public class EvaluationContext : IEnumerable<KeyValuePair<string, object>>
{
private readonly Dictionary<string, object> _internalContext = new Dictionary<string, object>();

public void Add<T>(string key, T value)
{
_internalContext.Add(key, value);
this._internalContext.Add(key, value);
}

public void Remove(string key)
{
_internalContext.Remove(key);
this._internalContext.Remove(key);
}

public T Get<T>(string key)
{
return (T)_internalContext[key];
return (T)this._internalContext[key];
}

public object this[string key]
{
get => _internalContext[key];
set => _internalContext[key] = value;
get => this._internalContext[key];
set => this._internalContext[key] = value;
}

public void Merge(EvaluationContext other)
{
foreach (var key in other._internalContext.Keys)
{
if (_internalContext.ContainsKey(key))
if (this._internalContext.ContainsKey(key))
{
_internalContext[key] = other._internalContext[key];
this._internalContext[key] = other._internalContext[key];
}
else
{
_internalContext.Add(key, other._internalContext[key]);
this._internalContext.Add(key, other._internalContext[key]);
}
}
}

public int Count => _internalContext.Count;

public IEnumerator<object> GetEnumerator()
public int Count => this._internalContext.Count;
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
return _internalContext.Values.GetEnumerator();
return this._internalContext.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
return this.GetEnumerator();
}
}
}
10 changes: 8 additions & 2 deletions src/OpenFeature/Model/FlagEvaluationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@ public class FlagEvaluationOptions

public FlagEvaluationOptions(IReadOnlyList<Hook> hooks, IReadOnlyDictionary<string, object> hookHints)
{
Hooks = hooks;
HookHints = hookHints;
this.Hooks = hooks;
this.HookHints = hookHints;
}

public FlagEvaluationOptions(Hook hook, IReadOnlyDictionary<string, object> hookHints)
{
this.Hooks = new[] { hook };
this.HookHints = hookHints;
}
}
}
16 changes: 9 additions & 7 deletions src/OpenFeature/Model/FlagEvalusationDetails.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
using OpenFeature.Constant;

namespace OpenFeature.Model
{
public class FlagEvaluationDetails<T>
{
public T Value { get; }
public string FlagKey { get; }
public string ErrorCode { get; }
public ErrorType ErrorType { get; }
public string Reason { get; }
public string Variant { get; }

public FlagEvaluationDetails(string flagKey, T value, string errorCode, string reason, string variant)
public FlagEvaluationDetails(string flagKey, T value, ErrorType errorType, string reason, string variant)
{
Value = value;
FlagKey = flagKey;
ErrorCode = errorCode;
Reason = reason;
Variant = variant;
this.Value = value;
this.FlagKey = flagKey;
this.ErrorType = errorType;
this.Reason = reason;
this.Variant = variant;
}
}
}
13 changes: 7 additions & 6 deletions src/OpenFeature/Model/HookContext.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using OpenFeature.Constant;

namespace OpenFeature.Model
Expand All @@ -18,12 +19,12 @@ public HookContext(string flagKey,
Metadata providerMetadata,
EvaluationContext evaluationContext)
{
FlagKey = flagKey;
DefaultValue = defaultValue;
FlagValueType = flagValueType;
ClientMetadata = clientMetadata;
ProviderMetadata = providerMetadata;
EvaluationContext = evaluationContext;
this.FlagKey = flagKey ?? throw new ArgumentNullException(nameof(flagKey));
this.DefaultValue = defaultValue;
this.FlagValueType = flagValueType;
this.ClientMetadata = clientMetadata ?? throw new ArgumentNullException(nameof(clientMetadata));
this.ProviderMetadata = providerMetadata ?? throw new ArgumentNullException(nameof(providerMetadata));
this.EvaluationContext = evaluationContext ?? throw new ArgumentNullException(nameof(evaluationContext));
}
}
}
2 changes: 1 addition & 1 deletion src/OpenFeature/Model/Metadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public class Metadata

public Metadata(string name)
{
Name = name;
this.Name = name;
}
}
}
16 changes: 9 additions & 7 deletions src/OpenFeature/Model/ResolutionDetails.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
using OpenFeature.Constant;

namespace OpenFeature.Model
{
public class ResolutionDetails<T>
{
public T Value { get; }
public string FlagKey { get; }
public string ErrorCode { get; }
public ErrorType ErrorType { get; }
public string Reason { get; }
public string Variant { get; }

public ResolutionDetails(string flagKey, T value, string errorCode = null, string reason = null, string variant = null)
public ResolutionDetails(string flagKey, T value, ErrorType errorType = ErrorType.None, string reason = null, string variant = null)
{
Value = value;
FlagKey = flagKey;
ErrorCode = errorCode;
Reason = reason;
Variant = variant;
this.Value = value;
this.FlagKey = flagKey;
this.ErrorType = errorType;
this.Reason = reason;
this.Variant = variant;
}
}
}
5 changes: 3 additions & 2 deletions src/OpenFeature/NoOpProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class NoOpFeatureProvider : IFeatureProvider

public Metadata GetMetadata()
{
return _metadata;
return this._metadata;
}

public Task<ResolutionDetails<bool>> ResolveBooleanValue(string flagKey, bool defaultValue, EvaluationContext context = null, FlagEvaluationOptions config = null)
Expand Down Expand Up @@ -42,7 +42,8 @@ private static ResolutionDetails<T> NoOpResponse<T>(string flagKey, T defaultVal
return new ResolutionDetails<T>(
flagKey,
defaultValue,
reason: NoOpProvider.ReasonNoOp
reason: NoOpProvider.ReasonNoOp,
variant: NoOpProvider.Variant
);
}
}
Expand Down
30 changes: 13 additions & 17 deletions src/OpenFeature/OpenFeature.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using OpenFeature.Model;

namespace OpenFeature
Expand All @@ -11,24 +9,22 @@ public sealed class OpenFeature
private EvaluationContext _evaluationContext = new EvaluationContext();
private IFeatureProvider _featureProvider = new NoOpFeatureProvider();
private readonly List<Hook> _hooks = new List<Hook>();
public static ILogger Logger { get; private set; } = new Logger<OpenFeature>(new NullLoggerFactory());

// Thread-safe singleton instance
private static readonly Lazy<OpenFeature> lazy = new Lazy<OpenFeature>();
private static OpenFeature Instance => lazy.Value;
public static OpenFeature Instance { get; } = new OpenFeature();
static OpenFeature() { }
private OpenFeature() { }

public static void SetProvider(IFeatureProvider featureProvider) => Instance._featureProvider = featureProvider;
public static IFeatureProvider GetProvider() => Instance._featureProvider;
public static Metadata GetProviderMetadata() => Instance._featureProvider.GetMetadata();
public static FeatureClient GetClient(string name = null, string version = null) => new FeatureClient(Instance._featureProvider, name, version);
public void SetProvider(IFeatureProvider featureProvider) => this._featureProvider = featureProvider;
public IFeatureProvider GetProvider() => this._featureProvider;
public Metadata GetProviderMetadata() => this._featureProvider.GetMetadata();
public FeatureClient GetClient(string name = null, string version = null, ILogger logger = null) => new FeatureClient(this._featureProvider, name, version, logger);

public static void AddHooks(IEnumerable<Hook> hooks) => Instance._hooks.AddRange(hooks);
public static IEnumerable<Hook> GetHooks() => Instance._hooks.AsReadOnly();
public static void ClearHooks() => Instance._hooks.Clear();
public void AddHooks(IEnumerable<Hook> hooks) => this._hooks.AddRange(hooks);
public void AddHooks(Hook hook) => this._hooks.Add(hook);
public IReadOnlyList<Hook> GetHooks() => this._hooks.AsReadOnly();
public void ClearHooks() => this._hooks.Clear();

public static void SetContext(EvaluationContext context) => Instance._evaluationContext = context;
public static EvaluationContext GetContext() => Instance._evaluationContext;

public static void SetLogger(ILogger logger) => Logger = logger;
public void SetContext(EvaluationContext context) => this._evaluationContext = context;
public EvaluationContext GetContext() => this._evaluationContext;
}
}
Loading

0 comments on commit 05de4b5

Please sign in to comment.