This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git

commit aceca29cbda1f223ac17753efb58eba726e58b2f
Author: Benjamin Le <[email protected]>
AuthorDate: Sat Jun 13 11:54:04 2026 -0700

    test(frontend): expand OperatorReuseCacheStatusService spec coverage (#5624)
    
    ### What changes were proposed in this PR?
    Expands the existing spec for `OperatorReuseCacheStatusService`, which
    previously only checked `should be created`. Adds behavior-focused tests
    covering both constructor subscriptions: the `CacheStatusUpdateEvent`
    websocket handler and the `getReuseCacheOperatorsChangedStream` handler.
    Tests verify that `JointUIService.changeOperatorReuseCacheStatus` is
    called correctly for each operator, that the `mainJointPaper` null guard
    is respected in both handlers, and that empty operator lists do not
    throw.
    
    ### Any related issues, documentation, discussions?
    Closes #5543
    
    ### How was this PR tested?
    New tests run via `yarn test -- operator-reuse-cache-status` and `yarn
    lint`. 6 tests passing.
    
    ### Was this PR authored or co-authored using generative AI tooling?
    Generated-by: Claude (Claude Sonnet 4.6)
    
    Co-authored-by: Benjamin Le <[email protected]>
---
 .../operator-reuse-cache-status.service.spec.ts    | 120 ++++++++++++++++++++-
 1 file changed, 119 insertions(+), 1 deletion(-)

diff --git 
a/frontend/src/app/workspace/service/workflow-status/operator-reuse-cache-status.service.spec.ts
 
b/frontend/src/app/workspace/service/workflow-status/operator-reuse-cache-status.service.spec.ts
index 0c3ccb89fd..bbfd9c55d8 100644
--- 
a/frontend/src/app/workspace/service/workflow-status/operator-reuse-cache-status.service.spec.ts
+++ 
b/frontend/src/app/workspace/service/workflow-status/operator-reuse-cache-status.service.spec.ts
@@ -18,10 +18,13 @@
  */
 
 import { TestBed } from "@angular/core/testing";
+import { Subject } from "rxjs";
 import { OperatorMetadataService } from 
"../operator-metadata/operator-metadata.service";
 import { StubOperatorMetadataService } from 
"../operator-metadata/stub-operator-metadata.service";
-
 import { OperatorReuseCacheStatusService } from 
"./operator-reuse-cache-status.service";
+import { JointUIService } from "../joint-ui/joint-ui.service";
+import { WorkflowActionService } from 
"../workflow-graph/model/workflow-action.service";
+import { WorkflowWebsocketService } from 
"../workflow-websocket/workflow-websocket.service";
 import { HttpClientTestingModule } from "@angular/common/http/testing";
 import { commonTestProviders } from "../../../common/testing/test-utils";
 
@@ -46,3 +49,118 @@ describe("OperatorCacheStatusService", () => {
     expect(service).toBeTruthy();
   });
 });
