Skip to content

Commit

Permalink
added xmldoc comments
Browse files Browse the repository at this point in the history
Signed-off-by: Florian Bacher <florian.bacher@dynatrace.com>
  • Loading branch information
bacherfl committed Jan 2, 2024
1 parent 5e9eb59 commit 0f5a4a8
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 44 deletions.
23 changes: 19 additions & 4 deletions src/OpenFeature/Constant/EventType.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
namespace OpenFeature.Constant
{
/// <summary>
/// The ProviderEventTypes enum represents the available event types of a provider.
/// </summary>
public enum ProviderEventTypes
{
PROVIDER_READY,
PROVIDER_ERROR,
PROVIDER_CONFIGURATION_CHANGED,
PROVIDER_STALE
/// <summary>
/// ProviderReady should be emitted by a provider upon completing its initialisation.
/// </summary>
ProviderReady,
/// <summary>
/// ProviderError should be emitted by a provider upon encountering an error.
/// </summary>
ProviderError,
/// <summary>
/// ProviderConfigurationChanged should be emitted by a provider when a flag configuration has been changed.
/// </summary>
ProviderConfigurationChanged,
/// <summary>
/// ProviderStale should be emitted by a provider when it goes into the stale state.
/// </summary>
ProviderStale
}
}
24 changes: 12 additions & 12 deletions src/OpenFeature/EventExecutor.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
Expand All @@ -9,10 +8,11 @@

