def test_submit_ok_reply(self): """Handle a normal query and response.""" with Client('endpoint', 'token') as client: client.session = mock.Mock() client.session.post = lambda a, _: choose_reply( a, { 'endpoint/problems/': '[%s]' % complete_no_answer_reply('123', 'abc123') }) client.session.get = lambda a: choose_reply( a, {'endpoint/problems/123/': complete_reply('123', 'abc123')}) solver = Solver(client, solver_data('abc123')) # Build a problem linear = {index: 1 for index in solver.nodes} quad = {key: -1 for key in solver.undirected_edges} results = solver.sample_ising(linear, quad, num_reads=100) self._check(results, linear, quad, 100)
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, solver_data('abc123')) linear, quadratic = test_problem(solver) results = solver.sample_ising(linear, quadratic) with self.assertRaises(InvalidAPIResponseError): 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' reply_body = '[%s]' % continue_reply(submission_id, 'solver') release_reply = threading.Event() with Client('endpoint', 'token') as client: client.session = mock.Mock() client.session.get = lambda a: choose_reply( a, {'endpoint/problems/?id={}'.format(submission_id): reply_body}) def post(a, _): release_reply.wait() return choose_reply(a, {'endpoint/problems/': reply_body}) client.session.post = post client.session.delete = DeleteEvent.handle solver = Solver(client, solver_data('abc123')) # Build a problem linear = {index: 1 for index in solver.nodes} quad = {key: -1 for key in solver.undirected_edges} future = solver.sample_ising(linear, quad) future.cancel() try: release_reply.set() future.samples self.fail() except DeleteEvent as event: if event.url == 'endpoint/problems/': self.assertEqual(event.body, '["{}"]'.format(submission_id)) else: self.assertEqual( event.url, 'endpoint/problems/{}/'.format(submission_id))
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/': '[%s]' % cancel_reply('123', 'abc123')}) return session with mock.patch.object(Client, 'create_session', create_mock_session): with Client('endpoint', 'token') as client: solver = Solver(client, solver_data('abc123')) linear, quadratic = test_problem(solver) results = solver.sample_ising(linear, quadratic, num_reads=100) with self.assertRaises(CanceledFutureError): results.samples
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/': '[%s]' % immediate_error_reply( 400, "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, solver_data('abc123')) linear, quadratic = test_problem(solver) results = solver.sample_ising(linear, quadratic) with self.assertRaises(SolverFailureError): results.samples
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/': '[%s]' % complete_no_answer_reply('123', 'abc123') }) session.get = lambda a: choose_reply( a, { 'problems/123/': complete_reply( '123', 'abc123', answer=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, solver_data('abc123')) linear, quadratic = test_problem(solver) 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)
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 = complete_reply(submission_id, solver_name) return choose_reply(path, {'problems/': '[%s]' % 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, solver_data(solver_name)) linear, quadratic = test_problem(solver) 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_continue_then_ok_reply(self): """Handle polling for a complete problem.""" now = datetime_in_future(0) eta_min, eta_max = datetime_in_future(10), datetime_in_future(30) # 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/': '[%s]' % continue_reply( '123', 'abc123', eta_min=eta_min, eta_max=eta_max, now=now) }, date=now) session.get = lambda a: choose_reply(a, { 'problems/?id=123': '[%s]' % complete_no_answer_reply('123', 'abc123'), 'problems/123/': complete_reply('123', 'abc123') }, date=now) return session with mock.patch.object(Client, 'create_session', create_mock_session): with Client('endpoint', 'token') as client: solver = Solver(client, solver_data('abc123')) linear, quadratic = test_problem(solver) params = dict(num_reads=100) results = solver.sample_ising(linear, quadratic, **params) self._check(results, linear, quadratic, **params) # test future has eta_min and eta_max parsed correctly self.assertEqual(results.eta_min, eta_min) self.assertEqual(results.eta_max, eta_max)
def test_submit_ok_reply(self): """Handle a normal query and response.""" # 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/': '[%s]' % complete_no_answer_reply('123', 'abc123') }) session.get = lambda a: choose_reply( a, {'problems/123/': complete_reply('123', 'abc123')}) return session with mock.patch.object(Client, 'create_session', create_mock_session): with Client('endpoint', 'token') as client: solver = Solver(client, solver_data('abc123')) linear, quadratic = test_problem(solver) results = solver.sample_ising(linear, quadratic, num_reads=100) self._check(results, linear, quadratic, 100)
def test_submit_continue_then_error_reply(self): """Handle polling for an error message.""" with Client('endpoint', 'token') as client: client.session = mock.Mock() client.session.post = lambda a, _: choose_reply( a, { 'endpoint/problems/': '[%s]' % continue_reply( '123', 'abc123') }) client.session.get = lambda a: choose_reply( a, { 'endpoint/problems/?id=123': '[%s]' % error_reply('123', 'abc123', "error message") }) solver = Solver(client, solver_data('abc123')) # Build a problem linear = {index: 1 for index in solver.nodes} quad = {key: -1 for key in solver.undirected_edges} results = solver.sample_ising(linear, quad, num_reads=100) with self.assertRaises(SolverFailureError): self._check(results, linear, quad, 100)
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': '[{}]'.format(continue_reply('1', 'abc123')), 'problems/?id=2': '[{}]'.format(continue_reply('2', 'abc123')), 'problems/1/': continue_reply('1', 'abc123'), 'problems/2/': continue_reply('2', 'abc123'), 'problems/?id=1,2': '[{},{}]'.format(continue_reply('1', 'abc123'), continue_reply('2', 'abc123')), 'problems/?id=2,1': '[{},{}]'.format(continue_reply('2', 'abc123'), continue_reply('1', 'abc123')) }) else: return choose_reply( path, { 'problems/?id=1': '[{}]'.format(error_reply('1', 'abc123', 'error')), 'problems/?id=2': '[{}]'.format( complete_no_answer_reply('2', 'abc123')), 'problems/1/': error_reply('1', 'abc123', 'error'), 'problems/2/': complete_reply('2', 'abc123'), 'problems/?id=1,2': '[{},{}]'.format( error_reply('1', 'abc123', 'error'), complete_no_answer_reply('2', 'abc123')), 'problems/?id=2,1': '[{},{}]'.format( complete_no_answer_reply('2', 'abc123'), error_reply('1', 'abc123', 'error')) }) def accept_problems_with_continue_reply(path, body, ids=iter('12')): problems = json.loads(body) return choose_reply( path, { 'problems/': json.dumps([ json.loads(continue_reply(next(ids), 'abc123')) 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, solver_data('abc123')) linear, quadratic = test_problem(solver) results1 = solver.sample_ising(linear, quadratic, num_reads=100) results2 = solver.sample_ising(linear, quadratic, num_reads=100) with self.assertRaises(SolverFailureError): self._check(results1, linear, quadratic, 100) self._check(results2, linear, quadratic, 100)
def test_submit_continue_then_ok_and_error_reply(self): """Handle polling for the status of multiple problems.""" with Client('endpoint', 'token') as client: client.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, { 'endpoint/problems/?id=1': '[{}]'.format(continue_reply('1', 'abc123')), 'endpoint/problems/?id=2': '[{}]'.format(continue_reply('2', 'abc123')), 'endpoint/problems/1/': continue_reply('1', 'abc123'), 'endpoint/problems/2/': continue_reply('2', 'abc123'), 'endpoint/problems/?id=1,2': '[{},{}]'.format(continue_reply('1', 'abc123'), continue_reply('2', 'abc123')), 'endpoint/problems/?id=2,1': '[{},{}]'.format(continue_reply('2', 'abc123'), continue_reply('1', 'abc123')) }) else: return choose_reply( path, { 'endpoint/problems/?id=1': '[{}]'.format(error_reply('1', 'abc123', 'error')), 'endpoint/problems/?id=2': '[{}]'.format( complete_no_answer_reply('2', 'abc123')), 'endpoint/problems/1/': error_reply('1', 'abc123', 'error'), 'endpoint/problems/2/': complete_reply('2', 'abc123'), 'endpoint/problems/?id=1,2': '[{},{}]'.format( error_reply('1', 'abc123', 'error'), complete_no_answer_reply('2', 'abc123')), 'endpoint/problems/?id=2,1': '[{},{}]'.format( complete_no_answer_reply('2', 'abc123'), error_reply('1', 'abc123', 'error')) }) client.session.get = continue_then_complete def accept_problems_with_continue_reply(path, body, ids=iter('12')): problems = json.loads(body) return choose_reply( path, { 'endpoint/problems/': json.dumps([ json.loads(continue_reply(next(ids), 'abc123')) for _ in problems ]) }) client.session.post = accept_problems_with_continue_reply solver = Solver(client, solver_data('abc123')) linear = {index: 1 for index in solver.nodes} quad = {key: -1 for key in solver.undirected_edges} results1 = solver.sample_ising(linear, quad, num_reads=100) results2 = solver.sample_ising(linear, quad, num_reads=100) with self.assertRaises(SolverFailureError): self._check(results1, linear, quad, 100) self._check(results2, linear, quad, 100)