def test_feedback(pathfinding_service_mock): token_network_address = TokenNetworkAddress(b"1" * 20) route = [Address(b"2" * 20), Address(b"3" * 20)] other_route = [Address(b"2" * 20), Address(b"4" * 20)] token = FeedbackToken(token_network_address=token_network_address) other_token = FeedbackToken(token_network_address=token_network_address) database = pathfinding_service_mock.database assert not db_has_feedback_for(database=database, token=token, route=route) assert not db_has_feedback_for(database=database, token=token, route=other_route) assert not db_has_feedback_for(database=database, token=other_token, route=route) database.prepare_feedback(token=token, route=route) assert not db_has_feedback_for(database=database, token=token, route=route) assert not db_has_feedback_for(database=database, token=other_token, route=route) assert not db_has_feedback_for(database=database, token=token, route=other_route) rowcount = database.update_feedback(token=token, route=route, successful=True) assert rowcount == 1 assert db_has_feedback_for(database=database, token=token, route=route) assert not db_has_feedback_for(database=database, token=other_token, route=route) assert not db_has_feedback_for(database=database, token=token, route=other_route) rowcount = database.update_feedback(token=token, route=route, successful=True) assert rowcount == 0
def test_stats_endpoint( api_sut_with_debug: ServiceApi, api_url: str, token_network_model: TokenNetwork ): database = api_sut_with_debug.pathfinding_service.database default_path = [Address(b"1" * 20), Address(b"2" * 20), Address(b"3" * 20)] feedback_token = FeedbackToken(token_network_model.address) def check_response(num_all: int, num_only_feedback: int, num_only_success: int) -> None: url = api_url + f"/_debug/stats" response = requests.get(url) assert response.status_code == 200 data = response.json() assert data["total_calculated_routes"] == num_all assert data["total_feedback_received"] == num_only_feedback assert data["total_successful_routes"] == num_only_success database.prepare_feedback(feedback_token, default_path) check_response(1, 0, 0) database.update_feedback(feedback_token, default_path, False) check_response(1, 1, 0) default_path2 = default_path[1:] feedback_token2 = FeedbackToken(token_network_model.address) database.prepare_feedback(feedback_token2, default_path2) check_response(2, 1, 0) database.update_feedback(feedback_token2, default_path2, True) check_response(2, 2, 1)
def test_feedback_stats(pathfinding_service_mock): token_network_address = TokenNetworkAddress(b"1" * 20) default_path = [b"1" * 20, b"2" * 20, b"3" * 20] feedback_token = FeedbackToken(token_network_address) database = pathfinding_service_mock.database database.prepare_feedback(feedback_token, default_path) assert database.get_num_routes_feedback() == 1 assert database.get_num_routes_feedback(only_with_feedback=True) == 0 assert database.get_num_routes_feedback(only_successful=True) == 0 database.update_feedback(feedback_token, default_path, False) assert database.get_num_routes_feedback() == 1 assert database.get_num_routes_feedback(only_with_feedback=True) == 1 assert database.get_num_routes_feedback(only_successful=True) == 0 default_path2 = default_path[1:] feedback_token2 = FeedbackToken(token_network_address) database.prepare_feedback(feedback_token2, default_path2) assert database.get_num_routes_feedback() == 2 assert database.get_num_routes_feedback(only_with_feedback=True) == 1 assert database.get_num_routes_feedback(only_successful=True) == 0 database.update_feedback(feedback_token2, default_path2, True) assert database.get_num_routes_feedback() == 2 assert database.get_num_routes_feedback(only_with_feedback=True) == 2 assert database.get_num_routes_feedback(only_successful=True) == 1
def test_feedback(api_sut: PFSApi, api_url: str, token_network_model: TokenNetwork): database = api_sut.pathfinding_service.database default_path_hex = ["0x" + "1" * 40, "0x" + "2" * 40, "0x" + "3" * 40] default_path = [to_canonical_address(e) for e in default_path_hex] estimated_fee = FeeAmount(0) def make_request(token_id: Optional[str] = None, success: bool = True, path: Optional[List[str]] = None): url = api_url + f"/v1/{to_checksum_address(token_network_model.address)}/feedback" token_id = token_id or uuid4().hex path = path or default_path_hex data = {"token": token_id, "success": success, "path": path} return requests.post(url, json=data) # Request with invalid UUID response = make_request(token_id="abc") assert response.status_code == 400 assert response.json( )["error_code"] == exceptions.InvalidRequest.error_code # Request with invalid path response = make_request(path=["abc"]) assert response.status_code == 400 assert response.json( )["error_code"] == exceptions.InvalidRequest.error_code # Test valid token, which is not stored in PFS DB token = FeedbackToken(token_network_address=token_network_model.address) response = make_request(token_id=token.uuid.hex) assert response.status_code == 400 assert not db_has_feedback_for(database, token, default_path) # Test expired token old_token = FeedbackToken( creation_time=datetime.utcnow() - timedelta(hours=1), token_network_address=token_network_model.address, ) database.prepare_feedback(old_token, default_path, estimated_fee) response = make_request(token_id=old_token.uuid.hex) assert response.status_code == 400 assert not db_has_feedback_for(database, token, default_path) # Test valid token token = FeedbackToken(token_network_address=token_network_model.address) database.prepare_feedback(token, default_path, estimated_fee) response = make_request(token_id=token.uuid.hex) assert response.status_code == 200 assert db_has_feedback_for(database, token, default_path)
def get_feedback_token(self, token_id: UUID, token_network_address: TokenNetworkAddress, route: List[Address]) -> Optional[FeedbackToken]: hexed_route = [to_checksum_address(e) for e in route] token = self.conn.execute( """SELECT * FROM feedback WHERE token_id = ? AND token_network_address = ? AND route = ?; """, [ token_id.hex, to_checksum_address(token_network_address), json.dumps(hexed_route) ], ).fetchone() if token: return FeedbackToken( token_network_address=decode_hex( token["token_network_address"]), id=UUID(token["token_id"]), creation_time=token["creation_time"], ) return None
def get_feedback_token(self, token_id: UUID, token_network_address: TokenNetworkAddress, route: List[Address]) -> Optional[FeedbackToken]: hexed_route = [to_checksum_address(e) for e in route] with self._cursor() as cursor: token = cursor.execute( """SELECT * FROM feedback WHERE token_id = ? AND token_network_address = ? AND route = ?; """, [ token_id.hex, to_checksum_address(token_network_address), json.dumps(hexed_route), ], ).fetchone() if token: return FeedbackToken( token_network_address=TokenNetworkAddress( to_canonical_address(token["token_network_address"])), uuid=UUID(token["token_id"]), creation_time=token["creation_time"], ) return None
def create_and_store_feedback_tokens( pathfinding_service: PathfindingService, token_network_address: TokenNetworkAddress, routes: List[Dict], ) -> FeedbackToken: feedback_token = FeedbackToken(token_network_address=token_network_address) # TODO: use executemany here for route in routes: pathfinding_service.database.prepare_feedback(token=feedback_token, route=route["path"]) return feedback_token
def create_and_store_feedback_tokens( pathfinding_service: PathfindingService, token_network_address: TokenNetworkAddress, routes: List[Path], ) -> FeedbackToken: with opentracing.tracer.start_span("store_feedback_token"): feedback_token = FeedbackToken(token_network_address=token_network_address) # TODO: use executemany here for route in routes: pathfinding_service.database.prepare_feedback( token=feedback_token, route=route.nodes, estimated_fee=route.estimated_fee ) return feedback_token
def test_insert_feedback_token(pathfinding_service_mock): token_network_address = TokenNetworkAddress(b"1" * 20) route = [Address(b"2" * 20), Address(b"3" * 20)] estimated_fee = -123 token = FeedbackToken(token_network_address=token_network_address) database = pathfinding_service_mock.database database.prepare_feedback(token=token, route=route, estimated_fee=estimated_fee) # Test round-trip stored = database.get_feedback_token( token_id=token.uuid, token_network_address=token_network_address, route=route) assert stored == token # Test different UUID stored = database.get_feedback_token( token_id=uuid4(), token_network_address=token_network_address, route=route) assert stored is None # Test different token network address token_network_address_wrong = TokenNetworkAddress(b"9" * 20) stored = database.get_feedback_token( token_id=uuid4(), token_network_address=token_network_address_wrong, route=route) assert stored is None # Test different route route_wrong = [Address(b"2" * 20), Address(b"3" * 20), Address(b"4" * 20)] stored = database.get_feedback_token( token_id=uuid4(), token_network_address=token_network_address, route=route_wrong) assert stored is None # Test empty route stored = database.get_feedback_token( token_id=uuid4(), token_network_address=token_network_address, route=[]) assert stored is None
def test_feedback_token_validity(): token_network_address = TokenNetworkAddress(b"1" * 20) # Newly created token is valid valid_token = FeedbackToken(token_network_address=token_network_address) assert valid_token.is_valid() # Test expiry in is_valid invalid_token = FeedbackToken( creation_time=datetime.utcnow() - MAX_AGE_OF_FEEDBACK_REQUESTS - timedelta(seconds=1), token_network_address=token_network_address, ) assert not invalid_token.is_valid()