Task Summary
CollaborationResource (amber/src/main/scala/org/apache/texera/web/resource/CollaborationResource.scala) is at 0% — all 87 tracked lines are unhit, and there is no spec. It looks websocket-bound but is not: the only dependency is the javax.websocket.Session interface, which mocks cleanly with the ScalaMock already on amber's test classpath. send is a one-hop session.getAsyncRemote.sendText, and every event carries a "type" discriminator from @JsonTypeInfo on CollabWebSocketEvent, so assertions are plain string matches. Roughly 70% of the file — about 60 of the 87 unhit lines — never touches SqlServer, and that is what this issue targets; the two DB-backed branches are scoped out below.
Behavior to add
Add amber/src/test/scala/org/apache/texera/web/resource/CollaborationResourceSpec.scala. Build a mockSession(id) helper returning a Session whose getId is fixed and whose getAsyncRemote.sendText is expectable.
Session lifecycle (no DB)
myOnOpen registers the session in sessionIdSessionMap.
myOnClose removes it and drops sessionIdWIdMap/wIdSessionIdsMap bookkeeping for the sender.
WIdRequest (no DB) — the authenticated path records sessionIdUIdMap(sessId) == uId; the anonymous path records sessionIdWIdMap(sessId) == DUMMY_WID. With two sessions on the same wid, assert both appear in wIdSessionIdsMap(wId) — the line building that set uses set.union(Set(senderSessId)), which returns a new set rather than mutating, and only survives because the result is reassigned. A multi-session test pins that.
Fan-out (no DB) — CommandRequest and RestoreVersionRequest: with three sessions, two on wid 1 and one on wid 2, assert the same-wid peer receives exactly one message, the sender receives none, and the other workflow's session is untouched.
HeartBeatRequest (no DB) — a single HeartBeatResponse back to the sender only.
TryLockRequest, DUMMY_WID branch (no DB) — sends WorkflowAccessEvent(workflowReadonly = false) then LockGrantedEvent.
AcquireLockRequest (no DB) — pre-seed wIdLockHolderSessionIdMap; assert the previous holder gets ReleaseLockEvent, the requester gets LockGrantedEvent, and the holder map flips.
Out of scope
Two branches reach WorkflowAccessResource.hasWriteAccess and therefore SqlServer: the read-only TryLockRequest rejection, and the lock hand-off inside myOnClose. Leave both uncovered. Everything above runs in a single JVM against a mocked interface with no database, no filesystem and no network — keep the spec that way rather than pulling in MockTexeraDB, which would spawn an embedded Postgres process for two branches.
Ordering hazard — do not skip
The five object-level maps (sessionIdSessionMap, sessionIdWIdMap, sessionIdUIdMap, wIdSessionIdsMap, wIdLockHolderSessionIdMap) are JVM-wide mutable state. Clear all five in beforeEach or the suite becomes order-dependent — that is the only realistic flakiness vector here. There are no clocks, threads or temp files involved. Also note wIdLockHolderSessionIdMap deliberately stores a null sentinel for "no holder"; tests must distinguish absent-key from null-value.
Task Type
Task Summary
CollaborationResource(amber/src/main/scala/org/apache/texera/web/resource/CollaborationResource.scala) is at 0% — all 87 tracked lines are unhit, and there is no spec. It looks websocket-bound but is not: the only dependency is thejavax.websocket.Sessioninterface, which mocks cleanly with the ScalaMock already on amber's test classpath.sendis a one-hopsession.getAsyncRemote.sendText, and every event carries a"type"discriminator from@JsonTypeInfoonCollabWebSocketEvent, so assertions are plain string matches. Roughly 70% of the file — about 60 of the 87 unhit lines — never touchesSqlServer, and that is what this issue targets; the two DB-backed branches are scoped out below.Behavior to add
Add
amber/src/test/scala/org/apache/texera/web/resource/CollaborationResourceSpec.scala. Build amockSession(id)helper returning aSessionwhosegetIdis fixed and whosegetAsyncRemote.sendTextis expectable.Session lifecycle (no DB)
myOnOpenregisters the session insessionIdSessionMap.myOnCloseremoves it and dropssessionIdWIdMap/wIdSessionIdsMapbookkeeping for the sender.WIdRequest(no DB) — the authenticated path recordssessionIdUIdMap(sessId) == uId; the anonymous path recordssessionIdWIdMap(sessId) == DUMMY_WID. With two sessions on the same wid, assert both appear inwIdSessionIdsMap(wId)— the line building that set usesset.union(Set(senderSessId)), which returns a new set rather than mutating, and only survives because the result is reassigned. A multi-session test pins that.Fan-out (no DB) —
CommandRequestandRestoreVersionRequest: with three sessions, two on wid 1 and one on wid 2, assert the same-wid peer receives exactly one message, the sender receives none, and the other workflow's session is untouched.HeartBeatRequest(no DB) — a singleHeartBeatResponseback to the sender only.TryLockRequest,DUMMY_WIDbranch (no DB) — sendsWorkflowAccessEvent(workflowReadonly = false)thenLockGrantedEvent.AcquireLockRequest(no DB) — pre-seedwIdLockHolderSessionIdMap; assert the previous holder getsReleaseLockEvent, the requester getsLockGrantedEvent, and the holder map flips.Out of scope
Two branches reach
WorkflowAccessResource.hasWriteAccessand thereforeSqlServer: the read-onlyTryLockRequestrejection, and the lock hand-off insidemyOnClose. Leave both uncovered. Everything above runs in a single JVM against a mocked interface with no database, no filesystem and no network — keep the spec that way rather than pulling inMockTexeraDB, which would spawn an embedded Postgres process for two branches.Ordering hazard — do not skip
The five
object-level maps (sessionIdSessionMap,sessionIdWIdMap,sessionIdUIdMap,wIdSessionIdsMap,wIdLockHolderSessionIdMap) are JVM-wide mutable state. Clear all five inbeforeEachor the suite becomes order-dependent — that is the only realistic flakiness vector here. There are no clocks, threads or temp files involved. Also notewIdLockHolderSessionIdMapdeliberately stores anullsentinel for "no holder"; tests must distinguish absent-key from null-value.Task Type