def test_submit_continue_then_ok_reply(self): """Handle polling for a complete problem.""" # each thread can have its instance of a session because # the mocked responses are stateless def create_mock_session(client): session = mock.Mock() session.post = lambda a, _: choose_reply( a, {'problems/': [self.sapi.continue_reply(id='123')]}) session.get = lambda a: choose_reply( a, { 'problems/?id=123': [self.sapi.complete_no_answer_reply(id='123')], 'problems/123/': self.sapi.complete_reply(id='123') }) return session with mock.patch.object(Client, 'create_session', create_mock_session): with Client('endpoint', 'token') as client: solver = Solver(client, self.sapi.solver.data) linear, quadratic = self.sapi.problem params = dict(num_reads=100) results = solver.sample_ising(linear, quadratic, **params) self._check(results, linear, quadratic, **params)
def test_deprecations(self): """Proper deprecation warnings are raised.""" def create_mock_session(client): session = mock.Mock() session.post = lambda a, _: choose_reply(a, { 'problems/': [self.sapi.complete_no_answer_reply(id='123')] }) session.get = lambda a: choose_reply( a, {'problems/123/': self.sapi.complete_reply(id='123')}) return session with mock.patch.object(Client, 'create_session', create_mock_session): with Client('endpoint', 'token') as client: solver = Solver(client, self.sapi.solver.data) linear, quadratic = self.sapi.problem params = dict(num_reads=100) results = solver.sample_ising(linear, quadratic, **params) # aliased keys are deprecated in 0.8.0 with self.assertWarns(DeprecationWarning): results['samples'] with self.assertWarns(DeprecationWarning): results['occurrences'] # .error is deprecated in 0.7.x, scheduled for removal in 0.9.0 with self.assertWarns(DeprecationWarning): results.error # .occurrences is deprecated in 0.8.0, scheduled for removal in 0.10.0+ with self.assertWarns(DeprecationWarning): results.occurrences
def test_submit_offset_answer_does_not_include_it(self): """Handle a normal query with offset and response that doesn't include it.""" # ising problem energy offset offset = 3 # each thread can have its instance of a session because # the mocked responses are stateless def create_mock_session(client): session = mock.Mock() session.post = lambda a, _: choose_reply(a, { 'problems/': [self.sapi.complete_no_answer_reply(id='123')] }) session.get = lambda a: choose_reply( a, {'problems/123/': self.sapi.complete_reply(id='123')}) return session with mock.patch.object(Client, 'create_session', create_mock_session): with Client('endpoint', 'token') as client: solver = Solver(client, self.sapi.solver.data) linear, quadratic = self.sapi.problem params = dict(num_reads=100) results = solver.sample_ising(linear, quadratic, offset, **params) # although SAPI response doesn't include offset, Future should patch it on-the-fly self._check(results, linear, quadratic, offset=offset, **params)
def test_answer_load_error(self): """Answer load error is propagated as exception.""" error_code = 404 error_message = 'Problem not found' # each thread can have its instance of a session because # the mocked responses are stateless def create_mock_session(client): session = mock.Mock() session.post = lambda path, _: choose_reply( path, {'problems/': [self.sapi.complete_no_answer_reply(id='123')]}) session.get = lambda path: choose_reply( path, replies={'problems/123/': error_message}, statuses={'problems/123/': iter([error_code])}) return session with mock.patch.object(Client, 'create_session', create_mock_session): with Client('endpoint', 'token') as client: solver = Solver(client, self.sapi.solver.data) linear, quadratic = self.sapi.problem future = solver.sample_ising(linear, quadratic) with self.assertRaises(SolverError) as exc: future.result() self.assertEqual(str(exc.exception), error_message)
def test_submit_immediate_error_reply(self): """Handle an (obvious) error on problem submission.""" # each thread can have its instance of a session because # the mocked responses are stateless def create_mock_session(client): session = mock.Mock() session.post = lambda a, _: choose_reply( a, { 'problems/': [ self.sapi.immediate_error_reply( code=400, msg="Missing parameter 'num_reads' in problem JSON" ) ] }) return session with mock.patch.object(Client, 'create_session', create_mock_session): with Client('endpoint', 'token') as client: solver = Solver(client, self.sapi.solver.data) linear, quadratic = self.sapi.problem results = solver.sample_ising(linear, quadratic) with self.assertRaises(SolverFailureError): results.samples
def test_cancel_without_id(self): """Make sure the cancel method submits to the right endpoint. When cancel is called before the submission has returned the problem id. """ submission_id = 'test-id' release_reply = threading.Event() # each thread can have its instance of a session because # we use a global lock (event) in the mocked responses def create_mock_session(client): reply_body = [self.sapi.continue_reply(id=submission_id)] session = mock.Mock() session.get = lambda a: choose_reply( a, {'problems/?id={}'.format(submission_id): reply_body}) def post(a, _): release_reply.wait() return choose_reply(a, {'problems/': reply_body}) session.post = post session.delete = DeleteEvent.handle return session with mock.patch.object(Client, 'create_session', create_mock_session): with Client('endpoint', 'token') as client: solver = Solver(client, self.sapi.solver.data) linear, quadratic = self.sapi.problem future = solver.sample_ising(linear, quadratic) future.cancel() try: release_reply.set() future.samples self.fail() except DeleteEvent as event: if event.url == 'problems/': self.assertEqual(event.body, '["{}"]'.format(submission_id)) else: self.assertEqual(event.url, 'problems/{}/'.format(submission_id))
def test_submit_null_reply(self): """Get an error when the server's response is incomplete.""" # each thread can have its instance of a session because # the mocked responses are stateless def create_mock_session(client): session = mock.Mock() session.post = lambda a, _: choose_reply(a, {'problems/': ''}) return session with mock.patch.object(Client, 'create_session', create_mock_session): with Client('endpoint', 'token') as client: solver = Solver(client, self.sapi.solver.data) linear, quadratic = self.sapi.problem results = solver.sample_ising(linear, quadratic) with self.assertRaises(InvalidAPIResponseError): results.samples
def test_submit_cancel_reply(self): """Handle a response for a canceled job.""" # each thread can have its instance of a session because # the mocked responses are stateless def create_mock_session(client): session = mock.Mock() session.post = lambda a, _: choose_reply( a, {'problems/': [self.sapi.cancel_reply()]}) return session with mock.patch.object(Client, 'create_session', create_mock_session): with Client('endpoint', 'token') as client: solver = Solver(client, self.sapi.solver.data) linear, quadratic = self.sapi.problem results = solver.sample_ising(linear, quadratic) with self.assertRaises(CanceledFutureError): results.samples
def test_id_integration(self): """Problem ID getter blocks correctly when ID set by the client.""" submission_id = 'test-id' solver_name = 'solver-id' release_reply = threading.Event() # each thread can have its instance of a session because # we use a global lock (event) in the mocked responses def create_mock_session(client): session = mock.Mock() # delayed submit; emulates waiting in queue def post(path, _): release_reply.wait() reply_body = self.sapi.complete_reply(id=submission_id, solver=solver_name) return choose_reply(path, {'problems/': [reply_body]}) session.post = post return session with mock.patch.object(Client, 'create_session', create_mock_session): with Client('endpoint', 'token') as client: solver = Solver(client, self.sapi.solver.data) linear, quadratic = self.sapi.problem future = solver.sample_ising(linear, quadratic) # initially, the id is not available with self.assertRaises(TimeoutError): future.wait_id(timeout=1) # release the mocked sapi reply with the id release_reply.set() # verify the id is now available self.assertEqual(future.wait_id(), submission_id)
def test_submit_offset_wrong_offset_in_answer(self): """Energy levels don't match because offset in answer is respected, even if wrong""" # ising problem energy offset offset = 3 answer_offset = 2 * offset # make it wrong # each thread can have its instance of a session because # the mocked responses are stateless def create_mock_session(client): session = mock.Mock() session.post = lambda a, _: choose_reply(a, { 'problems/': [self.sapi.complete_no_answer_reply(id='123')] }) session.get = lambda a: choose_reply( a, { 'problems/123/': self.sapi.complete_reply( id='123', answer_patch=dict(offset=answer_offset)) }) return session with mock.patch.object(Client, 'create_session', create_mock_session): with Client('endpoint', 'token') as client: solver = Solver(client, self.sapi.solver.data) linear, quadratic = self.sapi.problem params = dict(num_reads=100) results = solver.sample_ising(linear, quadratic, offset, **params) # since SAPI response includes offset, Future shouldn't patch it; # but because the offset in answer is wrong, energies are off with self.assertRaises(AssertionError): self._check(results, linear, quadratic, offset=offset, **params)
class TestEventDispatch(unittest.TestCase): def setUp(self): # mock client self.client = Client(token='token', solver={'qpu': True}) self.client._fetch_solvers = lambda **kw: self.solvers self.client._submit = lambda *pa, **kw: None # mock solvers self.solver = Solver(client=self.client, data={ "properties": { "supported_problem_types": ["qubo", "ising"], "qubits": [0, 1, 2], "couplers": [[0, 1], [0, 2], [1, 2]], "num_qubits": 3, "num_reads_range": [0, 100], "parameters": { "num_reads": "Number of samples to return.", "postprocess": "either 'sampling' or 'optimization'" }, "topology": { "type": "chimera", "shape": [16, 16, 4] }, "category": "qpu", "tags": ["lower_noise"] }, "id": "solver1", "description": "A test solver 1", "status": "online" }) self.solvers = [self.solver] def test_validation(self): """Event name and handler are validated.""" with self.assertRaises(ValueError): add_handler('invalid_event_name', lambda: None) with self.assertRaises(TypeError): add_handler('before_client_init', None) def test_client_init(self): """Before/After client init events are dispatched with correct signatures.""" # setup event handlers memo = {} def handler(event, **data): memo[event] = data add_handler('before_client_init', handler) add_handler('after_client_init', handler) # client init client = Client(token='token', unknown='unknown') # test entry values before = memo['before_client_init'] self.assertEqual(before['obj'], client) self.assertEqual(before['args']['endpoint'], None) self.assertEqual(before['args']['token'], 'token') self.assertEqual(before['args']['kwargs']['unknown'], 'unknown') # test exit values after = memo['after_client_init'] self.assertEqual(after['obj'], client) self.assertEqual(after['args']['token'], 'token') self.assertEqual(after['args']['kwargs']['unknown'], 'unknown') self.assertEqual(after['return_value'], None) def test_get_solvers(self): """Before/After get_solvers events are dispatched with correct signatures.""" # setup event handlers memo = {} def handler(event, **data): memo[event] = data add_handler('before_get_solvers', handler) add_handler('after_get_solvers', handler) # get solver(s) self.client.get_solver() # test entry values before = memo['before_get_solvers'] self.assertEqual(before['obj'], self.client) self.assertIn('refresh', before['args']) self.assertIn('filters', before['args']) self.assertIn('qpu', before['args']['filters']) # test exit values after = memo['after_get_solvers'] self.assertEqual(after['obj'], self.client) self.assertIn('qpu', after['args']['filters']) self.assertEqual(after['return_value'], self.solvers) def test_sample(self): """Before/After solver sample events are dispatched with correct signatures.""" # setup event handlers memo = {} def handler(event, **data): memo[event] = data add_handler('before_sample', handler) add_handler('after_sample', handler) # sample lin = {0: 1} quad = {(0, 1): 1} offset = 2 params = dict(num_reads=100) future = self.solver.sample_ising(lin, quad, offset, **params) # test entry values before = memo['before_sample'] args = dict(type_='ising', linear=lin, quadratic=quad, offset=offset, params=params, undirected_biases=False) self.assertEqual(before['obj'], self.solver) self.assertDictEqual(before['args'], args) # test exit values after = memo['after_sample'] self.assertEqual(after['obj'], self.solver) self.assertDictEqual(after['args'], args) self.assertEqual(after['return_value'], future)
def test_submit_continue_then_ok_and_error_reply(self): """Handle polling for the status of multiple problems.""" # we need a "global session", because mocked responses are stateful def global_mock_session(): session = mock.Mock() # on first status poll, return pending for both problems # on second status poll, return error for first problem and complete for second def continue_then_complete(path, state={'count': 0}): state['count'] += 1 if state['count'] < 2: return choose_reply( path, { 'problems/?id=1': [self.sapi.continue_reply(id='1')], 'problems/?id=2': [self.sapi.continue_reply(id='2')], 'problems/1/': self.sapi.continue_reply(id='1'), 'problems/2/': self.sapi.continue_reply(id='2'), 'problems/?id=1,2': [ self.sapi.continue_reply(id='1'), self.sapi.continue_reply(id='2') ], 'problems/?id=2,1': [ self.sapi.continue_reply(id='2'), self.sapi.continue_reply(id='1') ] }) else: return choose_reply( path, { 'problems/?id=1': [self.sapi.error_reply(id='1')], 'problems/?id=2': [self.sapi.complete_no_answer_reply(id='2')], 'problems/1/': self.sapi.error_reply(id='1'), 'problems/2/': self.sapi.complete_reply(id='2'), 'problems/?id=1,2': [ self.sapi.error_reply(id='1'), self.sapi.complete_no_answer_reply(id='2') ], 'problems/?id=2,1': [ self.sapi.complete_no_answer_reply(id='2'), self.sapi.error_reply(id='1') ] }) def accept_problems_with_continue_reply(path, body, ids=iter('12')): problems = json.loads(body) return choose_reply( path, { 'problems/': [ self.sapi.continue_reply(id=next(ids)) for _ in problems ] }) session.get = continue_then_complete session.post = accept_problems_with_continue_reply return session session = global_mock_session() with mock.patch.object(Client, 'create_session', lambda self: session): with Client('endpoint', 'token') as client: solver = Solver(client, self.sapi.solver.data) linear, quadratic = self.sapi.problem params = dict(num_reads=100) results1 = solver.sample_ising(linear, quadratic, **params) results2 = solver.sample_ising(linear, quadratic, **params) with self.assertRaises(SolverFailureError): self._check(results1, linear, quadratic, **params) self._check(results2, linear, quadratic, **params)