Skip to content

Commit fef6964

Browse files
mbhaskarCopilot
andcommitted
Add GSI live test infrastructure with pipeline configuration
- Add 'cosmosGSI' pytest mark to pytest.ini - Add GSITestConfig matrix entry in live-platform-matrix.json - Add GSI_ACCOUNT_HOST/GSI_ACCOUNT_KEY env var mappings from Key Vault secrets (gsi-pipeline-uri, gsi-pipeline-key) in tests.yml - Create test_global_secondary_index_live.py with live tests for: - Creating GSI container with GlobalSecondaryIndexDefinition class - Creating GSI container with raw dict - create_container_if_not_exists with GSI definition Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 137049f commit fef6964

4 files changed

Lines changed: 155 additions & 0 deletions

File tree

sdk/cosmos/azure-cosmos/pytest.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ markers =
88
cosmosCircuitBreaker: marks tests running on Cosmos DB live account with per partition circuit breaker enabled and multi-write enabled.
99
cosmosCircuitBreakerMultiRegion: marks tests running on Cosmos DB live account with one write region and multiple read regions and per partition circuit breaker enabled.
1010
cosmosPerPartitionAutomaticFailover: marks tests running on Cosmos DB live account with one write region and multiple read regions and per partition automatic failover enabled.
11+
cosmosGSI: marks tests running on a Cosmos DB live account with Global Secondary Index (GSI) support enabled.
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# The MIT License (MIT)
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
4+
import os
5+
import unittest
6+
import uuid
7+
8+
import pytest
9+
10+
import test_config
11+
from azure.cosmos import CosmosClient, PartitionKey
12+
from azure.cosmos._global_secondary_index import GlobalSecondaryIndexDefinition
13+
14+
15+
@pytest.mark.cosmosGSI
16+
class TestGlobalSecondaryIndexLive(unittest.TestCase):
17+
"""Live tests for Global Secondary Index (GSI) container operations.
18+
19+
These tests require a Cosmos DB account with GSI support enabled.
20+
The account endpoint and key are sourced from Key Vault secrets:
21+
- gsi-pipeline-uri -> GSI_ACCOUNT_HOST
22+
- gsi-pipeline-key -> GSI_ACCOUNT_KEY
23+
"""
24+
client: CosmosClient = None
25+
host = os.getenv('GSI_ACCOUNT_HOST', test_config.TestConfig.host)
26+
masterKey = os.getenv('GSI_ACCOUNT_KEY', test_config.TestConfig.masterKey)
27+
connectionPolicy = test_config.TestConfig.connectionPolicy
28+
29+
@classmethod
30+
def setUpClass(cls):
31+
if (cls.masterKey == '[YOUR_KEY_HERE]' or
32+
cls.host == '[YOUR_ENDPOINT_HERE]'):
33+
raise Exception(
34+
"You must specify your Azure Cosmos account values for "
35+
"'masterKey' and 'host' at the top of this class to run the "
36+
"tests.")
37+
cls.client = CosmosClient(cls.host, cls.masterKey)
38+
cls.test_db = cls.client.create_database(str(uuid.uuid4()))
39+
40+
@classmethod
41+
def tearDownClass(cls):
42+
if cls.test_db:
43+
cls.client.delete_database(cls.test_db.id)
44+
45+
def test_create_gsi_container(self):
46+
"""Test creating a GSI container derived from a source container."""
47+
# Create source container
48+
source_container = self.test_db.create_container(
49+
id="source-container-" + str(uuid.uuid4())[:8],
50+
partition_key=PartitionKey(path="/id")
51+
)
52+
53+
# Create GSI container using GlobalSecondaryIndexDefinition
54+
gsi_definition = GlobalSecondaryIndexDefinition(
55+
source_container_id=source_container.id,
56+
definition="SELECT c.id, c.email, c.name FROM c"
57+
)
58+
gsi_container = self.test_db.create_container(
59+
id="gsi-container-" + str(uuid.uuid4())[:8],
60+
partition_key=PartitionKey(path="/id"),
61+
global_secondary_index_definition=gsi_definition
62+
)
63+
64+
# Read back the container properties and verify GSI definition is present
65+
properties = gsi_container.read()
66+
self.assertIn("globalSecondaryIndexDefinition", properties)
67+
gsi_props = properties["globalSecondaryIndexDefinition"]
68+
self.assertEqual(gsi_props["sourceCollectionId"], source_container.id)
69+
self.assertEqual(gsi_props["definition"], "SELECT c.id, c.email, c.name FROM c")
70+
self.assertIn("status", gsi_props)
71+
72+
# Clean up - delete GSI container first, then source
73+
self.test_db.delete_container(gsi_container.id)
74+
self.test_db.delete_container(source_container.id)
75+
76+
def test_create_gsi_container_with_dict(self):
77+
"""Test creating a GSI container using a raw dict instead of the class."""
78+
# Create source container
79+
source_container = self.test_db.create_container(
80+
id="source-dict-" + str(uuid.uuid4())[:8],
81+
partition_key=PartitionKey(path="/id")
82+
)
83+
84+
# Create GSI container using a dict
85+
gsi_dict = {
86+
"sourceCollectionId": source_container.id,
87+
"definition": "SELECT c.id, c.category FROM c"
88+
}
89+
gsi_container = self.test_db.create_container(
90+
id="gsi-dict-" + str(uuid.uuid4())[:8],
91+
partition_key=PartitionKey(path="/id"),
92+
global_secondary_index_definition=gsi_dict
93+
)
94+
95+
# Verify
96+
properties = gsi_container.read()
97+
self.assertIn("globalSecondaryIndexDefinition", properties)
98+
99+
# Clean up
100+
self.test_db.delete_container(gsi_container.id)
101+
self.test_db.delete_container(source_container.id)
102+
103+
def test_create_gsi_container_if_not_exists(self):
104+
"""Test create_container_if_not_exists with GSI definition."""
105+
# Create source container
106+
source_container = self.test_db.create_container(
107+
id="source-ifne-" + str(uuid.uuid4())[:8],
108+
partition_key=PartitionKey(path="/id")
109+
)
110+
111+
gsi_definition = GlobalSecondaryIndexDefinition(
112+
source_container_id=source_container.id,
113+
definition="SELECT c.id, c.timestamp FROM c"
114+
)
115+
container_id = "gsi-ifne-" + str(uuid.uuid4())[:8]
116+
117+
# First call creates
118+
gsi_container = self.test_db.create_container_if_not_exists(
119+
id=container_id,
120+
partition_key=PartitionKey(path="/id"),
121+
global_secondary_index_definition=gsi_definition
122+
)
123+
self.assertEqual(gsi_container.id, container_id)
124+
125+
# Second call returns existing
126+
gsi_container_again = self.test_db.create_container_if_not_exists(
127+
id=container_id,
128+
partition_key=PartitionKey(path="/id"),
129+
global_secondary_index_definition=gsi_definition
130+
)
131+
self.assertEqual(gsi_container_again.id, container_id)
132+
133+
# Clean up
134+
self.test_db.delete_container(gsi_container.id)
135+
self.test_db.delete_container(source_container.id)
136+
137+
138+
if __name__ == "__main__":
139+
unittest.main()

sdk/cosmos/live-platform-matrix.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,18 @@
164164
"ArmTemplateParameters": "@{ enableMultipleWriteLocations = $true; defaultConsistencyLevel = 'Session'; enableMultipleRegions = $true }"
165165
}
166166
}
167+
},
168+
{
169+
"GSITestConfig": {
170+
"Ubuntu2404_313_gsi": {
171+
"OSVmImage": "env:LINUXVMIMAGE",
172+
"Pool": "env:LINUXPOOL",
173+
"PythonVersion": "3.13",
174+
"CoverageArg": "--disablecov",
175+
"TestSamples": "false",
176+
"TestMarkArgument": "cosmosGSI"
177+
}
178+
}
167179
}
168180
]
169181
}

sdk/cosmos/tests.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ extends:
1414
MaxParallel: 8
1515
BuildTargetingString: azure-cosmos
1616
ServiceDirectory: cosmos
17+
EnvVars:
18+
GSI_ACCOUNT_HOST: $(gsi-pipeline-uri)
19+
GSI_ACCOUNT_KEY: $(gsi-pipeline-key)

0 commit comments

Comments
 (0)