namespace OpenFeature
{
public class EventExecutor
[SuppressMessage("warning", "CS4014")]
internal class EventExecutor
{
private Mutex _mutex = new Mutex();
public readonly Channel<object> eventChannel = Channel.CreateBounded<object>(1);
private readonly Mutex _mutex = new Mutex();
public readonly Channel<object> EventChannel = Channel.CreateBounded<object>(1);
private FeatureProviderReference _defaultProvider;
private readonly Dictionary<string, FeatureProviderReference> _namedProviderReferences = new Dictionary<string, FeatureProviderReference>();
private readonly List<FeatureProviderReference> _activeSubscriptions = new List<FeatureProviderReference>();
Expand Down Expand Up @@ -162,15 +162,15 @@ private void EmitOnRegistration(FeatureProviderReference provider, ProviderEvent
var status = provider.Provider.GetStatus();

var message = "";
if (status == ProviderStatus.Ready && eventType == ProviderEventTypes.PROVIDER_READY)
if (status == ProviderStatus.Ready && eventType == ProviderEventTypes.ProviderReady)
{
message = "Provider is ready";
}
else if (status == ProviderStatus.Error && eventType == ProviderEventTypes.PROVIDER_ERROR)
else if (status == ProviderStatus.Error && eventType == ProviderEventTypes.ProviderError)
{
message = "Provider is in error state";
}
else if (status == ProviderStatus.Stale && eventType == ProviderEventTypes.PROVIDER_STALE)
else if (status == ProviderStatus.Stale && eventType == ProviderEventTypes.ProviderStale)
{
message = "Provider is in stale state";
}
Expand All @@ -181,7 +181,7 @@ private void EmitOnRegistration(FeatureProviderReference provider, ProviderEvent
{
ProviderName = provider.Provider.GetMetadata().Name,
Type = eventType,
Message = message,
Message = message
});
}
}
Expand All @@ -195,7 +195,7 @@ private async Task ProcessFeatureProviderEventsAsync(FeatureProviderReference pr
switch (item)
{
case ProviderEventPayload eventPayload:
this.eventChannel.Writer.TryWrite(new Event { Provider = providerRef, EventPayload = eventPayload });
this.EventChannel.Writer.TryWrite(new Event { Provider = providerRef, EventPayload = eventPayload });
break;
case ShutdownSignal _:
providerRef.ShutdownSemaphore.Release();
Expand All @@ -209,7 +209,7 @@ private async Task ProcessEventAsync()
{
while (true)
{
var item = await this.eventChannel.Reader.ReadAsync().ConfigureAwait(false);
var item = await this.EventChannel.Reader.ReadAsync().ConfigureAwait(false);

switch (item)
{
Expand Down Expand Up @@ -254,7 +254,7 @@ private async Task ProcessEventAsync()
public async Task SignalShutdownAsync()
{
// Enqueue a shutdown signal
this.eventChannel.Writer.TryWrite(new ShutdownSignal());
this.EventChannel.Writer.TryWrite(new ShutdownSignal());

// Wait for the processing loop to acknowledge the shutdown
await this._shutdownSemaphore.WaitAsync().ConfigureAwait(false);
Expand Down
11 changes: 9 additions & 2 deletions src/OpenFeature/FeatureProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ public abstract class FeatureProvider
/// <returns>Immutable list of hooks</returns>
public virtual IImmutableList<Hook> GetProviderHooks() => ImmutableList<Hook>.Empty;

protected Channel<object> _eventChannel = Channel.CreateBounded<object>(1);
/// <summary>
/// The event channel of the provider.
/// </summary>
protected Channel<object> EventChannel = Channel.CreateBounded<object>(1);

/// <summary>
/// Metadata describing the provider.
Expand Down Expand Up @@ -132,6 +135,10 @@ public virtual Task Shutdown()
return Task.CompletedTask;
}

public virtual Channel<object> GetEventChannel() => this._eventChannel;
/// <summary>
/// Returns the event channel of the provider.
/// </summary>
/// <returns>The event channel of the provider</returns>
public virtual Channel<object> GetEventChannel() => this.EventChannel;
}
}
3 changes: 3 additions & 0 deletions src/OpenFeature/IEventBus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

namespace OpenFeature
{
/// <summary>
/// Defines the methods required for handling events.
/// </summary>
public interface IEventBus
{
/// <summary>
Expand Down
20 changes: 19 additions & 1 deletion src/OpenFeature/Model/ProviderEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,35 @@

namespace OpenFeature.Model
{
/// <summary>
/// The EventHandlerDelegate is an implementation of an Event Handler
/// </summary>
public delegate void EventHandlerDelegate(ProviderEventPayload eventDetails);

/// <summary>
/// Contains the payload of an OpenFeature Event.
/// </summary>
public class ProviderEventPayload
{
/// <summary>
/// Name of the provider
/// Name of the provider.
/// </summary>
public string ProviderName { get; set; }
/// <summary>
/// Type of the event
/// </summary>
public ProviderEventTypes Type { get; set; }
/// <summary>
/// A message providing more information about the event.
/// </summary>
public string Message { get; set; }
/// <summary>
/// A List of flags that have been changed.
/// </summary>
public List<string> FlagChanges { get; set; }
/// <summary>
/// Metadata information for the event.
/// </summary>
public Dictionary<string, object> EventMetadata { get; set; }
}
}
39 changes: 16 additions & 23 deletions test/OpenFeature.Tests/OpenFeatureEventTests.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using FluentAssertions;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using OpenFeature.Constant;
using OpenFeature.Model;
using OpenFeature.Tests.Internal;
using Xunit;

namespace OpenFeature.Tests
Expand All @@ -28,24 +21,24 @@ public async Task Event_Executor_Should_Propagate_Events_ToGlobal_Handler()

var eventExecutor = new EventExecutor();

eventExecutor.AddApiLevelHandler(ProviderEventTypes.PROVIDER_READY, eventHandler);
eventExecutor.AddApiLevelHandler(ProviderEventTypes.ProviderReady, eventHandler);

var eventPayload = new Event { EventPayload = new ProviderEventPayload { Type = ProviderEventTypes.PROVIDER_READY }};
eventExecutor.eventChannel.Writer.TryWrite(eventPayload);
var eventPayload = new Event { EventPayload = new ProviderEventPayload { Type = ProviderEventTypes.ProviderReady }};
eventExecutor.EventChannel.Writer.TryWrite(eventPayload);

eventHandler.Received().Invoke(Arg.Is<ProviderEventPayload>(payload => payload.Type == ProviderEventTypes.PROVIDER_READY));
eventHandler.Received().Invoke(Arg.Is<ProviderEventPayload>(payload => payload.Type == ProviderEventTypes.ProviderReady));

// shut down the event executor
await eventExecutor.SignalShutdownAsync();

// the next event should not be propagated to the event handler
var newEventPayload = new ProviderEventPayload { Type = ProviderEventTypes.PROVIDER_STALE };
var newEventPayload = new ProviderEventPayload { Type = ProviderEventTypes.ProviderStale };

eventExecutor.eventChannel.Writer.TryWrite(newEventPayload);
eventExecutor.EventChannel.Writer.TryWrite(newEventPayload);

eventHandler.DidNotReceive().Invoke(newEventPayload);

eventHandler.DidNotReceive().Invoke(Arg.Is<ProviderEventPayload>(payload => payload.Type == ProviderEventTypes.PROVIDER_STALE));
eventHandler.DidNotReceive().Invoke(Arg.Is<ProviderEventPayload>(payload => payload.Type == ProviderEventTypes.ProviderStale));
}

[Fact]
Expand All @@ -55,7 +48,7 @@ public async Task API_Level_Event_Handlers_Should_Be_Registered()

eventHandler.Invoke(Arg.Any<ProviderEventPayload>());

Api.Instance.AddHandler(ProviderEventTypes.PROVIDER_READY, eventHandler);
Api.Instance.AddHandler(ProviderEventTypes.ProviderReady, eventHandler);

var testProvider = new TestProvider();
await Api.Instance.SetProvider(testProvider);
Expand All @@ -71,7 +64,7 @@ public async Task API_Level_Event_Handlers_Should_Be_Informed_About_Ready_State_
var testProvider = new TestProvider();
await Api.Instance.SetProvider(testProvider);

Api.Instance.AddHandler(ProviderEventTypes.PROVIDER_READY, eventHandler);
Api.Instance.AddHandler(ProviderEventTypes.ProviderReady, eventHandler);

Thread.Sleep(1000);
eventHandler.Received().Invoke(Arg.Is<ProviderEventPayload>(payload => payload.ProviderName == testProvider.GetMetadata().Name));
Expand All @@ -82,7 +75,7 @@ public async Task API_Level_Event_Handlers_Should_Be_Exchangeable()
{
var eventHandler = Substitute.For<EventHandlerDelegate>();

Api.Instance.AddHandler(ProviderEventTypes.PROVIDER_READY, eventHandler);
Api.Instance.AddHandler(ProviderEventTypes.ProviderReady, eventHandler);

var testProvider = new TestProvider();
await Api.Instance.SetProvider(testProvider);
Expand All @@ -99,7 +92,7 @@ public async Task API_Level_Event_Handlers_Should_Be_Removable()
{
var eventHandler = Substitute.For<EventHandlerDelegate>();

Api.Instance.AddHandler(ProviderEventTypes.PROVIDER_READY, eventHandler);
Api.Instance.AddHandler(ProviderEventTypes.ProviderReady, eventHandler);

var testProvider = new TestProvider();
await Api.Instance.SetProvider(testProvider);
Expand All @@ -108,7 +101,7 @@ public async Task API_Level_Event_Handlers_Should_Be_Removable()

eventHandler.Received().Invoke(Arg.Is<ProviderEventPayload>(payload => payload.ProviderName == testProvider.GetMetadata().Name));

Api.Instance.RemoveHandler(ProviderEventTypes.PROVIDER_READY, eventHandler);
Api.Instance.RemoveHandler(ProviderEventTypes.ProviderReady, eventHandler);

var newTestProvider = new TestProvider();
await Api.Instance.SetProvider(newTestProvider);
Expand All @@ -130,7 +123,7 @@ public async Task Client_Level_Event_Handlers_Should_Be_Registered()
var testProvider = new TestProvider();
await Api.Instance.SetProvider(myClient.GetMetadata().Name, testProvider);

myClient.AddHandler(ProviderEventTypes.PROVIDER_READY, eventHandler);
myClient.AddHandler(ProviderEventTypes.ProviderReady, eventHandler);

eventHandler.Received().Invoke(Arg.Is<ProviderEventPayload>(payload => payload.ProviderName == testProvider.GetMetadata().Name));
}
Expand All @@ -149,7 +142,7 @@ public async Task Client_Level_Event_Handlers_Should_Be_Informed_About_Ready_Sta
await Api.Instance.SetProvider(myClient.GetMetadata().Name, testProvider);

// add the event handler after the provider has already transitioned into the ready state
myClient.AddHandler(ProviderEventTypes.PROVIDER_READY, eventHandler);
myClient.AddHandler(ProviderEventTypes.ProviderReady, eventHandler);

eventHandler.Received().Invoke(Arg.Is<ProviderEventPayload>(payload => payload.ProviderName == testProvider.GetMetadata().Name));
}
Expand All @@ -163,14 +156,14 @@ public async Task Client_Level_Event_Handlers_Should_Be_Removable()

var myClient = Api.Instance.GetClient(fixture.Create<string>());

myClient.AddHandler(ProviderEventTypes.PROVIDER_READY, eventHandler);
myClient.AddHandler(ProviderEventTypes.ProviderReady, eventHandler);

var testProvider = new TestProvider();
await Api.Instance.SetProvider(myClient.GetMetadata().Name, testProvider);

// wait for the first event to be received
Thread.Sleep(1000);
myClient.RemoveHandler(ProviderEventTypes.PROVIDER_READY, eventHandler);
myClient.RemoveHandler(ProviderEventTypes.ProviderReady, eventHandler);

var newTestProvider = new TestProvider();
await Api.Instance.SetProvider(myClient.GetMetadata().Name, newTestProvider);
Expand Down
4 changes: 2 additions & 2 deletions test/OpenFeature.Tests/TestImplementations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,13 @@ public override ProviderStatus GetStatus()
public override Task Initialize(EvaluationContext context)
{
this._status = ProviderStatus.Ready;
this._eventChannel.Writer.TryWrite(new ProviderEventPayload { Type = ProviderEventTypes.PROVIDER_READY, ProviderName = this.GetMetadata().Name});
this.EventChannel.Writer.TryWrite(new ProviderEventPayload { Type = ProviderEventTypes.ProviderReady, ProviderName = this.GetMetadata().Name});
return base.Initialize(context);
}

internal void SendEvent(ProviderEventTypes eventType)
{
this._eventChannel.Writer.TryWrite(new ProviderEventPayload { Type = eventType, ProviderName = this.GetMetadata().Name });
this.EventChannel.Writer.TryWrite(new ProviderEventPayload { Type = eventType, ProviderName = this.GetMetadata().Name });
}
}
}

0 comments on commit 0f5a4a8

Please sign in to comment.