Skip to content

feat: Added ODPManager implementation #322

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
WIP Unit tests + changes to CUD
  • Loading branch information
mikechu-optimizely committed Nov 28, 2022
commit 443164c0d60e6e46dd921ee75dc84eb6c5079a08
121 changes: 102 additions & 19 deletions OptimizelySDK.Tests/OdpTests/OdpManagerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,70 +14,153 @@
* limitations under the License.
*/

using Castle.Core.Logging;
using Moq;
using NUnit.Framework;
using OptimizelySDK.Logger;
using OptimizelySDK.Odp;
using System.Collections.Generic;
using System.Linq;

namespace OptimizelySDK.Tests.OdpTests
{
[TestFixture]
public class OdpManagerTest
{
private const string API_KEY = "JUs7AFak3aP1K3y";
private const string API_HOST = "https://odp-api.example.com";
private const string UPDATED_API_KEY = "D1fF3rEn7kEy";
private const string UPDATED_ODP_ENDPOINT = "https://an-updated-odp-endpoint.example.com";

private readonly List<string> _updatedSegmentsToCheck = new List<string>
{
"updated-segment-1",
"updated-segment-2",
};

private readonly List<string> _emptySegmentsToCheck = new List<string>(0);

private OdpConfig _odpConfig;
private Mock<ILogger> _mockLogger;
private Mock<IOdpEventManager> _mockOdpEventManager;
private Mock<IOdpSegmentApiManager> _mockSegmentApiManager;
private Mock<IOdpSegmentManager> _mockSegmentManager;

[SetUp]
public void Setup() { }
public void Setup()
{
_odpConfig = new OdpConfig(API_KEY, API_HOST, _emptySegmentsToCheck);
_mockLogger = new Mock<ILogger>();
_mockOdpEventManager = new Mock<IOdpEventManager>();
_mockSegmentManager = new Mock<IOdpSegmentManager>();
}

[Test]
public void ShouldStartEventManagerWhenOdpManagerIsInitialized() { }
public void ShouldStartEventManagerWhenOdpManagerIsInitialized()
{
_mockOdpEventManager.Setup(e => e.Start());

[Test]
public void ShouldStopEventManagerWhenCloseIsCalled() { }
_ = new OdpManager(_odpConfig, _mockSegmentManager.Object,
_mockOdpEventManager.Object, _mockLogger.Object);

_mockOdpEventManager.Verify(e => e.Start(), Times.Once);
}

[Test]
public void ShouldUseNewSettingsInEventManagerWhenOdpConfigIsUpdated() { }
public void ShouldStopEventManagerWhenCloseIsCalled()
{
_mockOdpEventManager.Setup(e => e.Stop());
var manager = new OdpManager(_odpConfig, _mockSegmentManager.Object,
_mockOdpEventManager.Object, _mockLogger.Object);

manager.Close();

_mockOdpEventManager.Verify(e => e.Stop(), Times.Once);
}

[Test]
public void ShouldUseNewSettingsInSegmentManagerWhenOdpConfigIsUpdated() { }
public void ShouldUseNewSettingsInEventManagerWhenOdpConfigIsUpdated()
{
var eventManagerParameterCollector = new List<OdpConfig>();
_mockOdpEventManager.Setup(e =>
e.UpdateSettings(Capture.In(eventManagerParameterCollector)));
var manager = new OdpManager(_odpConfig, _mockSegmentManager.Object,
_mockOdpEventManager.Object, _mockLogger.Object);

var wasUpdated = manager.UpdateSettings(UPDATED_API_KEY, UPDATED_ODP_ENDPOINT,
_updatedSegmentsToCheck);

Assert.IsTrue(wasUpdated);
var configPassedToOdpEventManager = eventManagerParameterCollector.FirstOrDefault();
Assert.AreEqual(UPDATED_API_KEY, configPassedToOdpEventManager?.ApiKey);
Assert.AreEqual(UPDATED_ODP_ENDPOINT, configPassedToOdpEventManager.ApiHost);
Assert.AreEqual(_updatedSegmentsToCheck, configPassedToOdpEventManager.SegmentsToCheck);
}

[Test]
public void ShouldHandleSettingsNoChange() { }
public void ShouldUseNewSettingsInSegmentManagerWhenOdpConfigIsUpdated()
{
var segmentManagerParameterCollector = new List<OdpConfig>();
_mockSegmentManager.Setup(s =>
s.UpdateSettings(Capture.In(segmentManagerParameterCollector)));
var manager = new OdpManager(_odpConfig, _mockSegmentManager.Object,
_mockOdpEventManager.Object, _mockLogger.Object);

var wasUpdated = manager.UpdateSettings(UPDATED_API_KEY, UPDATED_ODP_ENDPOINT,
_updatedSegmentsToCheck);

Assert.IsTrue(wasUpdated);
var configPassedToSegmentManager = segmentManagerParameterCollector.FirstOrDefault();
Assert.AreEqual(UPDATED_API_KEY, configPassedToSegmentManager?.ApiKey);
Assert.AreEqual(UPDATED_ODP_ENDPOINT, configPassedToSegmentManager?.ApiHost);
Assert.AreEqual(_updatedSegmentsToCheck, configPassedToSegmentManager.SegmentsToCheck);
}

[Test]
public void ShouldHandleOdpConfigSettingsNoChange()
{
_mockSegmentManager.Setup(s => s.UpdateSettings(It.IsAny<OdpConfig>()));
_mockOdpEventManager.Setup(e => e.UpdateSettings(It.IsAny<OdpConfig>()));
var manager = new OdpManager(_odpConfig, _mockSegmentManager.Object,
_mockOdpEventManager.Object, _mockLogger.Object);

var wasUpdated = manager.UpdateSettings(_odpConfig.ApiKey, _odpConfig.ApiHost,
_odpConfig.SegmentsToCheck);

Assert.IsFalse(wasUpdated);
_mockSegmentManager.Verify(s => s.UpdateSettings(It.IsAny<OdpConfig>()), Times.Never);
_mockOdpEventManager.Verify(e => e.UpdateSettings(It.IsAny<OdpConfig>()), Times.Never);
}

[Ignore, Test]
public void ShouldUpdateSettingsWithReset() { }

[Test]
[Ignore, Test]
public void ShouldGetEventManager() { }

[Test]
[Ignore, Test]
public void ShouldGetSegmentManager() { }

[Test]
[Ignore, Test]
public void ShouldFetchQualifiedSegments() { }

[Test]
[Ignore, Test]
public void ShouldDisableOdpThroughConfiguration() { }

[Test]
[Ignore, Test]
public void ShouldIdentifyUserWhenDatafileNotReady() { }

[Test]
[Ignore, Test]
public void ShouldIdentifyUserWhenOdpIsIntegrated() { }

[Test]
[Ignore, Test]
public void ShouldNotIdentifyUserWhenOdpNotIntegrated() { }

[Test]
[Ignore, Test]
public void ShouldNotIdentifyUserWhenOdpDisabled() { }

[Test]
[Ignore, Test]
public void ShouldSendEventWhenOdpIsIntegrated() { }

[Test]
[Ignore, Test]
public void ShouldNotSendEventOdpNotIntegrated() { }
}
}
10 changes: 10 additions & 0 deletions OptimizelySDK/Odp/IOdpEventManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,15 @@ public interface IOdpEventManager
/// </summary>
/// <param name="odpConfig">Configuration object containing new values</param>
void UpdateSettings(OdpConfig odpConfig);

