Skip to content
Merged
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
114 changes: 114 additions & 0 deletions src/platform/tests/Bridge/OpenAi/Embeddings/ModelClientTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\AI\Platform\Tests\Bridge\OpenAi\Embeddings;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Small;
use PHPUnit\Framework\Attributes\TestWith;
use PHPUnit\Framework\Attributes\UsesClass;
use PHPUnit\Framework\TestCase;
use Symfony\AI\Platform\Bridge\OpenAi\Embeddings;
use Symfony\AI\Platform\Bridge\OpenAi\Embeddings\ModelClient;
use Symfony\AI\Platform\Exception\InvalidArgumentException;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;
use Symfony\Contracts\HttpClient\ResponseInterface as HttpResponse;

/**
* @author Oskar Stark <oskarstark@googlemail.com>
*/
#[CoversClass(ModelClient::class)]
#[UsesClass(Embeddings::class)]
#[Small]
final class ModelClientTest extends TestCase
{
public function testItThrowsExceptionWhenApiKeyIsEmpty()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The API key must not be empty.');

new ModelClient(new MockHttpClient(), '');
}

#[TestWith(['api-key-without-prefix'])]
#[TestWith(['pk-api-key'])]
#[TestWith(['SK-api-key'])]
#[TestWith(['skapikey'])]
#[TestWith(['sk api-key'])]
#[TestWith(['sk'])]
public function testItThrowsExceptionWhenApiKeyDoesNotStartWithSk(string $invalidApiKey)
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The API key must start with "sk-".');

new ModelClient(new MockHttpClient(), $invalidApiKey);
}

public function testItAcceptsValidApiKey()
{
$modelClient = new ModelClient(new MockHttpClient(), 'sk-valid-api-key');

$this->assertInstanceOf(ModelClient::class, $modelClient);
}

public function testItIsSupportingTheCorrectModel()
{
$modelClient = new ModelClient(new MockHttpClient(), 'sk-api-key');

$this->assertTrue($modelClient->supports(new Embeddings()));
}

public function testItIsExecutingTheCorrectRequest()
{
$resultCallback = static function (string $method, string $url, array $options): HttpResponse {
self::assertSame('POST', $method);
self::assertSame('https://api.openai.com/v1/embeddings', $url);
self::assertSame('Authorization: Bearer sk-api-key', $options['normalized_headers']['authorization'][0]);
self::assertSame('{"model":"text-embedding-3-small","input":"test text"}', $options['body']);

return new MockResponse();
};
$httpClient = new MockHttpClient([$resultCallback]);
$modelClient = new ModelClient($httpClient, 'sk-api-key');
$modelClient->request(new Embeddings(), 'test text', []);
}

public function testItIsExecutingTheCorrectRequestWithCustomOptions()
{
$resultCallback = static function (string $method, string $url, array $options): HttpResponse {
self::assertSame('POST', $method);
self::assertSame('https://api.openai.com/v1/embeddings', $url);
self::assertSame('Authorization: Bearer sk-api-key', $options['normalized_headers']['authorization'][0]);
self::assertSame('{"dimensions":256,"model":"text-embedding-3-large","input":"test text"}', $options['body']);

return new MockResponse();
};
$httpClient = new MockHttpClient([$resultCallback]);
$modelClient = new ModelClient($httpClient, 'sk-api-key');
$modelClient->request(new Embeddings(Embeddings::TEXT_3_LARGE), 'test text', ['dimensions' => 256]);
}

public function testItIsExecutingTheCorrectRequestWithArrayInput()
{
$resultCallback = static function (string $method, string $url, array $options): HttpResponse {
self::assertSame('POST', $method);
self::assertSame('https://api.openai.com/v1/embeddings', $url);
self::assertSame('Authorization: Bearer sk-api-key', $options['normalized_headers']['authorization'][0]);
self::assertSame('{"model":"text-embedding-3-small","input":["text1","text2","text3"]}', $options['body']);

return new MockResponse();
};
$httpClient = new MockHttpClient([$resultCallback]);
$modelClient = new ModelClient($httpClient, 'sk-api-key');
$modelClient->request(new Embeddings(), ['text1', 'text2', 'text3'], []);
}
}
48 changes: 48 additions & 0 deletions src/platform/tests/Bridge/OpenAi/EmbeddingsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\AI\Platform\Tests\Bridge\OpenAi;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Small;
use PHPUnit\Framework\TestCase;
use Symfony\AI\Platform\Bridge\OpenAi\Embeddings;

