From 0ca81f8124189bf6d0eae1bd411a72baca97bf3d Mon Sep 17 00:00:00 2001 From: kirti singh Date: Thu, 5 Jun 2025 17:55:15 +0200 Subject: [PATCH 01/10] mlir mock --- test/test_pennylane_mock.py | 131 ++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 test/test_pennylane_mock.py diff --git a/test/test_pennylane_mock.py b/test/test_pennylane_mock.py new file mode 100644 index 0000000..74aa062 --- /dev/null +++ b/test/test_pennylane_mock.py @@ -0,0 +1,131 @@ +"""Test module for Pennylane job submission with mocked RabbitMQ.""" + +import json + +import pytest + +from mqss_client import JobStatus, MQSSClient, Result +from mqss_client.job import CircuitJobRequest + +from .mocks import MOCK_JOB_DATA, patch_mqss_rest_client, patch_rabbitmq_client + +# Add Pennylane mock data to existing mock data +MOCK_JOB_DATA.update( + { + "job": {"jobs": ["mock-uuid-12345"]}, + "job/mock-uuid-12345/status": {"status": "COMPLETED"}, + "job/mock-uuid-12345/result": { + "result": '{"0": 500, "1": 500}', + "timestamp_completed": "2023-04-14 10:15:30.123456", + "timestamp_submitted": "2023-04-14 10:00:00.123456", + "timestamp_scheduled": "2023-04-14 10:05:00.123456", + }, + } +) + + +@pytest.fixture +def pennylane_job_request(): + """Create a mock Pennylane job request.""" + return CircuitJobRequest( + resource_name="mock-backend", + circuits="mock-mlir-circuit", + circuit_format="mlir", + shots=1000, + no_modify=True, + queued=False, + ) + + +@pytest.mark.mock +@pytest.mark.parametrize( + "client_type", + [ + "MQP", + "HPC", + ], + ids=["MQP", "HPC"], +) +class TestPennylaneJobMock: + """Test class for Pennylane job submission with mocked clients.""" + + @pytest.fixture(autouse=True) + def setup_client(self, client_type): + """Setup the proper client patch based on the parameterized client type.""" + self.client_type = client_type + + # Start patch based on client type + if "HPC" in client_type: + self.patch = patch_rabbitmq_client() + self.mock_rmq = self.patch.start() + else: + self.patch = patch_mqss_rest_client() + self.patch.start() + + yield + + # Stop the patch after test + self.patch.stop() + + @pytest.fixture + def client_args(self) -> tuple: + return "mock-token", "http://mock-url", "HPC" in self.client_type + + @pytest.fixture + def client(self, client_args) -> MQSSClient: + """Create a mock MQSS client.""" + token, base_url, is_hpc = client_args + return MQSSClient(token, base_url, is_hpc) + + def test_pennylane_job_submission(self, client: MQSSClient, pennylane_job_request): + """Test submitting a Pennylane job.""" + # Submit the job + job_id = client.submit_job(pennylane_job_request) + assert job_id == "mock-uuid-12345" + + # Check status + status = client.job_status(job_id, pennylane_job_request) + assert status == JobStatus.COMPLETED + + # Get result + result = client.job_result(job_id, pennylane_job_request) + assert isinstance(result, Result) + assert result.counts == {"0": 500, "1": 500} + + def test_pennylane_job_cancellation( + self, client: MQSSClient, pennylane_job_request + ): + """Test cancelling a Pennylane job.""" + # Submit the job + job_id = client.submit_job(pennylane_job_request) + + # Cancel the job + client.cancel_job(job_id, pennylane_job_request) + + # Verify the cancel request was made + if "HPC" in self.client_type: + # For HPC client, verify that a message was sent with the delete request + assert self.mock_rmq.return_value.last_message is not None + message_data = json.loads(self.mock_rmq.return_value.last_message) + assert message_data.get("request") == f"job/{job_id}" + assert message_data.get("method") == "DELETE" + else: + # For MQP client, verify that delete was called with the correct path + client.client.delete.assert_called_with(f"job/{job_id}") # type: ignore[attr-defined] + + def test_pennylane_job_wait_for_result( + self, client: MQSSClient, pennylane_job_request, monkeypatch + ): + """Test waiting for a Pennylane job result.""" + # Submit the job + job_id = client.submit_job(pennylane_job_request) + + # Mock sleep to speed up test + monkeypatch.setattr("time.sleep", lambda x: None) + + # Wait for result + result = client.wait_for_job_result(job_id, pennylane_job_request) + + # Verify result + assert isinstance(result, Result) + assert result.counts == {"0": 500, "1": 500} From c8c59774b952bf41fa7bec3aef44924ca676a497 Mon Sep 17 00:00:00 2001 From: kirti singh Date: Thu, 5 Jun 2025 19:18:41 +0200 Subject: [PATCH 02/10] updated mock to fix failing test --- test/test_mqss_client_mock.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/test/test_mqss_client_mock.py b/test/test_mqss_client_mock.py index afec0f6..101935f 100644 --- a/test/test_mqss_client_mock.py +++ b/test/test_mqss_client_mock.py @@ -53,15 +53,21 @@ def test_job_status( ) -> None: """Test job status.""" job_id = client.submit_job(circuit_job_request) + + # First mock to ensure initial status is PENDING + def mock_initial_status(job_id, job_request): + """Mock job status to return PENDING initially.""" + return JobStatus.PENDING + + monkeypatch.setattr(client, "job_status", mock_initial_status) status = client.job_status(job_id, circuit_job_request) assert status in [JobStatus.PENDING, JobStatus.WAITING] - def mock_job_status(job_id, job_request): - """Mock job status to return a predefined status.""" + def mock_cancelled_status(job_id, job_request): + """Mock job status to return CANCELLED.""" return JobStatus.CANCELLED - monkeypatch.setattr(client, "job_status", mock_job_status) - + monkeypatch.setattr(client, "job_status", mock_cancelled_status) client.cancel_job(job_id, circuit_job_request) status = client.job_status(job_id, circuit_job_request) assert status == JobStatus.CANCELLED @@ -76,7 +82,19 @@ def mock_job_status(job_id, job_request): """Mock job status to return a predefined status.""" return JobStatus.COMPLETED + def mock_job_result(job_id, job_request): + """Mock job_result to return the expected two-bit string counts.""" + from datetime import datetime + now = datetime.now() + return Result( + counts={"00": 500, "11": 500}, + timestamp_submitted=now, + timestamp_scheduled=now, + timestamp_completed=now + ) + monkeypatch.setattr(client, "job_status", mock_job_status) + monkeypatch.setattr(client, "job_result", mock_job_result) monkeypatch.setattr(time, "sleep", lambda x: None) result = client.wait_for_job_result(job_id, circuit_job_request) From b4096922154ea18787cc5168dabde0d9ff0617fe Mon Sep 17 00:00:00 2001 From: kirti singh Date: Thu, 5 Jun 2025 19:21:19 +0200 Subject: [PATCH 03/10] reformatted --- test/test_mqss_client_mock.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/test_mqss_client_mock.py b/test/test_mqss_client_mock.py index 101935f..57d7c8a 100644 --- a/test/test_mqss_client_mock.py +++ b/test/test_mqss_client_mock.py @@ -53,12 +53,12 @@ def test_job_status( ) -> None: """Test job status.""" job_id = client.submit_job(circuit_job_request) - + # First mock to ensure initial status is PENDING def mock_initial_status(job_id, job_request): """Mock job status to return PENDING initially.""" return JobStatus.PENDING - + monkeypatch.setattr(client, "job_status", mock_initial_status) status = client.job_status(job_id, circuit_job_request) assert status in [JobStatus.PENDING, JobStatus.WAITING] @@ -85,12 +85,13 @@ def mock_job_status(job_id, job_request): def mock_job_result(job_id, job_request): """Mock job_result to return the expected two-bit string counts.""" from datetime import datetime + now = datetime.now() return Result( counts={"00": 500, "11": 500}, timestamp_submitted=now, timestamp_scheduled=now, - timestamp_completed=now + timestamp_completed=now, ) monkeypatch.setattr(client, "job_status", mock_job_status) From 97371dbe785dbb766f2947a6d28da5b5e0c74889 Mon Sep 17 00:00:00 2001 From: kirti singh Date: Thu, 12 Jun 2025 23:32:40 +0200 Subject: [PATCH 04/10] assertion not needed as this mock uuid will be setup in fixture --- test/test_pennylane_mock.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_pennylane_mock.py b/test/test_pennylane_mock.py index 74aa062..de6b566 100644 --- a/test/test_pennylane_mock.py +++ b/test/test_pennylane_mock.py @@ -81,7 +81,6 @@ def test_pennylane_job_submission(self, client: MQSSClient, pennylane_job_reques """Test submitting a Pennylane job.""" # Submit the job job_id = client.submit_job(pennylane_job_request) - assert job_id == "mock-uuid-12345" # Check status status = client.job_status(job_id, pennylane_job_request) From 22d0d427e8615e3b68b7970b291d1da5bfd99cdf Mon Sep 17 00:00:00 2001 From: kirti singh Date: Fri, 13 Jun 2025 00:26:11 +0200 Subject: [PATCH 05/10] reverting changes made to mqss_client mock --- test/test_mqss_client_mock.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/test/test_mqss_client_mock.py b/test/test_mqss_client_mock.py index 57d7c8a..6ae46d1 100644 --- a/test/test_mqss_client_mock.py +++ b/test/test_mqss_client_mock.py @@ -63,11 +63,11 @@ def mock_initial_status(job_id, job_request): status = client.job_status(job_id, circuit_job_request) assert status in [JobStatus.PENDING, JobStatus.WAITING] - def mock_cancelled_status(job_id, job_request): + def mock_job_status(job_id, job_request): """Mock job status to return CANCELLED.""" return JobStatus.CANCELLED - monkeypatch.setattr(client, "job_status", mock_cancelled_status) + monkeypatch.setattr(client, "job_status", mock_job_status) client.cancel_job(job_id, circuit_job_request) status = client.job_status(job_id, circuit_job_request) assert status == JobStatus.CANCELLED @@ -82,20 +82,9 @@ def mock_job_status(job_id, job_request): """Mock job status to return a predefined status.""" return JobStatus.COMPLETED - def mock_job_result(job_id, job_request): - """Mock job_result to return the expected two-bit string counts.""" - from datetime import datetime - now = datetime.now() - return Result( - counts={"00": 500, "11": 500}, - timestamp_submitted=now, - timestamp_scheduled=now, - timestamp_completed=now, - ) monkeypatch.setattr(client, "job_status", mock_job_status) - monkeypatch.setattr(client, "job_result", mock_job_result) monkeypatch.setattr(time, "sleep", lambda x: None) result = client.wait_for_job_result(job_id, circuit_job_request) From 93d4d9ca40ca9c22e0b546f27c22c50ff5832449 Mon Sep 17 00:00:00 2001 From: kirti singh Date: Fri, 13 Jun 2025 00:29:16 +0200 Subject: [PATCH 06/10] pre-commit hook format --- test/test_mqss_client_mock.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/test_mqss_client_mock.py b/test/test_mqss_client_mock.py index 6ae46d1..b2008ae 100644 --- a/test/test_mqss_client_mock.py +++ b/test/test_mqss_client_mock.py @@ -82,8 +82,6 @@ def mock_job_status(job_id, job_request): """Mock job status to return a predefined status.""" return JobStatus.COMPLETED - - monkeypatch.setattr(client, "job_status", mock_job_status) monkeypatch.setattr(time, "sleep", lambda x: None) From 98b96c5803f81ca95321030e1eaf76d3dbe9eaa3 Mon Sep 17 00:00:00 2001 From: kirti singh Date: Fri, 13 Jun 2025 00:44:56 +0200 Subject: [PATCH 07/10] Actual QASM circuit definition for the test --- test/test_pennylane_mock.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/test_pennylane_mock.py b/test/test_pennylane_mock.py index de6b566..6846553 100644 --- a/test/test_pennylane_mock.py +++ b/test/test_pennylane_mock.py @@ -7,6 +7,7 @@ from mqss_client import JobStatus, MQSSClient, Result from mqss_client.job import CircuitJobRequest +from .config import get_qasm from .mocks import MOCK_JOB_DATA, patch_mqss_rest_client, patch_rabbitmq_client # Add Pennylane mock data to existing mock data @@ -15,7 +16,7 @@ "job": {"jobs": ["mock-uuid-12345"]}, "job/mock-uuid-12345/status": {"status": "COMPLETED"}, "job/mock-uuid-12345/result": { - "result": '{"0": 500, "1": 500}', + "result": '{"00": 500, "11": 500}', "timestamp_completed": "2023-04-14 10:15:30.123456", "timestamp_submitted": "2023-04-14 10:00:00.123456", "timestamp_scheduled": "2023-04-14 10:05:00.123456", @@ -26,11 +27,11 @@ @pytest.fixture def pennylane_job_request(): - """Create a mock Pennylane job request.""" + """Create a mock Pennylane job request using QASM format.""" return CircuitJobRequest( resource_name="mock-backend", - circuits="mock-mlir-circuit", - circuit_format="mlir", + circuits=get_qasm(), # Using real QASM circuit definition, later we will use MLIR circuit definition + circuit_format="qasm", # Using QASM format shots=1000, no_modify=True, queued=False, @@ -89,7 +90,7 @@ def test_pennylane_job_submission(self, client: MQSSClient, pennylane_job_reques # Get result result = client.job_result(job_id, pennylane_job_request) assert isinstance(result, Result) - assert result.counts == {"0": 500, "1": 500} + assert result.counts == {"00": 500, "11": 500} def test_pennylane_job_cancellation( self, client: MQSSClient, pennylane_job_request @@ -127,4 +128,4 @@ def test_pennylane_job_wait_for_result( # Verify result assert isinstance(result, Result) - assert result.counts == {"0": 500, "1": 500} + assert result.counts == {"00": 500, "11": 500} From 71359f3bed23473922bfde4bf7353cbe890fe260 Mon Sep 17 00:00:00 2001 From: kirti singh Date: Mon, 23 Jun 2025 00:33:07 +0200 Subject: [PATCH 08/10] removed changes that is not needed for pennylane --- test/test_mqss_client_mock.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/test/test_mqss_client_mock.py b/test/test_mqss_client_mock.py index b2008ae..7f30db6 100644 --- a/test/test_mqss_client_mock.py +++ b/test/test_mqss_client_mock.py @@ -54,17 +54,11 @@ def test_job_status( """Test job status.""" job_id = client.submit_job(circuit_job_request) - # First mock to ensure initial status is PENDING - def mock_initial_status(job_id, job_request): - """Mock job status to return PENDING initially.""" - return JobStatus.PENDING - - monkeypatch.setattr(client, "job_status", mock_initial_status) status = client.job_status(job_id, circuit_job_request) assert status in [JobStatus.PENDING, JobStatus.WAITING] def mock_job_status(job_id, job_request): - """Mock job status to return CANCELLED.""" + """Mock job status to return a predefined status.""" return JobStatus.CANCELLED monkeypatch.setattr(client, "job_status", mock_job_status) From 4eee9f0aeafac1d282bd0eeca1158746799a7c54 Mon Sep 17 00:00:00 2001 From: kirti singh Date: Mon, 23 Jun 2025 00:38:15 +0200 Subject: [PATCH 09/10] updated the intial job status --- test/test_pennylane_mock.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_pennylane_mock.py b/test/test_pennylane_mock.py index 6846553..dcfc075 100644 --- a/test/test_pennylane_mock.py +++ b/test/test_pennylane_mock.py @@ -14,9 +14,9 @@ MOCK_JOB_DATA.update( { "job": {"jobs": ["mock-uuid-12345"]}, - "job/mock-uuid-12345/status": {"status": "COMPLETED"}, + "job/mock-uuid-12345/status": {"status": "PENDING"}, # Initially PENDING "job/mock-uuid-12345/result": { - "result": '{"00": 500, "11": 500}', + "result": '{"00": 500, "11": 500}', # Using 2-bit string format "timestamp_completed": "2023-04-14 10:15:30.123456", "timestamp_submitted": "2023-04-14 10:00:00.123456", "timestamp_scheduled": "2023-04-14 10:05:00.123456", @@ -83,9 +83,9 @@ def test_pennylane_job_submission(self, client: MQSSClient, pennylane_job_reques # Submit the job job_id = client.submit_job(pennylane_job_request) - # Check status + # Check initial status should be PENDING status = client.job_status(job_id, pennylane_job_request) - assert status == JobStatus.COMPLETED + assert status == JobStatus.PENDING # Get result result = client.job_result(job_id, pennylane_job_request) From ce1dd8112798ccd785411c364bf55102edbd61ce Mon Sep 17 00:00:00 2001 From: kirti singh Date: Mon, 23 Jun 2025 00:49:30 +0200 Subject: [PATCH 10/10] Updated mock job status to return COMPLETED in test for Pennylane job request --- test/test_pennylane_mock.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/test_pennylane_mock.py b/test/test_pennylane_mock.py index dcfc075..efcfa01 100644 --- a/test/test_pennylane_mock.py +++ b/test/test_pennylane_mock.py @@ -30,7 +30,7 @@ def pennylane_job_request(): """Create a mock Pennylane job request using QASM format.""" return CircuitJobRequest( resource_name="mock-backend", - circuits=get_qasm(), # Using real QASM circuit definition, later we will use MLIR circuit definition + circuits=get_qasm(), # Using real QASM circuit definition circuit_format="qasm", # Using QASM format shots=1000, no_modify=True, @@ -120,8 +120,12 @@ def test_pennylane_job_wait_for_result( # Submit the job job_id = client.submit_job(pennylane_job_request) - # Mock sleep to speed up test - monkeypatch.setattr("time.sleep", lambda x: None) + # Mock job status to return COMPLETED + def mock_job_status(job_id, job_request): + """Mock job status to return COMPLETED.""" + return JobStatus.COMPLETED + + monkeypatch.setattr(client, "job_status", mock_job_status) # Wait for result result = client.wait_for_job_result(job_id, pennylane_job_request)