/// <summary>
/// Indicates the ODP Event Manager has been stopped and disposed
/// </summary>
bool Disposed { get; }

/// <summary>
/// Indicates the ODP Event Manager instance is in a running state
/// </summary>
bool IsStarted { get; }
}
}
4 changes: 4 additions & 0 deletions OptimizelySDK/Odp/IOdpSegmentManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,9 @@ public interface IOdpSegmentManager
/// <param name="options">An array of OptimizelySegmentOption used to ignore and/or reset the cache.</param>
/// <returns>Qualified segments for the user from the cache or the ODP server if the cache is empty.</returns>
List<string> FetchQualifiedSegments(string fsUserId, List<OdpSegmentOption> options = null);

void UpdateSettings(OdpConfig odpConfig);

void ResetCache();
}
}
9 changes: 9 additions & 0 deletions OptimizelySDK/Odp/OdpConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

using System;
using System.Collections.Generic;

namespace OptimizelySDK.Odp
Expand Down Expand Up @@ -117,5 +118,13 @@ public bool HasSegments()
{
return SegmentsToCheck?.Count > 0;
}

public bool Equals(OdpConfig toCompare)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the reason to add this method. This will raise exception if ApiKey is null. Secondly use equals method where needed in this class and implement IEqu... interface as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The goal of this is to control the equality determination of two ODP Configs.

Thanks for the callout on null exception. I'll change to use IEqualityComparer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh maybe IEquatable<T> might work instead of having a comparer. 🤔

{
return ApiKey.Equals(toCompare.ApiKey, StringComparison.OrdinalIgnoreCase) &&
ApiHost.Equals(toCompare.ApiHost, StringComparison.OrdinalIgnoreCase) &&
SegmentsToCheck.TrueForAll(
segment => toCompare.SegmentsToCheck.Contains(segment));
}
}
}
12 changes: 6 additions & 6 deletions OptimizelySDK/Odp/OdpManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,25 @@ public class OdpManager
{
private volatile OdpConfig _odpConfig;

public OdpSegmentManager SegmentManager { get; }
public IOdpSegmentManager SegmentManager { get; }

public OdpEventManager EventManager { get; }
public IOdpEventManager EventManager { get; }

private ILogger _logger;

public OdpManager(OdpConfig odpConfig, OdpSegmentManager segmentManager,
OdpEventManager eventManager, ILogger logger = null
public OdpManager(OdpConfig odpConfig, IOdpSegmentManager segmentManager,
IOdpEventManager eventManager, ILogger logger = null
)
{
_odpConfig = odpConfig;
SegmentManager = segmentManager;
EventManager = eventManager;
_logger = logger;
_logger = logger ?? new NoOpLogger();

EventManager.Start();
}

public bool UpdateSettings(string apiHost, string apiKey, List<string> segmentsToCheck)
public bool UpdateSettings(string apiKey, string apiHost, List<string> segmentsToCheck)
{
var newConfig = new OdpConfig(apiKey, apiHost, segmentsToCheck);
if (_odpConfig.Equals(newConfig))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't we use ==

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes Sir. I'll update once using the IEqualityComparer from OdpConfig

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried overriding the implicit operator, but it gets messy and unclear. I'd like to stay with the use of .Equals()

Expand Down