blob: eccd72f68f8694f9bcba463966c22592852671a1 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import itertools
import threading
import unittest
from http.server import BaseHTTPRequestHandler, HTTPServer
from pypaimon.api.auth import DLFAuthProvider
from pypaimon.api.client import HttpClient
from pypaimon.api.resource_paths import ResourcePaths
from pypaimon.api.token_loader import DLFToken
from pypaimon.api.typedef import RESTAuthParameter
class ResourcePathsTest(unittest.TestCase):
def test_url_encode(self):
database = "test_db"
object_name = "test_table$snapshot"
resource_paths = ResourcePaths("paimon")
self.assertEqual(
"/v1/paimon/databases/test_db/tables/test_table%24snapshot",
resource_paths.table(database, object_name))
resource_paths = ResourcePaths("paimon/aaaa")
self.assertEqual(
"/v1/paimon%2Faaaa/databases/test_db/tables/test_table%24snapshot",
resource_paths.table(database, object_name))
def test_database_and_table_names_are_url_encoded(self):
paths = ResourcePaths("catalog/id")
self.assertEqual(
"/v1/catalog%2Fid/databases/sales+db/tables/orders%2Fall",
paths.table("sales db", "orders/all"))
self.assertEqual(
"/v1/catalog%2Fid/databases/sales+db/table-details", paths.table_details("sales db"))
self.assertEqual("/v1/catalog%2Fid/tables/id/a%2Fb+c", paths.table_by_id("a/b c"))
def test_signature_matches_the_path_sent(self):
received = []
class Handler(BaseHTTPRequestHandler):
def log_message(self, *args):
pass
def do_GET(self):
received.append((self.path, dict(self.headers)))
self.send_response(204)
self.end_headers()
server = HTTPServer(("127.0.0.1", 0), Handler)
self.addCleanup(server.server_close)
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
self.addCleanup(thread.join)
self.addCleanup(server.shutdown)
uri = "http://127.0.0.1:{}".format(server.server_port)
client = HttpClient(uri)
self.addCleanup(client.session.close)
token = DLFToken("test-ak", "test-sk", "test-token", None)
paths = ResourcePaths("catalog~id")
builders = ((paths.table_details, "/v1/catalog~id/databases/{}/table-details"),
(paths.table_by_id, "/v1/catalog~id/tables/id/{}"))
for algorithm in ("default", "openapi-v4"):
provider = DLFAuthProvider(uri, "cn-hangzhou", algorithm, token=token)
for (build, template), (name, encoded) in itertools.product(
builders, (("sales~db", "sales~db"),
("sales~ db/a+b*", "sales~+db%2Fa%2Bb*"),
("sales%7Edb", "sales%257Edb"))):
with self.subTest(algorithm=algorithm, path=template, name=name):
signed = []
def sign(parameter):
signed.append(parameter.path)
return provider.merge_auth_header({}, parameter)
client.get(build(name), None, sign)
path, headers = received[-1]
self.assertEqual(template.format(encoded), path)
expected = provider.signer.authorization(
RESTAuthParameter("GET", path, "", {}), token,
provider.extract_host(uri), headers)
self.assertEqual(expected, headers["Authorization"])
self.assertEqual([path], signed)
if __name__ == '__main__':
unittest.main()