diff --git a/OptimizelySDK.Tests/EventTests/EventBuilderTest.cs b/OptimizelySDK.Tests/EventTests/EventBuilderTest.cs index c869d831..8b4c3ad5 100644 --- a/OptimizelySDK.Tests/EventTests/EventBuilderTest.cs +++ b/OptimizelySDK.Tests/EventTests/EventBuilderTest.cs @@ -115,7 +115,7 @@ public void TestCreateImpressionEventNoAttributes() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -207,7 +207,7 @@ public void TestCreateImpressionEventWithAttributes() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -327,7 +327,7 @@ public void TestCreateImpressionEventWithTypedAttributes() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -441,7 +441,7 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayload() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -531,7 +531,7 @@ public void TestCreateConversionEventNoAttributesNoValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -617,7 +617,7 @@ public void TestCreateConversionEventWithAttributesNoValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -709,7 +709,7 @@ public void TestCreateConversionEventNoAttributesWithValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -809,7 +809,7 @@ public void TestCreateConversionEventWithAttributesWithValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -909,7 +909,7 @@ public void TestCreateConversionEventNoAttributesWithInvalidValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1003,7 +1003,7 @@ public void TestConversionEventWithNumericTag() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1096,7 +1096,7 @@ public void TestConversionEventWithFalsyNumericAndRevenueValues() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1189,7 +1189,7 @@ public void TestConversionEventWithNumericValue1() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1282,7 +1282,7 @@ public void TestConversionEventWithRevenueValue1() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1381,7 +1381,7 @@ public void TestCreateConversionEventWithBucketingIDAttribute() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1487,7 +1487,7 @@ public void TestCreateImpressionEventWithBucketingIDAttribute() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1587,7 +1587,7 @@ public void TestCreateImpressionEventWhenBotFilteringIsProvidedInDatafile() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1680,7 +1680,7 @@ public void TestCreateImpressionEventWhenBotFilteringIsNotProvidedInDatafile() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1770,7 +1770,7 @@ public void TestCreateConversionEventWhenBotFilteringIsProvidedInDatafile() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1856,7 +1856,7 @@ public void TestCreateConversionEventWhenBotFilteringIsNotProvidedInDatafile() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1989,7 +1989,7 @@ public void TestCreateConversionEventWhenEventUsedInMultipleExp() var expectedLogEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -2082,7 +2082,7 @@ public void TestCreateConversionEventRemovesInvalidAttributesFromPayload() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary diff --git a/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs b/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs index 3199a8ae..8c839d67 100644 --- a/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs +++ b/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs @@ -66,6 +66,208 @@ public void Assert.IsNull(impressionEvent); } + [Test] + public void TestCreateImpressionEventNoAttributesEU() + { + var guid = Guid.NewGuid(); + var timeStamp = TestData.SecondsSince1970(); + + var payloadParams = new Dictionary + { + { + "visitors", new object[] + { + new Dictionary() + { + { + "snapshots", new object[] + { + new Dictionary + { + { + "decisions", new object[] + { + new Dictionary + { + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + { + "metadata", + new Dictionary + { + { "rule_type", "experiment" }, + { "rule_key", "test_experiment" }, + { "flag_key", "test_experiment" }, + { "variation_key", "control" }, + { "enabled", false }, + } + }, + }, + } + }, + { + "events", new object[] + { + new Dictionary + { + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, + } + }, + }, + } + }, + { + "attributes", new object[] + { + new Dictionary + { + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, + } + }, + { "visitor_id", TestUserId }, + }, + } + }, + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, + }; + + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["EU"], + payloadParams, + "POST", + new Dictionary + { + { "Content-Type", "application/json" }, + }); + + Config.Region = "EU"; + var impressionEvent = UserEventFactory.CreateImpressionEvent( + Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, + null, "test_experiment", "experiment"); + + var logEvent = EventFactory.CreateLogEvent(impressionEvent, Logger); + + TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, + Guid.Parse(impressionEvent.UUID)); + + Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); + } + + [Test] + public void TestCreateImpressionEventNoAttributesInvalid() + { + var guid = Guid.NewGuid(); + var timeStamp = TestData.SecondsSince1970(); + + var payloadParams = new Dictionary + { + { + "visitors", new object[] + { + new Dictionary() + { + { + "snapshots", new object[] + { + new Dictionary + { + { + "decisions", new object[] + { + new Dictionary + { + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + { + "metadata", + new Dictionary + { + { "rule_type", "experiment" }, + { "rule_key", "test_experiment" }, + { "flag_key", "test_experiment" }, + { "variation_key", "control" }, + { "enabled", false }, + } + }, + }, + } + }, + { + "events", new object[] + { + new Dictionary + { + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, + } + }, + }, + } + }, + { + "attributes", new object[] + { + new Dictionary + { + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, + } + }, + { "visitor_id", TestUserId }, + }, + } + }, + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, + }; + + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], + payloadParams, + "POST", + new Dictionary + { + { "Content-Type", "application/json" }, + }); + + Config.Region = "ZZ"; + var impressionEvent = UserEventFactory.CreateImpressionEvent( + Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, + null, "test_experiment", "experiment"); + + var logEvent = EventFactory.CreateLogEvent(impressionEvent, Logger); + + TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, + Guid.Parse(impressionEvent.UUID)); + + Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); + } + [Test] public void TestCreateImpressionEventNoAttributes() { @@ -146,7 +348,7 @@ public void TestCreateImpressionEventNoAttributes() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -251,7 +453,7 @@ public void TestCreateImpressionEventWithAttributes() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -383,7 +585,7 @@ public void TestCreateImpressionEventWithTypedAttributes() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -509,7 +711,7 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayload() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -642,7 +844,7 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayloadRollout( { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -735,7 +937,170 @@ public void TestCreateConversionEventNoAttributesNoValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], + payloadParams, + "POST", + new Dictionary + { + { "Content-Type", "application/json" }, + }); + var experimentToVariationMap = new Dictionary + { + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, + }; + + var conversionEvent = + UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, null); + var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); + + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); + + Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); + } + + [Test] + public void TestCreateConversionEventNoAttributesNoValueEU() + { + var guid = Guid.NewGuid(); + var timeStamp = TestData.SecondsSince1970(); + + var payloadParams = new Dictionary + { + { + "visitors", new object[] + { + new Dictionary + { + { + "snapshots", new object[] + { + new Dictionary + { + { + "events", new object[] + { + new Dictionary + { + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, + } + }, + }, + } + }, + { "visitor_id", TestUserId }, + { + "attributes", new object[] + { + new Dictionary + { + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, + } + }, + }, + } + }, + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, + }; + + var expectedEvent = new LogEvent( + EventFactory.EventEndpoints["EU"], + payloadParams, + "POST", + new Dictionary + { + { "Content-Type", "application/json" }, + }); + var experimentToVariationMap = new Dictionary + { + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, + }; + + Config.Region = "EU"; + var conversionEvent = + UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, null); + var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); + + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); + + Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); + } + + [Test] + public void TestCreateConversionEventNoAttributesNoValueInvalid() + { + var guid = Guid.NewGuid(); + var timeStamp = TestData.SecondsSince1970(); + + var payloadParams = new Dictionary + { + { + "visitors", new object[] + { + new Dictionary + { + { + "snapshots", new object[] + { + new Dictionary + { + { + "events", new object[] + { + new Dictionary + { + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, + } + }, + }, + } + }, + { "visitor_id", TestUserId }, + { + "attributes", new object[] + { + new Dictionary + { + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, + } + }, + }, + } + }, + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, + }; + + var expectedEvent = new LogEvent( + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -747,6 +1112,7 @@ public void TestCreateConversionEventNoAttributesNoValue() { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; + Config.Region = "ZZ"; var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, null); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); @@ -823,7 +1189,7 @@ public void TestCreateConversionEventWithAttributesNoValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -918,7 +1284,7 @@ public void TestCreateConversionEventNoAttributesWithValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1020,7 +1386,7 @@ public void TestCreateConversionEventWithAttributesWithValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1122,7 +1488,7 @@ public void TestCreateConversionEventNoAttributesWithInvalidValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1218,7 +1584,7 @@ public void TestConversionEventWithNumericTag() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1316,7 +1682,7 @@ public void TestConversionEventWithFalsyNumericAndRevenueValues() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1412,7 +1778,7 @@ public void TestConversionEventWithNumericValue1() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1507,7 +1873,7 @@ public void TestConversionEventWithRevenueValue1() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1609,7 +1975,7 @@ public void TestCreateConversionEventWithBucketingIDAttribute() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1727,7 +2093,7 @@ public void TestCreateImpressionEventWithBucketingIDAttribute() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1838,7 +2204,7 @@ public void TestCreateImpressionEventWhenBotFilteringIsProvidedInDatafile() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1945,7 +2311,7 @@ public void TestCreateImpressionEventWhenBotFilteringIsNotProvidedInDatafile() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -2039,7 +2405,7 @@ public void TestCreateConversionEventWhenBotFilteringIsProvidedInDatafile() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -2128,7 +2494,7 @@ public void TestCreateConversionEventWhenBotFilteringIsNotProvidedInDatafile() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -2250,7 +2616,7 @@ public void TestCreateConversionEventWhenEventUsedInMultipleExp() var expectedLogEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -2358,7 +2724,7 @@ public void TestCreateConversionEventRemovesInvalidAttributesFromPayload() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary diff --git a/OptimizelySDK.Tests/EventTests/TestForwardingEventDispatcher.cs b/OptimizelySDK.Tests/EventTests/TestForwardingEventDispatcher.cs index 01eca1ee..9b7cf533 100644 --- a/OptimizelySDK.Tests/EventTests/TestForwardingEventDispatcher.cs +++ b/OptimizelySDK.Tests/EventTests/TestForwardingEventDispatcher.cs @@ -18,7 +18,7 @@ public class TestForwardingEventDispatcher : IEventDispatcher public void DispatchEvent(LogEvent logEvent) { Assert.AreEqual(logEvent.HttpVerb, "POST"); - Assert.AreEqual(logEvent.Url, EventFactory.EVENT_ENDPOINT); + Assert.AreEqual(logEvent.Url, EventFactory.EventEndpoints["US"]); IsUpdated = true; } } diff --git a/OptimizelySDK.Tests/OptimizelyTest.cs b/OptimizelySDK.Tests/OptimizelyTest.cs index 0adb57ec..034b4bc0 100644 --- a/OptimizelySDK.Tests/OptimizelyTest.cs +++ b/OptimizelySDK.Tests/OptimizelyTest.cs @@ -3490,7 +3490,7 @@ public void TestTrackListener(UserAttributes userAttributes, EventTags eventTags var variation = Result.NewResult(Config.GetVariationFromKey(experimentKey, variationKey), DecisionReasons); - var logEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var logEvent = new LogEvent(EventFactory.EventEndpoints["US"], OptimizelyHelper.SingleParameter, "POST", new Dictionary()); diff --git a/OptimizelySDK/Config/DatafileProjectConfig.cs b/OptimizelySDK/Config/DatafileProjectConfig.cs index cb248f8c..465b384a 100644 --- a/OptimizelySDK/Config/DatafileProjectConfig.cs +++ b/OptimizelySDK/Config/DatafileProjectConfig.cs @@ -103,7 +103,7 @@ public enum OPTLYSDKVersion public string Datafile { get; set; } /// - /// Configured host name for the Optimizely Data Platform. + /// Configured host name for the Optimizely Data Platform. /// public string HostForOdp { get; private set; } @@ -492,8 +492,7 @@ private static DatafileProjectConfig GetConfig(string configData) !(((int)supportedVersion).ToString() == config.Version))) { throw new ConfigParseException( - $@"This version of the C# SDK does not support the given datafile version: { - config.Version}"); + $@"This version of the C# SDK does not support the given datafile version: {config.Version}"); } return config; @@ -632,8 +631,7 @@ public Variation GetVariationFromKey(string experimentKey, string variationKey) return _VariationKeyMap[experimentKey][variationKey]; } - var message = $@"No variation key ""{variationKey - }"" defined in datafile for experiment ""{experimentKey}""."; + var message = $@"No variation key ""{variationKey}"" defined in datafile for experiment ""{experimentKey}""."; Logger.Log(LogLevel.ERROR, message); ErrorHandler.HandleError( new InvalidVariationException("Provided variation is not in datafile.")); @@ -655,8 +653,7 @@ public Variation GetVariationFromKeyByExperimentId(string experimentId, string v return _VariationKeyMapByExperimentId[experimentId][variationKey]; } - var message = $@"No variation key ""{variationKey - }"" defined in datafile for experiment ""{experimentId}""."; + var message = $@"No variation key ""{variationKey}"" defined in datafile for experiment ""{experimentId}""."; Logger.Log(LogLevel.ERROR, message); ErrorHandler.HandleError( new InvalidVariationException("Provided variation is not in datafile.")); @@ -678,8 +675,7 @@ public Variation GetVariationFromId(string experimentKey, string variationId) return _VariationIdMap[experimentKey][variationId]; } - var message = $@"No variation ID ""{variationId - }"" defined in datafile for experiment ""{experimentKey}""."; + var message = $@"No variation ID ""{variationId}"" defined in datafile for experiment ""{experimentKey}""."; Logger.Log(LogLevel.ERROR, message); ErrorHandler.HandleError( new InvalidVariationException("Provided variation is not in datafile.")); @@ -701,11 +697,9 @@ public Variation GetVariationFromIdByExperimentId(string experimentId, string va return _VariationIdMapByExperimentId[experimentId][variationId]; } - var message = $@"No variation ID ""{variationId - }"" defined in datafile for experiment ""{experimentId}""."; + var message = $@"No variation ID ""{variationId}"" defined in datafile for experiment ""{experimentId}""."; Logger.Log(LogLevel.ERROR, message); - ErrorHandler.HandleError( - new InvalidVariationException("Provided variation is not in datafile.")); + ErrorHandler.HandleError(new InvalidVariationException("Provided variation is not in datafile.")); return new Variation(); } @@ -788,9 +782,7 @@ public string GetAttributeId(string attributeKey) if (hasReservedPrefix) { Logger.Log(LogLevel.WARN, - $@"Attribute {attributeKey} unexpectedly has reserved prefix { - RESERVED_ATTRIBUTE_PREFIX - }; using attribute ID instead of reserved attribute name."); + $@"Attribute {attributeKey} unexpectedly has reserved prefix {RESERVED_ATTRIBUTE_PREFIX}; using attribute ID instead of reserved attribute name."); } return attribute.Id; @@ -825,12 +817,20 @@ public bool IsFeatureExperiment(string experimentId) } /// - ///Returns the datafile corresponding to ProjectConfig + /// Gets or sets the region associated with the project configuration. + /// This typically indicates the data residency or deployment region (e.g., "us", "eu"). + /// Valid values depend on the Optimizely environment and configuration. /// /// the datafile string corresponding to ProjectConfig public string ToDatafile() { return _datafile; } + + /// + /// Returns the datafile corresponding to ProjectConfig + /// + /// the datafile string corresponding to ProjectConfig + public string Region { get; set; } } } diff --git a/OptimizelySDK/Event/Builder/EventBuilder.cs b/OptimizelySDK/Event/Builder/EventBuilder.cs index 1d73ff94..0dd4562a 100644 --- a/OptimizelySDK/Event/Builder/EventBuilder.cs +++ b/OptimizelySDK/Event/Builder/EventBuilder.cs @@ -27,9 +27,6 @@ namespace OptimizelySDK.Event.Builder [Obsolete("This class is deprecated. Use 'OptimizelySDK.Event.EventFactory'.")] public class EventBuilder { - private const string IMPRESSION_ENDPOINT = "https://logx.optimizely.com/v1/events"; - - private const string CONVERSION_ENDPOINT = "https://logx.optimizely.com/v1/events"; private const string HTTP_VERB = "POST"; @@ -245,7 +242,11 @@ public virtual LogEvent CreateImpressionEvent(ProjectConfig config, Experiment e GetImpressionOrConversionParamsWithCommonParams(commonParams, new object[] { impressionOnlyParams }); - return new LogEvent(IMPRESSION_ENDPOINT, impressionParams, HTTP_VERB, HTTP_HEADERS); + var region = !string.IsNullOrEmpty(config.Region) && EventFactory.EventEndpoints.ContainsKey(config.Region) ? config.Region : "US"; + + var endpoint = EventFactory.EventEndpoints[region]; + + return new LogEvent(endpoint, impressionParams, HTTP_VERB, HTTP_HEADERS); } @@ -271,7 +272,11 @@ public virtual LogEvent CreateConversionEvent(ProjectConfig config, string event var conversionParams = GetImpressionOrConversionParamsWithCommonParams(commonParams, conversionOnlyParams); - return new LogEvent(CONVERSION_ENDPOINT, conversionParams, HTTP_VERB, HTTP_HEADERS); + var region = !string.IsNullOrEmpty(config.Region) && EventFactory.EventEndpoints.ContainsKey(config.Region) ? config.Region : "US"; + + var endpoint = EventFactory.EventEndpoints[region]; + + return new LogEvent(endpoint, conversionParams, HTTP_VERB, HTTP_HEADERS); } } } diff --git a/OptimizelySDK/Event/Entity/EventContext.cs b/OptimizelySDK/Event/Entity/EventContext.cs index 44b77644..718deba6 100644 --- a/OptimizelySDK/Event/Entity/EventContext.cs +++ b/OptimizelySDK/Event/Entity/EventContext.cs @@ -41,6 +41,9 @@ public class EventContext [JsonProperty("anonymize_ip")] public bool AnonymizeIP { get; protected set; } + [JsonProperty("region")] + public string Region { get; protected set; } + /// /// EventContext builder /// @@ -50,6 +53,7 @@ public class Builder private string ProjectId; private string Revision; private bool AnonymizeIP; + private string Region; public Builder WithAccountId(string accountId) { @@ -75,6 +79,12 @@ public Builder WithAnonymizeIP(bool anonymizeIP) return this; } + public Builder WithRegion(string region) + { + Region = region; + return this; + } + /// /// Build EventContext instance /// @@ -89,6 +99,7 @@ public EventContext Build() eventContext.ClientName = Optimizely.SDK_TYPE; eventContext.ClientVersion = Optimizely.SDK_VERSION; eventContext.AnonymizeIP = AnonymizeIP; + eventContext.Region = Region; return eventContext; } diff --git a/OptimizelySDK/Event/EventFactory.cs b/OptimizelySDK/Event/EventFactory.cs index 841b650f..771e0f39 100644 --- a/OptimizelySDK/Event/EventFactory.cs +++ b/OptimizelySDK/Event/EventFactory.cs @@ -34,9 +34,15 @@ public class EventFactory { private const string CUSTOM_ATTRIBUTE_FEATURE_TYPE = "custom"; - public const string - EVENT_ENDPOINT = - "https://logx.optimizely.com/v1/events"; // Should be part of the datafile + // Supported regions for event endpoints + public static string[] SupportedRegions => EventEndpoints.Keys.ToArray(); + + // Dictionary of event endpoints for different regions + public static readonly Dictionary EventEndpoints = new Dictionary + { + {"US", "https://logx.optimizely.com/v1/events"}, + {"EU", "https://eu.logx.optimizely.com/v1/events"} + }; private const string ACTIVATE_EVENT_KEY = "campaign_activated"; @@ -63,6 +69,9 @@ public static LogEvent CreateLogEvent(UserEvent[] userEvents, ILogger logger) var visitors = new List(userEvents.Count()); + // Default to US region + string region = "US"; + foreach (var userEvent in userEvents) { if (userEvent is ImpressionEvent) @@ -81,6 +90,12 @@ public static LogEvent CreateLogEvent(UserEvent[] userEvents, ILogger logger) var userContext = userEvent.Context; + // Get region from the event's context, default to US if not specified + if (!string.IsNullOrEmpty(userContext.Region)) + { + region = userContext.Region; + } + builder.WithClientName(userContext.ClientName). WithClientVersion(userContext.ClientVersion). WithAccountId(userContext.AccountId). @@ -102,7 +117,16 @@ public static LogEvent CreateLogEvent(UserEvent[] userEvents, ILogger logger) var eventBatchDictionary = JObject.FromObject(eventBatch).ToObject>(); - return new LogEvent(EVENT_ENDPOINT, eventBatchDictionary, "POST", + // Use the region to determine the endpoint URL, falling back to US if the region is not found or not supported + string endpointUrl = EventEndpoints["US"]; // Default to US endpoint + + // Only try to use the region-specific endpoint if it's a supported region + if (SupportedRegions.Contains(region) && EventEndpoints.ContainsKey(region)) + { + endpointUrl = EventEndpoints[region]; + } + + return new LogEvent(endpointUrl, eventBatchDictionary, "POST", new Dictionary { { "Content-Type", "application/json" }, diff --git a/OptimizelySDK/Event/UserEventFactory.cs b/OptimizelySDK/Event/UserEventFactory.cs index f073237a..28d6fb87 100644 --- a/OptimizelySDK/Event/UserEventFactory.cs +++ b/OptimizelySDK/Event/UserEventFactory.cs @@ -80,6 +80,7 @@ public static ImpressionEvent CreateImpressionEvent(ProjectConfig projectConfig, WithAccountId(projectConfig.AccountId). WithAnonymizeIP(projectConfig.AnonymizeIP). WithRevision(projectConfig.Revision). + WithRegion(projectConfig.Region). Build(); var variationKey = ""; @@ -123,6 +124,7 @@ EventTags eventTags WithAccountId(projectConfig.AccountId). WithAnonymizeIP(projectConfig.AnonymizeIP). WithRevision(projectConfig.Revision). + WithRegion(projectConfig.Region). Build(); return new ConversionEvent.Builder(). diff --git a/OptimizelySDK/ProjectConfig.cs b/OptimizelySDK/ProjectConfig.cs index 58272aa7..8aab34f7 100644 --- a/OptimizelySDK/ProjectConfig.cs +++ b/OptimizelySDK/ProjectConfig.cs @@ -312,5 +312,10 @@ public interface ProjectConfig /// Returns the datafile corresponding to ProjectConfig /// string ToDatafile(); + + /// + /// Returns the datafile region to ProjectConfig + /// + string Region { get; set; } } }