Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.

Commit 9d696a2

Browse files
committed
feat: Add comprehensive unit tests for Albert API integration
- Add unit tests for EmbeddingsModelClient and GPTModelClient - Update PlatformFactory to require explicit API version in URL - Replace webmozart/assert with plain PHP exception handling - Use JsonMockResponse and TestWith attributes with named descriptions - Use sprintf for clean URL construction with leading slashes - Rename albertUrl to baseUrl for clarity - Apply rector and code style fixes
1 parent a6370de commit 9d696a2

File tree

7 files changed

+36
-36
lines changed

7 files changed

+36
-36
lines changed

examples/albert/chat.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
$platform = PlatformFactory::create(
2424
apiKey: $_ENV['ALBERT_API_KEY'],
25-
albertUrl: $_ENV['ALBERT_API_URL'],
25+
baseUrl: $_ENV['ALBERT_API_URL'],
2626
);
2727

2828
$model = new GPT('gpt-4o');

src/Platform/Bridge/Albert/EmbeddingsModelClient.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function supports(Model $model): bool
3333

3434
public function request(Model $model, array|string $payload, array $options = []): ResponseInterface
3535
{
36-
return $this->httpClient->request('POST', rtrim($this->baseUrl, '/').'/embeddings', [
36+
return $this->httpClient->request('POST', sprintf('%s/embeddings', $this->baseUrl), [
3737
'auth_bearer' => $this->apiKey,
3838
'json' => \is_array($payload) ? array_merge($payload, $options) : $payload,
3939
]);

src/Platform/Bridge/Albert/GPTModelClient.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public function supports(Model $model): bool
3838

3939
public function request(Model $model, array|string $payload, array $options = []): ResponseInterface
4040
{
41-
return $this->httpClient->request('POST', rtrim($this->baseUrl, '/').'/chat/completions', [
41+
return $this->httpClient->request('POST', sprintf('%s/chat/completions', $this->baseUrl), [
4242
'auth_bearer' => $this->apiKey,
4343
'json' => \is_array($payload) ? array_merge($payload, $options) : $payload,
4444
]);

src/Platform/Bridge/Albert/PlatformFactory.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,22 @@
1515
final class PlatformFactory
1616
{
1717
public static function create(
18-
string $apiKey,
19-
string $albertUrl,
18+
#[\SensititiveParameter] string $apiKey,
19+
string $baseUrl,
2020
?HttpClientInterface $httpClient = null,
2121
): Platform {
22-
if (!str_starts_with($albertUrl, 'https://')) {
22+
if (!str_starts_with($baseUrl, 'https://')) {
2323
throw new InvalidArgumentException('The Albert URL must start with "https://".');
2424
}
2525

2626
$httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient);
2727

2828
// The base URL should include the full path to the API endpoint including version
29-
$baseUrl = rtrim($albertUrl, '/');
30-
if (!preg_match('/\/v\d+$/', $baseUrl)) {
29+
if (!preg_match('/\/v\d+\/?$/', $baseUrl)) {
3130
throw new InvalidArgumentException('The Albert URL must include an API version (e.g., /v1, /v2).');
3231
}
33-
// Don't add trailing slash here - let the model clients handle it
32+
// Remove trailing slash for consistency
33+
$baseUrl = rtrim($baseUrl, '/');
3434

3535
// Create Albert-specific model clients with custom base URL
3636
$gptClient = new GPTModelClient($httpClient, $apiKey, $baseUrl);

tests/Platform/Bridge/Albert/EmbeddingsModelClientTest.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,10 @@ public function doesNotSupportNonEmbeddingsModel(): void
7373
}
7474

7575
#[Test]
76-
#[TestWith([['input' => 'test text', 'model' => 'text-embedding-ada-002'], [], ['input' => 'test text', 'model' => 'text-embedding-ada-002']], 'with array payload and no options')]
77-
#[TestWith(['test text', [], 'test text'], 'with string payload and no options')]
78-
#[TestWith([['input' => 'test text', 'model' => 'text-embedding-ada-002'], ['dimensions' => 1536], ['dimensions' => 1536, 'input' => 'test text', 'model' => 'text-embedding-ada-002']], 'with array payload and options')]
79-
#[TestWith([['input' => 'test text', 'model' => 'text-embedding-ada-002'], ['model' => 'text-embedding-3-small'], ['model' => 'text-embedding-3-small', 'input' => 'test text']], 'options override payload values')]
76+
#[TestWith([['input' => 'test text', 'model' => 'text-embedding-ada-002'], [], ['input' => 'test text', 'model' => 'text-embedding-ada-002']], name: 'with array payload and no options')]
77+
#[TestWith(['test text', [], 'test text'], name: 'with string payload and no options')]
78+
#[TestWith([['input' => 'test text', 'model' => 'text-embedding-ada-002'], ['dimensions' => 1536], ['dimensions' => 1536, 'input' => 'test text', 'model' => 'text-embedding-ada-002']], name: 'with array payload and options')]
79+
#[TestWith([['input' => 'test text', 'model' => 'text-embedding-ada-002'], ['model' => 'text-embedding-3-small'], ['model' => 'text-embedding-3-small', 'input' => 'test text']], name: 'options override payload values')]
8080
public function requestSendsCorrectHttpRequest(array|string $payload, array $options, array|string $expectedJson): void
8181
{
8282
$capturedRequest = null;
@@ -89,7 +89,7 @@ public function requestSendsCorrectHttpRequest(array|string $payload, array $opt
8989
$client = new EmbeddingsModelClient(
9090
$httpClient,
9191
'test-api-key',
92-
'https://albert.example.com/v1/'
92+
'https://albert.example.com/v1'
9393
);
9494

9595
$model = new Embeddings('text-embedding-ada-002');
@@ -147,7 +147,7 @@ public function requestHandlesBaseUrlWithTrailingSlash(): void
147147
$client = new EmbeddingsModelClient(
148148
$httpClient,
149149
'test-api-key',
150-
'https://albert.example.com/v1/'
150+
'https://albert.example.com/v1'
151151
);
152152

153153
$model = new Embeddings('text-embedding-ada-002');

tests/Platform/Bridge/Albert/GPTModelClientTest.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,11 @@ public function doesNotSupportNonGPTModel(): void
118118
}
119119

120120
#[Test]
121-
#[TestWith([['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo'], [], ['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo']], 'with array payload and no options')]
122-
#[TestWith(['test message', [], 'test message'], 'with string payload and no options')]
123-
#[TestWith([['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo'], ['temperature' => 0.7, 'max_tokens' => 150], ['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo', 'temperature' => 0.7, 'max_tokens' => 150]], 'with array payload and options')]
124-
#[TestWith([['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo', 'temperature' => 1.0], ['temperature' => 0.5], ['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo', 'temperature' => 0.5]], 'options override payload values')]
125-
#[TestWith([['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo'], ['stream' => true], ['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo', 'stream' => true]], 'with streaming option')]
121+
#[TestWith([['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo'], [], ['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo']], name: 'with array payload and no options')]
122+
#[TestWith(['test message', [], 'test message'], name: 'with string payload and no options')]
123+
#[TestWith([['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo'], ['temperature' => 0.7, 'max_tokens' => 150], ['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo', 'temperature' => 0.7, 'max_tokens' => 150]], name: 'with array payload and options')]
124+
#[TestWith([['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo', 'temperature' => 1.0], ['temperature' => 0.5], ['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo', 'temperature' => 0.5]], name: 'options override payload values')]
125+
#[TestWith([['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo'], ['stream' => true], ['messages' => [['role' => 'user', 'content' => 'Hello']], 'model' => 'gpt-3.5-turbo', 'stream' => true]], name: 'with streaming option')]
126126
public function requestSendsCorrectHttpRequest(array|string $payload, array $options, array|string $expectedJson): void
127127
{
128128
$capturedRequest = null;
@@ -135,7 +135,7 @@ public function requestSendsCorrectHttpRequest(array|string $payload, array $opt
135135
$client = new GPTModelClient(
136136
$httpClient,
137137
'test-api-key',
138-
'https://albert.example.com/v1/'
138+
'https://albert.example.com/v1'
139139
);
140140

141141
$model = new GPT('gpt-3.5-turbo');
@@ -193,7 +193,7 @@ public function requestHandlesBaseUrlWithTrailingSlash(): void
193193
$client = new GPTModelClient(
194194
$httpClient,
195195
'test-api-key',
196-
'https://albert.example.com/v1/'
196+
'https://albert.example.com/v1'
197197
);
198198

199199
$model = new GPT('gpt-3.5-turbo');

tests/Platform/Bridge/Albert/PlatformFactoryTest.php

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ public function createsPlatformWithCorrectBaseUrl(): void
2626
}
2727

2828
#[Test]
29-
#[TestWith(['https://albert.example.com/v1'], 'with v1 path')]
30-
#[TestWith(['https://albert.example.com/v1/'], 'with v1 path and trailing slash')]
31-
#[TestWith(['https://albert.example.com/v2'], 'with v2 path')]
32-
#[TestWith(['https://albert.example.com/v2/'], 'with v2 path and trailing slash')]
33-
#[TestWith(['https://albert.example.com/v3'], 'with v3 path')]
34-
#[TestWith(['https://albert.example.com/v10'], 'with v10 path')]
35-
#[TestWith(['https://albert.example.com/v99'], 'with v99 path')]
29+
#[TestWith(['https://albert.example.com/v1'], name: 'with v1 path')]
30+
#[TestWith(['https://albert.example.com/v1/'], name: 'with v1 path and trailing slash')]
31+
#[TestWith(['https://albert.example.com/v2'], name: 'with v2 path')]
32+
#[TestWith(['https://albert.example.com/v2/'], name: 'with v2 path and trailing slash')]
33+
#[TestWith(['https://albert.example.com/v3'], name: 'with v3 path')]
34+
#[TestWith(['https://albert.example.com/v10'], name: 'with v10 path')]
35+
#[TestWith(['https://albert.example.com/v99'], name: 'with v99 path')]
3636
public function handlesUrlsCorrectly(string $url): void
3737
{
3838
$platform = PlatformFactory::create('test-key', $url);
@@ -51,13 +51,13 @@ public function throwsExceptionForNonHttpsUrl(): void
5151
}
5252

5353
#[Test]
54-
#[TestWith(['https://albert.example.com'], 'without version')]
55-
#[TestWith(['https://albert.example.com/'], 'with trailing slash only')]
56-
#[TestWith(['https://albert.example.com/vx'], 'with vx path')]
57-
#[TestWith(['https://albert.example.com/version'], 'with version path')]
58-
#[TestWith(['https://albert.example.com/api'], 'with api path')]
59-
#[TestWith(['https://albert.example.com/v'], 'with v path only')]
60-
#[TestWith(['https://albert.example.com/v-1'], 'with v- path')]
54+
#[TestWith(['https://albert.example.com'], name: 'without version')]
55+
#[TestWith(['https://albert.example.com/'], name: 'with trailing slash only')]
56+
#[TestWith(['https://albert.example.com/vx'], name: 'with vx path')]
57+
#[TestWith(['https://albert.example.com/version'], name: 'with version path')]
58+
#[TestWith(['https://albert.example.com/api'], name: 'with api path')]
59+
#[TestWith(['https://albert.example.com/v'], name: 'with v path only')]
60+
#[TestWith(['https://albert.example.com/v-1'], name: 'with v- path')]
6161
public function throwsExceptionForUrlsWithoutVersion(string $url): void
6262
{
6363
$this->expectException(InvalidArgumentException::class);

0 commit comments

Comments
 (0)