Skip to content
Closed
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
14 changes: 12 additions & 2 deletions OptimizelySDK.Tests/OdpTests/OdpEventManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,11 @@ public void ShouldLogWhenOdpNotIntegratedAndIdentifyUserCalled()
eventManager.UpdateSettings(mockOdpConfig.
Object); // auto-start after update; Logs 1x here

eventManager.IdentifyUser(FS_USER_ID); // Logs 1x here too
eventManager.IdentifyUser(new Dictionary<string, string>
{
{ FS_USER_ID, "test-user" },
{ "email", "test@example.com" },
}); // Logs 1x here too

_mockLogger.Verify(
l => l.Log(LogLevel.WARN, Constants.ODP_NOT_INTEGRATED_MESSAGE),
Expand Down Expand Up @@ -622,7 +626,12 @@ public void ShouldPrepareCorrectPayloadForIdentifyUser()
Build();
eventManager.UpdateSettings(_odpConfig);

eventManager.IdentifyUser(USER_ID);
var identifiers = new Dictionary<string, string>
{
{ Constants.FS_USER_ID, USER_ID },
{ "email", "test@example.com" },
};
eventManager.IdentifyUser(identifiers);
cde.Wait(MAX_COUNT_DOWN_EVENT_WAIT_MS);

var eventsSentToApi = eventsCollector.FirstOrDefault();
Expand All @@ -631,6 +640,7 @@ public void ShouldPrepareCorrectPayloadForIdentifyUser()
Assert.AreEqual(Constants.ODP_EVENT_TYPE, actualEvent.Type);
Assert.AreEqual("identified", actualEvent.Action);
Assert.AreEqual(USER_ID, actualEvent.Identifiers[Constants.FS_USER_ID]);
Assert.AreEqual("test@example.com", actualEvent.Identifiers["email"]);
var eventData = actualEvent.Data;
Assert.AreEqual(Guid.NewGuid().ToString().Length,
eventData["idempotence_id"].ToString().Length);
Expand Down
72 changes: 65 additions & 7 deletions OptimizelySDK.Tests/OdpTests/OdpManagerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -283,40 +283,98 @@ public void ShouldGetSegmentManager()
}

[Test]
public void ShouldIdentifyUserWhenOdpIsIntegrated()
public void ShouldIdentifyUserWhenMultipleIdentifiersProvided()
{
_mockOdpEventManager.Setup(e => e.IdentifyUser(It.IsAny<string>()));
_mockOdpEventManager.Setup(e => e.IdentifyUser(It.IsAny<Dictionary<string, string>>()));
_mockOdpEventManager.Setup(e => e.IsStarted).Returns(true);
var manager = new OdpManager.Builder().
WithEventManager(_mockOdpEventManager.Object).
WithLogger(_mockLogger.Object).
Build();
manager.UpdateSettings(API_KEY, API_HOST, _emptySegmentsToCheck);

manager.IdentifyUser(VALID_FS_USER_ID);
var identifiers = new Dictionary<string, string>
{
{ "fs_user_id", VALID_FS_USER_ID },
{ "email", "user@example.com" },
};
manager.IdentifyUser(identifiers);
manager.Dispose();

_mockLogger.Verify(l => l.Log(It.IsAny<LogLevel>(), It.IsAny<string>()), Times.Never);
_mockOdpEventManager.Verify(e => e.IdentifyUser(It.IsAny<string>()), Times.Once);
_mockOdpEventManager.Verify(e => e.IdentifyUser(It.IsAny<Dictionary<string, string>>()), Times.Once);
}

[Test]
public void ShouldNotIdentifyUserWhenSingleIdentifierProvided()
{
_mockOdpEventManager.Setup(e => e.IdentifyUser(It.IsAny<Dictionary<string, string>>()));
_mockOdpEventManager.Setup(e => e.IsStarted).Returns(true);
var manager = new OdpManager.Builder().
WithEventManager(_mockOdpEventManager.Object).
WithLogger(_mockLogger.Object).
Build();
manager.UpdateSettings(API_KEY, API_HOST, _emptySegmentsToCheck);

var identifiers = new Dictionary<string, string>
{
{ "fs_user_id", VALID_FS_USER_ID },
};
manager.IdentifyUser(identifiers);
manager.Dispose();

_mockLogger.Verify(l =>
l.Log(LogLevel.DEBUG, "ODP identify event is not dispatched (only one identifier provided)."));
_mockOdpEventManager.Verify(e => e.IdentifyUser(It.IsAny<Dictionary<string, string>>()), Times.Never);
}

