Skip to content

Commit 3a350a5

Browse files
Merge pull request #28 from Learnosity/CAT-66/feature/add-telemetry
[FEATURE] Add telemetry CAT-66
2 parents e203a8b + 937adcc commit 3a350a5

File tree

2 files changed

+270
-12
lines changed

2 files changed

+270
-12
lines changed

LearnositySDK/Request/Init.cs

100755100644
Lines changed: 127 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Linq;
43
using System.Text;
54
using LearnositySDK.Utils;
65
using System.Web;
6+
using System.Runtime.InteropServices;
77

88
namespace LearnositySDK.Request
99
{
@@ -77,6 +77,11 @@ public class Init
7777
/// </summary>
7878
private string algorithm;
7979

80+
/// <summary>
81+
/// Determines if telemetry is enabled; default is true
82+
/// </summary>
83+
private static bool telemetryEnabled = true;
84+
8085
/// <summary>
8186
/// Instantiate this class with all security and request data. It will be used to create a signature.
8287
/// </summary>
@@ -153,6 +158,7 @@ private void Initialize(string service, JsonObject securityPacket, string secret
153158
//try
154159
//{
155160
this.validate(this.service, ref this.securityPacket, this.secret, this.requestPacket, this.action);
161+
this.addTelemetryData();
156162
this.requestString = this.generateRequestString();
157163
this.setServiceOptions();
158164
this.securityPacket.set("signature", this.generateSignature());
@@ -180,7 +186,7 @@ private string generateRequestString()
180186
{
181187
throw new Exception("Invalid data, please check you request packet.");
182188
}
183-
189+
184190
return request;
185191
}
186192

@@ -191,7 +197,7 @@ private string generateRequestString()
191197
/// - the `action` value if passed
192198
/// </summary>
193199
/// <returns>A signature hash for the request authentication</returns>
194-
private string generateSignature()
200+
public string generateSignature()
195201
{
196202
List<string> signatureList = new List<string>();
197203
string temp = null;
@@ -256,7 +262,7 @@ public string generate()
256262
{
257263
return this.generateData(output);
258264
}
259-
else if(this.service == "assess")
265+
else if (this.service == "assess")
260266
{
261267
output = this.generateAssess(output);
262268
}
@@ -277,7 +283,7 @@ public string generate()
277283
// do nothing
278284
break;
279285
}
280-
286+
281287
return output.toJson();
282288
}
283289

