Skip to content

Commit e96228a

Browse files
mnoman09jaeopt
authored andcommitted
feat: Added caching for OptimizelyConfig object (#206)
* Added getOptimizelyConfig api
1 parent 53ff0d9 commit e96228a

File tree

9 files changed

+180
-5
lines changed

9 files changed

+180
-5
lines changed

OptimizelySDK.Net35/OptimizelySDK.Net35.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,9 @@
290290
<Compile Include="..\OptimizelySDK\OptlyConfig\OptimizelyConfigService.cs">
291291
<Link>OptlyConfig\OptimizelyConfigService.cs</Link>
292292
</Compile>
293+
<Compile Include="..\OptimizelySDK\OptlyConfig\IOptimizelyConfigManager.cs">
294+
<Link>OptlyConfig\IOptimizelyConfigManager.cs</Link>
295+
</Compile>
293296
</ItemGroup>
294297
<ItemGroup>
295298
<None Include="..\OptimizelySDK\Utils\schema.json">

OptimizelySDK.Net40/OptimizelySDK.Net40.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,9 @@
306306
</Compile>
307307
<Compile Include="..\OptimizelySDK\OptlyConfig\OptimizelyConfigService.cs">
308308
<Link>OptlyConfig\OptimizelyConfigService.cs</Link>
309+
</Compile>
310+
<Compile Include="..\OptimizelySDK\OptlyConfig\IOptimizelyConfigManager.cs">
311+
<Link>OptlyConfig\IOptimizelyConfigManager.cs</Link>
309312
</Compile>
310313
</ItemGroup>
311314
<ItemGroup>

OptimizelySDK.NetStandard16/OptimizelySDK.NetStandard16.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
<Compile Include="..\OptimizelySDK\OptlyConfig\OptimizelyVariable.cs" />
8686
<Compile Include="..\OptimizelySDK\OptlyConfig\OptimizelyVariation.cs" />
8787
<Compile Include="..\OptimizelySDK\OptlyConfig\OptimizelyConfigService.cs" />
88+
<Compile Include="..\OptimizelySDK\OptlyConfig\IOptimizelyConfigManager.cs" />
8889
<Compile Include="..\OptimizelySDK\Config\FallbackProjectConfigManager.cs">
8990
<Link>AtomicProjectConfigManager.cs</Link>
9091
</Compile>

OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,9 @@
267267
</Compile>
268268
<Compile Include="..\OptimizelySDK\OptlyConfig\OptimizelyConfigService.cs">
269269
<Link>OptlyConfig\OptimizelyConfigService.cs</Link>
270+
</Compile>
271+
<Compile Include="..\OptimizelySDK\OptlyConfig\IOptimizelyConfigManager.cs">
272+
<Link>OptlyConfig\IOptimizelyConfigManager.cs</Link>
270273
</Compile>
271274
</ItemGroup>
272275
<ItemGroup>

OptimizelySDK.Tests/OptimizelyConfigTests/OptimizelyConfigTest.cs

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*
1+
/*
22
* Copyright 2020, Optimizely
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,19 +14,123 @@
1414
* limitations under the License.
1515
*/
1616

17+
using System;
18+
using Moq;
1719
using NUnit.Framework;
1820
using OptimizelySDK.Config;
1921
using OptimizelySDK.Logger;
2022
using OptimizelySDK.OptlyConfig;
2123
using System.Collections.Generic;
24+
using System.Threading;
2225

2326
namespace OptimizelySDK.Tests.OptimizelyConfigTests
2427
{
2528
[TestFixture]
2629
public class OptimizelyConfigTest
2730
{
31+
32+
private Mock<ILogger> LoggerMock;
33+
34+
[SetUp]
35+
public void Setup()
36+
{
37+
LoggerMock = new Mock<ILogger>();
38+
LoggerMock.Setup(l => l.Log(It.IsAny<LogLevel>(), It.IsAny<string>()));
39+
}
40+
2841
#region Test OptimizelyConfigService
2942

43+
[Test]
44+
public void TestAfterDisposeGetOptimizelyConfigIsNoLongerValid()
45+
{
46+
var httpManager = new HttpProjectConfigManager.Builder()
47+
.WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z")
48+
.WithDatafile(TestData.Datafile)
49+
.WithPollingInterval(TimeSpan.FromMilliseconds(50000))
50+
.WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500))
51+
.Build(true);
52+
var optimizely = new Optimizely(httpManager);
53+
httpManager.Start();
54+
55+
var optimizelyConfig = optimizely.GetOptimizelyConfig();
56+
57+
Assert.NotNull(optimizelyConfig);
58+
Assert.NotNull(optimizelyConfig.ExperimentsMap);
59+
Assert.NotNull(optimizelyConfig.FeaturesMap);
60+
Assert.NotNull(optimizelyConfig.Revision);
61+
62+
optimizely.Dispose();
63+
64+
var optimizelyConfigAfterDispose = optimizely.GetOptimizelyConfig();
65+
Assert.Null(optimizelyConfigAfterDispose);
66+
}
67+
68+
[Test]
69+
public void TestPollingGivenOnlySdkKeyGetOptimizelyConfig()
70+
{
71+
HttpProjectConfigManager httpManager = new HttpProjectConfigManager.Builder()
72+
.WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z")
73+
.WithLogger(LoggerMock.Object)
74+
.WithPollingInterval(TimeSpan.FromMilliseconds(1000))
75+
.WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500))
76+
.WithStartByDefault()
77+
.Build(true);
78+
79+
Assert.NotNull(httpManager.GetConfig());
80+
81+
var optimizely = new Optimizely(httpManager);
82+
83+
var optimizelyConfig = optimizely.GetOptimizelyConfig();
84+
85+
Assert.NotNull(optimizelyConfig);
86+
Assert.NotNull(optimizelyConfig.ExperimentsMap);
87+
Assert.NotNull(optimizelyConfig.FeaturesMap);
88+
Assert.NotNull(optimizelyConfig.Revision);
89+
90+
optimizely.Dispose();
91+
92+
var optimizelyConfigAfterDispose = optimizely.GetOptimizelyConfig();
93+
Assert.Null(optimizelyConfigAfterDispose);
94+
}
95+
96+
[Test]
97+
public void TestPollingMultipleTimesGetOptimizelyConfig()
98+
{
99+
HttpProjectConfigManager httpManager = new HttpProjectConfigManager.Builder()
100+
.WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z")
101+
.WithLogger(LoggerMock.Object)
102+
.WithPollingInterval(TimeSpan.FromMilliseconds(100))
103+
.WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500))
104+
.WithStartByDefault()
105+
.Build(true);
106+
107+
Assert.NotNull(httpManager.GetConfig());
108+
109+
var optimizely = new Optimizely(httpManager);
110+
111+
var optimizelyConfig = optimizely.GetOptimizelyConfig();
112+
113+
Assert.NotNull(optimizelyConfig);
114+
Assert.NotNull(optimizelyConfig.ExperimentsMap);
115+
Assert.NotNull(optimizelyConfig.FeaturesMap);
116+
Assert.NotNull(optimizelyConfig.Revision);
117+
118+
Thread.Sleep(210);
119+
120+
optimizelyConfig = optimizely.GetOptimizelyConfig();
121+
122+
Assert.NotNull(optimizelyConfig);
123+
Assert.NotNull(optimizelyConfig.ExperimentsMap);
124+
Assert.NotNull(optimizelyConfig.FeaturesMap);
125+
Assert.NotNull(optimizelyConfig.Revision);
126+
127+
128+
optimizely.Dispose();
129+
130+
var optimizelyConfigAfterDispose = optimizely.GetOptimizelyConfig();
131+
Assert.Null(optimizelyConfigAfterDispose);
132+
}
133+
30134
[Test]
31135
public void TestGetOptimizelyConfigServiceNullConfig()
32136
{

OptimizelySDK/Config/PollingProjectConfigManager.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019, Optimizely
2+
* Copyright 2019-2020, Optimizely
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
2020
using OptimizelySDK.Utils;
2121
using System.Threading.Tasks;
2222
using OptimizelySDK.ErrorHandler;
23+
using OptimizelySDK.OptlyConfig;
2324

2425
namespace OptimizelySDK.Config
2526
{
@@ -29,7 +30,7 @@ namespace OptimizelySDK.Config
2930
/// Instances of this class, must implement the <see cref="Poll()"/> method
3031
/// which is responsible for fetching a given ProjectConfig.
3132
/// </summary>
32-
public abstract class PollingProjectConfigManager : ProjectConfigManager, IDisposable
33+
public abstract class PollingProjectConfigManager : ProjectConfigManager, IOptimizelyConfigManager, IDisposable
3334
{
3435
public bool Disposed { get; private set; }
3536

@@ -44,6 +45,7 @@ public abstract class PollingProjectConfigManager : ProjectConfigManager, IDispo
4445
protected IErrorHandler ErrorHandler { get; set; }
4546
protected TimeSpan BlockingTimeout;
4647
protected TaskCompletionSource<bool> CompletableConfigManager = new TaskCompletionSource<bool>();
48+
private OptimizelyConfig CurrentOptimizelyConfig;
4749
// Variables to control blocking/syncing.
4850
public int resourceInUse = 0;
4951

@@ -145,6 +147,7 @@ public bool SetConfig(ProjectConfig projectConfig)
145147
return false;
146148

147149
CurrentProjectConfig = projectConfig;
150+
SetOptimizelyConfig(CurrentProjectConfig);
148151

149152
// SetResult raise exception if called again, that's why Try is used.
150153
CompletableConfigManager.TrySetResult(true);
@@ -154,7 +157,28 @@ public bool SetConfig(ProjectConfig projectConfig)
154157

155158
return true;
156159
}
157-
160+
161+
private void SetOptimizelyConfig(ProjectConfig projectConfig)
162+
{
163+
try
164+
{
165+
CurrentOptimizelyConfig = new OptimizelyConfigService(projectConfig).GetOptimizelyConfig();
166+
}
167+
catch (Exception ex)
168+
{
169+
Logger.Log(LogLevel.ERROR, ex.Message);
170+
}
171+
}
172+
173+
/// <summary>
174+
/// Returns the cached OptimizelyConfig object.
175+
/// </summary>
176+
/// <returns>OptimizelyConfig | cached OptimizelyConfig object</returns>
177+
public OptimizelyConfig GetOptimizelyConfig()
178+
{
179+
return CurrentOptimizelyConfig;
180+
}
181+
158182
public virtual void Dispose()
159183
{
160184
if (Disposed) return;

OptimizelySDK/Optimizely.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2019, Optimizely
2+
* Copyright 2017-2020, Optimizely
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use file except in compliance with the License.
@@ -739,6 +739,15 @@ public OptimizelyConfig GetOptimizelyConfig()
739739
return null;
740740
}
741741

742+
// PollingProjectConfigManager now also implements IOptimizelyConfigManager interface to support OptimizelyConfigService API.
743+
// This check is needed in case a consumer provides their own ProjectConfigManager which does not implement IOptimizelyConfigManager interface
744+
if (ProjectConfigManager is IOptimizelyConfigManager)
745+
{
746+
return ((IOptimizelyConfigManager) ProjectConfigManager).GetOptimizelyConfig();
747+
}
748+
749+
Logger.Log(LogLevel.DEBUG, "ProjectConfigManager is not instance of IOptimizelyConfigManager, generating new OptimizelyConfigObject as a fallback");
750+
742751
return new OptimizelyConfigService(config).GetOptimizelyConfig();
743752
}
744753

OptimizelySDK/OptimizelySDK.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
<Compile Include="Notifications\NotificationCenter.cs" />
114114
<Compile Include="Optimizely.cs" />
115115
<Compile Include="Bucketing\UserProfile.cs" />
116+
<Compile Include="OptlyConfig\IOptimizelyConfigManager.cs" />
116117
<Compile Include="OptlyConfig\OptimizelyConfig.cs" />
117118
<Compile Include="OptlyConfig\OptimizelyConfigService.cs" />
118119
<Compile Include="OptlyConfig\OptimizelyExperiment.cs" />
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Copyright 2020, Optimizely, Inc. and contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
namespace OptimizelySDK.OptlyConfig
18+
{
19+
public interface IOptimizelyConfigManager
20+
{
21+
/// <summary>
22+
/// Implementation of this method should return OptimizelyConfig
23+
/// </summary>
24+
/// <returns>OptimizelyConfig</returns>
25+
OptimizelyConfig GetOptimizelyConfig();
26+
}
27+
}

0 commit comments

Comments
 (0)