[Test]
public void ShouldNotIdentifyUserWhenEmptyValuesNotCounted()
{
_mockOdpEventManager.Setup(e => e.IdentifyUser(It.IsAny<Dictionary<string, string>>()));
_mockOdpEventManager.Setup(e => e.IsStarted).Returns(true);
var manager = new OdpManager.Builder().
WithEventManager(_mockOdpEventManager.Object).
WithLogger(_mockLogger.Object).
Build();
manager.UpdateSettings(API_KEY, API_HOST, _emptySegmentsToCheck);

var identifiers = new Dictionary<string, string>
{
{ "fs_user_id", VALID_FS_USER_ID },
{ "email", "" },
{ "vuid", null },
};
manager.IdentifyUser(identifiers);
manager.Dispose();

_mockLogger.Verify(l =>
l.Log(LogLevel.DEBUG, "ODP identify event is not dispatched (only one identifier provided)."));
_mockOdpEventManager.Verify(e => e.IdentifyUser(It.IsAny<Dictionary<string, string>>()), Times.Never);
}

[Test]
public void ShouldNotIdentifyUserWhenOdpDisabled()
{
_mockOdpEventManager.Setup(e => e.IdentifyUser(It.IsAny<string>()));
_mockOdpEventManager.Setup(e => e.IdentifyUser(It.IsAny<Dictionary<string, string>>()));
_mockOdpEventManager.Setup(e => e.IsStarted).Returns(true);
var manager = new OdpManager.Builder().
WithEventManager(_mockOdpEventManager.Object).
WithLogger(_mockLogger.Object).
Build(false);
manager.UpdateSettings(API_KEY, API_HOST, _emptySegmentsToCheck);

manager.IdentifyUser(VALID_FS_USER_ID);
var identifiers = new Dictionary<string, string>
{
{ "fs_user_id", VALID_FS_USER_ID },
{ "email", "user@example.com" },
};
manager.IdentifyUser(identifiers);
manager.Dispose();

_mockLogger.Verify(l =>
l.Log(LogLevel.DEBUG, "ODP identify event not dispatched (ODP disabled)."));
_mockOdpEventManager.Verify(e => e.IdentifyUser(It.IsAny<string>()), Times.Never);
_mockOdpEventManager.Verify(e => e.IdentifyUser(It.IsAny<Dictionary<string, string>>()), Times.Never);
}

[Test]
Expand Down
6 changes: 5 additions & 1 deletion OptimizelySDK.Tests/OptimizelyTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6232,7 +6232,11 @@ public void TestFetchQualifiedSegmentsInvalidOptimizelyObject()
public void TestIdentifyUserInvalidOptimizelyObject()
{
var optly = new Optimizely("Random datafile", null, LoggerMock.Object);
optly.IdentifyUser("some_user");
var identifiers = new Dictionary<string, string>
{
{ "fs_user_id", "some_user" },
};
optly.IdentifyUser(identifiers);
LoggerMock.Verify(
l => l.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'IdentifyUser'."),
Times.Once);
Expand Down
7 changes: 4 additions & 3 deletions OptimizelySDK/Odp/IOdpEventManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

using System;
using System.Collections.Generic;
using OptimizelySDK.Odp.Entity;

namespace OptimizelySDK.Odp
Expand Down Expand Up @@ -52,10 +53,10 @@ public interface IOdpEventManager
void Dispose();

/// <summary>
/// Associate a full-stack userid with an established VUID
/// Send an identify event with the provided identifiers
/// </summary>
/// <param name="userId">Full-stack User ID</param>
void IdentifyUser(string userId);
/// <param name="identifiers">Dictionary of identifier key-value pairs</param>
void IdentifyUser(Dictionary<string, string> identifiers);

/// <summary>
/// Update ODP configuration settings
Expand Down
6 changes: 3 additions & 3 deletions OptimizelySDK/Odp/IOdpManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ public interface IOdpManager
string[] FetchQualifiedSegments(string userId, List<OdpSegmentOption> options);

/// <summary>
/// Send identification event to ODP for a given full-stack User ID
/// Send identification event to ODP when 2+ valid identifiers are provided
/// </summary>
/// <param name="userId">User ID to send</param>
void IdentifyUser(string userId);
/// <param name="identifiers">Dictionary of identifier key-value pairs</param>
void IdentifyUser(Dictionary<string, string> identifiers);

/// <summary>
/// Add event to queue for sending to ODP
Expand Down
11 changes: 3 additions & 8 deletions OptimizelySDK/Odp/OdpEventManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -368,16 +368,11 @@ public void Dispose()
}

/// <summary>
/// Associate a full-stack userid with an established VUID
/// Send an identify event with the provided identifiers
/// </summary>
/// <param name="userId">Full-stack User ID</param>
public void IdentifyUser(string userId)
/// <param name="identifiers">Dictionary of identifier key-value pairs</param>
public void IdentifyUser(Dictionary<string, string> identifiers)
{
var identifiers = new Dictionary<string, string>
{
{ Constants.FS_USER_ID, userId },
};

var odpEvent = new OdpEvent(Constants.ODP_EVENT_TYPE, "identified", identifiers);
SendEvent(odpEvent);
}
Expand Down
24 changes: 20 additions & 4 deletions OptimizelySDK/Odp/OdpManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,34 @@ public string[] FetchQualifiedSegments(string userId, List<OdpSegmentOption> opt
}

/// <summary>
/// Send identification event to ODP for a given full-stack User ID
/// Send identification event to ODP when 2+ valid identifiers are provided
/// </summary>
/// <param name="userId">User ID to send</param>
public void IdentifyUser(string userId)
/// <param name="identifiers">Dictionary of identifier key-value pairs</param>
public void IdentifyUser(Dictionary<string, string> identifiers)
{
if (EventManagerOrConfigNotReady())
{
_logger.Log(LogLevel.DEBUG, "ODP identify event not dispatched (ODP disabled).");
return;
}

EventManager.IdentifyUser(userId);
var validIdentifiers = new Dictionary<string, string>();
foreach (var kvp in identifiers)
{
if (!string.IsNullOrEmpty(kvp.Value))
{
validIdentifiers[kvp.Key] = kvp.Value;
}
}

if (validIdentifiers.Count < 2)
{
_logger.Log(LogLevel.DEBUG,
"ODP identify event is not dispatched (only one identifier provided).");
return;
}

EventManager.IdentifyUser(validIdentifiers);
}

