Skip to content

uts: port LiveObjects unit-test harness helpers into infra/unit - #2233

Closed
maratal wants to merge 4 commits into
integration/liveobjects-sync-with-mainfrom
integration/liveobjects-uts-unit-helpers
Closed

uts: port LiveObjects unit-test harness helpers into infra/unit#2233
maratal wants to merge 4 commits into
integration/liveobjects-sync-with-mainfrom
integration/liveobjects-uts-unit-helpers

Conversation

@maratal

@maratal maratal commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Stacked on top of #2232 (integration/liveobjects-sync-with-main).

Summary

Brings the LiveObjects UTS unit-test harness into ably-cocoa's Test/UTS/infra/unit, so the objects UTS module's unit tests can be generated by the uts-to-swift skill without also generating harness code — the skill only emits test files.

This is a faithful, file-by-file port of the harness changes from ably-liveobjects-swift-plugin PR #135 (commit 9009067), applied onto ably-cocoa's existing UTS harness. The plugin's changes are applied verbatim; ably-cocoa's pre-existing extras are preserved.

Changes

Package.swift

  • Add AblyLiveObjects to the UTS test target's dependencies (the harness now references the plugin's types).

Test/UTS/infra/unit/ProtocolMessage.swift — apply the plugin's hunks:

  • OBJECT / OBJECT_SYNC / DETACHED / channel-ERROR message builders.
  • HAS_OBJECTS attach flag, connection-details siteCode / objectsGCGracePeriod, and ACK res serials.
  • Object state is delivered to ARTProtocolMessage.state via KVC as the plugin's ObjectMessageBox boxes.
  • (Kept ably-cocoa's existing connectedMessage.)

Test/UTS/infra/unit/MockWebSocket.swift — apply the plugin's hunks:

  • The onMessageFromClient hook, sentFrames, and provider wiring (used by setup_synced_channel to answer ATTACH with ATTACHED+OBJECT_SYNC and to auto-ACK OBJECT publishes).
  • (Kept ably-cocoa's existing parseQueryParams and respondWithSuccess(_:).)

Test/UTS/infra/unit/StandardTestPool.swift (new) — canonical object-tree fixtures + OBJECT/OBJECT_SYNC message builders (uts/objects/helpers/standard_test_pool.md). Verbatim from the plugin.

Test/UTS/infra/unit/UTSTestCase+LiveObjects.swift (new) — the setup_synced_channel pattern (connected client + synced objects channel via the mock) and sent-operation inspection. Verbatim from the plugin.

Notes

  • No objects tests are added here — only the harness. The tests come next, via the uts-to-swift skill.
  • The Instance+Testing.swift helper from the plugin is intentionally not included.

Verification

  • Clean build (swift package clean + swift build --build-tests) — succeeds.
  • Core UTS unit tests (ConnectionRecoveryTests, TimeTests) — 11/11 pass; the shared harness is unaffected.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
    • Expanded LiveObjects test coverage for connection, synchronization, object updates, acknowledgements, and outbound operations.
    • Added reusable test fixtures for maps, counters, object state, and deletion scenarios.
    • Improved mock WebSocket behavior to capture client messages and simulate server responses.
    • Enabled LiveObjects testing in the UTS suite.
  • Chores
    • Updated iOS and tvOS test deployment targets to version 14.0.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5bb38189-1b97-4f21-902c-d7b4d91f41d3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

The UTS target now depends on AblyLiveObjects. Test infrastructure supports LiveObjects protocol messages, standard object fixtures, mock WebSocket message handling, channel synchronization, operation inspection, and iOS/tvOS test deployment targets.

Changes

LiveObjects UTS infrastructure

Layer / File(s) Summary
Protocol messages and standard fixtures
Package.swift, Test/UTS/infra/unit/ProtocolMessage.swift, Test/UTS/infra/unit/StandardTestPool.swift
The UTS target adds the LiveObjects dependency. Protocol builders support object events and state. StandardTestPool supplies reusable object states and operations.
Mock WebSocket message routing
Test/UTS/infra/unit/MockWebSocket.swift
The mock WebSocket records raw frames and routes decoded client messages to provider callbacks.
LiveObjects channel test helpers
Test/UTS/infra/unit/UTSTestCase+LiveObjects.swift, fastlane/Fastfile
UTS helpers create mocked objects channels, inject synchronization and object messages, auto-acknowledge publications, and decode outbound operations. Test builds set iOS and tvOS deployment targets to 14.0.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant UTSTestCase
  participant MockWebSocketProvider
  participant LiveObjects channel
  participant MockWebSocket
  UTSTestCase->>MockWebSocketProvider: create objects channel
  MockWebSocketProvider->>LiveObjects channel: send connected and attached
  MockWebSocketProvider->>LiveObjects channel: send objectSync
  LiveObjects channel->>MockWebSocket: send object operation
  MockWebSocket->>MockWebSocketProvider: report decoded message
  MockWebSocketProvider->>LiveObjects channel: send ACK
Loading

Possibly related PRs

Suggested reviewers: lawrence-forooghian, ttypic

Poem

A rabbit builds a test pool,
With maps and counters, neat and cool.
Frames hop out; ACKs hop in,
Sync messages begin.
LiveObjects tests now run with cheer!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: porting LiveObjects unit-test harness helpers into infra/unit.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch integration/liveobjects-uts-unit-helpers

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

Comment @coderabbitai help to get the list of available commands.

@github-actions
github-actions Bot temporarily deployed to staging/pull/2233/features July 30, 2026 12:44 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2233/AblyLiveObjects July 30, 2026 12:45 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2233/jazzydoc July 30, 2026 12:47 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2233/markdown-api-reference July 30, 2026 12:47 Inactive
@maratal
maratal force-pushed the integration/liveobjects-uts-unit-helpers branch from 28aa9bd to c2277a7 Compare July 30, 2026 19:21
@github-actions
github-actions Bot temporarily deployed to staging/pull/2233/features July 30, 2026 19:22 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2233/AblyLiveObjects July 30, 2026 19:23 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2233/jazzydoc July 30, 2026 19:27 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/2233/markdown-api-reference July 30, 2026 19:27 Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Test/UTS/infra/unit/UTSTestCase`+LiveObjects.swift:
- Around line 90-109: Add derived LiveObjects UTS tests that exercise the
channel setup and protocol helpers introduced by this change. In
Test/UTS/infra/unit/UTSTestCase+LiveObjects.swift lines 18-89 and 90-109, cover
objectsChannel, setupSyncedChannel, sentObjectOperations, and StandardTestPool
behavior; in Test/UTS/infra/unit/ProtocolMessage.swift lines 113-130 and
154-169, add assertions covering the ProtocolMessage helpers. Ensure the tests
validate LiveObjects channel flow, sent operation decoding, and relevant
protocol-message behavior rather than only compiling the private APIs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 71e68f07-4f76-48d2-8a67-46e06d037f21

📥 Commits

Reviewing files that changed from the base of the PR and between c23859e and c2277a7.

📒 Files selected for processing (5)
  • Package.swift
  • Test/UTS/infra/unit/MockWebSocket.swift
  • Test/UTS/infra/unit/ProtocolMessage.swift
  • Test/UTS/infra/unit/StandardTestPool.swift
  • Test/UTS/infra/unit/UTSTestCase+LiveObjects.swift

Comment on lines +90 to +109
func sentObjectOperations(_ ws: MockWebSocketProvider) throws -> [WireObjectOperation] {
guard let connection = ws.activeConnection else { return [] }
var operations: [WireObjectOperation] = []
for frame in connection.sentFrames {
guard let root = try? JSONSerialization.jsonObject(with: frame) as? [String: Any],
(root["action"] as? Int) == WireAction.object,
let state = root["state"] as? [[String: Any]] else { continue }
for objectMessage in state {
guard let operationData = objectMessage["operation"] as? [String: Any] else { continue }
// Decode the operation directly into its wire type. We don't route through
// `InboundWireObjectMessage`: these are messages the client *sent*, so the inbound
// decoder (and its `DecodingContext`, which drives inbound synthetic-ID rules) would
// be the wrong direction. `WireObjectOperation` is `WireObjectCodable`, and its wire
// form is direction-agnostic and retains the outbound-only `*WithObjectId` fields.
let wireOperation = WireValue.objectFromPluginSupportData(operationData)
operations.append(try WireObjectOperation(wireObject: wireOperation))
}
}
return operations
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo files of interest =="
git ls-files | rg 'Test/UTS/infra/unit/(UTSTestCase\+LiveObjects|ProtocolMessage)\.(swift|swift\.mm)$|README|Package|Pod|Cartfile|Cartfile\.resolved|package\.json|tsconfig|Makefile|script|\.github/workflows' || true

echo
echo "== changed files/stat =="
git diff --stat HEAD~1..HEAD 2>/dev/null || git diff --stat || true

echo
echo "== target files outline/sections =="
if [ -f Test/UTS/infra/unit/UTSTestCase+LiveObjects.swift ]; then
  wc -l Test/UTS/infra/unit/UTSTestCase+LiveObjects.swift
  sed -n '1,240p' Test/UTS/infra/unit/UTSTestCase+LiveObjects.swift | cat -n
fi
echo
if [ -f Test/UTS/infra/unit/ProtocolMessage.swift ]; then
  wc -l Test/UTS/infra/unit/ProtocolMessage.swift
  sed -n '1,230p' Test/UTS/infra/unit/ProtocolMessage.swift | cat -n
fi

echo
echo "== search for objects/UTS/live objects/test mentions =="
rg -n "objects|LiveObjects|objectSync|sentObjectOperations|setupSyncedChannel|no [Oo]bjects|No [Oo]bjects|AblyLiveObjects|WireObjectOperation|JSONSerialization|default binary|useBinaryProtocol" --glob '*.swift' --glob '*.md' --glob 'Makefile' --glob 'README*' --glob '.github/**' | head -n 240

Repository: ably/ably-cocoa

Length of output: 20414


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== UTS README mentions =="
sed -n '1,260p' Test/UTS/README.md | cat -n

echo
echo "== LiveObjects README mentions =="
sed -n '1,260p' LiveObjects/README.md | cat -n

echo
echo "== Makefile pytest/uts/test commands =="
rg -n "pytest|uts|unit|test|objects|LiveObjects|objects\." Makefile Test/UTS/README.md LiveObjects/README.md README.md | head -n 200

echo
echo "== Search test invocations and object test files =="
git ls-files | rg -n '(\.py$|Makefile|README|README\.md)$' | xargs -r rg -n "objects|LiveObjects|setup_synced_channel|capture|standard_test_pool|objects\." | head -n 300

echo
echo "== ProtocolMessage references =="
rg -n "makeProtocolMessage|ProtocolMessage\(" --glob '*.swift' Test Source | head -n 200

echo
echo "== MockWebSocket definitions/capture =="
rg -n "struct MockWebSocket|class MockWebSocket|sentFrames|activeConnection|sendToClient" --glob '*.swift' Test Source | head -n 200

Repository: ably/ably-cocoa

Length of output: 48039


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== MockWebSocket implementations =="
fd -a 'MockWebSocket.swift|ProtocolMessage.swift|UTSTestCase.swift' Test/UTS/infra/unit -x sh -c 'echo "--- $1"; wc -l "$1"; sed -n "1,260p" "$1"' sh {}

echo
echo "== Search for LiveObjects UTS-derived identifiers across repo =="
rg -n "`@Test`|func .*objects|objectsChannel|setupSyncedChannel|sentObjectOperations|capture|StandardTestPool|LiveObjects|useBinaryProtocol|json.*format|binary" --glob '*.swift' --glob '*.md' --glob 'Makefile' --glob 'Package.swift' Test Source LiveObjects | head -n 400

echo
echo "== Check for `@Test` in LiveObjects helper file exactly =="
python3 - <<'PY'
from pathlib import Path
p = Path('Test/UTS/infra/unit/UTSTestCase+LiveObjects.swift')
if p.exists():
    text = p.read_text(encoding='utf-8')
    print('`@Test` occurrences:', text.count('`@Test`'))
    print('sendObjectOperations calls:', text.count('sentObjectOperations'))
else:
    print("missing")
PY

Repository: ably/ably-cocoa

Length of output: 50371


Add exercising tests for the LiveObjects UTS harness. This PR introduces objectsChannel, setupSyncedChannel, sentObjectOperations, ProtocolMessage helpers, and StandardTestPool, but no derived tests exercise the LiveObjects channel flow. The UTS guide documents infra/* as containing no @Tests, and the current UTS target has no LiveObjects-derived assertions, so these private-API/protocol assumptions can’t be caught until a later LiveObjects test hits them.

📍 Affects 2 files
  • Test/UTS/infra/unit/UTSTestCase+LiveObjects.swift#L90-L109 (this comment)
  • Test/UTS/infra/unit/UTSTestCase+LiveObjects.swift#L18-L89
  • Test/UTS/infra/unit/ProtocolMessage.swift#L113-L130
  • Test/UTS/infra/unit/ProtocolMessage.swift#L154-L169
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Test/UTS/infra/unit/UTSTestCase`+LiveObjects.swift around lines 90 - 109, Add
derived LiveObjects UTS tests that exercise the channel setup and protocol
helpers introduced by this change. In
Test/UTS/infra/unit/UTSTestCase+LiveObjects.swift lines 18-89 and 90-109, cover
objectsChannel, setupSyncedChannel, sentObjectOperations, and StandardTestPool
behavior; in Test/UTS/infra/unit/ProtocolMessage.swift lines 113-130 and
154-169, add assertions covering the ProtocolMessage helpers. Ensure the tests
validate LiveObjects channel flow, sent operation decoding, and relevant
protocol-message behavior rather than only compiling the private APIs.

maratal and others added 4 commits August 1, 2026 17:30
The UTS harness references the LiveObjects plugin's types (ProtocolTypes,
DefaultInternalPlugin.ObjectMessageBox) for the `objects` module, so the UTS
target must link against AblyLiveObjects.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Apply the harness changes from ably-liveobjects-swift-plugin PR #135
(commit 9009067) to the UTS unit mock:

- ProtocolMessage: OBJECT / OBJECT_SYNC / DETACHED / channel-ERROR builders,
  the HAS_OBJECTS attach flag, connection-details siteCode/objectsGCGracePeriod,
  and ack `res` serials. Object state is delivered to ARTProtocolMessage.state
  via KVC as the plugin's ObjectMessageBox boxes.
- MockWebSocket: the onMessageFromClient hook, sentFrames, and provider wiring
  (used by setup_synced_channel to answer ATTACH with ATTACHED+OBJECT_SYNC and
  to auto-ACK OBJECT publishes).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nced_channel)