/**
* @author Oskar Stark <oskarstark@googlemail.com>
*/
#[CoversClass(Embeddings::class)]
#[Small]
final class EmbeddingsTest extends TestCase
{
public function testItCreatesEmbeddingsWithDefaultSettings()
{
$embeddings = new Embeddings();

$this->assertSame(Embeddings::TEXT_3_SMALL, $embeddings->getName());
$this->assertSame([], $embeddings->getOptions());
}

public function testItCreatesEmbeddingsWithCustomSettings()
{
$embeddings = new Embeddings(Embeddings::TEXT_3_LARGE, ['dimensions' => 256]);

$this->assertSame(Embeddings::TEXT_3_LARGE, $embeddings->getName());
$this->assertSame(['dimensions' => 256], $embeddings->getOptions());
}

public function testItCreatesEmbeddingsWithAdaModel()
{
$embeddings = new Embeddings(Embeddings::TEXT_ADA_002);

$this->assertSame(Embeddings::TEXT_ADA_002, $embeddings->getName());
}
}
116 changes: 116 additions & 0 deletions src/platform/tests/Bridge/OpenAi/Gpt/ModelClientTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\AI\Platform\Tests\Bridge\OpenAi\Gpt;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Small;
use PHPUnit\Framework\Attributes\TestWith;
use PHPUnit\Framework\Attributes\UsesClass;
use PHPUnit\Framework\TestCase;
use Symfony\AI\Platform\Bridge\OpenAi\Gpt;
use Symfony\AI\Platform\Bridge\OpenAi\Gpt\ModelClient;
use Symfony\AI\Platform\Exception\InvalidArgumentException;
use Symfony\Component\HttpClient\EventSourceHttpClient;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;
use Symfony\Contracts\HttpClient\ResponseInterface as HttpResponse;

/**
* @author Oskar Stark <oskarstark@googlemail.com>
*/
#[CoversClass(ModelClient::class)]
#[UsesClass(Gpt::class)]
#[Small]
final class ModelClientTest extends TestCase
{
public function testItThrowsExceptionWhenApiKeyIsEmpty()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The API key must not be empty.');

new ModelClient(new MockHttpClient(), '');
}

#[TestWith(['api-key-without-prefix'])]
#[TestWith(['pk-api-key'])]
#[TestWith(['SK-api-key'])]
#[TestWith(['skapikey'])]
#[TestWith(['sk api-key'])]
#[TestWith(['sk'])]
public function testItThrowsExceptionWhenApiKeyDoesNotStartWithSk(string $invalidApiKey)
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The API key must start with "sk-".');

new ModelClient(new MockHttpClient(), $invalidApiKey);
}

public function testItAcceptsValidApiKey()
{
$modelClient = new ModelClient(new MockHttpClient(), 'sk-valid-api-key');

$this->assertInstanceOf(ModelClient::class, $modelClient);
}

public function testItWrapsHttpClientInEventSourceHttpClient()
{
$httpClient = new MockHttpClient();
$modelClient = new ModelClient($httpClient, 'sk-valid-api-key');

$this->assertInstanceOf(ModelClient::class, $modelClient);
}

public function testItAcceptsEventSourceHttpClientDirectly()
{
$httpClient = new EventSourceHttpClient(new MockHttpClient());
$modelClient = new ModelClient($httpClient, 'sk-valid-api-key');

$this->assertInstanceOf(ModelClient::class, $modelClient);
}

public function testItIsSupportingTheCorrectModel()
{
$modelClient = new ModelClient(new MockHttpClient(), 'sk-api-key');

$this->assertTrue($modelClient->supports(new Gpt()));
}

