Skip to content

[ECO-5338] Liveobjects: Setup tests #1092

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

sacOO7
Copy link
Collaborator

@sacOO7 sacOO7 commented May 28, 2025

Fixed #1089

  1. Added test specific dependencies, updated junit, added mockk
  2. Added test utils for mocking private classes, fields etc

Summary by CodeRabbit

  • New Features

    • Introduced integration and unit tests for Live Objects, including new test base classes and utilities for easier testing.
    • Added utility functions and enums for consistent error handling and status codes.
    • Enhanced test configuration with custom test tasks for running unit and integration tests separately.
    • Added sandbox environment setup and connection management utilities to support robust integration testing.
  • Bug Fixes

    • Improved test task setup to prevent duplicate test runs during release builds.
  • Chores

    • Upgraded and added dependencies for testing, including JUnit, MockK, and Ktor.
    • Updated continuous integration workflows to run new test tasks and improved test coverage.
  • Refactor

    • Simplified and streamlined the construction and initialization of core classes related to Live Objects.

1. Added test specific dependencies, updated junit, added mockk
2. Added test utils for mocking private classes, fields etc
Copy link

coderabbitai bot commented May 28, 2025

Walkthrough

This change introduces a comprehensive test setup for LiveObjects, including new unit and integration tests, supporting test utilities, and Gradle task configuration. It also updates dependency versions and refactors how the LiveObjectsPlugin is accessed in the main library, removing it from several constructors and making it publicly accessible via AblyRealtime.

Changes

File(s) Change Summary
.github/workflows/check.yml, .github/workflows/integration-test.yml Modified CI workflows to add new Gradle tasks for running LiveObject unit and integration tests.
gradle/libs.versions.toml Upgraded JUnit version, added MockK and Ktor dependencies, and introduced a kotlin-tests bundle for test dependencies.
lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java, lib/src/main/java/io/ably/lib/realtime/Connection.java, lib/src/main/java/io/ably/lib/transport/ConnectionManager.java Refactored to remove LiveObjectsPlugin from constructors, made liveObjectsPlugin public in AblyRealtime, and updated plugin access patterns.
lib/src/test/java/io/ably/lib/test/realtime/ConnectionManagerTest.java Updated test to match new ConnectionManager constructor signature.
live-objects/build.gradle.kts Enhanced test configuration, added custom test tasks for unit and integration tests, and improved test filtering and JVM args.
live-objects/src/main/kotlin/io/ably/lib/objects/ErrorCodes.kt Added internal enums for error and HTTP status codes.
live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt Introduced utility functions for consistent AblyException creation and error handling.
live-objects/src/test/kotlin/io/ably/lib/objects/TestUtils.kt Added reflection and coroutine utilities for testing private members and async code.
live-objects/src/test/kotlin/io/ably/lib/objects/integration/LiveObjectTest.kt Added integration test verifying the objects getter on a realtime channel.
live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt Added a parameterized integration test base class for multi-protocol testing, with client/channel lifecycle management.
live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/Sandbox.kt Introduced a sandbox environment utility for integration tests, including HTTP client with retry and Ably client/channel helpers.
live-objects/src/test/kotlin/io/ably/lib/objects/unit/LiveObjectTest.kt Added unit test verifying the objects getter on a mock channel.
live-objects/src/test/kotlin/io/ably/lib/objects/unit/setup/UnitTest.kt Added a unit test base class with helpers for creating and mocking realtime channels and managing test clients.

Sequence Diagram(s)

sequenceDiagram
    participant CI as GitHub Actions
    participant Gradle
    participant Tests as Test Suite

    CI->>Gradle: Run check (includes runLiveObjectUnitTests)
    Gradle->>Tests: Execute unit tests (filtered by package)
    Tests-->>Gradle: Report results
    Gradle-->>CI: Return check status

    CI->>Gradle: Run check-liveobjects (runLiveObjectIntegrationTests)
    Gradle->>Tests: Execute integration tests (filtered by package)
    Tests-->>Gradle: Report results
    Gradle-->>CI: Return integration test status
Loading

Assessment against linked issues

