Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
name: select_ai_py_tests
on:
push:
branches:
- "**"
workflow_call:

permissions:
Expand All @@ -9,6 +11,20 @@ permissions:
jobs:
test:
runs-on: ${{ matrix.os }}
services:
adb:
image: ghcr.io/oracle/adb-free:latest-26ai
env:
WORKLOAD_TYPE: ATP
START_ORDS: "False"
ENABLE_ARCHIVE_LOG: "False"
ADMIN_PASSWORD: ${{ secrets.PYSAI_TEST_ADMIN_PASSWORD }}
WALLET_PASSWORD: ${{ secrets.PYSAI_TEST_WALLET_PASSWORD }}
ports:
- 1521:1521
options: >-
--cap-add SYS_ADMIN
--device /dev/fuse
strategy:
fail-fast: true
matrix:
Expand Down Expand Up @@ -36,6 +52,17 @@ jobs:
pip install pytest anyio
pip install -e .

- name: Wait for ADB Free Container
run: |
for attempt in {1..60}; do
if nc -z localhost 1521; then
exit 0
fi
sleep 10
done
docker logs ${{ job.services.adb.id }}
exit 1

- name: Run select_ai tests
run: |
python_version=${{matrix.python-version}}
Expand All @@ -44,9 +71,9 @@ jobs:
env:
PYSAI_TEST_USER: ${{ secrets.PYSAI_TEST_USER }}_${{env.PYTHON_VERSION_WITHOUT_DOT}}
PYSAI_TEST_USER_PASSWORD: ${{ secrets.PYSAI_TEST_USER_PASSWORD }}
PYSAI_TEST_ADMIN_USER: ${{ secrets.PYSAI_TEST_ADMIN_USER }}
PYSAI_TEST_ADMIN_USER: ADMIN
PYSAI_TEST_ADMIN_PASSWORD: ${{ secrets.PYSAI_TEST_ADMIN_PASSWORD }}
PYSAI_TEST_CONNECT_STRING: ${{ secrets.PYSAI_TEST_CONNECT_STRING }}
PYSAI_TEST_CONNECT_STRING: localhost:1521/myatp
PYSAI_TEST_OCI_USER_OCID: ${{ secrets.PYSAI_TEST_OCI_USER_OCID }}
PYSAI_TEST_OCI_TENANCY_OCID: ${{ secrets.PYSAI_TEST_OCI_TENANCY_OCID }}
PYSAI_TEST_OCI_PRIVATE_KEY: ${{ secrets.PYSAI_TEST_OCI_PRIVATE_KEY }}
Expand Down
3 changes: 2 additions & 1 deletion tests/agents/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@


@pytest.fixture(scope="module")
def provider():
def provider(oci_compartment_id):
return select_ai.OCIGenAIProvider(
region="us-chicago-1",
oci_apiformat="GENERIC",
oci_compartment_id=oci_compartment_id,
model="meta.llama-4-maverick-17b-128e-instruct-fp8",
)

Expand Down
6 changes: 4 additions & 2 deletions tests/profiles/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,11 @@ def log_test_case(request, configure_module_logging):


@pytest.fixture(scope="module")
def provider():
def provider(oci_compartment_id):
return select_ai.OCIGenAIProvider(
region="us-phoenix-1", oci_apiformat="GENERIC"
region="us-phoenix-1",
oci_apiformat="GENERIC",
oci_compartment_id=oci_compartment_id,
)


Expand Down
3 changes: 2 additions & 1 deletion tests/profiles/test_1300_profile_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ async def test_1307():
assert profile.attributes.provider.model == "meta.llama-3.1-70b-instruct"


async def test_1308(oci_credential):
async def test_1308(oci_credential, oci_compartment_id):
"""Set multiple attributes for a Profile"""
logger.info(
"Setting multiple attributes for async profile %s",
Expand All @@ -290,6 +290,7 @@ async def test_1308(oci_credential):
model="meta.llama-4-maverick-17b-128e-instruct-fp8",
region="us-chicago-1",
oci_apiformat="GENERIC",
oci_compartment_id=oci_compartment_id,
),
object_list=[{"owner": "ADMIN", "name": "gymnasts"}],
comments=True,
Expand Down
10 changes: 8 additions & 2 deletions tests/vector_index/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,18 @@ def vcidx_object_store_credentials():

