class TestClient(unittest.TestCase): def setUp(self): self.server_url = 'https://test.url/' self.api_path = '/api/downstream/v1' self.size = 100 self.address = base58.b58encode_check(b'\x00' + os.urandom(20)) self.token = binascii.hexlify(os.urandom(16)).decode('ascii') self.msg = '' self.sig = '' self.thread_manager = ShellApplication() self.contract_thread = ManagedThread() self.chunk_dir = os.path.join('data', 'chunks') self.client = DownstreamClient(self.server_url, self.token, self.address, self.size, self.msg, self.sig, self.thread_manager, self.chunk_dir) self.test_contract = \ DownstreamContract(self.client, MockValues.get_chunks_response[ 'chunks'][0]['file_hash'], MockValues.get_chunks_response[ 'chunks'][0]['seed'], MockValues.get_chunks_response[ 'chunks'][0]['size'], Heartbeat.challenge_type().fromdict( MockValues .get_chunks_response ['chunks'][0]['challenge']), datetime.utcnow() + timedelta( seconds=int( MockValues .get_chunks_response ['chunks'][0]['due'])), Heartbeat.tag_type().fromdict( MockValues .get_chunks_response ['chunks'][0]['tag']), self.thread_manager, self.chunk_dir) self.test_heartbeat = Heartbeat.fromdict( MockValues.connect_response['heartbeat']) def tearDown(self): pass def test_initialization(self): self.assertEqual(self.client.server, self.server_url.strip('/')) self.assertEqual(self.client.address, self.address) self.assertEqual(self.client.token, self.token) self.assertEqual(self.client.desired_size, self.size) self.assertIsNone(self.client.heartbeat) def test_connect_no_token_no_address(self): self.client.address = None self.client.token = None with self.assertRaises(DownstreamError) as ex: self.client.connect() self.assertEqual( str(ex.exception), 'If no token is specified, address must be.') def test_connect_failed(self): with mock.patch('downstream_farmer.client.requests.get'),\ mock.patch('downstream_farmer.client.handle_json_response')\ as hp: hp.side_effect = DownstreamError('test error') with self.assertRaises(DownstreamError) as ex: self.client.connect() self.assertEqual( str(ex.exception), 'Unable to connect: test error') def test_connect_malformed(self): with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = {"invalid": "dict"} with self.assertRaises(DownstreamError) as ex: self.client.connect() self.assertEqual( str(ex.exception), 'Malformed response from server.') def test_connect_invalid_heartbeat(self): with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = {"heartbeat": "test heartbeat", "token": "test token", "type": "invalid type"} with self.assertRaises(DownstreamError) as ex: self.client.connect() self.assertEqual(str(ex.exception), 'Unknown Heartbeat Type') def test_connect_working_new(self): self.client.token = None with mock.patch('downstream_farmer.client.requests.get') as patch: patch.return_value.json.return_value = MockValues.connect_response self.client.connect() patch.assert_called_with( '{0}/new/{1}'.format(self.server_url.strip('/') + self.api_path, self.address), verify=None) self.assertEqual( self.client.token, MockValues.connect_response['token']) self.assertEqual(self.client.heartbeat, Heartbeat .fromdict(MockValues.connect_response['heartbeat'])) def test_connect_working(self): with mock.patch('downstream_farmer.client.requests.get') as patch: patch.return_value.json.return_value = MockValues.connect_response self.client.connect() patch.assert_called_with('{0}/heartbeat/{1}'.format( self.server_url.strip('/') + self.api_path, self.token), verify=None) self.assertEqual( self.client.token, MockValues.connect_response['token']) self.assertEqual(self.client.heartbeat, Heartbeat .fromdict(MockValues.connect_response['heartbeat'])) def test_connect_sign(self): self.client.msg = 'test message' self.client.sig = 'HyzVUenXXo4pa+kgm1vS8PNJM83eIXFC5r0q86FGbqFcdla6rcw' '72/ciXiEPfjli3ENfwWuESHhv6K9esI0dl5I=' self.client.address = '19qVgG8C6eXwKMMyvVegsi3xCsKyk3Z3jV' self.client.token = None with mock.patch('downstream_farmer.client.requests.post') as patch: patch.return_value.json.return_value = MockValues.connect_response self.client.connect() patch.assert_called_with('{0}/new/{1}'.format(self.server_url .strip('/') + self .api_path, self .client.address), data=json.dumps({ "message": self.client.msg, "signature": self.client.sig }), headers={ 'Content-Type': 'application/json' }, verify=None) self.assertEqual( self.client.token, MockValues.connect_response['token']) self.assertEqual(self.client.heartbeat, Heartbeat.fromdict(MockValues .connect_response['heartbeat'])) def test_get_contract_no_token(self): with mock.patch('downstream_farmer.client.requests.get'),\ mock.patch('downstream_farmer.client.handle_json_response')\ as hp: hp.side_effect = DownstreamError('test error') with self.assertRaises(DownstreamError) as ex: self.client._get_contracts() self.assertEqual( str(ex.exception), 'Unable to get token: test error') def test_get_contract_malformed(self): with mock.patch('downstream_farmer.client.requests.get') as patch: patch.return_value.json.return_value = {"invalid": "dict"} with self.assertRaises(DownstreamError) as ex: self.client._get_contracts() self.assertEqual( str(ex.exception), 'Malformed response from server.') def test_get_contracts_working(self): self.client.heartbeat = self.test_heartbeat with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = MockValues.get_chunks_response.copy() contracts = self.client._get_contracts(100) self.assertEqual( contracts[0].hash, self.test_contract.hash) self.assertEqual( contracts[0].seed, self.test_contract.seed) self.assertEqual( contracts[0].size, self.test_contract.size) self.assertEqual( contracts[0].challenge, self.test_contract.challenge) self.assertAlmostEqual((contracts[0].expiration - self.test_contract.expiration) .total_seconds(), 0, delta=1) self.assertEqual(contracts[0].tag, self.test_contract.tag) def test_get_contract_no_chunks_available(self): self.client.heartbeat = self.test_heartbeat with mock.patch('downstream_farmer.client.requests.get'),\ mock.patch( 'downstream_farmer.client.handle_json_response' ) as hpatch: hpatch.return_value = dict(chunks=[]) contracts = self.client._get_contracts() self.assertEqual(len(contracts), 0) def setup_run_mocks(self): self.client.thread_manager = mock.MagicMock() self.client.thread_manager.running = True self.client.worker_pool = mock.MagicMock() self.client._get_contracts = mock.MagicMock() self.client._get_contracts.return_value = [self.test_contract] self.client._add_contract = mock.MagicMock() self.client.contract_thread = mock.MagicMock() self.client.get_total_size = mock.MagicMock() self.client.get_total_size.return_value = 0 def test_run_contract_manager(self): self.setup_run_mocks() self.client.contract_thread.wait.side_effect = \ MockContractShutdown(self.client.thread_manager) self.client._add_contract.side_effect = AddContractMock(self.client) self.client._run_contract_manager() self.assertFalse(self.client.thread_manager.signal_shutdown.called) self.client._add_contract.assert_called_with(self.test_contract) def test_run_contract_manager_obtain_fail_no_retry(self): self.setup_run_mocks() self.client.contract_count = mock.MagicMock() self.client.contract_count.return_value = 0 self.client._get_contracts.side_effect = DownstreamError('test error') self.client.thread_manager.signal_shutdown.side_effect = \ MockContractShutdown(self.client.thread_manager) with self.assertRaises(DownstreamError) as ex: self.client._run_contract_manager() self.assertEqual(str(ex.exception), 'test error') def test_run_contract_manager_obtain_fail_retry(self): self.setup_run_mocks() self.client.contract_count = mock.MagicMock() self.client.contract_count.return_value = 0 self.client._get_contracts.side_effect = \ [DownstreamError('test error'), [self.test_contract]] self.client._add_contract.side_effect = AddContractMock(self.client) self.client.contract_thread.wait.side_effect = \ MockContractShutdown(self.client.thread_manager) self.client._run_contract_manager(True) self.assertFalse(self.client.thread_manager.signal_shutdown.called) def test_run_contract_manager_shutdown_during_acquisition(self): self.setup_run_mocks() self.client._add_contract.side_effect = \ AddContractMock(self.client, self.client.thread_manager) self.client._run_contract_manager() self.assertFalse(self.client.thread_manager.signal_shutdown.called) def test_run_contract_manager_number_requirement(self): self.setup_run_mocks() self.client._add_contract.side_effect = \ AddContractMock(self.client) self.client.heartbeat_count = 1 self.client.thread_manager.signal_shutdown.side_effect = \ MockContractShutdown(self.client.thread_manager) self.client.desired_heartbeats = 1 self.client._run_contract_manager() self.assertTrue(self.client.thread_manager.signal_shutdown.called) def test_run_async(self): self.client.thread_manager = mock.MagicMock() self.contract_thread = mock.MagicMock() self.client.thread_manager.create_thread.return_value = \ self.contract_thread self.client.run_async() self.assertTrue(self.contract_thread.start.called) def test_set_cert_path(self): test_path = 'testpath' self.client._set_requests_verify_arg = mock.MagicMock() self.client.set_cert_path(test_path) self.assertEqual(self.client.cert_path, test_path) self.assertTrue(self.client._set_requests_verify_arg.called) def test_set_verify_cert(self): val = not self.client.verify_cert self.client._set_requests_verify_arg = mock.MagicMock() self.client.set_verify_cert(val) self.assertEqual(self.client.verify_cert, val) self.assertTrue(self.client._set_requests_verify_arg.called) def test_set_requests_verify_arg_false(self): self.client.verify_cert = False self.client.requests_verify_arg = True self.client._set_requests_verify_arg() self.assertFalse(self.client.requests_verify_arg)
class TestClient(unittest.TestCase): def setUp(self): self.server_url = 'https://test.url/' self.api_path = '/api/downstream/v1' self.size = 100 self.address = base58.b58encode_check(b'\x00' + os.urandom(20)) self.token = binascii.hexlify(os.urandom(16)).decode('ascii') self.msg = '' self.sig = '' self.api = API() self.client = DownstreamClient(self.server_url, self.token, self.address, self.size, self.msg, self.sig, self.api) self.test_contract = DownstreamContract(self.client, MockValues.get_chunk_response[ 'file_hash'], MockValues.get_chunk_response[ 'seed'], MockValues.get_chunk_response[ 'size'], Heartbeat.challenge_type() .fromdict( MockValues. get_chunk_response['challe' 'nge']), datetime.utcnow() + timedelta( seconds=int( MockValues. get_chunk_response['du' 'e'] )), Heartbeat.tag_type().fromdict( MockValues .get_chunk_response['ta' 'g'], ), self.api) self.test_heartbeat = Heartbeat.fromdict( MockValues.connect_response['heartbeat']) def tearDown(self): pass def test_initialization(self): self.assertEqual(self.client.server, self.server_url.strip('/')) self.assertEqual(self.client.address, self.address) self.assertEqual(self.client.token, self.token) self.assertEqual(self.client.desired_size, self.size) self.assertIsNone(self.client.heartbeat) self.assertEqual(len(self.client.contracts), 0) def test_connect_no_token_no_address(self): self.client.address = None self.client.token = None with self.assertRaises(DownstreamError) as ex: self.client.connect() self.assertEqual( str(ex.exception), 'If no token is specified, address must be.') def test_connect_failed(self): with mock.patch('downstream_farmer.client.requests.get'),\ mock.patch('downstream_farmer.client.handle_json_response')\ as hp: hp.side_effect = DownstreamError('test error') with self.assertRaises(DownstreamError) as ex: self.client.connect() self.assertEqual( str(ex.exception), 'Unable to connect: test error') def test_connect_malformed(self): with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = {"invalid": "dict"} with self.assertRaises(DownstreamError) as ex: self.client.connect() self.assertEqual( str(ex.exception), 'Malformed response from server.') def test_connect_invalid_heartbeat(self): with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = {"heartbeat": "test heartbeat", "token": "test token", "type": "invalid type"} with self.assertRaises(DownstreamError) as ex: self.client.connect() self.assertEqual(str(ex.exception), 'Unknown Heartbeat Type') def test_connect_working_new(self): self.client.token = None with mock.patch('downstream_farmer.client.requests.get') as patch: patch.return_value.json.return_value = MockValues.connect_response self.client.connect() patch.assert_called_with( '{0}/new/{1}'.format(self.server_url.strip('/') + self.api_path, self.address), verify=None) self.assertEqual( self.client.token, MockValues.connect_response['token']) self.assertEqual(self.client.heartbeat, Heartbeat .fromdict(MockValues.connect_response['heartbeat'])) def test_connect_working(self): with mock.patch('downstream_farmer.client.requests.get') as patch: patch.return_value.json.return_value = MockValues.connect_response self.client.connect() patch.assert_called_with('{0}/heartbeat/{1}'.format( self.server_url.strip('/') + self.api_path, self.token), verify=None) self.assertEqual( self.client.token, MockValues.connect_response['token']) self.assertEqual(self.client.heartbeat, Heartbeat .fromdict(MockValues.connect_response['heartbeat'])) def test_connect_sign(self): self.client.msg = 'test message' self.client.sig = 'HyzVUenXXo4pa+kgm1vS8PNJM83eIXFC5r0q86FGbqFcdla6rcw' '72/ciXiEPfjli3ENfwWuESHhv6K9esI0dl5I=' self.client.address = '19qVgG8C6eXwKMMyvVegsi3xCsKyk3Z3jV' self.client.token = None with mock.patch('downstream_farmer.client.requests.post') as patch: patch.return_value.json.return_value = MockValues.connect_response self.client.connect() patch.assert_called_with('{0}/new/{1}'.format(self.server_url .strip('/') + self .api_path, self .client.address), data=json.dumps({ "message": self.client.msg, "signature": self.client.sig }), headers={ 'Content-Type': 'application/json' }, verify=None) self.assertEqual( self.client.token, MockValues.connect_response['token']) self.assertEqual(self.client.heartbeat, Heartbeat.fromdict(MockValues .connect_response['heartbeat'])) def test_get_chunk_no_token(self): with mock.patch('downstream_farmer.client.requests.get'),\ mock.patch('downstream_farmer.client.handle_json_response')\ as hp: hp.side_effect = DownstreamError('test error') with self.assertRaises(DownstreamError) as ex: self.client.get_chunk() self.assertEqual( str(ex.exception), 'Unable to get token: test error') def test_get_chunk_malformed(self): with mock.patch('downstream_farmer.client.requests.get') as patch: patch.return_value.json.return_value = {"invalid": "dict"} with self.assertRaises(DownstreamError) as ex: self.client.get_chunk() self.assertEqual( str(ex.exception), 'Malformed response from server.') def test_get_chunk_working(self): self.client.heartbeat = self.test_heartbeat with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = MockValues.get_chunk_response self.client.get_chunk() self.assertEqual( self.client.contracts[0].hash, self.test_contract.hash) self.assertEqual( self.client.contracts[0].seed, self.test_contract.seed) self.assertEqual( self.client.contracts[0].size, self.test_contract.size) self.assertEqual( self.client.contracts[0].challenge, self.test_contract.challenge) self.assertAlmostEqual((self.client.contracts[ 0].expiration - self.test_contract.expiration) .total_seconds(), 0, delta=1) self.assertEqual(self.client.contracts[0].tag, self.test_contract.tag) def test_get_total_size(self): client = mock.MagicMock(spec=DownstreamClient) contract1 = mock.MagicMock(spec=DownstreamContract) contract2 = mock.MagicMock(spec=DownstreamContract) contract1.size = 10 contract2.size = 100 client.contracts = [contract1, contract2] self.assertEqual(DownstreamClient.get_total_size(client), 110) client.contracts = list() self.assertEqual(DownstreamClient.get_total_size(client), 0) def test_get_next_contract(self): client = mock.MagicMock(spec=DownstreamClient) contract1 = mock.MagicMock(spec=DownstreamContract) contract2 = mock.MagicMock(spec=DownstreamContract) contract1.time_remaining.return_value = 10 contract2.time_remaining.return_value = 100 client.contracts = [contract1, contract2] self.assertEqual(contract1, DownstreamClient.get_next_contract(client)) def test_run_obtain_contract_fail(self): client = mock.MagicMock(spec=DownstreamClient) client.get_total_size.return_value = 0 client.desired_size = 100 client.api = API() client.get_chunk.side_effect = DownstreamError('test error') client.contracts = [] with self.assertRaises(DownstreamError) as ex: DownstreamClient.run(client, 1) self.assertEqual( str(ex.exception), 'Unable to obtain a contract: test error') def test_run_working(self): client = mock.MagicMock(spec=DownstreamClient) client.get_total_size.return_value = 0 client.desired_size = 100 client.api = API() contract = mock.MagicMock(spec=DownstreamContract) contract.time_remaining.return_value = 0 contract.hash = '1' contract.api = client.api def patch_get_chunk(size): client.get_total_size.return_value = \ client.get_total_size.return_value + \ size client.contracts = [contract] client.get_chunk.side_effect = patch_get_chunk client.get_next_contract.return_value = contract DownstreamClient.run(client, 1) self.assertEqual(client.get_chunk.call_count, 1) self.assertEqual(contract.update_challenge.call_count, 1) self.assertEqual(contract.answer_challenge.call_count, 1) def test_run_working_block(self): client = mock.MagicMock(spec=DownstreamClient) client.get_total_size.return_value = 0 client.desired_size = 100 client.api = API() contract = mock.MagicMock(spec=DownstreamContract) contract.time_remaining.return_value = 1 contract.hash = '1' contract.api = client.api def patch_get_chunk(size): client.get_total_size.return_value = \ client.get_total_size.return_value + \ size client.contracts = [contract] client.get_chunk.side_effect = patch_get_chunk client.get_next_contract.return_value = contract with mock.patch('time.sleep') as a: DownstreamClient.run(client, 1) self.assertEqual(client.get_chunk.call_count, 1) self.assertEqual(contract.update_challenge.call_count, 1) self.assertEqual(contract.answer_challenge.call_count, 1) self.assertEqual(a.call_count, 1) def test_run_update_failed(self): client = mock.MagicMock(spec=DownstreamClient) client.get_total_size.return_value = 100 client.desired_size = 100 client.api = API() contract = mock.MagicMock(spec=DownstreamContract) contract.time_remaining.return_value = 0 contract.hash = '1' contract.api = client.api client.contracts = mock.MagicMock() client.contracts.remove = mock.MagicMock() contract.update_challenge.side_effect = DownstreamError('test error') client.get_next_contract.return_value = contract DownstreamClient.run(client, 1) self.assertTrue(client.contracts.remove.called) def test_run_answer_failed(self): client = mock.MagicMock(spec=DownstreamClient) client.get_total_size.return_value = 100 client.desired_size = 100 client.api = API() contract = mock.MagicMock(spec=DownstreamContract) contract.time_remaining.return_value = 0 contract.hash = '1' contract.api = client.api client.contracts = mock.MagicMock() client.contracts.remove = mock.MagicMock() contract.answer_challenge.side_effect = DownstreamError('test error') client.get_next_contract.return_value = contract DownstreamClient.run(client, 1) self.assertTrue(client.contracts.remove.called)
class TestClient(unittest.TestCase): def setUp(self): self.server_url = 'https://test.url/' self.address = base58.b58encode_check(b'\x00'+os.urandom(20)) self.client = DownstreamClient(self.address) self.test_contract = Contract(MockValues.get_chunk_response['file_hash'], MockValues.get_chunk_response['seed'], MockValues.get_chunk_response['size'], Heartbeat.challenge_type().fromdict( MockValues.get_chunk_response['challenge']), datetime.strptime( MockValues.get_chunk_response['expiration'], '%Y-%m-%dT%H:%M:%S'), Heartbeat.tag_type().fromdict( MockValues.get_chunk_response['tag'])) self.test_heartbeat = Heartbeat.fromdict(MockValues.connect_response['heartbeat']) def tearDown(self): pass def test_initialization(self): self.assertEqual(self.client.address, self.address) self.assertEqual(len(self.client.token),0) self.assertEqual(len(self.client.server),0) self.assertIsNone(self.client.heartbeat) self.assertIsNone(self.client.contract) def test_connect_malformed(self): with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = {"invalid":"dict"} with self.assertRaises(DownstreamError) as ex: self.client.connect(self.server_url) self.assertEqual(str(ex.exception),'Malformed response from server.') def test_connect_invalid_heartbeat(self): with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = {"heartbeat":"test heartbeat", "token":"test token", "type":"invalid type"} with self.assertRaises(DownstreamError) as ex: self.client.connect(self.server_url) self.assertEqual(str(ex.exception),'Unknown Heartbeat Type') def test_connect_working(self): with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = MockValues.connect_response self.client.connect(self.server_url) self.assertEqual(self.client.token,MockValues.connect_response['token']) self.assertEqual(self.client.heartbeat, Heartbeat.fromdict(MockValues.connect_response['heartbeat'])) def test_get_chunk_malformed(self): with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = {"invalid":"dict"} with self.assertRaises(DownstreamError) as ex: self.client.get_chunk() self.assertEqual(str(ex.exception),'Malformed response from server.') def test_get_chunk_working(self): self.client.heartbeat = self.test_heartbeat with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = MockValues.get_chunk_response self.client.get_chunk() self.assertEqual(self.client.contract.hash, self.test_contract.hash) self.assertEqual(self.client.contract.seed, self.test_contract.seed) self.assertEqual(self.client.contract.size, self.test_contract.size) self.assertEqual(self.client.contract.challenge, self.test_contract.challenge) self.assertEqual(self.client.contract.expiration, self.test_contract.expiration) self.assertEqual(self.client.contract.tag, self.test_contract.tag) def test_challenge_no_contract(self): self.client.contract = None with self.assertRaises(DownstreamError) as ex: self.client.get_challenge() self.assertEqual(str(ex.exception),'No contract to get a new challenge for.') def test_challenge_malformed(self): self.client.contract = self.test_contract self.client.heartbeat = self.test_heartbeat with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = {"invalid":"dict"} with self.assertRaises(DownstreamError) as ex: self.client.get_challenge() self.assertEqual(str(ex.exception),'Malformed response from server.') def test_challenge_block_til_expired(self): self.client.contract = self.test_contract self.client.heartbeat = self.test_heartbeat self.client.contract.expiration = datetime.utcnow()+timedelta(seconds=3) with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = MockValues.get_challenge_response self.assertIsNotNone(self.client.get_challenge()) def test_challenge_no_block(self): self.client.contract = self.test_contract self.client.heartbeat = self.test_heartbeat self.client.contract.expiration = datetime.utcnow()+timedelta(seconds=3) with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = MockValues.get_challenge_response self.assertIsNone(self.client.get_challenge(block=False)) def test_challenge_working(self): self.client.contract = self.test_contract self.client.heartbeat = self.test_heartbeat with mock.patch('downstream_farmer.client.requests.get') as patch: inst = patch.return_value inst.json.return_value = MockValues.get_challenge_response self.client.get_challenge() self.assertEqual(self.client.contract.challenge, Heartbeat.challenge_type().fromdict( MockValues.get_challenge_response['challenge'])) self.assertEqual(self.client.contract.expiration, datetime.strptime( MockValues.get_challenge_response['expiration'], '%Y-%m-%dT%H:%M:%S')) def test_answer_no_contract(self): self.client.contract = None with self.assertRaises(DownstreamError) as ex: self.client.answer_challenge() self.assertEqual(str(ex.exception),'No contract to answer.') def test_answer_malformed(self): self.client.contract = self.test_contract self.client.heartbeat = self.test_heartbeat with mock.patch('downstream_farmer.client.requests.post') as patch: inst = patch.return_value inst.json.return_value = {"invalid":"dict"} with self.assertRaises(DownstreamError) as ex: self.client.answer_challenge() self.assertEqual(str(ex.exception),'Malformed response from server.') def test_answer_invalid(self): self.client.contract = self.test_contract self.client.heartbeat = self.test_heartbeat with mock.patch('downstream_farmer.client.requests.post') as patch: inst = patch.return_value inst.json.return_value = {"status":"dict"} with self.assertRaises(DownstreamError) as ex: self.client.answer_challenge() self.assertEqual(str(ex.exception),'Challenge response rejected.') def test_answer_working(self): self.client.contract = self.test_contract self.client.heartbeat = self.test_heartbeat with mock.patch('downstream_farmer.client.requests.post') as patch: inst = patch.return_value inst.json.return_value = {"status":"ok"} self.client.answer_challenge()
class TestClient(unittest.TestCase): def setUp(self): self.server_url = 'https://test.url/' self.api_path = '/api/downstream/v1' self.size = 100 self.address = base58.b58encode_check(b'\x00' + os.urandom(20)) self.token = binascii.hexlify(os.urandom(16)).decode('ascii') self.msg = '' self.sig = '' self.thread_manager = ShellApplication() self.contract_thread = ManagedThread() self.chunk_dir = os.path.join('data', 'chunks') self.client = DownstreamClient(self.server_url, self.token, self.address, self.size, self.msg, self.sig, self.thread_manager, self.chunk_dir) self.client.session = mock.MagicMock() self.test_contract = \ DownstreamContract(self.client, MockValues.get_chunks_response[ 'chunks'][0]['file_hash'], MockValues.get_chunks_response[ 'chunks'][0]['seed'], MockValues.get_chunks_response[ 'chunks'][0]['size'], Heartbeat.challenge_type().fromdict( MockValues .get_chunks_response ['chunks'][0]['challenge']), datetime.utcnow() + timedelta( seconds=int( MockValues .get_chunks_response ['chunks'][0]['due'])), Heartbeat.tag_type().fromdict( MockValues .get_chunks_response ['chunks'][0]['tag']), self.thread_manager, self.chunk_dir) self.test_heartbeat = Heartbeat.fromdict( MockValues.connect_response['heartbeat']) def tearDown(self): pass def test_initialization(self): self.assertEqual(self.client.server, self.server_url.strip('/')) self.assertEqual(self.client.address, self.address) self.assertEqual(self.client.token, self.token) self.assertEqual(self.client.desired_size, self.size) self.assertIsNone(self.client.heartbeat) def test_connect_no_token_no_address(self): self.client.address = None self.client.token = None with self.assertRaises(DownstreamError) as ex: self.client.connect() self.assertEqual(str(ex.exception), 'If no token is specified, address must be.') def test_connect_failed(self): with mock.patch('downstream_farmer.client.handle_json_response')\ as hp: hp.side_effect = DownstreamError('test error') with self.assertRaises(DownstreamError) as ex: self.client.connect() self.assertEqual(str(ex.exception), 'Unable to connect: test error') def test_connect_malformed(self): inst = self.client.session.get.return_value inst.json.return_value = {"invalid": "dict"} with self.assertRaises(DownstreamError) as ex: self.client.connect() self.assertEqual(str(ex.exception), 'Malformed response from server.') def test_connect_invalid_heartbeat(self): inst = self.client.session.get.return_value inst.json.return_value = { "heartbeat": "test heartbeat", "token": "test token", "type": "invalid type" } with self.assertRaises(DownstreamError) as ex: self.client.connect() self.assertEqual(str(ex.exception), 'Unknown Heartbeat Type') def test_connect_working_new(self): self.client.token = None self.client.session.get.return_value.json.return_value \ = MockValues.connect_response self.client.connect() self.client.session.get.assert_called_with('{0}/new/{1}'.format( self.server_url.strip('/') + self.api_path, self.address), verify=None) self.assertEqual(self.client.token, MockValues.connect_response['token']) self.assertEqual( self.client.heartbeat, Heartbeat.fromdict(MockValues.connect_response['heartbeat'])) def test_connect_working(self): self.client.session.get.return_value.json.return_value \ = MockValues.connect_response self.client.connect() self.client.session.get.assert_called_with('{0}/heartbeat/{1}'.format( self.server_url.strip('/') + self.api_path, self.token), verify=None) self.assertEqual(self.client.token, MockValues.connect_response['token']) self.assertEqual( self.client.heartbeat, Heartbeat.fromdict(MockValues.connect_response['heartbeat'])) def test_connect_sign(self): self.client.msg = 'test message' self.client.sig = 'HyzVUenXXo4pa+kgm1vS8PNJM83eIXFC5r0q86FGbqFcdla6rcw' '72/ciXiEPfjli3ENfwWuESHhv6K9esI0dl5I=' self.client.address = '19qVgG8C6eXwKMMyvVegsi3xCsKyk3Z3jV' self.client.token = None self.client.session.post.return_value.json.return_value \ = MockValues.connect_response self.client.connect() self.client.session.post.\ assert_called_with( '{0}/new/{1}' .format(self.server_url.strip('/') + self.api_path, self.client.address), data=json.dumps({ "message": self.client.msg, "signature": self.client.sig }), headers={ 'Content-Type': 'application/json' }, verify=None) self.assertEqual(self.client.token, MockValues.connect_response['token']) self.assertEqual( self.client.heartbeat, Heartbeat.fromdict(MockValues.connect_response['heartbeat'])) def test_get_contract_no_token(self): with mock.patch('downstream_farmer.client.handle_json_response')\ as hp: hp.side_effect = DownstreamError('test error') with self.assertRaises(DownstreamError) as ex: self.client._get_contracts() self.assertEqual(str(ex.exception), 'Unable to get contracts: test error') def test_get_contract_malformed(self): patch = self.client.session.get patch.return_value.json.return_value = {"invalid": "dict"} with self.assertRaises(DownstreamError) as ex: self.client._get_contracts() self.assertEqual(str(ex.exception), 'Malformed response from server.') def test_get_contracts_working(self): self.client.heartbeat = self.test_heartbeat patch = self.client.session.get inst = patch.return_value inst.json.return_value = MockValues.get_chunks_response.copy() contracts = self.client._get_contracts(100) self.assertEqual(contracts[0].hash, self.test_contract.hash) self.assertEqual(contracts[0].seed, self.test_contract.seed) self.assertEqual(contracts[0].size, self.test_contract.size) self.assertEqual(contracts[0].challenge, self.test_contract.challenge) self.assertAlmostEqual((contracts[0].expiration - self.test_contract.expiration).total_seconds(), 0, delta=1) self.assertEqual(contracts[0].tag, self.test_contract.tag) def test_get_contract_no_chunks_available(self): self.client.heartbeat = self.test_heartbeat with mock.patch( 'downstream_farmer.client.handle_json_response') as hpatch: hpatch.return_value = dict(chunks=[]) contracts = self.client._get_contracts() self.assertEqual(len(contracts), 0) def setup_run_mocks(self): self.client.thread_manager = mock.MagicMock() self.client.thread_manager.running = True self.client.worker_pool = mock.MagicMock() self.client._get_contracts = mock.MagicMock() self.client._get_contracts.return_value = [self.test_contract] self.client._add_contract = mock.MagicMock() self.client.contract_thread = mock.MagicMock() self.client.get_total_size = mock.MagicMock() self.client.get_total_size.return_value = 0 def test_run_contract_manager(self): self.setup_run_mocks() self.client.contract_thread.wait.side_effect = \ MockContractShutdown(self.client.thread_manager) self.client._add_contract.side_effect = AddContractMock(self.client) self.client._run_contract_manager() self.assertFalse(self.client.thread_manager.signal_shutdown.called) self.client._add_contract.assert_called_with(self.test_contract) def test_run_contract_manager_obtain_fail_no_retry(self): self.setup_run_mocks() self.client.contract_count = mock.MagicMock() self.client.contract_count.return_value = 0 self.client._get_contracts.side_effect = DownstreamError('test error') self.client.thread_manager.signal_shutdown.side_effect = \ MockContractShutdown(self.client.thread_manager) with self.assertRaises(DownstreamError) as ex: self.client._run_contract_manager() self.assertEqual(str(ex.exception), 'test error') def test_run_contract_manager_obtain_fail_retry(self): self.setup_run_mocks() self.client.contract_count = mock.MagicMock() self.client.contract_count.return_value = 0 self.client._get_contracts.side_effect = \ [DownstreamError('test error'), [self.test_contract]] self.client._add_contract.side_effect = AddContractMock(self.client) self.client.contract_thread.wait.side_effect = \ MockContractShutdown(self.client.thread_manager) self.client._run_contract_manager(True) self.assertFalse(self.client.thread_manager.signal_shutdown.called) def test_run_contract_manager_shutdown_during_acquisition(self): self.setup_run_mocks() self.client._add_contract.side_effect = \ AddContractMock(self.client, self.client.thread_manager) self.client._run_contract_manager() self.assertFalse(self.client.thread_manager.signal_shutdown.called) def test_run_contract_manager_number_requirement(self): self.setup_run_mocks() self.client._add_contract.side_effect = \ AddContractMock(self.client) self.client.heartbeat_count = 1 self.client.thread_manager.signal_shutdown.side_effect = \ MockContractShutdown(self.client.thread_manager) self.client.desired_heartbeats = 1 self.client._run_contract_manager() self.assertTrue(self.client.thread_manager.signal_shutdown.called) def test_run_async(self): self.client.thread_manager = mock.MagicMock() self.contract_thread = mock.MagicMock() self.client.thread_manager.create_thread.return_value = \ self.contract_thread self.client.run_async() self.assertTrue(self.contract_thread.start.called) def test_set_cert_path(self): test_path = 'testpath' self.client._set_requests_verify_arg = mock.MagicMock() self.client.set_cert_path(test_path) self.assertEqual(self.client.cert_path, test_path) self.assertTrue(self.client._set_requests_verify_arg.called) def test_set_verify_cert(self): val = not self.client.verify_cert self.client._set_requests_verify_arg = mock.MagicMock() self.client.set_verify_cert(val) self.assertEqual(self.client.verify_cert, val) self.assertTrue(self.client._set_requests_verify_arg.called) def test_set_requests_verify_arg_false(self): self.client.verify_cert = False self.client.requests_verify_arg = True self.client._set_requests_verify_arg() self.assertFalse(self.client.requests_verify_arg)