blob: ddc3cea515380e9f12e3f753d91d338c43f2bc6d [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 os
import shutil
import tempfile
import unittest
import pyarrow as pa
from pypaimon import CatalogFactory, Schema
from pypaimon.table.source.batch_vector_search_builder import (
BatchVectorSearchBuilderImpl,
)
from pypaimon.table.source.full_text_search_builder import FullTextSearchBuilderImpl
from pypaimon.table.source.hybrid_search_builder import HybridSearchBuilderImpl
from pypaimon.table.source.vector_search_builder import VectorSearchBuilderImpl
REJECTED = "Search is not supported on a query-auth table"
def _entry_points(table):
return {
"vector scan": VectorSearchBuilderImpl(table).new_vector_search_scan,
"vector read": VectorSearchBuilderImpl(table).new_vector_search_read,
"batch vector scan": BatchVectorSearchBuilderImpl(
table).new_vector_search_scan,
"batch vector read": BatchVectorSearchBuilderImpl(
table).new_batch_vector_search_read,
"full-text scan": FullTextSearchBuilderImpl(table).new_full_text_scan,
"full-text read": FullTextSearchBuilderImpl(table).new_full_text_read,
"hybrid routes": HybridSearchBuilderImpl(table).route_builders,
}
class TestSearchRejectedUnderQueryAuth(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.tempdir = tempfile.mkdtemp()
cls.catalog = CatalogFactory.create(
{'warehouse': os.path.join(cls.tempdir, 'warehouse')})
cls.catalog.create_database('db', False)
pa_schema = pa.schema([
('id', pa.int32()),
('embedding', pa.list_(pa.float32())),
('text', pa.string()),
])
cls.catalog.create_table(
'db.plain', Schema.from_pyarrow_schema(pa_schema), False)
cls.catalog.create_table(
'db.authed',
Schema.from_pyarrow_schema(
pa_schema, options={'query-auth.enabled': 'true'}),
False)
cls.plain = cls.catalog.get_table('db.plain')
cls.authed = cls.catalog.get_table('db.authed')
@classmethod
def tearDownClass(cls):
shutil.rmtree(cls.tempdir, ignore_errors=True)
def test_every_scan_and_read_entry_point_is_rejected(self):
self.assertTrue(self.authed.options.query_auth_enabled)
for name, entry in _entry_points(self.authed).items():
with self.subTest(entry=name):
with self.assertRaises(ValueError) as ctx:
entry()
self.assertIn(REJECTED, str(ctx.exception))
def test_without_query_auth_the_builders_reach_their_own_validation(self):
self.assertFalse(self.plain.options.query_auth_enabled)
for name, entry in _entry_points(self.plain).items():
with self.subTest(entry=name):
with self.assertRaises(ValueError) as ctx:
entry()
self.assertNotIn(REJECTED, str(ctx.exception))
if __name__ == '__main__':
unittest.main()