From 77196655d9c12ca390789676ee078199a3292f5c Mon Sep 17 00:00:00 2001 From: Kevin Tian Date: Wed, 8 Nov 2023 17:38:04 -0500 Subject: [PATCH] Update integration tests (#1208) --- test/integration/test_backend.py | 8 +- test/integration/test_ibm_job.py | 128 ++------------------ test/integration/test_ibm_qasm_simulator.py | 45 ++----- 3 files changed, 29 insertions(+), 152 deletions(-) diff --git a/test/integration/test_backend.py b/test/integration/test_backend.py index 605ab8bc2..7c726b492 100644 --- a/test/integration/test_backend.py +++ b/test/integration/test_backend.py @@ -82,7 +82,7 @@ def setUpClass(cls): super().setUpClass() if cls.dependencies.channel == "ibm_cloud": # TODO use real device when cloud supports it - cls.backend = cls.dependencies.service.least_busy(simulator=False, min_num_qubits=5) + cls.backend = cls.dependencies.service.least_busy(min_num_qubits=5) if cls.dependencies.channel == "ibm_quantum": cls.backend = cls.dependencies.service.least_busy( simulator=False, min_num_qubits=5, instance=cls.dependencies.instance @@ -202,11 +202,15 @@ def test_backend_deepcopy(self): def test_backend_pending_jobs(self): """Test pending jobs are returned.""" + if self.dependencies.channel == "ibm_cloud": + raise SkipTest("Cloud account does not have real backend.") backends = self.service.backends() self.assertTrue(any(backend.status().pending_jobs > 0 for backend in backends)) def test_backend_fetch_all_qubit_properties(self): """Check retrieving properties of all qubits""" + if self.dependencies.channel == "ibm_cloud": + raise SkipTest("Cloud channel does not have instance.") num_qubits = self.backend.num_qubits qubits = list(range(num_qubits)) qubit_properties = self.backend.qubit_properties(qubits) @@ -260,6 +264,8 @@ def test_retrieve_backend_not_exist(self): def test_too_many_qubits_in_circuit(self): """Check error message if circuit contains more qubits than supported on the backend.""" + if self.dependencies.channel == "ibm_cloud": + raise SkipTest("Cloud channel does not have instance.") num = len(self.backend.properties().qubits) num_qubits = num + 1 circuit = QuantumCircuit(num_qubits, num_qubits) diff --git a/test/integration/test_ibm_job.py b/test/integration/test_ibm_job.py index dfffc21e4..0c60c080a 100644 --- a/test/integration/test_ibm_job.py +++ b/test/integration/test_ibm_job.py @@ -14,7 +14,6 @@ import copy import time from datetime import datetime, timedelta -from threading import Thread, Event from unittest import SkipTest, mock from unittest import skip @@ -27,14 +26,9 @@ from qiskit_ibm_provider.api.rest.job import Job as RestJob from qiskit_ibm_provider.exceptions import IBMBackendApiError -from qiskit_ibm_runtime import IBMBackend, RuntimeJob from qiskit_ibm_runtime.api.exceptions import RequestsApiError from qiskit_ibm_runtime.exceptions import RuntimeJobTimeoutError, RuntimeJobNotFound -from ..decorators import ( - IntegrationTestDependencies, - integration_test_setup_with_backend, -) -from ..fake_account_client import BaseFakeAccountClient, CancelableFakeJob + from ..ibm_test_case import IBMIntegrationTestCase from ..utils import ( most_busy_backend, @@ -46,23 +40,13 @@ class TestIBMJob(IBMIntegrationTestCase): """Test ibm_job module.""" - sim_backend: IBMBackend - real_device_backend: IBMBackend - bell = QuantumCircuit - sim_job: RuntimeJob - last_month: datetime - - @classmethod - @integration_test_setup_with_backend(simulator=False, min_num_qubits=2) - def setUpClass(cls, backend: IBMBackend, dependencies: IntegrationTestDependencies) -> None: - """Initial class level setup.""" - # pylint: disable=arguments-differ - super().setUpClass(dependencies=dependencies) - cls.sim_backend = dependencies.service.backend("ibmq_qasm_simulator") - cls.real_device_backend = backend - cls.bell = transpile(ReferenceCircuits.bell(), cls.sim_backend) - cls.sim_job = cls.sim_backend.run(cls.bell) - cls.last_month = datetime.now() - timedelta(days=30) + def setUp(self): + """Initial test setup.""" + super().setUp() + self.sim_backend = self.service.backend("ibmq_qasm_simulator") + self.bell = ReferenceCircuits.bell() + self.sim_job = self.sim_backend.run(self.bell) + self.last_month = datetime.now() - timedelta(days=30) def test_run_multiple_simulator(self): """Test running multiple jobs in a simulator.""" @@ -116,6 +100,8 @@ def test_run_multiple_simulator(self): def test_cancel(self): """Test job cancellation.""" + if self.dependencies.channel == "ibm_cloud": + raise SkipTest("Cloud account does not have real backend.") # Find the most busy backend backend = most_busy_backend(self.service) submit_and_cancel(backend, self.log) @@ -142,9 +128,7 @@ def test_retrieve_completed_jobs(self): def test_retrieve_pending_jobs(self): """Test retrieving jobs with the pending filter.""" - pending_job_list = self.service.jobs( - backend_name=self.sim_backend.name, limit=3, pending=True - ) + pending_job_list = self.service.jobs(program_id="sampler", limit=3, pending=True) for job in pending_job_list: self.assertTrue(job.status() in [JobStatus.QUEUED, JobStatus.RUNNING]) @@ -155,30 +139,6 @@ def test_retrieve_job(self): self.assertEqual(self.sim_job.inputs["circuits"], retrieved_job.inputs["circuits"]) self.assertEqual(self.sim_job.result().get_counts(), retrieved_job.result().get_counts()) - def test_retrieve_job_uses_appropriate_backend(self): - """Test that retrieved jobs come from their appropriate backend.""" - backend_1 = self.real_device_backend - # Get a second backend. - backend_2 = None - service = self.real_device_backend.service - for my_backend in service.backends(): - if my_backend.status().operational and my_backend.name != backend_1.name: - backend_2 = my_backend - break - if not backend_2: - raise SkipTest("Skipping test that requires multiple backends") - - job_1 = backend_1.run(transpile(ReferenceCircuits.bell())) - job_2 = backend_2.run(transpile(ReferenceCircuits.bell())) - - # test a retrieved job's backend is the same as the queried backend - self.assertEqual(service.job(job_1.job_id()).backend().name, backend_1.name) - self.assertEqual(service.job(job_2.job_id()).backend().name, backend_2.name) - - # Cleanup - for job in [job_1, job_2]: - cancel_job_safe(job, self.log) - def test_retrieve_job_error(self): """Test retrieving an invalid job.""" self.assertRaises(RuntimeJobNotFound, self.service.job, "BAD_JOB_ID") @@ -304,72 +264,10 @@ def test_refresh_job_result(self): self.assertDictEqual(cached_result, result.to_dict()) self.assertNotEqual(result.results[0].header.name, "modified_result") - @skip("TODO update test case") - def test_wait_for_final_state(self): - """Test waiting for job to reach final state.""" - - def final_state_callback(c_job_id, c_status, c_job, **kwargs): - """Job status query callback function.""" - self.assertEqual(c_job_id, job.job_id()) - self.assertNotIn(c_status, JOB_FINAL_STATES) - self.assertEqual(c_job.job_id(), job.job_id()) - self.assertIn("queue_info", kwargs) - - queue_info = kwargs.pop("queue_info", None) - callback_info["called"] = True - - if wait_time is None: - # Look for status change. - data = {"status": c_status, "queue_info": queue_info} - self.assertNotEqual(data, callback_info["last data"]) - callback_info["last data"] = data - else: - # Check called within wait time. - if callback_info["last call time"] and job._status not in JOB_FINAL_STATES: - self.assertAlmostEqual( - time.time() - callback_info["last call time"], - wait_time, - delta=0.2, - ) - callback_info["last call time"] = time.time() - - def job_canceller(job_, exit_event, wait): - exit_event.wait(wait) - cancel_job_safe(job_, self.log) - - wait_args = [2, None] - - saved_api = self.sim_backend._api_client - try: - self.sim_backend._api_client = BaseFakeAccountClient(job_class=CancelableFakeJob) - for wait_time in wait_args: - with self.subTest(wait_time=wait_time): - # Put callback data in a dictionary to make it mutable. - callback_info = { - "called": False, - "last call time": 0.0, - "last data": {}, - } - cancel_event = Event() - job = self.sim_backend.run(self.bell) - # Cancel the job after a while. - Thread(target=job_canceller, args=(job, cancel_event, 7), daemon=True).start() - try: - job.wait_for_final_state( - timeout=10, wait=wait_time, callback=final_state_callback - ) - self.assertTrue(job.in_final_state()) - self.assertTrue(callback_info["called"]) - cancel_event.set() - finally: - # Ensure all threads ended. - for thread in job._executor._threads: - thread.join(0.1) - finally: - self.sim_backend._api_client = saved_api - def test_wait_for_final_state_timeout(self): """Test waiting for job to reach final state times out.""" + if self.dependencies.channel == "ibm_cloud": + raise SkipTest("Cloud account does not have real backend.") backend = most_busy_backend(TestIBMJob.service) job = backend.run(transpile(ReferenceCircuits.bell(), backend=backend)) try: diff --git a/test/integration/test_ibm_qasm_simulator.py b/test/integration/test_ibm_qasm_simulator.py index 1cb074c84..daf96f11b 100644 --- a/test/integration/test_ibm_qasm_simulator.py +++ b/test/integration/test_ibm_qasm_simulator.py @@ -17,41 +17,25 @@ from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister from qiskit.compiler import transpile -from qiskit.providers.aer.noise import ( # pylint: disable=import-error,no-name-in-module - NoiseModel, -) from qiskit.test.reference_circuits import ReferenceCircuits -from qiskit_ibm_runtime import IBMBackend -from ..decorators import ( - integration_test_setup_with_backend, - IntegrationTestDependencies, -) from ..ibm_test_case import IBMIntegrationTestCase class TestIBMQasmSimulator(IBMIntegrationTestCase): """Test IBM Quantum QASM Simulator.""" - @integration_test_setup_with_backend(simulator=False) - def setUp(self, backend: IBMBackend, dependencies: IntegrationTestDependencies) -> None: - """Initial test setup.""" - # pylint: disable=unused-argument - # pylint: disable=arguments-differ - super().setUp() - self.sim_backend = self.service.backend("ibmq_qasm_simulator") - self.real_device_backend = backend - def test_execute_one_circuit_simulator_online(self): """Test execute_one_circuit_simulator_online.""" + backend = self.service.get_backend("ibmq_qasm_simulator") quantum_register = QuantumRegister(1) classical_register = ClassicalRegister(1) quantum_circuit = QuantumCircuit(quantum_register, classical_register, name="qc") quantum_circuit.h(quantum_register[0]) quantum_circuit.measure(quantum_register[0], classical_register[0]) - circs = transpile(quantum_circuit, backend=self.sim_backend) + circs = transpile(quantum_circuit, backend=backend) shots = 1024 - job = self.sim_backend.run(circs, shots=shots) + job = backend.run(circs, shots=shots) result = job.result() counts = result.get_counts(quantum_circuit) target = {"0": shots / 2, "1": shots / 2} @@ -60,6 +44,7 @@ def test_execute_one_circuit_simulator_online(self): def test_execute_several_circuits_simulator_online(self): """Test execute_several_circuits_simulator_online.""" + backend = self.service.get_backend("ibmq_qasm_simulator") quantum_register = QuantumRegister(2) classical_register = ClassicalRegister(2) qcr1 = QuantumCircuit(quantum_register, classical_register, name="qc1") @@ -72,8 +57,8 @@ def test_execute_several_circuits_simulator_online(self): qcr2.measure(quantum_register[0], classical_register[0]) qcr2.measure(quantum_register[1], classical_register[1]) shots = 1024 - circs = transpile([qcr1, qcr2], backend=self.sim_backend) - job = self.sim_backend.run(circs, shots=shots) + circs = transpile([qcr1, qcr2], backend=backend) + job = backend.run(circs, shots=shots) result = job.result() counts1 = result.get_counts(qcr1) counts2 = result.get_counts(qcr2) @@ -85,6 +70,7 @@ def test_execute_several_circuits_simulator_online(self): def test_online_qasm_simulator_two_registers(self): """Test online_qasm_simulator_two_registers.""" + backend = self.service.get_backend("ibmq_qasm_simulator") qr1 = QuantumRegister(2) cr1 = ClassicalRegister(2) qr2 = QuantumRegister(2) @@ -101,8 +87,8 @@ def test_online_qasm_simulator_two_registers(self): qcr2.measure(qr1[1], cr1[1]) qcr2.measure(qr2[0], cr2[0]) qcr2.measure(qr2[1], cr2[1]) - circs = transpile([qcr1, qcr2], self.sim_backend) - job = self.sim_backend.run(circs, shots=1024) + circs = transpile([qcr1, qcr2], backend) + job = backend.run(circs, shots=1024) result = job.result() result1 = result.get_counts(qcr1) result2 = result.get_counts(qcr2) @@ -156,16 +142,3 @@ def _new_submit(qobj, *args, **kwargs): finally: backend._configuration._data["simulation_method"] = sim_method backend._submit_job = submit_fn - - # @skip( - # "NoiseModel.from_backend does not currently support V2 Backends. \ - # Skip test until it's fixed in aer." - # ) - def test_simulator_with_noise_model(self): - """Test using simulator with a noise model.""" - noise_model = NoiseModel.from_backend(self.real_device_backend) - result = self.sim_backend.run( - transpile(ReferenceCircuits.bell(), backend=self.sim_backend), - noise_model=noise_model, - ).result() - self.assertTrue(result)