@@ -291,7 +297,7 @@ private string generateData(JsonObject output)
291297
StringBuilder sb = new StringBuilder();
292298
JsonObject obj = null;
293299
string str = "";
294-
300+
295301
obj = output.getJsonObject("security");
296302
if (!Tools.empty(obj))
297303
{
@@ -380,7 +386,7 @@ private void setServiceOptions()
380386
case "assess":
381387
// fall-through
382388
case "questions":
383-
389+
384390
this.signRequestData = false;
385391

386392
if (this.service == "assess" && Tools.array_key_exists("questionsApiActivity", this.requestPacket))
@@ -456,18 +462,21 @@ private void setServiceOptions()
456462
this.signRequestData = false;
457463

458464
JsonObject requestPackageUsers = this.requestPacket.getJsonObject("users");
459-
if (requestPackageUsers != null) {
460-
string[] users = requestPackageUsers.getValuesArray();
461-
if (users != null && users.Length > 0) {
465+
if (requestPackageUsers != null)
466+
{
467+
string[] users = requestPackageUsers.getValuesArray();
468+
if (users != null && users.Length > 0)
469+
{
462470
hashedUsers = new JsonObject();
463-
for (int i = 0; i < users.Length; i++) {
471+
for (int i = 0; i < users.Length; i++)
472+
{
464473
string user_id = users[i];
465474
hashedUsers.set(user_id, Tools.hash(this.algorithm, user_id + this.secret));
466475
}
467476
this.requestPacket.set("users", hashedUsers);
468477
}
469478
}
470-
479+
471480
break;
472481
default:
473482
// do nothing
@@ -518,5 +527,111 @@ public void validate(string service, ref JsonObject securityPacket, string secre
518527
throw new Exception("The `secret` argument must be a valid string");
519528
}
520529
}
530+
531+
/// <summary>
532+
/// Adds a meta field with SDK information in it to the requestPacket
533+
/// </summary>
534+
public void addTelemetryData()
535+
{
536+
if (this.isTelemetryEnabled())
537+
{
538+
JsonObject meta;
539+
if (this.requestPacket.getJsonObject("meta") != null)
540+
{
541+
meta = this.requestPacket.getJsonObject("meta");
542+
}
543+
else
544+
{
545+
meta = new JsonObject();
546+
}
547+
548+
meta.set("sdk", this.getSdkMeta());
549+
this.requestPacket.set("meta", meta);
550+
}
551+
}
552+
553+
public bool isTelemetryEnabled()
554+
{
555+
return telemetryEnabled;
556+
}
557+
558+
public JsonObject getSdkMeta()
559+
{
560+
JsonObject sdkMeta = new JsonObject();
561+
sdkMeta.set("version", this.getSdkVersion());
562+
sdkMeta.set("lang", "asp.net");
563+
sdkMeta.set("lang_version", this.getLanguageVersion());
564+
sdkMeta.set("platform", this.getPlatform());
565+
sdkMeta.set("platform_version", this.getPlatformVersion());
566+
567+
return sdkMeta;
568+
}
569+
570+
/// <summary>
571+
/// Returns the version number of ASP.NET
572+
/// </summary>
573+
/// <returns></returns>
574+
public string getLanguageVersion()
575+
{
576+
return Environment.Version.ToString();
577+
}
578+
579+
/// <summary>
580+
/// Returns the name of the platform the code is running on
581+
/// </summary>
582+
/// <returns></returns>
583+
public string getPlatform()
584+
{
585+
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
586+
{
587+
return "darwin";
588+
}
589+
590+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
591+
{
592+
return "win";
593+
}
594+
595+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
596+
{
597+
return "linux";
598+
}
599+
600+
return Environment.OSVersion.Platform.ToString();
601+
}
602+
603+
/// <summary>
604+
/// Returns the version number of the platform the code is running on
605+
/// </summary>
606+
/// <returns></returns>
607+
public string getPlatformVersion()
608+
{
609+
var os = Environment.OSVersion;
610+
return string.Concat(os.Version.Major, '.', os.Version.Minor);
611+
}
612+
613+
/// <summary>
614+
/// Extracts the version number of this SDK from the project meta data
615+
/// </summary>
616+
/// <returns>The version number</returns>
617+
public string getSdkVersion()
618+
{
619+
return GetType().Assembly.GetName().Version.ToString();
620+
}
621+
622+
/// <summary>
623+
/// We use telemetry to enable better support and feature planning.
624+
/// It will not interfere with any usage.
625+
/// However, it is not advised to disable it.
626+
/// </summary>
627+
public static void disableTelemetry()
628+
{
629+
telemetryEnabled = false;
630+
}
631+
632+
public static void enableTelemetry()
633+
{
634+
telemetryEnabled = true;
635+
}
521636
}
522637
}

LearnositySDKIntegrationTests/LearnositySDKIntegrationTests.cs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using Xunit;
3+
using System.IO;
34
using LearnositySDK.Utils;
45
using LearnositySDK.Request;
56

@@ -69,5 +70,147 @@ private static string BuildDataAPIBaseUrl(string env, string region, string vers
6970

7071
return "https://data" + regionDomain + envDomain + ".learnosity.com/" + versionPath;
7172
}
73+
74+
[Fact]
75+
public void InitGeneratesExactSameSignature()
76+
{
77+
string action = "get";
78+
79+
JsonObject security = this.generateSecurityObject();
80+
81+
JsonObject request = new JsonObject();
82+
request.set("limit", 100);
83+
84+
Init.disableTelemetry();
85+
Init init = new Init("data", security, this.consumerSecret, request, action);
86+
87+
// Assert signature is still the same
88+
Assert.Equal(
89+
init.generateSignature(),
90+
"e1eae0b86148df69173cb3b824275ea73c9c93967f7d17d6957fcdd299c8a4fe"
91+
);
92+
93+
// Assert telemetry is turned off
94+
Assert.False(init.isTelemetryEnabled());
95+
Init.enableTelemetry();
96+
}
97+
98+
[Fact]
99+
public void InitGenerateBuildsNonEmptyRequest()
100+
{
101+
string action = "get";
102+
103+
JsonObject security = this.generateSecurityObject();
104+
105+
JsonObject request = new JsonObject();
106+
request.set("page", 1);
107+
108+
Init init = new Init("data", security, this.consumerSecret, request, action);
109+
string generatedString = init.generate();
110+
111+
// Assert generated string is not empty
112+
Assert.NotEmpty(generatedString);
113+
114+
// Assert telemetry is turned on
115+
Assert.True(init.isTelemetryEnabled());
116+
}
117+
118+
[Fact]
119+
public void EnabledTelemetryAddsSdkField()
120+
{
121+
string action = "get";
122+
JsonObject security = this.generateSecurityObject();
123+
124+
JsonObject request = new JsonObject();
125+
request.set("page", 1);
126+
127+
Init init = new Init("data", security, this.consumerSecret, request, action);
128+
string generatedString = init.generate();
129+
130+
Assert.Contains("meta", generatedString);
131+
Assert.Contains("sdk", generatedString);
132+
}
133+
134+
[Fact]
135+
public void EnabledTelemetryPreservesOtherMetaProps()
136+
{
137+
string action = "get";
138+
JsonObject security = this.generateSecurityObject();
139+
140+
JsonObject metaField = new JsonObject();
141+
metaField.set("test_key_string", "test-string");
142+
metaField.set("test_key_integer", 12345);
143+
144+
JsonObject request = new JsonObject();
145+
request.set("page", 1);
146+
request.set("meta", metaField);
147+
148+
Init init = new Init("data", security, this.consumerSecret, request, action);
149+
string generatedString = init.generate();
150+
151+
Assert.Contains("meta", generatedString);
152+
Assert.Contains("sdk", generatedString);
153+
Assert.Contains("test_key_string", generatedString);
154+
Assert.Contains("test_key_integer", generatedString);
155+
}
156+
157+
[Fact]
158+
public void DisabledTelemetryPreservesEmptyProps()
159+
{
160+
string action = "get";
161+
JsonObject security = this.generateSecurityObject();
162+
163+
Init.disableTelemetry();
164+
165+
JsonObject request = new JsonObject();
166+
request.set("page", 1);
167+
168+
Init init = new Init("data", security, this.consumerSecret, request, action);
169+
string generatedString = init.generate();
170+
171+
Assert.DoesNotContain("meta", generatedString);
172+
Assert.DoesNotContain("sdk", generatedString);
173+
174+
Init.enableTelemetry();
175+
}
176+
177+
[Fact]
178+
public void DisabledTelemetryPreservesFilledProps()
179+
{
180+
string action = "get";
181+
JsonObject security = this.generateSecurityObject();
182+
183+
Init.disableTelemetry();
184+
185+
JsonObject metaField = new JsonObject();
186+
metaField.set("test_key_string", "test-string");
187+
metaField.set("test_key_integer", 12345);
188+
189+
JsonObject request = new JsonObject();
190+
request.set("page", 1);
191+
request.set("meta", metaField);
192+
193+
Init init = new Init("data", security, this.consumerSecret, request, action);
194+
string generatedString = init.generate();
195+
196+
Assert.Contains("meta", generatedString);
197+
Assert.DoesNotContain("sdk", generatedString);
198+
Assert.Contains("test_key_string", generatedString);
199+
Assert.Contains("test_key_integer", generatedString);
200+
201+
Init.enableTelemetry();
202+
}
203+
204+
private JsonObject generateSecurityObject()
205+
{
206+
string timestamp = "20140626-0528";
207+
208+
JsonObject security = new JsonObject();
209+
security.set("consumer_key", this.consumerKey);
210+
security.set("domain", this.domain);
211+
security.set("timestamp", timestamp);
212+
213+
return security;
214+
}
72215
}
73216
}

0 commit comments

Comments
 (0)