Objective Addressed Explanation
Setup LiveObjects unit and integration test infrastructure (#1089, ECO-5338)
Provide test utilities for LiveObjects (mocking, reflection, coroutine helpers) (#1089, ECO-5338)
Add and configure Gradle tasks and CI for LiveObjects tests (#1089, ECO-5338)
Refactor core library to support LiveObjects testability (#1089, ECO-5338)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Possibly related PRs

  • Setup : LiveObject plugin #1085: Refactors and reverses the integration of LiveObjectsPlugin in the same classes, indicating a direct code-level relationship.

Suggested reviewers

  • ttypic

Poem

In the warren of code, new tests now appear,
LiveObjects leap forward, their purpose is clear!
With helpers and sandboxes, they hop and they bound,
Ensuring our channels are robust and sound.
CI runs swiftly, the carrots are sweet—
For every green checkmark, a rabbit’s delight is complete!
🥕


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 37eedc2 and 5d3316f.

📒 Files selected for processing (3)
  • gradle/libs.versions.toml (3 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/TestUtils.kt (1 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/setup/UnitTest.kt (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • live-objects/src/test/kotlin/io/ably/lib/objects/TestUtils.kt
🚧 Files skipped from review as they are similar to previous changes (2)
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/setup/UnitTest.kt
  • gradle/libs.versions.toml
⏰ Context from checks skipped due to timeout of 90000ms (11)
  • GitHub Check: check (29)
  • GitHub Check: check (21)
  • GitHub Check: check (19)
  • GitHub Check: check (24)
  • GitHub Check: check-liveobjects
  • GitHub Check: check-realtime-okhttp
  • GitHub Check: check-rest-okhttp
  • GitHub Check: check-rest
  • GitHub Check: check-realtime
  • GitHub Check: check
  • GitHub Check: build
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot temporarily deployed to staging/pull/1092/features May 28, 2025 12:10 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1092/javadoc May 28, 2025 12:16 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1092/features May 29, 2025 12:25 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1092/javadoc May 29, 2025 12:30 Inactive
1. Updated separate gradlew task for both unit and integration tests
2. Updated check.yml and integration-test.yml file to run respective tests
@sacOO7 sacOO7 force-pushed the chore/setup-liveobjects-tests branch from c605937 to 0b44a36 Compare May 29, 2025 12:43
@github-actions github-actions bot temporarily deployed to staging/pull/1092/features May 29, 2025 12:45 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1092/javadoc May 29, 2025 12:51 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1092/features May 30, 2025 13:03 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1092/javadoc May 30, 2025 13:09 Inactive
@sacOO7 sacOO7 force-pushed the chore/setup-liveobjects-tests branch from f48c58b to 2e3a11e Compare May 30, 2025 13:36
@github-actions github-actions bot temporarily deployed to staging/pull/1092/features May 30, 2025 13:37 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1092/javadoc May 30, 2025 13:43 Inactive
@sacOO7 sacOO7 force-pushed the chore/setup-liveobjects-tests branch from 2e3a11e to 911f57e Compare May 30, 2025 13:57
@github-actions github-actions bot temporarily deployed to staging/pull/1092/features May 30, 2025 13:58 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1092/javadoc May 30, 2025 14:04 Inactive
@sacOO7 sacOO7 force-pushed the chore/setup-liveobjects-tests branch from 911f57e to 98bbb2a Compare May 30, 2025 14:06
@github-actions github-actions bot temporarily deployed to staging/pull/1092/features May 30, 2025 14:07 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1092/javadoc May 30, 2025 14:13 Inactive
@sacOO7 sacOO7 force-pushed the chore/setup-liveobjects-tests branch from 98bbb2a to 08b8e76 Compare May 30, 2025 14:15
@github-actions github-actions bot temporarily deployed to staging/pull/1092/features May 30, 2025 14:16 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1092/javadoc May 30, 2025 14:23 Inactive
1. Added ktor http dependencies and updated kotlin tests bundle
2. Added IntegrationTest parameterized class to run tests for both msgpack and json
3. Updated LiveObjectTest extending IntegrationTest class
@sacOO7 sacOO7 force-pushed the chore/setup-liveobjects-tests branch from 08b8e76 to af9deda Compare May 30, 2025 14:31
@github-actions github-actions bot temporarily deployed to staging/pull/1092/features May 30, 2025 14:32 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1092/javadoc May 30, 2025 14:38 Inactive
1. Updated LiveObjectTest to extend UnitTest class
2. Marked test utility methods as internal
@sacOO7 sacOO7 force-pushed the chore/setup-liveobjects-tests branch from 25bce5e to 1adf275 Compare June 2, 2025 12:25
@sacOO7 sacOO7 marked this pull request as ready for review June 2, 2025 12:25
@github-actions github-actions bot temporarily deployed to staging/pull/1092/features June 2, 2025 12:26 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1092/javadoc June 2, 2025 12:32 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (4)
live-objects/src/test/kotlin/io/ably/lib/objects/unit/setup/UnitTest.kt (1)

23-28: Improve API key configuration for security and maintainability.

The hardcoded API key "keyName:Value" should be externalized to avoid potential security issues and improve maintainability.

Consider using a test-specific constant or configuration:

+  companion object {
+    private const val TEST_API_KEY = "test:key"
+  }
+
   private val realtimeClients = mutableMapOf<String, AblyRealtime>()
   internal fun getMockRealtimeChannel(channelName: String, clientId: String = "client1"): Channel {
     val client = realtimeClients.getOrPut(clientId) {
       AblyRealtime(ClientOptions().apply {
         autoConnect = false
-        key = "keyName:Value"
+        key = TEST_API_KEY
         this.clientId = clientId
       })
     }
live-objects/src/test/kotlin/io/ably/lib/objects/TestUtils.kt (2)

10-19: Improve assertWaiter flexibility and error handling.

The assertWaiter function is useful for async testing, but has some limitations:

Consider these improvements:

-suspend fun assertWaiter(timeoutInMs: Long = 10_000, block: suspend () -> Boolean) {
+suspend fun assertWaiter(
+    timeoutInMs: Long = 10_000, 
+    intervalMs: Long = 100,
+    message: String = "Assertion failed within timeout",
+    block: suspend () -> Boolean
+) {
     withContext(Dispatchers.Default) {
-        withTimeout(timeoutInMs) {
+        try {
+            withTimeout(timeoutInMs) {
                 do {
                     val success = block()
-                    delay(100)
+                    if (!success) delay(intervalMs)
                 } while (!success)
             }
+        } catch (e: TimeoutCancellationException) {
+            throw AssertionError(message, e)
+        }
     }
 }

This adds configurable intervals, better error messages, and proper timeout handling.


34-46: Improve field traversal error handling.

The field traversal logic is good but the error handling could be more informative:

 private fun Class<*>.findField(name: String): Field {
     var result = kotlin.runCatching { getDeclaredField(name) }
     var currentClass = this
     while (result.isFailure && currentClass.superclass != null) {
         currentClass = currentClass.superclass!!
         result = kotlin.runCatching { currentClass.getDeclaredField(name) }
     }
-    if (result.isFailure) {
-        throw result.exceptionOrNull() as Exception
-    }
-    return result.getOrNull() as Field
+    return result.getOrElse { 
+        throw NoSuchFieldException("Field '$name' not found in class hierarchy of ${this.simpleName}")
+    }
 }
live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt (1)

87-92: Remove the empty tearDownAfterClass method.

The empty tearDownAfterClass() method serves no purpose and should be removed to clean up the code.

-    @JvmStatic
-    @AfterClass
-    @Throws(Exception::class)
-    fun tearDownAfterClass() {
-    }
🧰 Tools
🪛 detekt (1.23.8)

[warning] 90-91: This empty block of code can be removed.

(detekt.empty-blocks.EmptyFunctionBlock)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ac0ece7 and 1adf275.

📒 Files selected for processing (16)
  • .github/workflows/check.yml (1 hunks)
  • .github/workflows/integration-test.yml (1 hunks)
  • gradle/libs.versions.toml (3 hunks)
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (3 hunks)
  • lib/src/main/java/io/ably/lib/realtime/Connection.java (1 hunks)
  • lib/src/main/java/io/ably/lib/transport/ConnectionManager.java (2 hunks)
  • lib/src/test/java/io/ably/lib/test/realtime/ConnectionManagerTest.java (1 hunks)
  • live-objects/build.gradle.kts (2 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/ErrorCodes.kt (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt (1 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/TestUtils.kt (1 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/LiveObjectTest.kt (1 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt (1 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/Sandbox.kt (1 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/LiveObjectTest.kt (1 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/setup/UnitTest.kt (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
live-objects/src/test/kotlin/io/ably/lib/objects/unit/LiveObjectTest.kt (1)
live-objects/src/test/kotlin/io/ably/lib/objects/unit/setup/UnitTest.kt (1)
  • getMockRealtimeChannel (21-43)
live-objects/src/test/kotlin/io/ably/lib/objects/integration/LiveObjectTest.kt (1)
live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt (2)
  • generateChannelName (53-55)
  • getRealtimeChannel (36-47)
live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt (1)
live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/Sandbox.kt (2)
  • ensureConnected (74-90)
  • ensureAttached (92-107)
live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt (1)
lib/src/main/java/io/ably/lib/types/ErrorInfo.java (1)
  • ErrorInfo (17-197)
🪛 detekt (1.23.8)
live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt

[warning] 90-91: This empty block of code can be removed.

(detekt.empty-blocks.EmptyFunctionBlock)

⏰ Context from checks skipped due to timeout of 90000ms (9)
  • GitHub Check: check-realtime-okhttp
  • GitHub Check: check-liveobjects
  • GitHub Check: check-rest-okhttp
  • GitHub Check: check-rest
  • GitHub Check: check-realtime
  • GitHub Check: check (19)
  • GitHub Check: check (24)
  • GitHub Check: check (29)
  • GitHub Check: check (21)
🔇 Additional comments (33)
live-objects/src/main/kotlin/io/ably/lib/objects/ErrorCodes.kt (1)

1-12: LGTM! Clean error code definitions.

The enum implementations follow Kotlin best practices with appropriate internal visibility, clear naming, and readable numeric formatting using underscores for large numbers. The error code values align well with standard HTTP and application-level error conventions.

.github/workflows/check.yml (1)

22-22: Good integration of live object unit tests into CI.

The addition of runLiveObjectUnitTests to the Gradle command properly integrates the new unit tests into the main check workflow, ensuring they run on every PR and push to main.

lib/src/test/java/io/ably/lib/test/realtime/ConnectionManagerTest.java (1)

140-140: Correct constructor update for refactored ConnectionManager.

This change appropriately removes the LiveObjectsPlugin parameter from the ConnectionManager constructor call, aligning with the broader refactoring mentioned in the PR summary where LiveObjectsPlugin access was moved to be available via AblyRealtime instead of being passed to individual constructors.

.github/workflows/integration-test.yml (1)

94-110: Excellent addition of live object integration tests to CI.

The new check-liveobjects job follows the established workflow pattern perfectly, using consistent JDK version (17), distribution (temurin), and setup steps. This properly separates integration tests from unit tests and ensures comprehensive CI coverage for the live objects module.

live-objects/src/test/kotlin/io/ably/lib/objects/integration/LiveObjectTest.kt (1)

8-17: Well-structured integration test for live objects setup.

This integration test follows good practices:

  • Properly extends the IntegrationTest base class
  • Uses runTest for coroutine-based testing
  • Leverages helper methods (generateChannelName(), getRealtimeChannel()) from the base class
  • Has a focused scope - verifying the objects property is accessible on channels
  • Uses appropriate assertions with assertNotNull

The test is simple but effective for validating the basic live objects integration in a real environment.

lib/src/main/java/io/ably/lib/realtime/Connection.java (1)

125-128: LGTM! Clean refactoring of plugin dependency management.

The removal of LiveObjectsPlugin from the constructor parameters simplifies the Connection class and aligns with the broader refactoring to centralize plugin access via AblyRealtime. This reduces coupling between Connection and the plugin system.

lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (1)

76-86:

✅ Verification successful

Verify initialization timing doesn't create dependency issues.

The initialization order has changed so that connection is created before liveObjectsPlugin is initialized. Since ConnectionManager now accesses the plugin via ably.liveObjectsPlugin, ensure this doesn't create timing issues where the plugin is accessed before initialization.

Verify that all plugin access in ConnectionManager occurs after plugin initialization:


🏁 Script executed:

#!/bin/bash
# Search for liveObjectsPlugin usage in ConnectionManager to verify access patterns
rg -A 3 -B 3 "liveObjectsPlugin" lib/src/main/java/io/ably/lib/transport/ConnectionManager.java

Length of output: 508


Initialization order is safe; plugin access is null-guarded

The ConnectionManager only invokes ably.liveObjectsPlugin.handle(...) if ably.liveObjectsPlugin != null, so creating the connection before initializing the plugin cannot cause NPEs or race-condition errors. No changes required.

lib/src/main/java/io/ably/lib/transport/ConnectionManager.java (2)

768-768: LGTM! Constructor simplification aligns with architectural changes.

Removing the LiveObjectsPlugin parameter from the constructor is consistent with the refactoring to centralize plugin access via the AblyRealtime instance. This reduces the coupling between ConnectionManager and plugin initialization.


1226-1228: Good defensive programming with null safety checks.

The change from using a local liveObjectsPlugin field to accessing ably.liveObjectsPlugin is implemented safely with proper null checking. This ensures the code handles cases where the LiveObjects plugin is not available gracefully.

The existing error handling (catching Throwable and logging) provides additional robustness against plugin implementation issues.

live-objects/build.gradle.kts (4)

1-1: Good addition for detailed test logging.

The import for TestExceptionFormat enables comprehensive test failure reporting, which will be valuable for debugging test issues.


20-32: Excellent comprehensive test configuration.

The test configuration includes several best practices:

  • Full exception format for detailed error reporting
  • JVM args to open Java modules for reflection (essential for modern Java versions)
  • Lifecycle logging for test visibility
  • Forcing tests to run (preventing false cache hits)
  • Disabling tests for release builds to avoid duplication

This setup will facilitate effective testing and debugging.


34-46:

✅ Verification successful

Well-structured test task separation.

The separation of unit and integration tests is excellent for CI/CD pipelines. The package-based filtering and exclusion of base test classes is appropriate.

However, verify that the excluded base classes (UnitTest.class and IntegrationTest.class) are indeed intended to be abstract base classes and not runnable tests themselves.


🏁 Script executed:

#!/bin/bash
# Description: Verify base test classes are abstract or contain no test methods
# Expected: These should be base classes without @Test methods

# Check UnitTest class structure
ast-grep --pattern 'class UnitTest {
  $$$
}'

# Check IntegrationTest class structure  
ast-grep --pattern 'class IntegrationTest {
  $$$
}'

# Look for any @Test annotations in these base classes
rg -A 2 -B 2 "@Test" live-objects/src/test/kotlin/io/ably/lib/objects/unit/setup/UnitTest.kt live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt

Length of output: 281


🏁 Script executed:

#!/usr/bin/env bash
set -e

echo "== Locating UnitTest.kt =="
fd UnitTest.kt

echo "== Inspecting UnitTest.kt (first 50 lines) =="
fd UnitTest.kt -x sed -n '1,50p' {}

echo "== Locating IntegrationTest.kt =="
fd IntegrationTest.kt

echo "== Inspecting IntegrationTest.kt (first 50 lines) =="
fd IntegrationTest.kt -x sed -n '1,50p' {}

echo "== Searching for @Test annotations in both files =="
rg -n "@Test" $(fd UnitTest.kt) $(fd IntegrationTest.kt) || echo "No @Test annotations found"

Length of output: 4349


Tests Task Configuration Approved
Confirmed that UnitTest.kt and IntegrationTest.kt contain no @Test methods or runnable test cases, so excluding UnitTest.class and IntegrationTest.class is safe.


16-18:

✅ Verification successful

Verify the kotlin-tests bundle contents.

The addition of the kotlin-tests bundle is good for consistent dependency management. Please ensure this bundle includes all necessary testing dependencies.


🏁 Script executed:

#!/bin/bash
# Description: Verify the kotlin-tests bundle contains expected dependencies
# Expected: Bundle should include junit, mockk, coroutine-test, and other testing libs

# Check what's included in the kotlin-tests bundle
rg -A 10 "kotlin-tests.*=" gradle/libs.versions.toml

Length of output: 773


Bundle verification successful

The kotlin-tests bundle in gradle/libs.versions.toml includes:

  • junit
  • mockk
  • coroutine-test
  • nanohttpd
  • turbine
  • ktor-client-cio
  • ktor-client-core

This covers all required testing libraries—no further changes needed.

live-objects/src/test/kotlin/io/ably/lib/objects/unit/setup/UnitTest.kt (2)

30-43: Well-structured mock setup with comprehensive behavior coverage.

The spy-based mocking approach is excellent, providing real object behavior while allowing specific method overrides. The mock covers all essential channel operations (attach, detach, subscribe variants) and properly manages state transitions.

The forced state setting to attached at the end ensures consistent test conditions.


45-48: Proper test isolation with cleanup.

The @After method ensures proper test isolation by clearing client instances between tests, preventing state leakage.

gradle/libs.versions.toml (3)

52-55: Good addition of testing dependencies.

The new MockK and Ktor client dependencies support the enhanced testing infrastructure. The library definitions follow the proper format and reference the correct version variables.


61-61: Well-structured kotlin-tests bundle.

The new kotlin-tests bundle provides a good collection of testing dependencies including JUnit, MockK, coroutine testing, and HTTP client libraries. This promotes consistent dependency management across test modules.


3-3:

✅ Verification successful

Verify JUnit version for latest security updates.

The upgrade from JUnit 4.12 to 4.13.2 is good, but please verify this is the latest stable version to ensure any security fixes are included.


🌐 Web query:

What is the latest stable version of JUnit 4.x and are there any known security vulnerabilities in version 4.13.2?

💡 Result:

The latest stable version of JUnit 4.x is 4.13.2. (junit.org)

Regarding security vulnerabilities, JUnit 4.13.2 addresses a known issue in the TemporaryFolder rule. Prior to version 4.13.1, this rule could inadvertently expose sensitive information when writing to temporary directories on Unix-like systems, as these directories are typically shared among users. This vulnerability was identified as CVE-2020-15250. (acunetix.com)

In JUnit 4.13.1, the TemporaryFolder rule was updated to limit access to temporary folders, mitigating this information disclosure risk. Therefore, JUnit 4.13.2, being a subsequent release, includes this fix and does not have known security vulnerabilities.

Citations:


Verified JUnit version is current and secure

JUnit 4.13.2 is the latest stable 4.x release and includes the fix for CVE-2020-15250; there are no known security vulnerabilities in this version.

live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt (5)

6-14: LGTM! Well-designed utility function with proper parameter defaults.

The function signature and implementation look correct. The default HttpStatusCode.BadRequest for client errors is appropriate, and the delegation to helper functions maintains good separation of concerns.


16-19: LGTM! Clean overload for ErrorInfo-based exception creation.

This overload provides a nice convenience method when you already have an ErrorInfo object, maintaining consistency with the primary function.


21-25: LGTM! Correct ErrorInfo constructor usage.

The parameter order matches the ErrorInfo(message, statusCode, code) constructor signature from the Java class as shown in the relevant code snippets.


27-32: LGTM! Proper null-safe exception creation.

The Elvis operator correctly handles both cases - with and without a cause. The use of AblyException.fromErrorInfo variants is appropriate.


33-35: LGTM! Convenient error creation functions with appropriate mappings.

The clientError and serverError functions provide good defaults:

  • clientError: BadRequest (400) error code and status
  • serverError: InternalError (500) error code and status

These mappings are semantically correct for their intended use cases.

live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt (4)

15-22: LGTM! Proper parameterized test setup with appropriate timeout.

The parameterized test configuration and 10-second timeout rule are well-configured for integration testing scenarios.


36-47: LGTM! Well-designed client and channel management with proper async handling.

The function correctly:

  • Uses getOrPut for lazy client creation
  • Applies protocol selection based on test parameters
  • Ensures client connection and channel attachment using suspend functions
  • Properly chains the operations

The use of ensureConnected() and ensureAttached() from the sandbox utilities ensures proper async state management.


53-55: LGTM! Good practice for test isolation.

Using UUID-based channel names prevents test interference and state collisions, which is essential for reliable integration testing.


57-67: LGTM! Comprehensive resource cleanup.

The cleanup logic properly:

  • Removes all event listeners with channel.off()
  • Releases channels from the client
  • Closes all realtime clients
  • Clears the client map

This ensures no resource leaks between test runs.

live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/Sandbox.kt (6)

25-38: LGTM! Well-configured HTTP client with comprehensive retry logic.

The retry configuration is robust:

  • Appropriate max retries (5)
  • Retries on HTTP failures and common timeout exceptions
  • Exponential backoff strategy

This should handle transient network issues effectively during integration testing.


42-46: LGTM! Proper JSON configuration loading.

The file path correctly references the shared test resources, and the JSON parsing extracts the right configuration section for app creation.


65-72: LGTM! Clean client creation with proper configuration.

The extension function properly applies the provided options while ensuring the sandbox API key and environment are set correctly.


74-90: LGTM! Robust connection state management.

The suspend function correctly:

  • Returns early if already connected
  • Waits for connection events using CompletableDeferred
  • Handles both success (connected) and failure cases
  • Cleans up event listeners properly
  • Closes the client on connection failure

The error handling using ablyException(it.reason) integrates well with the utility functions from Utils.kt.


92-107: LGTM! Consistent channel attachment state management.

The function mirrors the connection logic appropriately:

  • Returns early if already attached
  • Waits for attachment events
  • Handles success and failure cases
  • Proper event listener cleanup

The implementation is consistent with the connection management function above.


48-62:

❓ Verification inconclusive

Fix API key selection discrepancy.

There's a mismatch between the comment and implementation:

  • Comment mentions "index 5" with specific permissions for Chat and Channels
  • Code uses index 0

Please verify which index is correct for the required permissions.


🏁 Script executed:

#!/bin/bash
# Check the test-app-setup.json file to understand the keys structure
cat ../lib/src/test/resources/ably-common/test-resources/test-app-setup.json | jq '.post_apps.keys[] | {keyStr: .keyStr, capability: .capability}' 2>/dev/null || echo "jq not available or file structure different"

Length of output: 253


#!/bin/bash
set -e

echo "1. Locate loadAppCreationJson definition in Kotlin tests"
rg -n "loadAppCreationJson" -g "*.kt" || echo "No loadAppCreationJson found"

echo
echo "2. List all JSON files under test resources"
find . -type f -path "/src/test/resources/.json" -print

echo
echo "3. Search JSON files for 'post_apps' structure"
grep -RIl '"post_apps"' -n . | while read -r file; do
echo "---- Inspecting $file ----"
if command -v jq >/dev/null 2>&1; then
jq '.post_apps.keys | to_entries[] | {index: .key, keyStr: .value.keyStr, capability: .value.capability}' "$file"
else
echo "jq not available; raw content:"
sed -n '1,50p' "$file"
fi
done


Verify API key index against test-app JSON structure
There’s still a mismatch between the inline comment and the code:

  • Comment says “index 5” is needed for Chat/Channels permissions
  • Code uses keys[0]

Please confirm which key index in your app-creation JSON actually grants the required permissions and update the code or comment accordingly.

• File: live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/Sandbox.kt
– Lines 48–62: adjust the body.asJsonObject["keys"].asJsonArray[…] index

@github-actions github-actions bot temporarily deployed to staging/pull/1092/features June 3, 2025 09:17 Inactive
Copy link
Contributor

@ttypic ttypic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good, except I would get rid of inheritance in the tests

import org.junit.Test
import kotlin.test.assertNotNull

class LiveObjectTest : UnitTest() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't like inheritance in the tests, could you take a look at this SO answer I think we can setup common parts the same way

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

LiveObjects : Setup liveobject tests
2 participants