|
20 | 20 | DYNAMIC_TOOLS, |
21 | 21 | MEASUREIT_SWEEP_QUEUE_SETUP, |
22 | 22 | MEASUREIT_START_QUEUE, |
| 23 | + MEASUREIT_SWEEP2D_QUEUE_SETUP, |
| 24 | + MEASUREIT_START_SWEEP2D_QUEUE, |
23 | 25 | ) |
24 | 26 |
|
25 | 27 |
|
@@ -918,3 +920,89 @@ def test_wait_for_sweep_with_running_queue(self, mcp_server_measureit_sweepqueue |
918 | 920 | assert ( |
919 | 921 | "sweep_queue" in content or success |
920 | 922 | ), f"wait_for_sweep should find sweep_queue: {content}" |
| 923 | + |
| 924 | + @pytest.mark.p1 |
| 925 | + def test_sweep2d_queue_wait_for_sweep_no_early_exit( |
| 926 | + self, mcp_server_measureit_sweepqueue |
| 927 | + ): |
| 928 | + """OF-054: Test wait_for_sweep does not exit early with 3 Sweep2D (save_data=True). |
| 929 | +
|
| 930 | + This test verifies that wait_for_sweep correctly waits for all 3 Sweep2D |
| 931 | + operations to complete when using save_data=True, and does not exit |
| 932 | + prematurely after the first or second sweep finishes. |
| 933 | +
|
| 934 | + The test: |
| 935 | + 1. Sets up 3 Sweep2D with save_data=True |
| 936 | + 2. Starts the SweepQueue |
| 937 | + 3. Calls wait_for_sweep with sufficient timeout |
| 938 | + 4. Verifies the queue completed all sweeps (state should be "idle" or "done") |
| 939 | + 5. Verifies no premature exit (timed_out should be False) |
| 940 | + """ |
| 941 | + page = mcp_server_measureit_sweepqueue["page"] |
| 942 | + base_url = mcp_server_measureit_sweepqueue["url"] |
| 943 | + |
| 944 | + # Create 3 Sweep2D with save_data=True |
| 945 | + run_cell(page, MEASUREIT_SWEEP2D_QUEUE_SETUP) |
| 946 | + page.wait_for_timeout(1000) |
| 947 | + |
| 948 | + # Verify setup completed |
| 949 | + output = get_cell_output(page) |
| 950 | + assert "is_queued = True" in output, f"is_queued not set properly: {output}" |
| 951 | + |
| 952 | + # Start the sweep queue and IMMEDIATELY call wait_for_sweep (no delay) |
| 953 | + # This tests the race condition where the queue might still be in "pending" state |
| 954 | + # when wait_for_sweep checks the status for the first time |
| 955 | + run_cell(page, MEASUREIT_START_SWEEP2D_QUEUE) |
| 956 | + # NO delay here - we want to catch the timing bug where "pending" is misinterpreted |
| 957 | + |
| 958 | + # Wait for sweep with sufficient timeout (30s should be enough for 3 small sweeps) |
| 959 | + # Each Sweep2D has 9 points with 0.05s delay = ~0.45s per sweep |
| 960 | + # Plus save_data overhead, 30s is generous |
| 961 | + result = call_mcp_tool( |
| 962 | + base_url, |
| 963 | + "measureit_wait_for_sweep", |
| 964 | + { |
| 965 | + "variable_name": "sweep_queue", |
| 966 | + "timeout": 30, |
| 967 | + "kill": True, |
| 968 | + "detailed": True, |
| 969 | + }, |
| 970 | + ) |
| 971 | + success, content = parse_tool_result(result) |
| 972 | + |
| 973 | + # Verify wait_for_sweep did not timeout (no early exit) |
| 974 | + assert ( |
| 975 | + "timed_out" not in content or '"timed_out": false' in content.lower() |
| 976 | + ), f"wait_for_sweep should not timeout - may have exited early: {content}" |
| 977 | + |
| 978 | + # Verify the queue completed (state should be idle after completion and kill) |
| 979 | + # The sweep should have finished successfully |
| 980 | + assert ( |
| 981 | + success or "sweep_queue" in content |
| 982 | + ), f"wait_for_sweep should complete successfully: {content}" |
| 983 | + |
| 984 | + # Verify no error occurred during the sweep |
| 985 | + if "sweep_error" in content: |
| 986 | + # If there's a sweep_error, this is a different issue (not early exit) |
| 987 | + assert ( |
| 988 | + '"sweep_error": false' in content.lower() |
| 989 | + or "sweep_error" not in content |
| 990 | + ), f"Sweep completed with error (not early exit issue): {content}" |
| 991 | + |
| 992 | + # CRITICAL: Verify no premature exit by checking the final state |
| 993 | + # If wait_for_sweep exited early with "pending" state, it would show that |
| 994 | + assert ( |
| 995 | + '"state": "pending"' not in content.lower() |
| 996 | + ), f"wait_for_sweep exited with 'pending' state - this indicates early exit bug: {content}" |
| 997 | + |
| 998 | + # Also check that not_started is not in the response |
| 999 | + assert ( |
| 1000 | + "not_started" not in content.lower() |
| 1001 | + ), f"wait_for_sweep returned not_started - queue was not properly waited for: {content}" |
| 1002 | + |
| 1003 | + # Verify the queue is now idle (all sweeps completed) |
| 1004 | + # After all sweeps complete and kill is called, state should be "idle" or "killed" |
| 1005 | + assert ( |
| 1006 | + '"state": "idle"' in content.lower() |
| 1007 | + or '"state": "killed"' in content.lower() |
| 1008 | + ), f"Queue should be idle/killed after completion, got: {content}" |
0 commit comments