/// <summary>
Expand Down
6 changes: 3 additions & 3 deletions OptimizelySDK/Optimizely.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@
try
{
#if USE_ODP
InitializeComponents(eventDispatcher, logger, errorHandler, userProfileService,

Check warning on line 149 in OptimizelySDK/Optimizely.cs

View workflow job for this annotation

GitHub Actions / Build Standard 2.0

'Optimizely.InitializeComponents(IEventDispatcher, ILogger, IErrorHandler, UserProfileService, NotificationCenter, EventProcessor, OptimizelyDecideOption[], IOdpManager, ICmabService, CmabConfig)' is obsolete

Check warning on line 149 in OptimizelySDK/Optimizely.cs

View workflow job for this annotation

GitHub Actions / Build Standard 2.0

'Optimizely.InitializeComponents(IEventDispatcher, ILogger, IErrorHandler, UserProfileService, NotificationCenter, EventProcessor, OptimizelyDecideOption[], IOdpManager, ICmabService, CmabConfig)' is obsolete
null, eventProcessor, defaultDecideOptions, odpManager);
#else
InitializeComponents(eventDispatcher, logger, errorHandler, userProfileService,
Expand Down Expand Up @@ -218,7 +218,7 @@
ProjectConfigManager = configManager;

#if USE_ODP && USE_CMAB
InitializeComponents(eventDispatcher, logger, errorHandler, userProfileService,

Check warning on line 221 in OptimizelySDK/Optimizely.cs

View workflow job for this annotation

GitHub Actions / Build Standard 2.0

'Optimizely.InitializeComponents(IEventDispatcher, ILogger, IErrorHandler, UserProfileService, NotificationCenter, EventProcessor, OptimizelyDecideOption[], IOdpManager, ICmabService, CmabConfig)' is obsolete

Check warning on line 221 in OptimizelySDK/Optimizely.cs

View workflow job for this annotation

GitHub Actions / Build Standard 2.0

'Optimizely.InitializeComponents(IEventDispatcher, ILogger, IErrorHandler, UserProfileService, NotificationCenter, EventProcessor, OptimizelyDecideOption[], IOdpManager, ICmabService, CmabConfig)' is obsolete
notificationCenter, eventProcessor, defaultDecideOptions, odpManager, null, cmabConfig);
#elif USE_ODP
InitializeComponents(eventDispatcher, logger, errorHandler, userProfileService,
Expand Down Expand Up @@ -1499,8 +1499,8 @@
/// <summary>
/// Send identification event to Optimizely Data Platform
/// </summary>
/// <param name="userId">FS User ID to send</param>
internal void IdentifyUser(string userId)
/// <param name="identifiers">Dictionary of identifier key-value pairs</param>
internal void IdentifyUser(Dictionary<string, string> identifiers)
{
var config = ProjectConfigManager?.GetConfig();

Expand All @@ -1510,7 +1510,7 @@
return;
}

OdpManager?.IdentifyUser(userId);
OdpManager?.IdentifyUser(identifiers);
}

/// <summary>
Expand Down
6 changes: 5 additions & 1 deletion OptimizelySDK/OptimizelyUserContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
private List<string> QualifiedSegments;

// Optimizely object to be used.
private Optimizely Optimizely;

Check warning on line 55 in OptimizelySDK/OptimizelyUserContext.cs

View workflow job for this annotation

GitHub Actions / Build Standard 1.6

'Optimizely' is obsolete: 'Net standard 1.6 SDK support is deprecated, use Net standard 2.0 or above'

/// <summary>
/// Determine if User Context has already been disposed
Expand All @@ -61,18 +61,18 @@

private ForcedDecisionsStore ForcedDecisionsStore { get; set; }

public OptimizelyUserContext(Optimizely optimizely, string userId,

Check warning on line 64 in OptimizelySDK/OptimizelyUserContext.cs

View workflow job for this annotation

GitHub Actions / Build Standard 1.6

'Optimizely' is obsolete: 'Net standard 1.6 SDK support is deprecated, use Net standard 2.0 or above'
UserAttributes userAttributes, IErrorHandler errorHandler, ILogger logger
) : this(optimizely, userId, userAttributes, null, null, errorHandler, logger) { }

public OptimizelyUserContext(Optimizely optimizely, string userId,

Check warning on line 68 in OptimizelySDK/OptimizelyUserContext.cs

View workflow job for this annotation

GitHub Actions / Build Standard 1.6

'Optimizely' is obsolete: 'Net standard 1.6 SDK support is deprecated, use Net standard 2.0 or above'
UserAttributes userAttributes, ForcedDecisionsStore forcedDecisionsStore,
IErrorHandler errorHandler, ILogger logger
) : this(optimizely, userId, userAttributes, forcedDecisionsStore, null, errorHandler,
logger)
{ }

public OptimizelyUserContext(Optimizely optimizely, string userId,

Check warning on line 75 in OptimizelySDK/OptimizelyUserContext.cs

View workflow job for this annotation

GitHub Actions / Build Standard 1.6

'Optimizely' is obsolete: 'Net standard 1.6 SDK support is deprecated, use Net standard 2.0 or above'
UserAttributes userAttributes, ForcedDecisionsStore forcedDecisionsStore,
List<string> qualifiedSegments, IErrorHandler errorHandler, ILogger logger
#if USE_ODP
Expand All @@ -91,7 +91,11 @@
#if USE_ODP
if (shouldIdentifyUser)
{
optimizely.IdentifyUser(UserId);
var identifiers = new Dictionary<string, string>
{
{ Odp.Constants.FS_USER_ID, UserId },
};
optimizely.IdentifyUser(identifiers);
}
#endif
}
Expand All @@ -108,7 +112,7 @@
/// Returns Optimizely instance associated with the UserContext.
/// </summary>
/// <returns> Optimizely instance.</returns>
public virtual Optimizely GetOptimizely()

Check warning on line 115 in OptimizelySDK/OptimizelyUserContext.cs

View workflow job for this annotation

GitHub Actions / Build Standard 1.6

'Optimizely' is obsolete: 'Net standard 1.6 SDK support is deprecated, use Net standard 2.0 or above'
{
return Optimizely;
}
Expand Down
Loading