Skip to content

Commit

Permalink
Update integration tests (#1208)
Browse files Browse the repository at this point in the history
  • Loading branch information
kt474 authored Nov 8, 2023
1 parent e9f93ec commit 7719665
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 152 deletions.
8 changes: 7 additions & 1 deletion test/integration/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
128 changes: 13 additions & 115 deletions test/integration/test_ibm_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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,
Expand All @@ -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."""
Expand Down Expand Up @@ -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)
Expand All @@ -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])

Expand All @@ -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")
Expand Down Expand Up @@ -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:
Expand Down
45 changes: 9 additions & 36 deletions test/integration/test_ibm_qasm_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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")
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)

0 comments on commit 7719665

Please sign in to comment.