Port the LiveObjects UTS helpers from ably-liveobjects-swift-plugin PR #135
(commit 9009067) into Test/UTS/infra/unit:

- StandardTestPool: canonical object-tree fixtures and OBJECT/OBJECT_SYNC
  message builders (uts/objects/helpers/standard_test_pool.md).
- UTSTestCase+LiveObjects: the setup_synced_channel pattern (connected client +
  synced objects channel via the mock) and sent-operation inspection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The UTS test target links AblyLiveObjects (iOS 14 / tvOS 14 / macOS 11), but the
package's platform floor is lower and SwiftPM has no per-target floor. The core
SDK's fastlane integration build compiles the `ably-cocoa` scheme's test target
at that low floor, so the UTS harness's direct references to AblyLiveObjects
types failed on the iOS/tvOS simulators with "'ProtocolTypes' is only available
in iOS 14.0 or newer".

Rather than annotate/erase the harness, raise the deployment target of the test
build itself via fastlane xcargs (IPHONEOS/TVOS_DEPLOYMENT_TARGET = 14.0),
mirroring LiveObjects/BuildTool's `testDeploymentTargetOverrides`. This affects
the test build only — shipped artifacts and the package's declared floor are
unchanged (respecting the ADR-128 / #2222 decision to keep ably-cocoa's
platforms low and gate LiveObjects via @available). It also lets the UTS
harness embed the plugin's OBJECT/OBJECT_SYNC types verbatim (no erasure) and
lets future objects @suite tests compile without @available/#available guards
(the Swift Testing macros reject @available).

macOS needs no override (its default test-build floor already satisfies
AblyLiveObjects).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant