def test_success_get_info_with_existing_files_and_hide_blocked(self): """ Successful getting files info with existing files and hide blocked ones. """ self.files_id.extend( files.insert().values( hash=self.blocked_hash, role='000', size=len(self.blocked_data), owner=test_owner_address ).execute().inserted_primary_key ) with self.app.test_client() as c: response = c.get(path=self.url) self.assertEqual(200, response.status_code, "'OK' status code is expected.") self.assertEqual('application/json', response.content_type, "Has to be a JSON-response.") data = json.loads(response.data.decode()) self.assertIsInstance(data, list, "Has to be an array.") self.assertSetEqual( set(_['hash'] for _ in files.select( files.c.hash != self.blocked_hash ).execute()), set(data), "Has to contain all files hashes without blacklisted ones." )
def test_reached_limit(self): """ Try to upload file with bandwidth limit reached. """ mock_config = copy.deepcopy(self.app.config) mock_config['NODE'].set_limits(incoming=1) with patch('metacore.storj.app.config', mock_config): response = self._make_request(self.send_data) self.assertEqual(400, response.status_code, "Response has to be marked as 'Bad Request'.") self.assertEqual('application/json', response.content_type, "Has to be a JSON-response.") self.assertDictEqual( {'error_code': ERR_TRANSFER['LIMIT_REACHED']}, json.loads(response.data.decode()), "Unexpected response data." ) self.assertSetEqual( self.files, set(tuple(_) for _ in files.select().execute()), "Database has to be unchanged." ) self.assertFalse(os.path.exists(self._get_saved_file_path()), "File should not be saved.")
def test_huge_file(self): """ Try to upload too big file. """ mock_config = copy.deepcopy(self.app.config) mock_config['MAX_FILE_SIZE'] = len(self.file_data) - 1 with patch('metacore.storj.app.config', mock_config): response = self._make_request(self.send_data) self.assertEqual(400, response.status_code, "Response has to be marked as 'Bad Request'.") self.assertEqual('application/json', response.content_type, "Has to be a JSON-response.") self.assertDictEqual( {'error_code': ERR_TRANSFER['HUGE_FILE']}, json.loads(response.data.decode()), "Unexpected response data." ) self.assertSetEqual( self.files, set(tuple(_) for _ in files.select().execute()), "Database has to be unchanged." ) self.assertFalse(os.path.exists(self._get_saved_file_path()), "File should not be saved.")
def test_full_disk(self): """ Try to upload file with no enough space on disk. """ mock_config = copy.deepcopy(self.app.config) mock_config['NODE'] = Mock(capacity=1) with patch('metacore.storj.app.config', mock_config): response = self._make_request(self.send_data) self.assertEqual(400, response.status_code, "Response has to be marked as 'Bad Request'.") self.assertEqual('application/json', response.content_type, "Has to be a JSON-response.") self.assertDictEqual( {'error_code': ERR_TRANSFER['FULL_DISK']}, json.loads(response.data.decode()), "Unexpected response data." ) self.assertSetEqual( self.files, set(tuple(_) for _ in files.select().execute()), "Database has to be unchanged." ) self.assertFalse(os.path.exists(self._get_saved_file_path()), "File should not be saved.")
def test_mismatched_hash(self): """ Try to upload file with mismatched SHA-256 hash. """ self.send_data['data_hash'] = sha256(self.file_data + b'_').hexdigest() self.headers['signature'] = test_btctx_api.sign_unicode( test_owner_wif, self.send_data['data_hash'] ) response = self._make_request(self.send_data) self.assertEqual(400, response.status_code, "Response has to be marked as 'Bad Request'.") self.assertEqual('application/json', response.content_type, "Has to be a JSON-response.") self.assertDictEqual( {'error_code': ERR_TRANSFER['MISMATCHED_HASH']}, json.loads(response.data.decode()), "Unexpected response data." ) self.assertSetEqual( self.files, set(tuple(_) for _ in files.select().execute()), "Database has to be unchanged." ) self.assertFalse(os.path.exists(self._get_saved_file_path()), "File should not be saved.")
def test_invalid_signature(self): """ Try to upload file with invalid signature. """ self.headers['signature'] = self.headers['signature'].swapcase() response = self._make_request(self.send_data) self.assertEqual(400, response.status_code, "Response has to be marked as 'Bad Request'.") self.assertEqual('application/json', response.content_type, "Has to be a JSON-response.") self.assertDictEqual( {'error_code': ERR_TRANSFER['INVALID_SIGNATURE']}, json.loads(response.data.decode()), "Unexpected response data." ) self.assertSetEqual( self.files, set(tuple(_) for _ in files.select().execute()), "Database has to be unchanged." ) self.assertFalse(os.path.exists(self._get_saved_file_path()), "File should not be saved.")
def test_blocked_hash(self): """ Try to upload file with blacklisted SHA-256 hash. """ self.send_data.update({ 'file_data': (BytesIO(self.blocked_data), 'test_file'), 'data_hash': self.blocked_hash }) self.headers['signature'] = test_btctx_api.sign_unicode( test_owner_wif, self.send_data['data_hash'] ) response = self._make_request(self.send_data) self.assertEqual(404, response.status_code, "'Not Found' status code is expected.") self.assertSetEqual( self.files, set(tuple(_) for _ in files.select().execute()), "Database has to be unchanged." ) self.assertFalse(os.path.exists(self._get_saved_file_path()), "File should not be saved.")
def test_success_upload(self): """ Upload file with all valid data. """ response = self._make_request(self.send_data) self.assertEqual(201, response.status_code, "'Created' status code is expected.") self.assertEqual('application/json', response.content_type, "Has to be a JSON-response.") self.assertDictEqual( {'data_hash': self.send_data['data_hash'], 'file_role': self.send_data['file_role']}, json.loads(response.data.decode()), "Unexpected response data." ) uploaded_file_record = files.select( files.c.hash == self.send_data['data_hash'] ).execute().first() self.assertIsNotNone(uploaded_file_record, "File record does not exist in the table.") self.assertEqual(self.headers['sender_address'], uploaded_file_record.owner, "Sender address has to be stored into 'owner' field.") self.assertSetEqual( self.files | {tuple(uploaded_file_record)}, set(tuple(_) for _ in files.select().execute()), "Only new record has to be inserted in the database. " "No other changes." ) try: with open(self._get_saved_file_path(), 'rb') as stored_file: self.assertEqual( self.file_data, stored_file.read(), "Stored file data does not match with uploaded one." ) except OSError: self.assertTrue(False, 'Uploaded file is not saved.')
def files_list(): """ Get list of files hashes stored on the Node. :return: list of hashes """ with open(app.config['BLACKLIST_FILE']) as fp: blocked_hashes = [_.strip() for _ in fp.readlines()] hash_list = [_['hash'] for _ in files.select().execute() if _['hash'] not in blocked_hashes] return hash_list
def _check_file_existence(self): """ Check if file with data_hash is already downloaded on the Node. Prevent repeated downloading the same data. :return: """ self.file = files.select( files.c.hash == self.data_hash ).execute().first() if self.file: return ERR_TRANSFER['REPEATED_UPLOAD']
def _get_file_from_hash(self): """ Check if file record with data_hash exists in the `files` table and allowed for getting and then store it as self.file. :return: 'Not Found' error code or None if the record exists. :rtype: Response or RowProxy """ self.file = files.select( files.c.hash == self.data_hash ).execute().first() if not self.file or ( self.file.role[1] != '0' and self.file.owner != self.sender_address ): return ERR_AUDIT['NOT_FOUND']
def info(self): """ Aggregate common status info for Node (public key, bandwidth, storage). :return: Node status info :rtype: dict """ files_size = [_['size'] for _ in files.select().execute()] info = { 'public_key': self.public_key, 'bandwidth': { 'current': self.__current_bandwidth, 'limits': self.__limits, 'total': self.__total_bandwidth }, 'storage': { 'capacity': self.__capacity, 'max_file_size': max(files_size) if files_size else 0, 'used': sum(files_size) } } return info
def test_success_get_info_with_existing_files(self): """ Successful getting files info with existing files. """ with self.app.test_client() as c: response = c.get(path=self.url) self.assertEqual(200, response.status_code, "'OK' status code is expected.") self.assertEqual('application/json', response.content_type, "Has to be a JSON-response.") data = json.loads(response.data.decode()) self.assertIsInstance(data, list, "Has to be an array.") self.assertSetEqual( set(_['hash'] for _ in files.select().execute()), set(data), "Has to contain all files hashes." )
def setUp(self): """ Switch to test config. Remember initial records in the 'files' table. Remember initial files set in the Upload Dir. Remember initial blacklist content. """ self.app = storj.app self.app.config['TESTING'] = True self.files = set(tuple(_) for _ in files.select().execute()) self.stored_files = set(os.listdir(self.app.config['UPLOAD_FOLDER'])) self.file_data = b'some data' valid_hash = sha256(self.file_data).hexdigest() valid_signature = test_btctx_api.sign_unicode(test_owner_wif, valid_hash) self.blocked_data = b'blocked_data' self.blocked_hash = sha256(self.blocked_data).hexdigest() with open(self.app.config['BLACKLIST_FILE'], 'r+') as fp: self.initial_blacklist = fp.read() fp.writelines((self.blocked_hash + '\n',)) self.send_data = { 'data_hash': valid_hash, 'file_data': (BytesIO(self.file_data), 'test_file'), 'file_role': '000' } self.headers = { 'sender_address': test_owner_address, 'signature': valid_signature } self.patcher = patch('metacore.processor.BTCTX_API', test_btctx_api) self.patcher.start()