public function testItIsExecutingTheCorrectRequest()
{
$resultCallback = static function (string $method, string $url, array $options): HttpResponse {
self::assertSame('POST', $method);
self::assertSame('https://api.openai.com/v1/chat/completions', $url);
self::assertSame('Authorization: Bearer sk-api-key', $options['normalized_headers']['authorization'][0]);
self::assertSame('{"temperature":1,"model":"gpt-4o","messages":[{"role":"user","content":"test message"}]}', $options['body']);

return new MockResponse();
};
$httpClient = new MockHttpClient([$resultCallback]);
$modelClient = new ModelClient($httpClient, 'sk-api-key');
$modelClient->request(new Gpt(), ['model' => 'gpt-4o', 'messages' => [['role' => 'user', 'content' => 'test message']]], ['temperature' => 1]);
}

public function testItIsExecutingTheCorrectRequestWithArrayPayload()
{
$resultCallback = static function (string $method, string $url, array $options): HttpResponse {
self::assertSame('POST', $method);
self::assertSame('https://api.openai.com/v1/chat/completions', $url);
self::assertSame('Authorization: Bearer sk-api-key', $options['normalized_headers']['authorization'][0]);
self::assertSame('{"temperature":0.7,"model":"gpt-4o","messages":[{"role":"user","content":"Hello"}]}', $options['body']);

return new MockResponse();
};
$httpClient = new MockHttpClient([$resultCallback]);
$modelClient = new ModelClient($httpClient, 'sk-api-key');
$modelClient->request(new Gpt(), ['model' => 'gpt-4o', 'messages' => [['role' => 'user', 'content' => 'Hello']]], ['temperature' => 0.7]);
}
}
41 changes: 41 additions & 0 deletions src/platform/tests/Bridge/OpenAi/GptTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\AI\Platform\Tests\Bridge\OpenAi;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Small;
use PHPUnit\Framework\TestCase;
use Symfony\AI\Platform\Bridge\OpenAi\Gpt;

/**
* @author Oskar Stark <oskarstark@googlemail.com>
*/
#[CoversClass(Gpt::class)]
#[Small]
final class GptTest extends TestCase
{
public function testItCreatesGptWithDefaultSettings()
{
$gpt = new Gpt();

$this->assertSame(Gpt::GPT_4O, $gpt->getName());
$this->assertSame(['temperature' => 1.0], $gpt->getOptions());
}

public function testItCreatesGptWithCustomSettings()
{
$gpt = new Gpt(Gpt::GPT_4_TURBO, ['temperature' => 0.5, 'max_tokens' => 1000]);

$this->assertSame(Gpt::GPT_4_TURBO, $gpt->getName());
$this->assertSame(['temperature' => 0.5, 'max_tokens' => 1000], $gpt->getOptions());
}
}
51 changes: 51 additions & 0 deletions src/platform/tests/Bridge/OpenAi/PlatformFactoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\AI\Platform\Tests\Bridge\OpenAi;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Small;
use PHPUnit\Framework\TestCase;
use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory;
use Symfony\AI\Platform\Platform;
use Symfony\Component\HttpClient\EventSourceHttpClient;
use Symfony\Component\HttpClient\MockHttpClient;

/**
* @author Oskar Stark <oskarstark@googlemail.com>
*/
#[CoversClass(PlatformFactory::class)]
#[Small]
final class PlatformFactoryTest extends TestCase
{
public function testItCreatesPlatformWithDefaultSettings()
{
$platform = PlatformFactory::create('sk-test-api-key');

$this->assertInstanceOf(Platform::class, $platform);
}

public function testItCreatesPlatformWithCustomHttpClient()
{
$httpClient = new MockHttpClient();
$platform = PlatformFactory::create('sk-test-api-key', $httpClient);

$this->assertInstanceOf(Platform::class, $platform);
}

public function testItCreatesPlatformWithEventSourceHttpClient()
{
$httpClient = new EventSourceHttpClient(new MockHttpClient());
$platform = PlatformFactory::create('sk-test-api-key', $httpClient);

$this->assertInstanceOf(Platform::class, $platform);
}
}
Loading