Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding test suite for testing IBMQJob in isolation. #515

Merged
merged 4 commits into from
Jun 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions qiskit/backends/ibmq/ibmqjob.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,22 @@ def result(self, timeout=None, wait=5):
raise IBMQJobError('error submitting job: {}'.format(
repr(self._future_submit.exception())))
time.sleep(0.1)
this_result = self._wait_for_job(timeout=timeout, wait=wait)
try:
this_result = self._wait_for_job(timeout=timeout, wait=wait)
except TimeoutError as err:
# A timeout error retrieving the results does not imply the job
# is failing. The job can be still running.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, but the Result has an ERROR status, so for the user something wrong happened with this Job. Should we state in any way, that this may not be a real Job error?... like having another status for "TIMEOUT" or something similar.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's mark this for future improvements... we need to merge this asap.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #588 for the follow-up.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When job cancellation works on all IBM Q systems timeout could use that to cancel the job, which could be considered an error.

return Result({'id': self._id, 'status': 'ERROR',
'result': str(err)})

if self._is_device and self.done:
_reorder_bits(this_result)
if this_result.get_status() == 'ERROR':
self._status = JobStatus.ERROR
else:
self._status = JobStatus.DONE

if self._status not in self._final_states:
if this_result.get_status() == 'ERROR':
self._status = JobStatus.ERROR
else:
self._status = JobStatus.DONE
return this_result

def cancel(self):
Expand All @@ -142,7 +151,7 @@ def cancel(self):
bool: True if job can be cancelled, else False.

Raises:
QISKitError: if server returned error
IBMQJobError: if server returned error
"""
if self._is_commercial:
hub = self._api.config['hub']
Expand All @@ -151,8 +160,9 @@ def cancel(self):
response = self._api.cancel_job(self._id, hub, group, project)
if 'error' in response:
err_msg = response.get('error', '')
self._exception = QISKitError('Error cancelling job: %s' % err_msg)
raise QISKitError('Error canceelling job: %s' % err_msg)
error = IBMQJobError('Error cancelling job: %s' % err_msg)
self._exception = error
raise error
else:
self._cancelled = True
return True
Expand Down Expand Up @@ -210,6 +220,7 @@ def _update_status(self):
elif api_job['status'] == 'CANCELLED':
self._status = JobStatus.CANCELLED
self._status_msg = self._status.value
self._cancelled = True

elif 'ERROR' in api_job['status']:
# ERROR_CREATING_JOB or ERROR_RUNNING_JOB
Expand Down Expand Up @@ -405,15 +416,15 @@ def _wait_for_job(self, timeout=60, wait=5):

Raises:
QISKitError: job didn't return status or reported error in status
TimeoutError: if the job does not return results before an
specified timeout.
"""
start_time = time.time()
api_result = self._update_status()
while self._status not in self._final_states:
elapsed_time = time.time() - start_time
if timeout is not None and elapsed_time >= timeout:
job_result = {'id': self._id, 'status': 'ERROR',
'result': 'QISkit Time Out'}
return Result(job_result)
raise TimeoutError('QISKit timed out')
logger.info('status = %s (%d seconds)', api_result['status'],
elapsed_time)

Expand Down
40 changes: 34 additions & 6 deletions test/python/_dummybackend.py → test/python/_mockutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.


"""
Dummy backend simulator.
The purpose of this class is to create a Simulator that we can trick for testing
purposes. Testing local timeouts, arbitrary responses or behavior, etc.
Supporting fake, stubs and mocking classes.

The module includes, among other, a dummy backend simulator. The purpose of
this class is to create a Simulator that we can trick for testing purposes:
testing local timeouts, arbitrary responses or behavior, etc.
"""

import uuid
Expand All @@ -19,7 +22,7 @@
from qiskit import Result
from qiskit.backends import BaseBackend
from qiskit.backends import BaseJob
from qiskit.backends import JobStatus
from qiskit.backends.jobstatus import JobStatus
from qiskit.backends.baseprovider import BaseProvider

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -70,10 +73,10 @@ def run(self, qobj):
def run_job(self, qobj):
""" Main dummy simulator loop """
job_id = str(uuid.uuid4())

time.sleep(self.time_alive)

return Result({'job_id': job_id, 'result': [], 'status': 'COMPLETED'})
return Result(
{'job_id': job_id, 'result': [], 'status': 'COMPLETED'})


class DummyJob(BaseJob):
Expand Down Expand Up @@ -131,3 +134,28 @@ def error(self):
Exception: exception raised by attempting to run job.
"""
return self._future.exception(timeout=0)


def new_fake_qobj():
"""Creates a fake qobj dictionary."""
return {
'id': 'test-id',
'config': {
'backend_name': 'test-backend',
'shots': 1024,
'max_credits': 100
},
'circuits': [{
'compiled_circuit_qasm': 'fake-code',
'config': {
'seed': 123456
},
'compiled_circuit': {}
}]
}


class FakeBackend():
"""Fakes qiskit.backends.basebackend.BaseBackend instances."""
def __init__(self):
self.name = 'test-backend'
Loading