Skip to content

Commit

Permalink
Merge branch 'main' into enable-test-basic-server-paths
Browse files Browse the repository at this point in the history
  • Loading branch information
rathishcholarajan committed Mar 18, 2022
2 parents fc687e6 + 1ab1a41 commit a21bd7f
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 138 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
matrix:
python-version: [ 3.9 ]
os: [ "ubuntu-latest" ]
environment: [ "legacy-production" ]
environment: [ "legacy-production", "legacy-staging" ]
environment: ${{ matrix.environment }}
env:
QISKIT_IBM_TOKEN: ${{ secrets.QISKIT_IBM_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ unit-test-coverage:

integration-test:
# TODO: enable all tests in "test/integration" directory
python -m unittest -v test/integration/test_backend.py
python -m unittest -v test/integration/test_backend.py test/integration/test_account_client.py

black:
black qiskit_ibm_provider test setup.py docs/tutorials
4 changes: 2 additions & 2 deletions qiskit_ibm_provider/ibm_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,9 @@ def __init__(
proxies=self._account.proxies,
verify=self._account.verify,
)
auth_client = self._authenticate_legacy_account(self._client_params)
self._auth_client = self._authenticate_legacy_account(self._client_params)

self._hgps = self._initialize_hgps(auth_client)
self._hgps = self._initialize_hgps(self._auth_client)
self._initialize_services()

@staticmethod
Expand Down
139 changes: 50 additions & 89 deletions test/integration/test_account_client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# pylint: disable-all
# type: ignore
# TODO: Reenable and fix integration tests.

# This code is part of Qiskit.
#
# (C) Copyright IBM 2021.
Expand All @@ -17,20 +13,22 @@
"""Tests for the AccountClient class."""

import re
import traceback
from unittest import mock

from qiskit.circuit import ClassicalRegister, QuantumCircuit, QuantumRegister
from qiskit.compiler import assemble, transpile
from urllib3.connectionpool import HTTPConnectionPool
from urllib3.exceptions import MaxRetryError

from qiskit_ibm_provider import IBMBackend
from qiskit_ibm_provider.api.client_parameters import ClientParameters
from qiskit_ibm_provider.api.clients import AccountClient, AuthClient
from qiskit_ibm_provider.api.exceptions import ApiError, RequestsApiError
from qiskit_ibm_provider.apiconstants import ApiJobStatus
from qiskit_ibm_provider.utils.utils import RefreshQueue
from ..contextmanagers import custom_envs, no_envs
from ..decorators import requires_qe_access, requires_provider
from ..decorators import (
integration_test_setup,
integration_test_setup_with_backend,
IntegrationTestDependencies,
)
from ..http_server import SimpleServer, ServerErrorOnceHandler, ClientErrorHandler
from ..ibm_test_case import IBMTestCase

Expand All @@ -39,17 +37,13 @@ class TestAccountClient(IBMTestCase):
"""Tests for AccountClient."""

@classmethod
@requires_provider
def setUpClass(cls, provider, hub, group, project):
@integration_test_setup()
def setUpClass(cls, dependencies: IntegrationTestDependencies) -> None:
"""Initial class level setup."""
# pylint: disable=arguments-differ
super().setUpClass()
cls.provider = provider
cls.hub = hub
cls.group = group
cls.project = project
default_hgp = cls.provider.backend._default_hgp
cls.access_token = default_hgp._api_client.account_api.session._access_token
cls.dependencies = dependencies
cls.access_token = cls.dependencies.provider._auth_client.current_access_token()

def setUp(self):
"""Initial test setup."""
Expand Down Expand Up @@ -77,8 +71,7 @@ def tearDown(self) -> None:

def _get_client(self):
"""Helper for instantiating an AccountClient."""
# pylint: disable=no-value-for-parameter
return AccountClient(self.provider.backend._default_hgp.credentials)
return AccountClient(self.dependencies.provider._client_params)

def test_exception_message(self):
"""Check exception has proper message."""
Expand Down Expand Up @@ -116,37 +109,6 @@ def test_custom_client_app_header(self):
custom_header, client._session.headers["X-Qx-Client-Application"]
)

def test_access_token_not_in_exception_traceback(self):
"""Check that access token is replaced within chained request exceptions."""
backend_name = "ibmq_qasm_simulator"
backend = self.provider.get_backend(
backend_name, hub=self.hub, group=self.group, project=self.project
)
circuit = transpile(self.qc1, backend, seed_transpiler=self.seed)
qobj = assemble(circuit, backend, shots=1)
client = backend._api_client

exception_message = (
"The access token in this exception "
"message should be replaced: {}".format(self.access_token)
)
exception_traceback_str = ""
try:
with mock.patch.object(
HTTPConnectionPool,
"urlopen",
side_effect=MaxRetryError(
HTTPConnectionPool("host"), "url", reason=exception_message
),
):
_ = client.job_submit(backend.name(), qobj.to_dict())
except RequestsApiError:
exception_traceback_str = traceback.format_exc()

self.assertTrue(exception_traceback_str)
if self.access_token in exception_traceback_str:
self.fail("Access token not replaced in request exception traceback.")

def test_job_submit_retry(self):
"""Test job submit requests get retried."""
client = self._get_client()
Expand Down Expand Up @@ -195,23 +157,19 @@ class TestAccountClientJobs(IBMTestCase):
"""

@classmethod
@requires_provider
def setUpClass(cls, provider, hub, group, project):
@integration_test_setup_with_backend(backend_name="ibmq_qasm_simulator")
def setUpClass(
cls, dependencies: IntegrationTestDependencies, backend: IBMBackend
) -> None:
# pylint: disable=arguments-differ
super().setUpClass()
cls.provider = provider
cls.hub = hub
cls.group = group
cls.project = project
default_hgp = cls.provider.backend._default_hgp
cls.access_token = default_hgp._api_client.account_api.session._access_token

backend_name = "ibmq_qasm_simulator"
backend = cls.provider.get_backend(
backend_name, hub=cls.hub, group=cls.group, project=cls.project
)
cls.dependencies = dependencies
cls.access_token = cls.dependencies.provider._auth_client.current_access_token()

cls.client = backend._api_client
cls.job = cls.client.job_submit(backend_name, cls._get_qobj(backend).to_dict())
cls.job = cls.client.job_submit(
"ibmq_qasm_simulator", cls._get_qobj(backend).to_dict()
)
cls.job_id = cls.job["job_id"]

@staticmethod
Expand Down Expand Up @@ -262,52 +220,55 @@ def test_list_jobs_statuses_skip(self):
class TestAuthClient(IBMTestCase):
"""Tests for the AuthClient."""

@requires_qe_access
def test_valid_login(self, qe_token, qe_url):
@classmethod
@integration_test_setup()
def setUpClass(cls, dependencies: IntegrationTestDependencies) -> None:
# pylint: disable=arguments-differ
super().setUpClass()
cls.dependencies = dependencies

def test_valid_login(self):
"""Test valid authentication."""
client = AuthClient(qe_token, qe_url)
self.assertTrue(client.base_api.session._access_token)
client = AuthClient(self.dependencies.provider._client_params)
self.assertTrue(client.access_token)
self.assertTrue(client.api_token)

@requires_qe_access
def test_url_404(self, qe_token, qe_url):
def test_url_404(self):
"""Test login against a 404 URL"""
url_404 = re.sub(r"/api.*$", "/api/TEST_404", qe_url)
url_404 = re.sub(r"/api.*$", "/api/TEST_404", self.dependencies.url)
with self.assertRaises(ApiError):
_ = AuthClient(qe_token, url_404)
_ = AuthClient(ClientParameters(token=self.dependencies.token, url=url_404))

@requires_qe_access
def test_invalid_token(self, qe_token, qe_url):
def test_invalid_token(self):
"""Test login using invalid token."""
qe_token = "INVALID_TOKEN"
with self.assertRaises(ApiError):
_ = AuthClient(qe_token, qe_url)
_ = AuthClient(
ClientParameters(token="INVALID_TOKEN", url=self.dependencies.url)
)

@requires_qe_access
def test_url_unreachable(self, qe_token, qe_url):
def test_url_unreachable(self):
"""Test login against an invalid (malformed) URL."""
qe_url = "INVALID_URL"
with self.assertRaises(ApiError):
_ = AuthClient(qe_token, qe_url)
_ = AuthClient(
ClientParameters(token=self.dependencies.token, url="INVALID_URL")
)

@requires_qe_access
def test_api_version(self, qe_token, qe_url):
def test_api_version(self):
"""Check the version of the QX API."""
client = AuthClient(qe_token, qe_url)
client = AuthClient(self.dependencies.provider._client_params)
version = client.api_version()
self.assertIsNotNone(version)

@requires_qe_access
def test_user_urls(self, qe_token, qe_url):
def test_user_urls(self):
"""Check the user urls of the QX API."""
client = AuthClient(qe_token, qe_url)
client = AuthClient(self.dependencies.provider._client_params)
user_urls = client.user_urls()
self.assertIsNotNone(user_urls)
self.assertTrue("http" in user_urls and "ws" in user_urls)

@requires_qe_access
def test_user_hubs(self, qe_token, qe_url):
def test_user_hubs(self):
"""Check the user hubs of the QX API."""
client = AuthClient(qe_token, qe_url)
client = AuthClient(self.dependencies.provider._client_params)
user_hubs = client.user_hubs()
self.assertIsNotNone(user_hubs)
for user_hub in user_hubs:
Expand Down
63 changes: 18 additions & 45 deletions test/integration/test_serialization.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# pylint: disable-all
# type: ignore
# TODO: Reenable and fix integration tests.

# This code is part of Qiskit.
#
# (C) Copyright IBM 2021.
Expand All @@ -28,7 +24,7 @@

from qiskit_ibm_provider import least_busy
from qiskit_ibm_provider.utils.json_encoder import IBMJsonEncoder
from ..decorators import requires_provider
from ..decorators import IntegrationTestDependencies, integration_test_setup
from ..ibm_test_case import IBMTestCase
from ..utils import cancel_job

Expand All @@ -37,35 +33,28 @@ class TestSerialization(IBMTestCase):
"""Test data serialization."""

@classmethod
@requires_provider
def setUpClass(cls, provider, hub, group, project):
@integration_test_setup()
def setUpClass(cls, dependencies: IntegrationTestDependencies) -> None:
"""Initial class level setup."""
# pylint: disable=arguments-differ
super().setUpClass()
cls.provider = provider
cls.hub = hub
cls.group = group
cls.project = project
cls.sim_backend = provider.get_backend(
"ibmq_qasm_simulator", hub=cls.hub, group=cls.group, project=cls.project
cls.dependencies = dependencies
cls.sim_backend = cls.dependencies.provider.get_backend(
"ibmq_qasm_simulator",
)
cls.bell = transpile(ReferenceCircuits.bell(), backend=cls.sim_backend)

def test_qasm_qobj(self):
"""Test serializing qasm qobj data."""
job = self.sim_backend.run(self.bell)
rqobj = self.provider.backend.job(job.job_id())._get_qobj()
rqobj = self.dependencies.provider.backend.job(job.job_id())._get_qobj()

self.assertEqual(_array_to_list(job._get_qobj().to_dict()), rqobj.to_dict())

def test_pulse_qobj(self):
"""Test serializing pulse qobj data."""
backends = self.provider.backends(
operational=True,
open_pulse=True,
hub=self.hub,
group=self.group,
project=self.project,
backends = self.dependencies.provider.backends(
operational=True, open_pulse=True, instance=self.dependencies.instance
)
if not backends:
self.skipTest("Need pulse backends.")
Expand All @@ -80,7 +69,7 @@ def test_pulse_qobj(self):
schedules = x_pulse | measure

job = backend.run(schedules, meas_level=1, shots=256)
rqobj = self.provider.backend.job(job.job_id())._get_qobj()
rqobj = self.dependencies.provider.backend.job(job.job_id())._get_qobj()
# Convert numpy arrays to lists since they now get converted right
# before being sent to the server.
self.assertEqual(_array_to_list(job._get_qobj().to_dict()), rqobj.to_dict())
Expand All @@ -89,12 +78,8 @@ def test_pulse_qobj(self):

def test_backend_configuration(self):
"""Test deserializing backend configuration."""
backends = self.provider.backends(
operational=True,
simulator=False,
hub=self.hub,
group=self.group,
project=self.project,
backends = self.dependencies.provider.backends(
operational=True, simulator=False, instance=self.dependencies.instance
)

# Known keys that look like a serialized complex number.
Expand All @@ -119,12 +104,8 @@ def test_backend_configuration(self):

def test_pulse_defaults(self):
"""Test deserializing backend configuration."""
backends = self.provider.backends(
operational=True,
open_pulse=True,
hub=self.hub,
group=self.group,
project=self.project,
backends = self.dependencies.provider.backends(
operational=True, open_pulse=True, instance=self.dependencies.instance
)
if not backends:
self.skipTest("Need pulse backends.")
Expand All @@ -138,12 +119,8 @@ def test_pulse_defaults(self):

def test_backend_properties(self):
"""Test deserializing backend properties."""
backends = self.provider.backends(
operational=True,
simulator=False,
hub=self.hub,
group=self.group,
project=self.project,
backends = self.dependencies.provider.backends(
operational=True, simulator=False, instance=self.dependencies.instance
)

# Known keys that look like a serialized object.
Expand All @@ -169,12 +146,8 @@ def test_qasm_job_result(self):
@slow_test
def test_pulse_job_result(self):
"""Test deserializing a pulse job result."""
backends = self.provider.backends(
open_pulse=True,
operational=True,
hub=self.hub,
group=self.group,
project=self.project,
backends = self.dependencies.provider.backends(
open_pulse=True, operational=True, instance=self.dependencies.instance
)
if not backends:
raise SkipTest("Skipping pulse test since no pulse backend found.")
Expand Down

0 comments on commit a21bd7f

Please sign in to comment.