mirror of
https://github.com/BushlanovDev/max-bot-api-client-php.git
synced 2026-10-06 20:10:31 +00:00
Refactoring update dispatchers
This commit is contained in:
+2
-236
@@ -56,8 +56,8 @@ use BushlanovDev\MaxMessengerBot\Models\Updates\MessageCreatedUpdate;
|
||||
use BushlanovDev\MaxMessengerBot\Models\UploadEndpoint;
|
||||
use BushlanovDev\MaxMessengerBot\Models\VideoAttachmentDetails;
|
||||
use BushlanovDev\MaxMessengerBot\Models\VideoUrls;
|
||||
use BushlanovDev\MaxMessengerBot\UpdateDispatcher;
|
||||
use BushlanovDev\MaxMessengerBot\WebhookHandler;
|
||||
use GuzzleHttp\Psr7\ServerRequest;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
@@ -117,6 +117,7 @@ use RuntimeException;
|
||||
#[UsesClass(ChatPatch::class)]
|
||||
#[UsesClass(VideoAttachmentDetails::class)]
|
||||
#[UsesClass(VideoUrls::class)]
|
||||
#[UsesClass(UpdateDispatcher::class)]
|
||||
final class ApiTest extends TestCase
|
||||
{
|
||||
use PHPMock;
|
||||
@@ -613,201 +614,6 @@ final class ApiTest extends TestCase
|
||||
$this->api->getUpdates();
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function createWebhookHandlerReturnsInstanceWithProvidedSecret(): void
|
||||
{
|
||||
$secret = 'my-test-secret-key';
|
||||
$webhookHandler = $this->api->createWebhookHandler($secret);
|
||||
|
||||
$this->assertInstanceOf(WebhookHandler::class, $webhookHandler);
|
||||
|
||||
$reflection = new ReflectionClass($webhookHandler);
|
||||
|
||||
$apiProperty = $reflection->getProperty('api');
|
||||
$this->assertSame($this->api, $apiProperty->getValue($webhookHandler));
|
||||
|
||||
$factoryProperty = $reflection->getProperty('modelFactory');
|
||||
$this->assertSame($this->modelFactoryMock, $factoryProperty->getValue($webhookHandler));
|
||||
|
||||
$secretProperty = $reflection->getProperty('secret');
|
||||
$this->assertSame($secret, $secretProperty->getValue($webhookHandler));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function getWebhookUpdateCreatesHandlerAndReturnsUpdate(): void
|
||||
{
|
||||
$api = new Api('fake-token', $this->clientMock, $this->modelFactoryMock);
|
||||
|
||||
$payload = '{"update_type":"bot_started","timestamp":123,"chat_id":1,"user":{"user_id":1,"first_name":"Test","is_bot":false,"last_activity_time":123}}';
|
||||
$request = new ServerRequest('POST', '/webhook', [], $payload);
|
||||
|
||||
$expectedUpdate = new BotStartedUpdate(
|
||||
123,
|
||||
1,
|
||||
new User(1, 'Test', null, null, false, 123, null, null, null),
|
||||
null,
|
||||
null,
|
||||
);
|
||||
|
||||
$this->modelFactoryMock
|
||||
->expects($this->once())
|
||||
->method('createUpdate')
|
||||
->with(json_decode($payload, true))
|
||||
->willReturn($expectedUpdate);
|
||||
|
||||
$result = $api->getWebhookUpdate(null, $request);
|
||||
|
||||
$this->assertSame($expectedUpdate, $result);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function handleWebhooksDispatchesCorrectHandler(): void
|
||||
{
|
||||
$api = new Api('fake-token', $this->clientMock, $this->modelFactoryMock);
|
||||
$secret = 'my-secret';
|
||||
|
||||
$payload = '{"update_type":"message_created","timestamp":123,"message":{"timestamp":1,"body":{"mid":"m1","seq":1},"recipient":{"chat_type":"dialog"}}}';
|
||||
$request = new \GuzzleHttp\Psr7\ServerRequest(
|
||||
'POST',
|
||||
'/webhook',
|
||||
['X-Max-Bot-Api-Secret' => $secret],
|
||||
$payload,
|
||||
);
|
||||
|
||||
$expectedUpdate = new MessageCreatedUpdate(
|
||||
123,
|
||||
Message::fromArray(
|
||||
['timestamp' => 1, 'body' => ['mid' => 'm1', 'seq' => 1], 'recipient' => ['chat_type' => 'dialog']]
|
||||
),
|
||||
null,
|
||||
);
|
||||
|
||||
$this->modelFactoryMock
|
||||
->expects($this->once())
|
||||
->method('createUpdate')
|
||||
->with(json_decode($payload, true))
|
||||
->willReturn($expectedUpdate);
|
||||
|
||||
$messageHandlerCallCount = 0;
|
||||
$messageHandlerCapturedUpdate = null;
|
||||
|
||||
$messageHandler = function (MessageCreatedUpdate $update, Api $receivedApi) use (
|
||||
&$messageHandlerCallCount,
|
||||
&$messageHandlerCapturedUpdate,
|
||||
) {
|
||||
$messageHandlerCallCount++;
|
||||
$messageHandlerCapturedUpdate = $update;
|
||||
};
|
||||
|
||||
$botStartedHandlerCallCount = 0;
|
||||
$botStartedHandler = function () use (&$botStartedHandlerCallCount) {
|
||||
$botStartedHandlerCallCount++;
|
||||
};
|
||||
|
||||
$handlers = [
|
||||
UpdateType::MessageCreated->value => $messageHandler,
|
||||
UpdateType::BotStarted->value => $botStartedHandler,
|
||||
];
|
||||
|
||||
$api->handleWebhooks($handlers, $secret, $request);
|
||||
|
||||
$this->assertSame(1, $messageHandlerCallCount, 'MessageCreated handler should be called once.');
|
||||
$this->assertSame(0, $botStartedHandlerCallCount, 'BotStarted handler should not be called.');
|
||||
$this->assertSame($expectedUpdate, $messageHandlerCapturedUpdate);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function processUpdatesBatchDispatchesHandlersAndUpdatesMarker(): void
|
||||
{
|
||||
$messageUpdate = new MessageCreatedUpdate(
|
||||
1,
|
||||
Message::fromArray(
|
||||
['timestamp' => 1, 'body' => ['mid' => 'm1', 'seq' => 1], 'recipient' => ['chat_type' => 'dialog']]
|
||||
),
|
||||
null,
|
||||
);
|
||||
$botStartedUpdate = new BotStartedUpdate(
|
||||
2, 123,
|
||||
User::fromArray(['user_id' => 1, 'first_name' => 'Test', 'is_bot' => false, 'last_activity_time' => 1]),
|
||||
null,
|
||||
null,
|
||||
);
|
||||
|
||||
$messageHandlerCallCount = 0;
|
||||
$botStartedHandlerCallCount = 0;
|
||||
$handlers = [
|
||||
UpdateType::MessageCreated->value => function () use (&$messageHandlerCallCount) {
|
||||
$messageHandlerCallCount++;
|
||||
},
|
||||
UpdateType::BotStarted->value => function () use (&$botStartedHandlerCallCount) {
|
||||
$botStartedHandlerCallCount++;
|
||||
},
|
||||
];
|
||||
|
||||
$apiMock = $this->getMockBuilder(Api::class)
|
||||
->setConstructorArgs(['fake-token', $this->clientMock, $this->modelFactoryMock])
|
||||
->onlyMethods(['getUpdates'])
|
||||
->getMock();
|
||||
|
||||
$apiMock->expects($this->once())
|
||||
->method('getUpdates')
|
||||
->willReturn(new UpdateList([$messageUpdate, $botStartedUpdate], 12345));
|
||||
|
||||
$marker = null;
|
||||
|
||||
$apiMock->processUpdatesBatch($handlers, 90, $marker);
|
||||
|
||||
$this->assertSame(1, $messageHandlerCallCount, 'MessageCreated handler should have been called once.');
|
||||
$this->assertSame(1, $botStartedHandlerCallCount, 'BotStarted handler should have been called once.');
|
||||
$this->assertSame(12345, $marker, 'Marker should have been updated to the new value.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @var int Counter for processUpdatesBatch method calls.
|
||||
*/
|
||||
private int $processUpdatesBatchCallCount = 0;
|
||||
|
||||
/**
|
||||
* @throws \Throwable We catch a base \Error, so we need to declare it here.
|
||||
*/
|
||||
#[Test]
|
||||
public function handleUpdatesLoopContinuesAfterException(): void
|
||||
{
|
||||
$this->processUpdatesBatchCallCount = 0;
|
||||
$handlers = [UpdateType::MessageCreated->value => fn() => null];
|
||||
|
||||
$apiMock = $this->getMockBuilder(Api::class)
|
||||
->setConstructorArgs(['fake-token', $this->clientMock, $this->modelFactoryMock, $this->loggerMock])
|
||||
->onlyMethods(['processUpdatesBatch'])
|
||||
->getMock();
|
||||
|
||||
$this->loggerMock->expects($this->once())->method('error');
|
||||
|
||||
$apiMock->expects($this->any())
|
||||
->method('processUpdatesBatch')
|
||||
->willReturnCallback(function () {
|
||||
switch ($this->processUpdatesBatchCallCount++) {
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
throw new \BushlanovDev\MaxMessengerBot\Exceptions\NetworkException("Simulated network error");
|
||||
default:
|
||||
throw new \Error("LoopBreak");
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
$apiMock->handleUpdates($handlers);
|
||||
} catch (\Error $e) {
|
||||
$this->assertSame('LoopBreak', $e->getMessage());
|
||||
$this->assertSame(
|
||||
3,
|
||||
$this->processUpdatesBatchCallCount,
|
||||
'processUpdatesBatch should have been called 3 times.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[Test]
|
||||
#[RunInSeparateProcess]
|
||||
#[PreserveGlobalState(false)]
|
||||
@@ -825,46 +631,6 @@ final class ApiTest extends TestCase
|
||||
new Api('some-token');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function handleUpdatesLoopCatchesGenericExceptionAndContinues(): void
|
||||
{
|
||||
$this->processUpdatesBatchCallCount = 0;
|
||||
$handlers = [UpdateType::MessageCreated->value => fn() => null];
|
||||
|
||||
$apiMock = $this->getMockBuilder(Api::class)
|
||||
->setConstructorArgs(['fake-token', $this->clientMock, $this->modelFactoryMock, $this->loggerMock])
|
||||
->onlyMethods(['processUpdatesBatch'])
|
||||
->getMock();
|
||||
|
||||
$this->loggerMock->expects($this->once())->method('error');
|
||||
|
||||
$apiMock->expects($this->any())
|
||||
->method('processUpdatesBatch')
|
||||
->willReturnCallback(function () {
|
||||
switch ($this->processUpdatesBatchCallCount++) {
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
throw new \BushlanovDev\MaxMessengerBot\Exceptions\SerializationException(
|
||||
"Simulated JSON error"
|
||||
);
|
||||
default:
|
||||
throw new \Error("LoopBreak");
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
$apiMock->handleUpdates($handlers);
|
||||
} catch (\Error $e) {
|
||||
$this->assertSame('LoopBreak', $e->getMessage());
|
||||
$this->assertSame(
|
||||
3,
|
||||
$this->processUpdatesBatchCallCount,
|
||||
'processUpdatesBatch should have been called 3 times, indicating the loop continued after the exception.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function uploadAttachmentThrowsRuntimeExceptionWhenPathIsADirectory(): void
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user