Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

Commit d132593

Browse files
abodalevskysergey-akhalkov
authored andcommitted
Windows: Implemented TelemetryManager (#812)
* Examples updated to RNW 0.43.0 * Initial implementation * interim commit * getUpdateReport - completed * getBinaryUpdateReport - completed * getRetryStatusReport - completed * getRollbackReport - completed * recordStatusReported - completed saveStatusReportForRetry - completed * Commented unused variables * Fixed telemetry report * Optimization: run telemetry in async mode * neat fixes * react-native-windows updated to 0.43.0-rc.0 * neat fix * added async to some ReactMEthod calls
1 parent 6a1d1ff commit d132593

File tree

10 files changed

+486
-13
lines changed

10 files changed

+486
-13
lines changed

windows/CodePush.Net46.Test/CodePush.Net46.Test.csproj

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@
7171
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
7272
</PropertyGroup>
7373
<ItemGroup>
74+
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
75+
<SpecificVersion>False</SpecificVersion>
76+
<HintPath>..\..\Examples\CodePushDemoApp\windows\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
77+
<Private>True</Private>
78+
</Reference>
7479
<Reference Include="System" />
7580
</ItemGroup>
7681
<Choose>
@@ -81,20 +86,27 @@
8186
</When>
8287
<Otherwise>
8388
<ItemGroup>
84-
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
89+
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework">
90+
<Private>False</Private>
91+
</Reference>
8592
</ItemGroup>
8693
</Otherwise>
8794
</Choose>
8895
<ItemGroup>
8996
<Compile Include="ApplicationDataContainerTest.cs" />
9097
<Compile Include="Properties\AssemblyInfo.cs" />
98+
<Compile Include="TelemetryManagerTest.cs" />
9199
</ItemGroup>
92100
<ItemGroup>
93101
<ProjectReference Include="..\CodePush.Net46\CodePush.Net46.csproj">
94102
<Project>{4dfe3f9f-5e15-4f17-8fd4-33ff0519348e}</Project>
95103
<Name>CodePush.Net46</Name>
96104
</ProjectReference>
97105
</ItemGroup>
106+
<ItemGroup>
107+
<None Include="app.config" />
108+
<None Include="packages.config" />
109+
</ItemGroup>
98110
<Choose>
99111
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
100112
<ItemGroup>
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using CodePush.ReactNative;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
using Newtonsoft.Json;
4+
using Newtonsoft.Json.Linq;
5+
6+
namespace CodePush.Net46.Test
7+
{
8+
/// <summary>
9+
/// Some tests for telemetry manager
10+
/// As implementation of TelemetryManager was ported from android version, we do not test logic here.
11+
/// Here are tests for some tricky parts of implementation, or check some data transformation that
12+
/// has no full equvalent in C#
13+
/// </summary>
14+
[TestClass]
15+
public class TelemetryManagerTest
16+
{
17+
#region Constants from TelemetryManager
18+
//private static readonly string APP_VERSION_KEY = "appVersion";
19+
private static readonly string DEPLOYMENT_FAILED_STATUS = "DeploymentFailed";
20+
private static readonly string DEPLOYMENT_KEY_KEY = "deploymentKey";
21+
private static readonly string DEPLOYMENT_SUCCEEDED_STATUS = "DeploymentSucceeded";
22+
private static readonly string LABEL_KEY = "label";
23+
private static readonly string LAST_DEPLOYMENT_REPORT_KEY = "CODE_PUSH_LAST_DEPLOYMENT_REPORT";
24+
//private static readonly string PACKAGE_KEY = "package";
25+
//private static readonly string PREVIOUS_DEPLOYMENT_KEY_KEY = "previousDeploymentKey";
26+
//private static readonly string PREVIOUS_LABEL_OR_APP_VERSION_KEY = "previousLabelOrAppVersion";
27+
private static readonly string RETRY_DEPLOYMENT_REPORT_KEY = "CODE_PUSH_RETRY_DEPLOYMENT_REPORT";
28+
private static readonly string STATUS_KEY = "status";
29+
#endregion
30+
31+
[TestMethod]
32+
public void TestGetUpdateReportNoPreviousUpdate()
33+
{
34+
var input = new JObject();
35+
input.Add(DEPLOYMENT_KEY_KEY, "depKeyParam");
36+
input.Add(LABEL_KEY, "labelParam");
37+
38+
var output = TelemetryManager.GetUpdateReport(input);
39+
Assert.IsNotNull(output);
40+
Assert.IsTrue(output.ToString(Formatting.None).Contains("\"status\":\"DeploymentSucceeded\""));
41+
}
42+
43+
[TestMethod]
44+
public void TestGetUpdateReportWithPreviousUpdate()
45+
{
46+
SettingsManager.SetString(LAST_DEPLOYMENT_REPORT_KEY, "prevKey:prevLabel");
47+
var input = new JObject();
48+
input.Add(DEPLOYMENT_KEY_KEY, "depKeyParam");
49+
input.Add(LABEL_KEY, "labelParam");
50+
51+
var output = TelemetryManager.GetUpdateReport(input);
52+
Assert.IsNotNull(output);
53+
Assert.IsTrue(output.ToString(Formatting.None).Contains("\"status\":\"DeploymentSucceeded\""));
54+
Assert.IsTrue(output.ToString(Formatting.None).Contains("\"previousDeploymentKey\":\"prevKey\",\"previousLabelOrAppVersion\":\"prevLabel\""));
55+
56+
//Clean Up
57+
SettingsManager.RemoveString(LAST_DEPLOYMENT_REPORT_KEY);
58+
}
59+
60+
[TestMethod]
61+
public void TestGetUpdateReportNegative()
62+
{
63+
var inputNoLabel = new JObject();
64+
inputNoLabel.Add(DEPLOYMENT_KEY_KEY, "depKeyParam");
65+
Assert.IsNull(TelemetryManager.GetUpdateReport(inputNoLabel));
66+
67+
var inputNoKey = new JObject();
68+
inputNoKey.Add(LABEL_KEY, "labelParam");
69+
Assert.IsNull(TelemetryManager.GetUpdateReport(inputNoKey));
70+
}
71+
72+
[TestMethod]
73+
public void TestRecordStatusReportWithRollback()
74+
{
75+
var report = new JObject();
76+
report.Add(STATUS_KEY, DEPLOYMENT_FAILED_STATUS);
77+
78+
TelemetryManager.RecordStatusReported(report);
79+
Assert.IsTrue(true);
80+
}
81+
82+
[TestMethod]
83+
public void TestRecordStatusReportWithoutRollback()
84+
{
85+
var reportSuccess = new JObject();
86+
reportSuccess.Add(STATUS_KEY, DEPLOYMENT_SUCCEEDED_STATUS);
87+
TelemetryManager.RecordStatusReported(reportSuccess);
88+
89+
var reportNoStatus = new JObject();
90+
TelemetryManager.RecordStatusReported(reportNoStatus);
91+
92+
Assert.IsTrue(true);
93+
}
94+
95+
[TestMethod]
96+
public void TestStatusReportForRetrySerialization()
97+
{
98+
SettingsManager.RemoveString(RETRY_DEPLOYMENT_REPORT_KEY);
99+
var original = new JObject();
100+
original.Add("keyString", "stringValue");
101+
original.Add("keyInt", 42);
102+
original.Add("keyBool", true);
103+
104+
TelemetryManager.SaveStatusReportForRetry(original);
105+
106+
var stringified = SettingsManager.GetString(RETRY_DEPLOYMENT_REPORT_KEY);
107+
SettingsManager.RemoveString(RETRY_DEPLOYMENT_REPORT_KEY);
108+
109+
Assert.IsNotNull(stringified);
110+
var result = JObject.Parse(stringified);
111+
112+
Assert.IsTrue((bool)result.GetValue("keyBool"));
113+
Assert.AreEqual(42, (int)result.GetValue("keyInt"));
114+
Assert.AreEqual("stringValue", (string)result.GetValue("keyString"));
115+
}
116+
}
117+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
<runtime>
4+
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
5+
<dependentAssembly>
6+
<assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" />
7+
<bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0" />
8+
</dependentAssembly>
9+
</assemblyBinding>
10+
</runtime>
11+
</configuration>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net46" />
4+
</packages>

windows/CodePush.Net46/UpdateManager.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
using System.Runtime.CompilerServices;
99
using System.Threading.Tasks;
1010

11-
12-
[assembly: InternalsVisibleTo("CodePush.Net46.UnitTest")]
13-
1411
namespace CodePush.ReactNative
1512
{
1613
internal class UpdateManager

windows/CodePush.Shared/CodePush.Shared.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<Compile Include="$(MSBuildThisFileDirectory)InstallMode.cs" />
1717
<Compile Include="$(MSBuildThisFileDirectory)MinimumBackgroundListener.cs" />
1818
<Compile Include="$(MSBuildThisFileDirectory)SettingsManager.cs" />
19+
<Compile Include="$(MSBuildThisFileDirectory)TelemetryManager.cs" />
1920
<Compile Include="$(MSBuildThisFileDirectory)UpdateState.cs" />
2021
</ItemGroup>
2122
</Project>

windows/CodePush.Shared/CodePushNativeModule.cs

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ internal class CodePushNativeModule : ReactContextNativeModuleBase
2121
private MinimumBackgroundListener _minimumBackgroundListener;
2222
private ReactContext _reactContext;
2323

24-
public CodePushNativeModule(ReactContext reactContext, CodePushReactPackage codePush) : base(reactContext)
24+
public CodePushNativeModule(ReactContext reactContext, CodePushReactPackage codePush)
25+
: base(reactContext)
2526
{
2627
_reactContext = reactContext;
2728
_codePush = codePush;
@@ -174,10 +175,60 @@ public async void getUpdateMetadata(UpdateState updateState, IPromise promise)
174175

175176

176177
[ReactMethod]
177-
public void getNewStatusReport(IPromise promise)
178+
public async void getNewStatusReport(IPromise promise)
178179
{
179-
// TODO implement this
180-
promise.Resolve("");
180+
await Task.Run(() =>
181+
{
182+
if (_codePush.NeedToReportRollback)
183+
{
184+
_codePush.NeedToReportRollback = false;
185+
186+
var failedUpdates = SettingsManager.GetFailedUpdates();
187+
if (failedUpdates != null && failedUpdates.Count > 0)
188+
{
189+
var lastFailedPackage = (JObject)failedUpdates[failedUpdates.Count - 1];
190+
var failedStatusReport = TelemetryManager.GetRollbackReport(lastFailedPackage);
191+
if (failedStatusReport != null)
192+
{
193+
promise.Resolve(failedStatusReport);
194+
return;
195+
}
196+
}
197+
}
198+
else if (_codePush.DidUpdate)
199+
{
200+
var currentPackage = _codePush.UpdateManager.GetCurrentPackageAsync().Result;
201+
if (currentPackage != null)
202+
{
203+
var newPackageStatusReport = TelemetryManager.GetUpdateReport(currentPackage);
204+
if (newPackageStatusReport != null)
205+
{
206+
promise.Resolve(newPackageStatusReport);
207+
return;
208+
}
209+
}
210+
}
211+
else if (_codePush.IsRunningBinaryVersion)
212+
{
213+
var newAppVersionStatusReport = TelemetryManager.GetBinaryUpdateReport(_codePush.AppVersion);
214+
if (newAppVersionStatusReport != null)
215+
{
216+
promise.Resolve(newAppVersionStatusReport);
217+
return;
218+
}
219+
}
220+
else
221+
{
222+
var retryStatusReport = TelemetryManager.GetRetryStatusReport();
223+
if (retryStatusReport != null)
224+
{
225+
promise.Resolve(retryStatusReport);
226+
return;
227+
}
228+
}
229+
230+
promise.Resolve("");
231+
}).ConfigureAwait(false);
181232
}
182233

183234
[ReactMethod]
@@ -245,6 +296,18 @@ public async void restartApp(bool onlyIfUpdateIsPending)
245296
}
246297
}
247298

299+
[ReactMethod]
300+
public async void recordStatusReported(JObject statusReport)
301+
{
302+
await Task.Run(() => TelemetryManager.RecordStatusReported(statusReport)).ConfigureAwait(false);
303+
}
304+
305+
[ReactMethod]
306+
public async void saveStatusReportForRetry(JObject statusReport)
307+
{
308+
await Task.Run(() => TelemetryManager.SaveStatusReportForRetry(statusReport)).ConfigureAwait(false);
309+
}
310+
248311
internal async Task LoadBundleAsync()
249312
{
250313
// #1) Get the private ReactInstanceManager, which is what includes

windows/CodePush.Shared/CodePushReactPackage.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ public sealed class CodePushReactPackage : IReactPackage
1717
internal string AppVersion { get; private set; }
1818
internal string DeploymentKey { get; private set; }
1919
internal string AssetsBundleFileName { get; private set; }
20-
internal bool DidUpdate { get; private set; }
21-
internal bool IsRunningBinaryVersion { get; set; }
20+
internal bool NeedToReportRollback { get; set; } = false;
21+
internal bool DidUpdate { get; private set; } = false;
22+
internal bool IsRunningBinaryVersion { get; private set; } = false;
2223
internal ReactPage MainPage { get; private set; }
2324
internal UpdateManager UpdateManager { get; private set; }
2425

@@ -28,9 +29,6 @@ public CodePushReactPackage(string deploymentKey, ReactPage mainPage)
2829
DeploymentKey = deploymentKey;
2930
MainPage = mainPage;
3031
UpdateManager = new UpdateManager();
31-
IsRunningBinaryVersion = false;
32-
// TODO implement telemetryManager
33-
// _codePushTelemetryManager = new CodePushTelemetryManager(this.applicationContext, CODE_PUSH_PREFERENCES);
3432

3533
if (CurrentInstance != null)
3634
{
@@ -129,6 +127,10 @@ public async Task<string> GetJavaScriptBundleFileAsync(string assetsBundleFileNa
129127

130128
internal void InitializeUpdateAfterRestart()
131129
{
130+
// Reset the state which indicates that
131+
// the app was just freshly updated.
132+
DidUpdate = false;
133+
132134
JObject pendingUpdate = SettingsManager.GetPendingUpdate();
133135
if (pendingUpdate != null)
134136
{
@@ -138,6 +140,7 @@ internal void InitializeUpdateAfterRestart()
138140
// Pending update was initialized, but notifyApplicationReady was not called.
139141
// Therefore, deduce that it is a broken update and rollback.
140142
CodePushUtils.Log("Update did not finish loading the last time, rolling back to a previous version.");
143+
NeedToReportRollback = true;
141144
RollbackPackageAsync().Wait();
142145
}
143146
else

windows/CodePush.Shared/SettingsManager.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,5 +129,20 @@ internal static void SavePendingUpdate(string packageHash, bool isLoading)
129129

130130
Settings.Values[CodePushConstants.PendingUpdateKey] = JsonConvert.SerializeObject(pendingUpdate);
131131
}
132+
133+
internal static void SetString(string key, string value)
134+
{
135+
Settings.Values[key] = value;
136+
}
137+
138+
internal static string GetString(string key)
139+
{
140+
return (string)Settings.Values[key];
141+
}
142+
143+
internal static void RemoveString(string key)
144+
{
145+
Settings.Values.Remove(key);
146+
}
132147
}
133148
}

0 commit comments

Comments
 (0)