Skip to content

Commit 703342c

Browse files
OskarStarkchr-hertel
authored andcommitted
[Store] Add missing unit tests
1 parent c978b59 commit 703342c

File tree

5 files changed

+1658
-0
lines changed

5 files changed

+1658
-0
lines changed
Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\AI\Store\Tests\Bridge\Azure;
13+
14+
use PHPUnit\Framework\Attributes\CoversClass;
15+
use PHPUnit\Framework\Attributes\Test;
16+
use PHPUnit\Framework\TestCase;
17+
use Symfony\AI\Platform\Vector\NullVector;
18+
use Symfony\AI\Platform\Vector\Vector;
19+
use Symfony\AI\Store\Bridge\Azure\SearchStore;
20+
use Symfony\AI\Store\Document\Metadata;
21+
use Symfony\AI\Store\Document\VectorDocument;
22+
use Symfony\Component\HttpClient\Exception\ClientException;
23+
use Symfony\Component\HttpClient\MockHttpClient;
24+
use Symfony\Component\HttpClient\Response\JsonMockResponse;
25+
use Symfony\Component\Uid\Uuid;
26+
27+
#[CoversClass(SearchStore::class)]
28+
final class SearchStoreTest extends TestCase
29+
{
30+
#[Test]
31+
public function addDocumentsSuccessfully(): void
32+
{
33+
$httpClient = new MockHttpClient([
34+
new JsonMockResponse([
35+
'value' => [
36+
['key' => 'doc1', 'status' => true, 'errorMessage' => null, 'statusCode' => 201],
37+
],
38+
], [
39+
'http_code' => 200,
40+
]),
41+
]);
42+
43+
$store = new SearchStore(
44+
$httpClient,
45+
'https://test.search.windows.net',
46+
'test-api-key',
47+
'test-index',
48+
'2023-11-01',
49+
);
50+
51+
$uuid = Uuid::v4();
52+
$document = new VectorDocument($uuid, new Vector([0.1, 0.2, 0.3]));
53+
54+
$store->add($document);
55+
56+
$this->assertSame(1, $httpClient->getRequestsCount());
57+
}
58+
59+
#[Test]
60+
public function addDocumentsWithMetadata(): void
61+
{
62+
$httpClient = new MockHttpClient([
63+
function (string $method, string $url, array $options): JsonMockResponse {
64+
$this->assertSame('POST', $method);
65+
$this->assertSame('https://test.search.windows.net/indexes/test-index/docs/index?api-version=2023-11-01', $url);
66+
// Check normalized headers as Symfony HTTP client might lowercase them
67+
$this->assertArrayHasKey('normalized_headers', $options);
68+
$this->assertIsArray($options['normalized_headers']);
69+
$this->assertArrayHasKey('api-key', $options['normalized_headers']);
70+
$this->assertSame(['api-key: test-api-key'], $options['normalized_headers']['api-key']);
71+
72+
$this->assertArrayHasKey('body', $options);
73+
$this->assertIsString($options['body']);
74+
$body = json_decode($options['body'], true);
75+
$this->assertIsArray($body);
76+
$this->assertArrayHasKey('value', $body);
77+
$this->assertIsArray($body['value']);
78+
$this->assertCount(1, $body['value']);
79+
$this->assertArrayHasKey(0, $body['value']);
80+
$this->assertIsArray($body['value'][0]);
81+
$this->assertArrayHasKey('title', $body['value'][0]);
82+
$this->assertSame('Test Document', $body['value'][0]['title']);
83+
84+
return new JsonMockResponse([
85+
'value' => [
86+
['key' => 'doc1', 'status' => true, 'errorMessage' => null, 'statusCode' => 201],
87+
],
88+
], [
89+
'http_code' => 200,
90+
]);
91+
},
92+
]);
93+
94+
$store = new SearchStore(
95+
$httpClient,
96+
'https://test.search.windows.net',
97+
'test-api-key',
98+
'test-index',
99+
'2023-11-01',
100+
);
101+
102+
$uuid = Uuid::v4();
103+
$document = new VectorDocument($uuid, new Vector([0.1, 0.2, 0.3]), new Metadata(['title' => 'Test Document']));
104+
105+
$store->add($document);
106+
107+
$this->assertSame(1, $httpClient->getRequestsCount());
108+
}
109+
110+
#[Test]
111+
public function addDocumentsFailure(): void
112+
{
113+
$httpClient = new MockHttpClient([
114+
new JsonMockResponse([
115+
'error' => [
116+
'code' => 'InvalidRequest',
117+
'message' => 'Invalid document format',
118+
],
119+
], [
120+
'http_code' => 400,
121+
]),
122+
]);
123+
124+
$store = new SearchStore(
125+
$httpClient,
126+
'https://test.search.windows.net',
127+
'test-api-key',
128+
'test-index',
129+
'2023-11-01',
130+
);
131+
132+
$uuid = Uuid::v4();
133+
$document = new VectorDocument($uuid, new Vector([0.1, 0.2, 0.3]));
134+
135+
$this->expectException(ClientException::class);
136+
$this->expectExceptionMessage('HTTP 400 returned');
137+
$this->expectExceptionCode(400);
138+
139+
$store->add($document);
140+
}
141+
142+
#[Test]
143+
public function queryReturnsDocuments(): void
144+
{
145+
$uuid1 = Uuid::v4();
146+
$uuid2 = Uuid::v4();
147+
148+
$httpClient = new MockHttpClient([
149+
new JsonMockResponse([
150+
'value' => [
151+
[
152+
'id' => $uuid1->toRfc4122(),
153+
'vector' => [0.1, 0.2, 0.3],
154+
'@search.score' => 0.95,
155+
'title' => 'First Document',
156+
],
157+
[
158+
'id' => $uuid2->toRfc4122(),
159+
'vector' => [0.4, 0.5, 0.6],
160+
'@search.score' => 0.85,
161+
'title' => 'Second Document',
162+
],
163+
],
164+
], [
165+
'http_code' => 200,
166+
]),
167+
]);
168+
169+
$store = new SearchStore(
170+
$httpClient,
171+
'https://test.search.windows.net',
172+
'test-api-key',
173+
'test-index',
174+
'2023-11-01',
175+
);
176+
177+
$results = $store->query(new Vector([0.1, 0.2, 0.3]));
178+
179+
$this->assertCount(2, $results);
180+
$this->assertInstanceOf(VectorDocument::class, $results[0]);
181+
$this->assertInstanceOf(VectorDocument::class, $results[1]);
182+
$this->assertEquals($uuid1, $results[0]->id);
183+
$this->assertEquals($uuid2, $results[1]->id);
184+
$this->assertSame('First Document', $results[0]->metadata['title']);
185+
$this->assertSame('Second Document', $results[1]->metadata['title']);
186+
}
187+
188+
#[Test]
189+
public function queryWithCustomVectorFieldName(): void
190+
{
191+
$httpClient = new MockHttpClient([
192+
function (string $method, string $url, array $options): JsonMockResponse {
193+
$this->assertArrayHasKey('body', $options);
194+
$this->assertIsString($options['body']);
195+
$body = json_decode($options['body'], true);
196+
$this->assertIsArray($body);
197+
$this->assertArrayHasKey('vectorQueries', $body);
198+
$this->assertIsArray($body['vectorQueries']);
199+
$this->assertArrayHasKey(0, $body['vectorQueries']);
200+
$this->assertIsArray($body['vectorQueries'][0]);
201+
$this->assertArrayHasKey('fields', $body['vectorQueries'][0]);
202+
$this->assertSame('custom_vector_field', $body['vectorQueries'][0]['fields']);
203+
204+
return new JsonMockResponse([
205+
'value' => [
206+
[
207+
'id' => Uuid::v4()->toRfc4122(),
208+
'custom_vector_field' => [0.1, 0.2, 0.3],
209+
'@search.score' => 0.95,
210+
],
211+
],
212+
], [
213+
'http_code' => 200,
214+
]);
215+
},
216+
]);
217+
218+
$store = new SearchStore(
219+
$httpClient,
220+
'https://test.search.windows.net',
221+
'test-api-key',
222+
'test-index',
223+
'2023-11-01',
224+
'custom_vector_field',
225+
);
226+
227+
$results = $store->query(new Vector([0.1, 0.2, 0.3]));
228+
229+
$this->assertCount(1, $results);
230+
$this->assertInstanceOf(VectorDocument::class, $results[0]);
231+
}
232+
233+
#[Test]
234+
public function queryFailure(): void
235+
{
236+
$httpClient = new MockHttpClient([
237+
new JsonMockResponse([
238+
'error' => [
239+
'code' => 'InvalidRequest',
240+
'message' => 'Invalid query format',
241+
],
242+
], [
243+
'http_code' => 400,
244+
]),
245+
]);
246+
247+
$store = new SearchStore(
248+
$httpClient,
249+
'https://test.search.windows.net',
250+
'test-api-key',
251+
'test-index',
252+
'2023-11-01',
253+
);
254+
255+
$this->expectException(ClientException::class);
256+
$this->expectExceptionMessage('HTTP 400 returned');
257+
$this->expectExceptionCode(400);
258+
259+
$store->query(new Vector([0.1, 0.2, 0.3]));
260+
}
261+
262+
#[Test]
263+
public function queryWithNullVector(): void
264+
{
265+
$uuid = Uuid::v4();
266+
267+
$httpClient = new MockHttpClient([
268+
new JsonMockResponse([
269+
'value' => [
270+
[
271+
'id' => $uuid->toRfc4122(),
272+
'vector' => null,
273+
'@search.score' => 0.95,
274+
'title' => 'Document without vector',
275+
],
276+
],
277+
], [
278+
'http_code' => 200,
279+
]),
280+
]);
281+
282+
$store = new SearchStore(
283+
$httpClient,
284+
'https://test.search.windows.net',
285+
'test-api-key',
286+
'test-index',
287+
'2023-11-01',
288+
);
289+
290+
$results = $store->query(new Vector([0.1, 0.2, 0.3]));
291+
292+
$this->assertCount(1, $results);
293+
$this->assertInstanceOf(VectorDocument::class, $results[0]);
294+
$this->assertInstanceOf(NullVector::class, $results[0]->vector);
295+
}
296+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\AI\Store\Tests\Bridge\ChromaDB;
13+
14+
use Codewithkyrian\ChromaDB\Client;
15+
use Codewithkyrian\ChromaDB\Resources\CollectionResource;
16+
use PHPUnit\Framework\Attributes\CoversClass;
17+
use PHPUnit\Framework\Attributes\Test;
18+
use PHPUnit\Framework\TestCase;
19+
use Symfony\AI\Platform\Vector\Vector;
20+
use Symfony\AI\Store\Bridge\ChromaDB\Store;
21+
use Symfony\AI\Store\Document\Metadata;
22+
use Symfony\AI\Store\Document\VectorDocument;
23+
use Symfony\Component\Uid\Uuid;
24+
25+
#[CoversClass(Store::class)]
26+
final class StoreTest extends TestCase
27+
{
28+
#[Test]
29+
public function addDocumentsSuccessfully(): void
30+
{
31+
$collection = $this->createMock(CollectionResource::class);
32+
$client = $this->createMock(Client::class);
33+
34+
$client->expects($this->once())
35+
->method('getOrCreateCollection')
36+
->with('test-collection')
37+
->willReturn($collection);
38+
39+
$uuid1 = Uuid::v4();
40+
$uuid2 = Uuid::v4();
41+
42+
$collection->expects($this->once())
43+
->method('add')
44+
->with(
45+
[(string) $uuid1, (string) $uuid2],
46+
[[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]],
47+
[[], ['title' => 'Test Document']],
48+
);
49+
50+
$store = new Store($client, 'test-collection');
51+
52+
$document1 = new VectorDocument($uuid1, new Vector([0.1, 0.2, 0.3]));
53+
$document2 = new VectorDocument($uuid2, new Vector([0.4, 0.5, 0.6]), new Metadata(['title' => 'Test Document']));
54+
55+
$store->add($document1, $document2);
56+
}
57+
58+
#[Test]
59+
public function addSingleDocument(): void
60+
{
61+
$collection = $this->createMock(CollectionResource::class);
62+
$client = $this->createMock(Client::class);
63+
64+
$client->expects($this->once())
65+
->method('getOrCreateCollection')
66+
->with('test-collection')
67+
->willReturn($collection);
68+
69+
$uuid = Uuid::v4();
70+
71+
$collection->expects($this->once())
72+
->method('add')
73+
->with(
74+
[(string) $uuid],
75+
[[0.1, 0.2, 0.3]],
76+
[['title' => 'Test Document', 'category' => 'test']],
77+
);
78+
79+
$store = new Store($client, 'test-collection');
80+
81+
$document = new VectorDocument($uuid, new Vector([0.1, 0.2, 0.3]), new Metadata(['title' => 'Test Document', 'category' => 'test']));
82+
83+
$store->add($document);
84+
}
85+
}

0 commit comments

Comments
 (0)