+
+describe("OperatorCacheStatusService - behavior", () => {
+  let service: OperatorReuseCacheStatusService;
+  let cacheStatusEvents$: Subject<any>;
+  let reuseCacheOpsChanged$: Subject<any>;
+  let mockJointUIService: any;
+  let mockJointGraphWrapper: any;
+  let mockTexeraGraph: any;
+  let mockWorkflowActionService: any;
+  let mockWorkflowWebsocketService: any;
+  const mockMainJointPaper = {};
+
+  beforeEach(() => {
+    cacheStatusEvents$ = new Subject<any>();
+    reuseCacheOpsChanged$ = new Subject<any>();
+
+    mockJointUIService = {
+      changeOperatorReuseCacheStatus: vi.fn(),
+    };
+
+    mockJointGraphWrapper = {
+      getMainJointPaper: vi.fn().mockReturnValue(mockMainJointPaper),
+    };
+
+    mockTexeraGraph = {
+      getReuseCacheOperatorsChangedStream: 
vi.fn().mockReturnValue(reuseCacheOpsChanged$),
+      getOperator: vi.fn().mockImplementation((opID: string) => ({ operatorID: 
opID })),
+    };
+
+    mockWorkflowActionService = {
+      getTexeraGraph: vi.fn().mockReturnValue(mockTexeraGraph),
+      getJointGraphWrapper: vi.fn().mockReturnValue(mockJointGraphWrapper),
+    };
+
+    mockWorkflowWebsocketService = {
+      subscribeToEvent: vi.fn().mockReturnValue(cacheStatusEvents$),
+    };
+
+    TestBed.configureTestingModule({
+      providers: [
+        OperatorReuseCacheStatusService,
+        { provide: JointUIService, useValue: mockJointUIService },
+        { provide: WorkflowActionService, useValue: mockWorkflowActionService 
},
+        { provide: WorkflowWebsocketService, useValue: 
mockWorkflowWebsocketService },
+      ],
+    });
+
+    service = TestBed.inject(OperatorReuseCacheStatusService);
+  });
+
+  it("calls changeOperatorReuseCacheStatus for each operator in a 
CacheStatusUpdateEvent", () => {
+    const event = {
+      cacheStatusMap: {
+        op1: "cache",
+        op2: "no-cache",
+      },
+    };
+
+    cacheStatusEvents$.next(event);
+
+    
expect(mockJointUIService.changeOperatorReuseCacheStatus).toHaveBeenCalledTimes(2);
+    
expect(mockJointUIService.changeOperatorReuseCacheStatus).toHaveBeenCalledWith(
+      mockMainJointPaper,
+      { operatorID: "op1" },
+      "cache"
+    );
+    
expect(mockJointUIService.changeOperatorReuseCacheStatus).toHaveBeenCalledWith(
+      mockMainJointPaper,
+      { operatorID: "op2" },
+      "no-cache"
+    );
+  });
+
+  it("does not call changeOperatorReuseCacheStatus when mainJointPaper is null 
on CacheStatusUpdateEvent", () => {
+    mockJointGraphWrapper.getMainJointPaper.mockReturnValue(null);
+
+    cacheStatusEvents$.next({ cacheStatusMap: { op1: "cache" } });
+
+    
expect(mockJointUIService.changeOperatorReuseCacheStatus).not.toHaveBeenCalled();
+  });
+
+  it("calls changeOperatorReuseCacheStatus for all ops in a reuse cache 
operators changed event", () => {
+    const event = {
+      newReuseCacheOps: ["op1", "op2"],
+      newUnreuseCacheOps: ["op3"],
+    };
+
+    reuseCacheOpsChanged$.next(event);
+
+    
expect(mockJointUIService.changeOperatorReuseCacheStatus).toHaveBeenCalledTimes(3);
+    
expect(mockJointUIService.changeOperatorReuseCacheStatus).toHaveBeenCalledWith(mockMainJointPaper,
 {
+      operatorID: "op1",
+    });
+    
expect(mockJointUIService.changeOperatorReuseCacheStatus).toHaveBeenCalledWith(mockMainJointPaper,
 {
+      operatorID: "op2",
+    });
+    
expect(mockJointUIService.changeOperatorReuseCacheStatus).toHaveBeenCalledWith(mockMainJointPaper,
 {
+      operatorID: "op3",
+    });
+  });
+
+  it("does not call changeOperatorReuseCacheStatus when mainJointPaper is null 
on reuse cache changed event", () => {
+    mockJointGraphWrapper.getMainJointPaper.mockReturnValue(null);
+
+    reuseCacheOpsChanged$.next({ newReuseCacheOps: ["op1"], 
newUnreuseCacheOps: [] });
+
+    
expect(mockJointUIService.changeOperatorReuseCacheStatus).not.toHaveBeenCalled();
+  });
+
+  it("does not throw when reuse cache changed event has empty operator lists", 
() => {
+    expect(() => {
+      reuseCacheOpsChanged$.next({ newReuseCacheOps: [], newUnreuseCacheOps: 
[] });
+    }).not.toThrow();
+  });
+});

Reply via email to