Skip to content

Commit

Permalink
feat: Integrated ODPManager with UserContext and Optimizely client (#323
Browse files Browse the repository at this point in the history
)

* Include ODP Manager instantiation in Optimizely.cs

Includes lint/format updates...Sorry PR-Reviewer :-/

* Add FetchQualifiedSegments to Optimizely.cs

* Add FetchQualifiedSegments to UserContext

* Add IdentifyUser, fetch segments callback, & docs

* WIP existing test fixes

* Fix legacy test (mock) constructors

* Add SendOdpEvent to Optimizely

* WIP Init OdpManager

* WIP Add OptimizelySdkSettings & fix some legacy tests

* WIP fixes

* Remove early UpdateOdpSettings

* Add internal accessor for ProjectConfig Segments

Sorry for the linter formatting updates

* Linter fixes

* Preprocessing conditional compilation directives

* Add Segments array to ProjectConfig

* Lint corrections

* More linter fixes

hopefully ;-)

* WIP PR review changes

* Lint fix

* Lint fix

* Add async FetchQualifiedSegments

* WIP parse TypedAudience to ODP Segments

* WIP parsing Segments

* More ODP test datafile more scenarios

* Revert IMultipleConditions concept

* Correct Segments from datafile

* Lint fix

* Add segment unit tests

* WIP satisfying legacy tests

* Remove Ignore from legacy tests

* Finalize SetupOdp; add Dispose to OptimizelyUserContext

* Add missing preprocessing conditions

* Fix linting

* PR code review updates

* Lint fixes