@pytest.fixture(scope="class")
def vcidx_params(
request,
test_env,
oci_credential,
oci_compartment_id,
embedding_location,
vcidx_object_store_credentials,
):
# Test modules share a schema. Include the module name in every generated
# resource so credentials, profiles, and indexes never overlap.
module_suffix = (
Path(request.module.__file__).stem.removeprefix("test_").upper()
)
py_suffix = os.environ.get("PYTHON_VERSION_WITHOUT_DOT")
run_suffix = os.environ.get("GITHUB_RUN_ID")
run_attempt = os.environ.get("GITHUB_RUN_ATTEMPT")
Expand All @@ -113,9 +119,9 @@ def vcidx_params(
run_suffix = uuid.uuid4().hex[:12].upper()

if py_suffix:
resource_suffix = f"PY{py_suffix}_{run_suffix}"
resource_suffix = f"PY{py_suffix}_{run_suffix}_{module_suffix}"
else:
resource_suffix = f"PYSAI_{run_suffix}"
resource_suffix = f"PYSAI_{run_suffix}_{module_suffix}"

return {
"resource_suffix": resource_suffix,
Expand Down
38 changes: 26 additions & 12 deletions tests/vector_index/test_5100_async_drop_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ async def vector_index_test_state(request):

@pytest.mark.usefixtures("delete_vec_params", "setup_and_teardown")
class TestAsyncDeleteVectorIndex:
def resource_name(self, name: str) -> str:
return f"{name}_{self.delete_vec_params['resource_suffix']}"

@classmethod
def get_native_cred_param(cls, cred_name=None) -> dict:
logger.info("Preparing native credential params for: %s", cred_name)
Expand Down Expand Up @@ -420,14 +423,16 @@ async def test_5108(self):
async def test_5109(self):
"""Test delete of a nonexistent index (should not error)."""
idx = select_ai.AsyncVectorIndex(
index_name="nonexistent_index",
index_name=self.resource_name("nonexistent_index"),
attributes=self.vector_index_attributes,
profile=self.profile,
)
logger.info("Attempting to delete nonexistent index")
await idx.delete(force=True)
await asyncio.sleep(1)
await self.assert_index_count("^nonexistent_index", 0)
await self.assert_index_count(
f"^{self.resource_name('nonexistent_index')}$", 0
)
logger.info("Nonexistent delete verified (no error)")

async def test_5110(self):
Expand Down Expand Up @@ -458,7 +463,7 @@ async def test_5110(self):
async def test_5111(self):
"""Test case-sensitive name for create and delete."""
idx = select_ai.AsyncVectorIndex(
index_name="CaseSensitiveIndex",
index_name=self.resource_name("CaseSensitiveIndex"),
attributes=self.vector_index_attributes,
profile=self.profile,
)
Expand All @@ -467,12 +472,14 @@ async def test_5111(self):
logger.info("Deleting case-sensitive index")
await idx.delete(force=True)
await asyncio.sleep(1)
await self.assert_index_count("^CaseSensitiveIndex", 0)
await self.assert_index_count(
f"^{self.resource_name('CaseSensitiveIndex')}$", 0
)
logger.info("Case-sensitive index delete verified")

async def test_5112(self):
"""Test creation and deletion with long index name."""
long_name = "index_" + "x" * 40
long_name = self.resource_name("index_" + "x" * 40)
idx = select_ai.AsyncVectorIndex(
index_name=long_name,
attributes=self.vector_index_attributes,
Expand All @@ -488,7 +495,10 @@ async def test_5112(self):

async def test_5113(self):
"""Test creation and bulk deletion of indexes."""
names = [f"bulk_idx_{i}" for i in range(3)]
names = [
f"bulk_idx_{self.delete_vec_params['resource_suffix']}_{i}"
for i in range(3)
]
logger.info("Creating bulk indexes")
for name in names:
await select_ai.AsyncVectorIndex(
Expand All @@ -506,7 +516,9 @@ async def test_5113(self):
).delete(force=True)
await asyncio.sleep(1)
logger.info("Deleted %s", name)
await self.assert_index_count("^bulk_idx_", 0)
await self.assert_index_count(
f"^bulk_idx_{self.delete_vec_params['resource_suffix']}_", 0
)
logger.info("Bulk delete verified")

async def test_5114(self):
Expand Down Expand Up @@ -545,24 +557,26 @@ async def test_5115(self):
async def test_5116(self):
"""Test delete of one out of multiple indexes."""
idx1 = select_ai.AsyncVectorIndex(
index_name="IDX_1",
index_name=self.resource_name("IDX_1"),
attributes=self.vector_index_attributes,
profile=self.profile,
)
idx2 = select_ai.AsyncVectorIndex(
index_name="IDX_2",
index_name=self.resource_name("IDX_2"),
attributes=self.vector_index_attributes,
profile=self.profile,
)
logger.info("Creating two indexes IDX_1 and IDX_2")
logger.info("Creating two isolated indexes")
await idx1.create(replace=True)
await idx2.create(replace=True)
logger.info("Deleting IDX_1 only")
await self.delete_and_wait(force=True, pattern="^IDX_1$")
await self.delete_and_wait(
force=True, pattern=f"^{self.resource_name('IDX_1')}$"
)
remaining_idx2 = [
index
async for index in self.async_vector_index.list(
index_name_pattern="^IDX_2$"
index_name_pattern=f"^{self.resource_name('IDX_2')}$"
)
]
logger.info("IDX_2 entries after IDX_1 delete: %s", remaining_idx2)
Expand Down
40 changes: 28 additions & 12 deletions tests/vector_index/test_5100_drop_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ def log_test_name(request):

@pytest.mark.usefixtures("delete_vec_params", "setup_and_teardown")
class TestDeleteVectorIndex:
def resource_name(self, name: str) -> str:
return f"{name}_{self.delete_vec_params['resource_suffix']}"

@classmethod
def get_native_cred_param(cls, cred_name=None) -> dict:
logger.info(f"Preparing native credential params for: {cred_name}")
Expand Down Expand Up @@ -443,14 +446,16 @@ def test_5108(self):
def test_5109(self):
"""Test delete of a nonexistent index (should not error)."""
idx = select_ai.VectorIndex(
index_name="nonexistent_index",
index_name=self.resource_name("nonexistent_index"),
attributes=self.vector_index_attributes,
profile=self.profile,
)
logger.info("Attempting to delete nonexistent index")
idx.delete(force=True)
time.sleep(1)
self.assert_index_count("^nonexistent_index", 0)
self.assert_index_count(
f"^{self.resource_name('nonexistent_index')}$", 0
)
logger.info("Nonexistent delete verified (no error)")

def test_5110(self):
Expand All @@ -477,7 +482,7 @@ def test_5110(self):
def test_5111(self):
"""Test case-sensitive name for create and delete."""
idx = select_ai.VectorIndex(
index_name="CaseSensitiveIndex",
index_name=self.resource_name("CaseSensitiveIndex"),
attributes=self.vector_index_attributes,
profile=self.profile,
)
Expand All @@ -486,12 +491,14 @@ def test_5111(self):
logger.info("Deleting case-sensitive index")
idx.delete(force=True)
time.sleep(1)
self.assert_index_count("^CaseSensitiveIndex", 0)
self.assert_index_count(
f"^{self.resource_name('CaseSensitiveIndex')}$", 0
)
logger.info("Case-sensitive index delete verified")

def test_5112(self):
"""Test creation and deletion with long index name."""
long_name = "index_" + "x" * 40
long_name = self.resource_name("index_" + "x" * 40)
idx = select_ai.VectorIndex(
index_name=long_name,
attributes=self.vector_index_attributes,
Expand All @@ -507,7 +514,10 @@ def test_5112(self):

def test_5113(self):
"""Test creation and bulk deletion of indexes."""
names = [f"bulk_idx_{i}" for i in range(3)]
names = [
f"bulk_idx_{self.delete_vec_params['resource_suffix']}_{i}"
for i in range(3)
]
logger.info("Creating bulk indexes")
for n in names:
select_ai.VectorIndex(
Expand All @@ -525,7 +535,9 @@ def test_5113(self):
).delete(force=True)
time.sleep(1)
logger.info(f"Deleted {n}")
self.assert_index_count("^bulk_idx_", 0)
self.assert_index_count(
f"^bulk_idx_{self.delete_vec_params['resource_suffix']}_", 0
)
logger.info("Bulk delete verified")

def test_5114(self):
Expand Down Expand Up @@ -556,22 +568,26 @@ def test_5115(self):
def test_5116(self):
"""Test delete of one out of multiple indexes."""
idx1 = select_ai.VectorIndex(
index_name="IDX_1",
index_name=self.resource_name("IDX_1"),
attributes=self.vector_index_attributes,
profile=self.profile,
)
idx2 = select_ai.VectorIndex(
index_name="IDX_2",
index_name=self.resource_name("IDX_2"),
attributes=self.vector_index_attributes,
profile=self.profile,
)
logger.info("Creating two indexes IDX_1 and IDX_2")
logger.info("Creating two isolated indexes")
idx1.create(replace=True)
idx2.create(replace=True)
logger.info("Deleting IDX_1 only")
self.delete_and_wait(force=True, pattern="^IDX_1$")
self.delete_and_wait(
force=True, pattern=f"^{self.resource_name('IDX_1')}$"
)
remaining_idx2 = list(
self.vector_index.list(index_name_pattern="^IDX_2$")
self.vector_index.list(
index_name_pattern=f"^{self.resource_name('IDX_2')}$"
)
)
logger.info(f"IDX_2 entries after IDX_1 delete: {remaining_idx2}")
assert len(remaining_idx2) == 1
Expand Down
4 changes: 3 additions & 1 deletion tests/vector_index/test_5200_async_setindex_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,9 @@ async def test_5228(self):
async def test_5229(self):
"""Update on nonexistent vector index."""
logger.info("Testing update on nonexistent vector index...")
temp_index = AsyncVectorIndex(index_name="does_not_exist")
temp_index = AsyncVectorIndex(
index_name=f"does_not_exist_{self.resource_suffix}"
)
with pytest.raises(AttributeError):
await temp_index.set_attribute("chunk_size", 512)
logger.info(
Expand Down
4 changes: 3 additions & 1 deletion tests/vector_index/test_5200_setindex_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -911,7 +911,9 @@ def test_5228(self):
def test_5229(self):
"""Update on nonexistent vector index."""
logger.info("Testing update on nonexistent vector index...")
temp_index = VectorIndex(index_name="does_not_exist")
temp_index = VectorIndex(
index_name=f"does_not_exist_{self.resource_suffix}"
)
with pytest.raises(AttributeError):
temp_index.set_attribute("chunk_size", 512)
logger.info(
Expand Down
Loading