diff --git a/README.md b/README.md index cddbb79..44a7449 100644 --- a/README.md +++ b/README.md @@ -142,11 +142,11 @@ The first section of code discussed is (`ItemsApp.java`) and this is executed se ### **Server-side code** -Starting with `ItemsApp.java`, we start by including some LearnositySDK helpers - they'll make it easy to generate and sign the config options. We also include the standard UUID library for generating unique user and session IDs. +Starting with `ItemsApp.java`, we start by including some LearnositySDK helpers - they'll make it easy to generate and sign the config options, and to generate unique user and session IDs. ``` Java import learnositysdk.request.Init; -import java.util.UUID; +import learnositysdk.request.Uuid; ``` Now we'll declare the configuration options for Items API. These specify which assessment content should be rendered, how it should be displayed, which user is taking this assessment and how their responses should be stored. @@ -168,7 +168,7 @@ private Map createRequestObject() { * `user_id`: unique student identifier. Note: we never send or save student's names or other personally identifiable information in these requests. The unique identifier should be used to look up the entry in a database of students accessible within your system only. [Learn more](https://help.learnosity.com/hc/en-us/articles/360002309578-Student-Privacy-and-Personally-Identifiable-Information-PII-). * `activity_template_id`: reference of the Activity to retrieve from the Item bank. The Activity defines which Items will be served in this assessment. -* `session_id`: uniquely identifies this specific assessment attempt for save/resume, data retrieval and reporting purposes. Here, we're using the `UUID` library to auto-generate a unique session id. +* `session_id`: uniquely identifies this specific assessment attempt for save/resume, data retrieval and reporting purposes. Here, we're using the `Uuid.generate()` utility to auto-generate a unique session id. * `activity_id`: a string you define, used solely for analytics to allow you run reporting and compare results of users submitting the same assessment. * `rendering_type`: selects a rendering mode, `assess` mode is a "standalone" mode (loading a complete assessment player for navigation, as opposed to `inline` for embedding without). * `type`: selects the context for the student response storage. `submit_practice` mode means the student responses will be stored in the Learnosity cloud, allowing for grading and review. diff --git a/REFERENCE.md b/REFERENCE.md index e525a14..4a03887 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -203,6 +203,34 @@ An optional string used only if integrating with the Data API. Valid options are
+### Uuid + +The Uuid utility class provides a simple way to generate UUIDv4 identifiers, commonly used for `user_id` and `session_id` in Learnosity API requests. + +This utility provides a consistent API across Learnosity SDKs, allowing developers to use the same patterns regardless of language. + +```java +import learnositysdk.request.Uuid; + +// Generate a unique user ID +String userId = Uuid.generate(); + +// Generate a unique session ID +String sessionId = Uuid.generate(); +``` + +#### Methods + +**generate()**
+Returns a UUIDv4 string in the format `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`. + +```java +String uuid = Uuid.generate(); +// Example output: "550e8400-e29b-41d4-a716-446655440000" +``` + +
+ ### Remote The Remote class is used to make server side, cross domain requests. Think of it as a cURL wrapper. diff --git a/docs/quickstart/assessment/src/main/java/com/learnosity/quickstart/App.java b/docs/quickstart/assessment/src/main/java/com/learnosity/quickstart/App.java index 0329476..5e7c781 100644 --- a/docs/quickstart/assessment/src/main/java/com/learnosity/quickstart/App.java +++ b/docs/quickstart/assessment/src/main/java/com/learnosity/quickstart/App.java @@ -1,18 +1,18 @@ package com.learnosity.quickstart; import learnositysdk.request.Init; +import learnositysdk.request.Uuid; import java.io.InputStream; import java.io.IOException; import java.util.Map; import java.util.Properties; -import java.util.UUID; import org.json.JSONObject; public abstract class App { Properties config = new Properties(); - UUID user_id = UUID.randomUUID(); - UUID session_id = UUID.randomUUID(); + String user_id = Uuid.generate(); + String session_id = Uuid.generate(); String domain; String put; diff --git a/src/main/java/learnositysdk/request/Uuid.java b/src/main/java/learnositysdk/request/Uuid.java new file mode 100644 index 0000000..ef3f245 --- /dev/null +++ b/src/main/java/learnositysdk/request/Uuid.java @@ -0,0 +1,32 @@ +package learnositysdk.request; + +/** + * UUID utility for generating UUIDv4 identifiers. + * Commonly used for user_id and session_id in Learnosity API requests. + * + * This utility provides a consistent API across Learnosity SDKs, + * allowing developers to use the same patterns regardless of language. + * + * Example usage: + *
+ * import learnositysdk.request.Uuid;
+ * 
+ * String userId = Uuid.generate();
+ * String sessionId = Uuid.generate();
+ * 
+ */ +public class Uuid { + + /** + * Generate a UUIDv4 string. + * + * This method wraps java.util.UUID.randomUUID() to provide a consistent + * API across Learnosity SDKs. + * + * @return A UUIDv4 string in the format xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx + */ + public static String generate() { + return java.util.UUID.randomUUID().toString(); + } +} + diff --git a/src/test/java/learnositysdk/request/DataApiIT.java b/src/test/java/learnositysdk/request/DataApiIT.java index 9e901ee..188bbda 100644 --- a/src/test/java/learnositysdk/request/DataApiIT.java +++ b/src/test/java/learnositysdk/request/DataApiIT.java @@ -4,7 +4,6 @@ import java.nio.charset.StandardCharsets; -import java.util.UUID; import java.util.HashMap; import java.util.Map; @@ -70,7 +69,7 @@ public void testGetActivitites() activity.put("status","published"); activity.put("description","My test description Title √"); activity.put("data", data); - activity.put("reference", UUID.randomUUID().toString()); + activity.put("reference", Uuid.generate()); JSONArray activities = new JSONArray(); activities.put(activity); diff --git a/src/test/java/learnositysdk/request/UuidTest.java b/src/test/java/learnositysdk/request/UuidTest.java new file mode 100644 index 0000000..4706d60 --- /dev/null +++ b/src/test/java/learnositysdk/request/UuidTest.java @@ -0,0 +1,116 @@ +package learnositysdk.request; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * Unit tests for the Uuid utility class. + */ +public class UuidTest { + + // UUIDv4 format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx + // where y is one of [8, 9, a, b] + private static final Pattern UUID_V4_PATTERN = Pattern.compile( + "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", + Pattern.CASE_INSENSITIVE + ); + + @Test + public void testGenerateReturnsString() { + System.out.println("Uuid: Generate returns String"); + + String uuid = Uuid.generate(); + + assertNotNull(uuid, "Generated UUID should not be null"); + assertTrue(uuid instanceof String, "Generated UUID should be a String"); + } + + @Test + public void testGenerateReturnsValidUuidV4Format() { + System.out.println("Uuid: Generate returns valid UUIDv4 format"); + + String uuid = Uuid.generate(); + + assertEquals(36, uuid.length(), "UUID should be 36 characters long"); + assertTrue(UUID_V4_PATTERN.matcher(uuid).matches(), + "UUID should match UUIDv4 format: " + uuid); + } + + @Test + public void testGenerateReturnsUniqueValues() { + System.out.println("Uuid: Generate returns unique values"); + + String uuid1 = Uuid.generate(); + String uuid2 = Uuid.generate(); + + assertNotEquals(uuid1, uuid2, "Two generated UUIDs should be different"); + } + + @Test + public void testGenerateMultipleUniqueValues() { + System.out.println("Uuid: Generate 1000 unique UUIDs"); + + Set uuids = new HashSet<>(); + int count = 1000; + + for (int i = 0; i < count; i++) { + uuids.add(Uuid.generate()); + } + + assertEquals(count, uuids.size(), + "All " + count + " generated UUIDs should be unique"); + } + + @Test + public void testGenerateConsistentFormat() { + System.out.println("Uuid: Generate consistent format across multiple calls"); + + for (int i = 0; i < 100; i++) { + String uuid = Uuid.generate(); + assertTrue(UUID_V4_PATTERN.matcher(uuid).matches(), + "UUID should consistently match UUIDv4 format: " + uuid); + } + } + + @Test + public void testGenerateContainsHyphens() { + System.out.println("Uuid: Generate contains hyphens in correct positions"); + + String uuid = Uuid.generate(); + + assertEquals('-', uuid.charAt(8), "UUID should have hyphen at position 8"); + assertEquals('-', uuid.charAt(13), "UUID should have hyphen at position 13"); + assertEquals('-', uuid.charAt(18), "UUID should have hyphen at position 18"); + assertEquals('-', uuid.charAt(23), "UUID should have hyphen at position 23"); + } + + @Test + public void testGenerateVersion4Indicator() { + System.out.println("Uuid: Generate has version 4 indicator"); + + String uuid = Uuid.generate(); + + // The 15th character (index 14) should be '4' for UUIDv4 + assertEquals('4', uuid.charAt(14), + "UUID should have '4' at position 14 (version indicator)"); + } + + @Test + public void testGenerateVariantIndicator() { + System.out.println("Uuid: Generate has correct variant indicator"); + + String uuid = Uuid.generate(); + + // The 20th character (index 19) should be 8, 9, a, or b + char variantChar = uuid.charAt(19); + assertTrue(variantChar == '8' || variantChar == '9' || + variantChar == 'a' || variantChar == 'b' || + variantChar == 'A' || variantChar == 'B', + "UUID should have variant indicator (8, 9, a, or b) at position 19, got: " + variantChar); + } +} +