mirror of https://github.com/Qiskit/qiskit.git
Use FakeProvider for jupyter and monitor tests (#4296)
* Use FakeProvider for jupyter and monitor tests Right now the jupyter widget tests and backend monitor tests are the only place in the qiskit-terra unittests that require talking to IQX. This commit removes that dependency by leveraging the FakeProvider and FakeBackends which contain snapshots of the responses from the IBMQ api. To accomplish mocking out the qiskit-ibmq-provider usage the backend_overview module had to be renamed because it conflicted with the backend_overview function and was not importable via an absolute import. * Fix tests and lint * Remove online tests from contributing documentation There are no longer any online tests in the suite now that the provider interactions have been mocked out. This commit removes the documentation about how to configure the online tests. * Fixes from review comments
This commit is contained in:
parent
d4bbaf605c
commit
a87fe61992
|
@ -280,19 +280,6 @@ C:\..\> set LOG_LEVEL="INFO"
|
|||
C:\..\> python -m unittest test/python/circuit/test_circuit_operations.py
|
||||
```
|
||||
|
||||
##### Online Tests
|
||||
|
||||
Some tests require that you an IBMQ account configured. By default these
|
||||
tests are always skipped. If you want to run these tests locally please
|
||||
go to this
|
||||
[page](https://quantumexperience.ng.bluemix.net/qx/account/advanced) and
|
||||
register an account. Then you can either set the credentials explicitly
|
||||
with the `IBMQ_TOKEN` and `IBMQ_URL` environment variables to specify
|
||||
the token and url respectively for the IBMQ service. Alternatively, if
|
||||
you already have a single set of credentials configured in your
|
||||
environment (using a `.qiskitrc`) then you can just set
|
||||
`QISKIT_TESTS_USE_CREDENTIALS_FILE` to `1` and it will use that.
|
||||
|
||||
##### Test Skip Options
|
||||
|
||||
How and which tests are executed is controlled by an environment
|
||||
|
@ -300,7 +287,6 @@ variable, `QISKIT_TESTS`:
|
|||
|
||||
Option | Description | Default
|
||||
------ | ----------- | -------
|
||||
`skip_online` | Skips tests that require remote requests. Does not require user credentials. | `False`
|
||||
`run_slow` | It runs tests tagged as *slow*. | `False`
|
||||
|
||||
It is possible to provide more than one option separated with commas.
|
||||
|
|
|
@ -23,6 +23,7 @@ The mock devices are mainly for testing the compiler.
|
|||
"""
|
||||
|
||||
from .fake_provider import FakeProvider
|
||||
from .fake_provider import FakeProviderFactory
|
||||
from .fake_backend import FakeBackend
|
||||
from .fake_job import FakeJob
|
||||
from .fake_qobj import FakeQobj
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
# copyright notice, and modified files need to carry a notice indicating
|
||||
# that they have been altered from the originals.
|
||||
|
||||
# pylint: disable=wildcard-import
|
||||
# pylint: disable=wildcard-import,unused-argument
|
||||
|
||||
"""
|
||||
Fake provider class that provides access to fake backends.
|
||||
|
@ -76,3 +76,43 @@ class FakeProvider(BaseProvider):
|
|||
FakeAthens()]
|
||||
|
||||
super().__init__()
|
||||
|
||||
|
||||
class FakeProviderFactory:
|
||||
"""Fake provider factory class."""
|
||||
|
||||
def __init__(self):
|
||||
self.fake_provider = FakeProvider()
|
||||
|
||||
def load_account(self):
|
||||
"""Fake load_account method to mirror the IBMQ provider."""
|
||||
pass
|
||||
|
||||
def enable_account(self, *args, **kwargs):
|
||||
"""Fake enable_account method to mirror the IBMQ provider factory."""
|
||||
pass
|
||||
|
||||
def disable_account(self):
|
||||
"""Fake disable_account method to mirror the IBMQ provider factory."""
|
||||
pass
|
||||
|
||||
def save_account(self, *args, **kwargs):
|
||||
"""Fake save_account method to mirror the IBMQ provider factory."""
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def delete_account():
|
||||
"""Fake delete_account method to mirror the IBMQ provider factory."""
|
||||
pass
|
||||
|
||||
def update_account(self, force=False):
|
||||
"""Fake update_account method to mirror the IBMQ provider factory."""
|
||||
pass
|
||||
|
||||
def providers(self):
|
||||
"""Fake providers method to mirror the IBMQ provider."""
|
||||
return [self.fake_provider]
|
||||
|
||||
def get_provider(self, hub=None, group=None, project=None):
|
||||
"""Fake get_provider method to mirror the IBMQ provider."""
|
||||
return self.fake_provider
|
||||
|
|
|
@ -22,7 +22,7 @@ from IPython.core.magic import line_magic, Magics, magics_class # pylint: disab
|
|||
from IPython.core import magic_arguments # pylint: disable=import-error
|
||||
import matplotlib.pyplot as plt # pylint: disable=import-error
|
||||
import ipywidgets as widgets # pylint: disable=import-error
|
||||
from qiskit.tools.monitor.backend_overview import get_unique_backends
|
||||
from qiskit.tools.monitor.overview import get_unique_backends
|
||||
from qiskit.visualization.gate_map import plot_gate_map
|
||||
|
||||
|
||||
|
|
|
@ -18,7 +18,11 @@
|
|||
from IPython.core.magic import (line_magic, # pylint: disable=import-error
|
||||
Magics, magics_class)
|
||||
from qiskit.tools.events.pubsub import Subscriber
|
||||
from qiskit.providers.ibmq.job.exceptions import IBMQJobApiError
|
||||
try:
|
||||
from qiskit.providers.ibmq.job.exceptions import IBMQJobApiError
|
||||
HAS_IBMQ = True
|
||||
except ImportError:
|
||||
HAS_IBMQ = False
|
||||
from .job_widgets import (build_job_viewer, make_clear_button,
|
||||
make_labels, create_job_widget)
|
||||
from .watcher_monitor import _job_monitor
|
||||
|
@ -29,6 +33,10 @@ class JobWatcher(Subscriber):
|
|||
"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
if not HAS_IBMQ:
|
||||
raise ImportError("qiskit-ibmq-provider is required to use the "
|
||||
"job watcher. To install it run 'pip install "
|
||||
"qiskit-ibmq-provider'")
|
||||
self.jobs = []
|
||||
self._init_subscriber()
|
||||
self.job_viewer = None
|
||||
|
|
|
@ -16,4 +16,4 @@
|
|||
"""
|
||||
|
||||
from .job_monitor import job_monitor
|
||||
from .backend_overview import backend_monitor, backend_overview
|
||||
from .overview import backend_monitor, backend_overview
|
||||
|
|
|
@ -22,9 +22,8 @@ import unittest
|
|||
|
||||
import nbformat
|
||||
from nbconvert.preprocessors import ExecutePreprocessor
|
||||
import qiskit
|
||||
from qiskit.tools.visualization import HAS_MATPLOTLIB
|
||||
from qiskit.test import (Path, QiskitTestCase, online_test, slow_test)
|
||||
from qiskit.test import (Path, QiskitTestCase, slow_test)
|
||||
|
||||
|
||||
# Timeout (in seconds) for a single notebook.
|
||||
|
@ -33,14 +32,12 @@ TIMEOUT = 1000
|
|||
JUPYTER_KERNEL = 'python3'
|
||||
|
||||
|
||||
@unittest.skipUnless(hasattr(qiskit, 'IBMQ'),
|
||||
'qiskit-ibmq-provider is required for these tests')
|
||||
class TestJupyter(QiskitTestCase):
|
||||
"""Notebooks test case."""
|
||||
def setUp(self):
|
||||
self.execution_path = os.path.join(Path.SDK.value, '..')
|
||||
|
||||
def _execute_notebook(self, filename, qe_token=None, qe_url=None):
|
||||
def _execute_notebook(self, filename):
|
||||
# Create the preprocessor.
|
||||
execute_preprocessor = ExecutePreprocessor(timeout=TIMEOUT,
|
||||
kernel_name=JUPYTER_KERNEL)
|
||||
|
@ -49,16 +46,26 @@ class TestJupyter(QiskitTestCase):
|
|||
with open(filename) as file_:
|
||||
notebook = nbformat.read(file_, as_version=4)
|
||||
|
||||
if qe_token and qe_url:
|
||||
top_str = "from qiskit import IBMQ\n"
|
||||
top_str += "IBMQ.enable_account('{token}', '{url}')".format(token=qe_token,
|
||||
url=qe_url)
|
||||
top = nbformat.notebooknode.NotebookNode({'cell_type': 'code',
|
||||
'execution_count': 0,
|
||||
'metadata': {},
|
||||
'outputs': [],
|
||||
'source': top_str})
|
||||
notebook.cells = [top] + notebook.cells
|
||||
top_str = """
|
||||
import qiskit
|
||||
import sys
|
||||
from unittest.mock import create_autospec, MagicMock
|
||||
from qiskit.test.mock import FakeProviderFactory
|
||||
from qiskit.providers import basicaer
|
||||
fake_prov = FakeProviderFactory()
|
||||
qiskit.IBMQ = fake_prov
|
||||
ibmq_mock = create_autospec(basicaer)
|
||||
ibmq_mock.IBMQJobApiError = MagicMock()
|
||||
sys.modules['qiskit.providers.ibmq'] = ibmq_mock
|
||||
sys.modules['qiskit.providers.ibmq.job'] = ibmq_mock
|
||||
sys.modules['qiskit.providers.ibmq.job.exceptions'] = ibmq_mock
|
||||
"""
|
||||
top = nbformat.notebooknode.NotebookNode({'cell_type': 'code',
|
||||
'execution_count': 0,
|
||||
'metadata': {},
|
||||
'outputs': [],
|
||||
'source': top_str})
|
||||
notebook.cells = [top] + notebook.cells
|
||||
|
||||
# Run the notebook into the folder containing the `qiskit/` module.
|
||||
execute_preprocessor.preprocess(
|
||||
|
@ -73,14 +80,11 @@ class TestJupyter(QiskitTestCase):
|
|||
'notebooks/test_pbar_status.ipynb'))
|
||||
|
||||
@unittest.skipIf(not HAS_MATPLOTLIB, 'matplotlib not available.')
|
||||
@online_test
|
||||
@slow_test
|
||||
def test_backend_tools(self, qe_token, qe_url):
|
||||
def test_backend_tools(self):
|
||||
"""Test Jupyter backend tools."""
|
||||
self._execute_notebook(self._get_resource_path(
|
||||
'notebooks/test_backend_tools.ipynb'),
|
||||
qe_token=qe_token,
|
||||
qe_url=qe_url)
|
||||
'notebooks/test_backend_tools.ipynb'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -14,24 +14,69 @@
|
|||
|
||||
"""Tests for the wrapper functionality."""
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import MagicMock
|
||||
from io import StringIO
|
||||
|
||||
import qiskit
|
||||
from qiskit import providers
|
||||
from qiskit.tools.monitor import backend_overview, backend_monitor
|
||||
from qiskit.test import QiskitTestCase, online_test
|
||||
from qiskit.test import QiskitTestCase
|
||||
from qiskit.test.mock import FakeProviderFactory
|
||||
from qiskit.test.mock import FakeBackend
|
||||
from qiskit.test.mock import FakeVigo
|
||||
|
||||
|
||||
class TestBackendOverview(QiskitTestCase):
|
||||
"""Tools test case."""
|
||||
|
||||
@online_test
|
||||
def test_backend_overview(self, qe_token, qe_url):
|
||||
"""Test backend_overview"""
|
||||
from qiskit import IBMQ # pylint: disable: import-error
|
||||
IBMQ.enable_account(qe_token, qe_url)
|
||||
self.addCleanup(IBMQ.disable_account)
|
||||
def _restore_ibmq(self):
|
||||
if not self.import_error:
|
||||
qiskit.IBMQ = self.ibmq_back
|
||||
else:
|
||||
del qiskit.IBMQ
|
||||
if self.prov_backup:
|
||||
providers.ibmq = self.prov_backup
|
||||
else:
|
||||
del providers.ibmq
|
||||
|
||||
def _restore_ibmq_mod(self):
|
||||
if self.ibmq_module_backup is not None:
|
||||
sys.modules['qiskit.providers.ibmq'] = self.ibmq_module_backup
|
||||
else:
|
||||
sys.modules.pop('qiskit.providers.ibmq')
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
ibmq_mock = MagicMock()
|
||||
ibmq_mock.IBMQBackend = FakeBackend
|
||||
if 'qiskit.providers.ibmq' in sys.modules:
|
||||
self.ibmq_module_backup = sys.modules['qiskit.providers.ibmq']
|
||||
else:
|
||||
self.ibmq_module_backup = None
|
||||
sys.modules['qiskit.providers.ibmq'] = ibmq_mock
|
||||
self.addCleanup(self._restore_ibmq_mod)
|
||||
|
||||
if hasattr(qiskit, 'IBMQ'):
|
||||
self.import_error = False
|
||||
else:
|
||||
self.import_error = True
|
||||
qiskit.IBMQ = None
|
||||
self.ibmq_back = qiskit.IBMQ
|
||||
qiskit.IBMQ = FakeProviderFactory()
|
||||
self.addCleanup(self._restore_ibmq)
|
||||
if hasattr(providers, 'ibmq'):
|
||||
self.prov_backup = providers.ibmq
|
||||
else:
|
||||
self.prov_backup = None
|
||||
providers.ibmq = MagicMock()
|
||||
|
||||
@patch('qiskit.tools.monitor.overview.get_unique_backends',
|
||||
return_value=[FakeVigo()])
|
||||
def test_backend_overview(self, _):
|
||||
"""Test backend_overview"""
|
||||
with patch('sys.stdout', new=StringIO()) as fake_stdout:
|
||||
backend_overview()
|
||||
stdout = fake_stdout.getvalue()
|
||||
|
@ -39,18 +84,14 @@ class TestBackendOverview(QiskitTestCase):
|
|||
self.assertIn('Avg. T1:', stdout)
|
||||
self.assertIn('Num. Qubits:', stdout)
|
||||
|
||||
@online_test
|
||||
def test_backend_monitor(self, qe_token, qe_url):
|
||||
@patch('qiskit.tools.monitor.overview.get_unique_backends',
|
||||
return_value=[FakeVigo()])
|
||||
def test_backend_monitor(self, _):
|
||||
"""Test backend_monitor"""
|
||||
from qiskit import IBMQ # pylint: disable: import-error
|
||||
IBMQ.enable_account(qe_token, qe_url)
|
||||
self.addCleanup(IBMQ.disable_account)
|
||||
|
||||
for provider in IBMQ.providers():
|
||||
for back in provider.backends():
|
||||
if not back.configuration().simulator:
|
||||
backend = back
|
||||
break
|
||||
for back in [FakeVigo()]:
|
||||
if not back.configuration().simulator:
|
||||
backend = back
|
||||
break
|
||||
with patch('sys.stdout', new=StringIO()) as fake_stdout:
|
||||
backend_monitor(backend)
|
||||
|
||||
|
|
Loading…
Reference in New Issue