* feat: Fix NotificationCenter Issue for ODPManager (#324)

* PR changes

* More PR changes

* proposed changes

* Understanding & additional updates

* WIP Refactors & test fixes

* WIP correcting tests...

* Refactors

* WIP OdpEventManagerTest resolutions

* Remove NotificationCenter from NotificationCenterRegistry on Dispose

* Fix Disposed = true location

* Modify NCR Dispose

* Mods to NCR and NC disposal

* Mods to NCR and NC disposal

* Fix OdpEventManager & tests

* Remove double lock in NotificationCenterRegistry

* Fix final test corrections

* Pass logger into NotificationCenterRegistry

* Last PR change request

* Remove TODO comments

Co-authored-by: msohailhussain <[email protected]>

* Lint fixes + Copyright year updates

* Lint fix PollingProjectConfigManager

* Trying to fix TestPollingConfigManagerBlocksWhenProjectConfigIsNotProvided

* Another attempt to figure out TestPollingConfigManagerBlocksWhenProjectConfigIsNotProvided

* Update OptimizelySDK/Config/PollingProjectConfigManager.cs

Co-authored-by: Muhammad Noman  <[email protected]>

* Update OptimizelySDK/Config/HttpProjectConfigManager.cs

Co-authored-by: Muhammad Noman  <[email protected]>

* Update OptimizelySDK/Config/FallbackProjectConfigManager.cs

Co-authored-by: Muhammad Noman  <[email protected]>

* Update OptimizelySDK/Config/FallbackProjectConfigManager.cs

Co-authored-by: Muhammad Noman  <[email protected]>

* Implement a NoOpOdpManager

* Remove configurable batch size for OdpEventManager

* Fix lint (Mike not happy)

* OMG Linter needs config

* Split condition for UpdateSettings & NotificationCenterRegistry add

* Remove optional chaining

* PR review changes

* Fix InternalsVisibleTo & use internal for testing

* PR change requests

* Add unit test for defaults from OdpManager & below

* Remove NoOpOdpManager & default OdpManager instantiation

* Lint fixes

* Allow signed + assigned friend assemblies

* Use pubkey of OptimizelySDK.Tests

* Testing InternalsVisibleTo in csproj

* More testing signed assems

* WIP fix InternalsVisibleTo with Release build

* Require providing SDK key in HttpProjectConfigManager constructor

* Fix: Some suggested changes related to ODP (#325)

* Some suggested changes to fix null pointer exception

* - Removed batchsize support from ODP event manager
- Made some general fixes

* Flush previous event

* reverting this change

Co-authored-by: mnoman09 <[email protected]>

* Merge fixes + lint

* Lint fixes

* Build fix and lint

* PR change requests

* Lint fix

* Fix: ODP Event manager not consistent in triggering events. (#326)

* Refactored OdpEventManager flushEvent function.

* To wait for events using flushInterval when eventBatch is not empty.

* Or wait indefinitely if no event is in batch until any event arrive.

* Avoid calling flush on shutdown if no events are present

* Avoid calling unnecessary flushQueue if _currentBatch.Count is zero.

* Fixed the test as when there are no remaining items in queue then odpEventManager should not  flush.

* Removing mutex lock from notification registry instead using concurrentDictionary

* Revert "Removing mutex lock from notification registry instead using concurrentDictionary"

This reverts commit 64cdf80.

* Added Thread.sleep which somehow enabling thread to shutdown gracefully.

---------

Co-authored-by: mnoman09 <[email protected]>

---------

Co-authored-by: msohailhussain <[email protected]>
Co-authored-by: Muhammad Noman  <[email protected]>
Co-authored-by: mnoman09 <[email protected]>
  • Loading branch information
4 people authored Feb 14, 2023
1 parent bdaef7f commit 2d8b71a
Show file tree
Hide file tree
Showing 38 changed files with 6,991 additions and 2,797 deletions.
81 changes: 81 additions & 0 deletions OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,84 @@
<Compile Include="..\OptimizelySDK\IOptimizely.cs">
<Link>IOptimizely.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Notifications\NotificationCenterRegistry.cs">
<Link>Notifications\NotificationCenterRegistry.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\Constants.cs">
<Link>Odp\Constants.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\Entity\Audience.cs">
<Link>Odp\Entity\Audience.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\Entity\Customer.cs">
<Link>Odp\Entity\Customer.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\Entity\Data.cs">
<Link>Odp\Entity\Data.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\Entity\Edge.cs">
<Link>Odp\Entity\Edge.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\Entity\Error.cs">
<Link>Odp\Entity\Error.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\Entity\Extension.cs">
<Link>Odp\Entity\Extension.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\Entity\Location.cs">
<Link>Odp\Entity\Location.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\Entity\Node.cs">
<Link>Odp\Entity\Node.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\Entity\OdpEvent.cs">
<Link>Odp\Entity\OdpEvent.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\Entity\Response.cs">
<Link>Odp\Entity\Response.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\Enums.cs">
<Link>Odp\Enums.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\ICache.cs">
<Link>Odp\ICache.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\IOdpEventApiManager.cs">
<Link>Odp\IOdpEventApiManager.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\IOdpEventManager.cs">
<Link>Odp\IOdpEventManager.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\IOdpManager.cs">
<Link>Odp\IOdpManager.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\IOdpSegmentApiManager.cs">
<Link>Odp\IOdpSegmentApiManager.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\IOdpSegmentManager.cs">
<Link>Odp\IOdpSegmentManager.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\LruCache.cs">
<Link>Odp\LruCache.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\OdpConfig.cs">
<Link>Odp\OdpConfig.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\OdpEventApiManager.cs">
<Link>Odp\OdpEventApiManager.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\OdpEventManager.cs">
<Link>Odp\OdpEventManager.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\OdpManager.cs">
<Link>Odp\OdpManager.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\OdpSegmentApiManager.cs">
<Link>Odp\OdpSegmentApiManager.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Odp\OdpSegmentManager.cs">
<Link>Odp\OdpSegmentManager.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Optimizely.cs">
<Link>Optimizely.cs</Link>
</Compile>
Expand Down Expand Up @@ -223,6 +301,9 @@
<Compile Include="..\OptimizelySDK\Utils\AttributeMatchTypes.cs">
<Link>Utils\AttributeMatchTypes.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Utils\CollectionExtensions.cs">
<Link>Utils\CollectionExtensions.cs</Link>
</Compile>
<Compile Include="..\OptimizelySDK\Utils\ConditionParser.cs">
<Link>Utils\ConditionParser.cs</Link>
</Compile>
Expand Down
176 changes: 176 additions & 0 deletions OptimizelySDK.Tests/AudienceConditionsTests/SegmentsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
* Copyright 2022-2023 Optimizely
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using Moq;
using NUnit.Framework;
using OptimizelySDK.AudienceConditions;
using OptimizelySDK.Entity;
using OptimizelySDK.Logger;
using System.Collections.Generic;
using System.Linq;

namespace OptimizelySDK.Tests.AudienceConditionsTests
{
[TestFixture]
public class SegmentsTests
{
private BaseCondition _firstThirdPartyOdpQualifiedMatchCondition;
private BaseCondition _secondThirdPartyOdpQualifiedMatchCondition;
private ICondition _customExactMatchCondition;
private Mock<ILogger> _mockLogger;

private const string FIRST_CONDITION_VALUE = "first_condition_value";
private const string SECOND_CONDITION_VALUE = "second_condition_value";

[TestFixtureSetUp]
public void Setup()
{
_firstThirdPartyOdpQualifiedMatchCondition = new BaseCondition
{
Value = FIRST_CONDITION_VALUE,
Type = "third_party_dimension",
Name = "odp.audiences",
Match = "qualified",
};

_secondThirdPartyOdpQualifiedMatchCondition = new BaseCondition
{
Value = SECOND_CONDITION_VALUE,
Type = "third_party_dimension",
Name = "odp.audiences",
Match = "qualified",
};

_customExactMatchCondition = new BaseCondition()
{
Value = "test_custom_value",
Type = "custom_attribute",
Name = "test_custom_name",
Match = "exact",
};

_mockLogger = new Mock<ILogger>();
_mockLogger.Setup(l => l.Log(It.IsAny<LogLevel>(), It.IsAny<string>()));
}

[Test]
public void ShouldGetSegmentsFromDatafileTypedAudiences()
{
var expectedSegments = new SortedSet<string>
{
"ats_bug_bash_segment_gender",
"ats_bug_bash_segment_has_purchased",
"has_email_opted_out",
"ats_bug_bash_segment_dob",
};
var optimizelyClient = new Optimizely(TestData.OdpSegmentsDatafile,
new ValidEventDispatcher(), _mockLogger.Object);

var allSegments = optimizelyClient.ProjectConfigManager.GetConfig().Segments;

var orderedDistinctSegments = new SortedSet<string>(allSegments);
// check for no duplicates
Assert.AreEqual(allSegments.Length, orderedDistinctSegments.Count);
Assert.AreEqual(expectedSegments, orderedDistinctSegments);
}

[Test]
public void ShouldFindOdpSegmentFromAndCondition()
{
var conditions = new AndCondition
{
Conditions = new[]
{
_firstThirdPartyOdpQualifiedMatchCondition, _customExactMatchCondition,
},
};

var allSegments = Audience.GetSegments(conditions);

Assert.AreEqual(_firstThirdPartyOdpQualifiedMatchCondition.Value.ToString(),
allSegments.FirstOrDefault());
}

[Test]
public void ShouldFindOdpSegmentFromOrCondition()
{
var conditions = new OrCondition
{
Conditions = new[]
{
_customExactMatchCondition, _firstThirdPartyOdpQualifiedMatchCondition,
},
};

var allSegments = Audience.GetSegments(conditions);

Assert.AreEqual(_firstThirdPartyOdpQualifiedMatchCondition.Value.ToString(),
allSegments.FirstOrDefault());
}

[Test]
public void ShouldNotFindOdpSegmentsFromConditions()
{
var conditions = new AndCondition
{
Conditions = new[]
{
_customExactMatchCondition, _customExactMatchCondition, _customExactMatchCondition,
},
};

var allSegments = Audience.GetSegments(conditions);

Assert.IsEmpty(allSegments);
}

[Test]
public void ShouldFindAndDedupeNestedOdpSegments()
{
var qualifiedAndExact = new AndCondition
{
Conditions = new ICondition[]
{
_firstThirdPartyOdpQualifiedMatchCondition, _customExactMatchCondition,
},
};
var twoQualified = new AndCondition
{
Conditions = new ICondition[]
{
_secondThirdPartyOdpQualifiedMatchCondition, _firstThirdPartyOdpQualifiedMatchCondition,
},
};
var orConditions = new OrCondition
{
Conditions = new ICondition[]
{
qualifiedAndExact, twoQualified,
},
};
var notCondition = new NotCondition
{
Condition = orConditions,
};

var allSegments = Audience.GetSegments(notCondition).ToList();

Assert.AreEqual(2, allSegments.Count);
Assert.Contains(FIRST_CONDITION_VALUE, allSegments);
Assert.Contains(SECOND_CONDITION_VALUE, allSegments);
}
}
}
Loading

0 comments on commit 2d8b71a

Please sign in to comment.