Skip to content

Commit b37e7b6

Browse files
committed
Laravel support tests
1 parent 3b242c1 commit b37e7b6

9 files changed

+935
-11
lines changed

src/Laravel/MaxBotManager.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ public function handleWebhook(Request $request): JsonResponse|Response
113113
* It will run indefinitely until stopped.
114114
*
115115
* @throws BindingResolutionException
116+
* @codeCoverageIgnore
116117
*/
117118
public function startLongPolling(int $timeout = 90, ?int $marker = null): void
118119
{
@@ -129,6 +130,7 @@ public function startLongPolling(int $timeout = 90, ?int $marker = null): void
129130
* @param callable|string $handler Can be a closure, callable, or Laravel container binding.
130131
*
131132
* @throws BindingResolutionException
133+
* @codeCoverageIgnore
132134
*/
133135
public function addHandler(UpdateType $type, callable|string $handler): void
134136
{
@@ -142,6 +144,7 @@ public function addHandler(UpdateType $type, callable|string $handler): void
142144
* @param callable|string $handler Can be a closure, callable, or Laravel container binding.
143145
*
144146
* @throws BindingResolutionException
147+
* @codeCoverageIgnore
145148
*/
146149
public function onCommand(string $command, callable|string $handler): void
147150
{
@@ -154,6 +157,7 @@ public function onCommand(string $command, callable|string $handler): void
154157
* @param callable|string $handler Can be a closure, callable, or Laravel container binding.
155158
*
156159
* @throws BindingResolutionException
160+
* @codeCoverageIgnore
157161
*/
158162
public function onMessageCreated(callable|string $handler): void
159163
{
@@ -166,6 +170,7 @@ public function onMessageCreated(callable|string $handler): void
166170
* @param callable|string $handler Can be a closure, callable, or Laravel container binding.
167171
*
168172
* @throws BindingResolutionException
173+
* @codeCoverageIgnore
169174
*/
170175
public function onMessageCallback(callable|string $handler): void
171176
{
@@ -178,6 +183,7 @@ public function onMessageCallback(callable|string $handler): void
178183
* @param callable|string $handler Can be a closure, callable, or Laravel container binding.
179184
*
180185
* @throws BindingResolutionException
186+
* @codeCoverageIgnore
181187
*/
182188
public function onMessageEdited(callable|string $handler): void
183189
{
@@ -190,6 +196,7 @@ public function onMessageEdited(callable|string $handler): void
190196
* @param callable|string $handler Can be a closure, callable, or Laravel container binding.
191197
*
192198
* @throws BindingResolutionException
199+
* @codeCoverageIgnore
193200
*/
194201
public function onMessageRemoved(callable|string $handler): void
195202
{
@@ -202,6 +209,7 @@ public function onMessageRemoved(callable|string $handler): void
202209
* @param callable|string $handler Can be a closure, callable, or Laravel container binding.
203210
*
204211
* @throws BindingResolutionException
212+
* @codeCoverageIgnore
205213
*/
206214
public function onBotAdded(callable|string $handler): void
207215
{
@@ -214,6 +222,7 @@ public function onBotAdded(callable|string $handler): void
214222
* @param callable|string $handler Can be a closure, callable, or Laravel container binding.
215223
*
216224
* @throws BindingResolutionException
225+
* @codeCoverageIgnore
217226
*/
218227
public function onBotRemoved(callable|string $handler): void
219228
{
@@ -226,6 +235,7 @@ public function onBotRemoved(callable|string $handler): void
226235
* @param callable|string $handler Can be a closure, callable, or Laravel container binding.
227236
*
228237
* @throws BindingResolutionException
238+
* @codeCoverageIgnore
229239
*/
230240
public function onUserAdded(callable|string $handler): void
231241
{
@@ -238,6 +248,7 @@ public function onUserAdded(callable|string $handler): void
238248
* @param callable|string $handler Can be a closure, callable, or Laravel container binding.
239249
*
240250
* @throws BindingResolutionException
251+
* @codeCoverageIgnore
241252
*/
242253
public function onUserRemoved(callable|string $handler): void
243254
{
@@ -250,6 +261,7 @@ public function onUserRemoved(callable|string $handler): void
250261
* @param callable|string $handler Can be a closure, callable, or Laravel container binding.
251262
*
252263
* @throws BindingResolutionException
264+
* @codeCoverageIgnore
253265
*/
254266
public function onBotStarted(callable|string $handler): void
255267
{
@@ -262,6 +274,7 @@ public function onBotStarted(callable|string $handler): void
262274
* @param callable|string $handler Can be a closure, callable, or Laravel container binding.
263275
*
264276
* @throws BindingResolutionException
277+
* @codeCoverageIgnore
265278
*/
266279
public function onChatTitleChanged(callable|string $handler): void
267280
{
@@ -274,6 +287,7 @@ public function onChatTitleChanged(callable|string $handler): void
274287
* @param callable|string $handler Can be a closure, callable, or Laravel container binding.
275288
*
276289
* @throws BindingResolutionException
290+
* @codeCoverageIgnore
277291
*/
278292
public function onMessageChatCreated(callable|string $handler): void
279293
{
@@ -282,6 +296,7 @@ public function onMessageChatCreated(callable|string $handler): void
282296

283297
/**
284298
* Get the API instance.
299+
* @codeCoverageIgnore
285300
*/
286301
public function getApi(): Api
287302
{
@@ -290,6 +305,7 @@ public function getApi(): Api
290305

291306
/**
292307
* Get the update dispatcher.
308+
* @codeCoverageIgnore
293309
*/
294310
public function getDispatcher(): UpdateDispatcher
295311
{

src/Laravel/MaxBotServiceProvider.php

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use BushlanovDev\MaxMessengerBot\Api;
88
use BushlanovDev\MaxMessengerBot\Client;
99
use BushlanovDev\MaxMessengerBot\ClientApiInterface;
10+
use BushlanovDev\MaxMessengerBot\Laravel\Commands\PollingStartCommand;
1011
use BushlanovDev\MaxMessengerBot\ModelFactory;
1112
use BushlanovDev\MaxMessengerBot\UpdateDispatcher;
1213
use BushlanovDev\MaxMessengerBot\WebhookHandler;
@@ -19,6 +20,7 @@
1920
use Illuminate\Contracts\Config\Repository as Config;
2021
use Psr\Log\LoggerInterface;
2122
use InvalidArgumentException;
23+
use Psr\Log\NullLogger;
2224

2325
/**
2426
* Laravel Service Provider for Max Bot API Client.
@@ -37,6 +39,7 @@ public function register(): void
3739
);
3840

3941
$this->app->singleton(ClientApiInterface::class, function (Application $app) {
42+
/** @var Config $config */
4043
$config = $app->make(Config::class);
4144
$accessToken = $config->get('maxbot.access_token');
4245

@@ -52,16 +55,14 @@ public function register(): void
5255
);
5356
}
5457

55-
$timeout = $config->get('maxbot.timeout', 10);
56-
$connectTimeout = $config->get('maxbot.connect_timeout', 5);
57-
$readTimeout = $config->get('maxbot.read_timeout', 10);
58-
$baseUrl = $config->get('maxbot.base_url', 'https://botapi.max.ru');
59-
$apiVersion = $config->get('maxbot.api_version', Api::API_VERSION);
58+
$logger = $config->get('maxbot.logging.enabled', false)
59+
? $app->make(LoggerInterface::class)
60+
: new NullLogger();
6061

6162
$guzzle = new \GuzzleHttp\Client([
62-
'timeout' => $timeout,
63-
'connect_timeout' => $connectTimeout,
64-
'read_timeout' => $readTimeout,
63+
'timeout' => (int)$config->get('maxbot.timeout', 10),
64+
'connect_timeout' => (int)$config->get('maxbot.connect_timeout', 5),
65+
'read_timeout' => (int)$config->get('maxbot.read_timeout', 10),
6566
'headers' => [
6667
'User-Agent' => 'max-bot-api-client-php/' . Api::LIBRARY_VERSION
6768
. ' Laravel/' . $app->version() . ' PHP/' . PHP_VERSION
@@ -75,9 +76,9 @@ public function register(): void
7576
$guzzle,
7677
$httpFactory,
7778
$httpFactory,
78-
$baseUrl,
79-
$apiVersion,
80-
$app->make(LoggerInterface::class),
79+
$config->get('maxbot.base_url', 'https://botapi.max.ru'),
80+
$config->get('maxbot.api_version', Api::API_VERSION),
81+
$logger,
8182
);
8283
});
8384

@@ -90,6 +91,7 @@ public function register(): void
9091
});
9192

9293
$this->app->singleton(Api::class, function (Application $app) {
94+
/** @var Config $config */
9395
$config = $app->make(Config::class);
9496
$accessToken = $config->get('maxbot.access_token');
9597

@@ -109,6 +111,7 @@ public function register(): void
109111
});
110112

111113
$this->app->bind(WebhookHandler::class, function (Application $app) {
114+
/** @var Config $config */
112115
$config = $app->make(Config::class);
113116
$secret = $config->get('maxbot.webhook_secret');
114117

@@ -159,6 +162,7 @@ public function boot(): void
159162
WebhookSubscribeCommand::class,
160163
WebhookUnsubscribeCommand::class,
161164
WebhookListCommand::class,
165+
PollingStartCommand::class,
162166
]);
163167
}
164168
}

src/Laravel/config/maxbot.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
declare(strict_types=1);
44

5+
// @codeCoverageIgnoreStart
56
return [
67
/*
78
|--------------------------------------------------------------------------
@@ -65,3 +66,4 @@
6566
'level' => env('MAXBOT_LOGGING_LEVEL', 'debug'),
6667
],
6768
];
69+
// @codeCoverageIgnoreEnd
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace BushlanovDev\MaxMessengerBot\Tests\Laravel\Commands;
6+
7+
use BushlanovDev\MaxMessengerBot\Laravel\Commands\PollingStartCommand;
8+
use BushlanovDev\MaxMessengerBot\Laravel\MaxBotManager;
9+
use Illuminate\Support\Facades\Log;
10+
use PHPUnit\Framework\Attributes\CoversClass;
11+
use PHPUnit\Framework\Attributes\Test;
12+
use PHPUnit\Framework\Attributes\UsesClass;
13+
use PHPUnit\Framework\MockObject\MockObject;
14+
use Symfony\Component\Console\Application as ConsoleApplication;
15+
use Symfony\Component\Console\Tester\CommandTester;
16+
17+
#[CoversClass(PollingStartCommand::class)]
18+
#[UsesClass(MaxBotManager::class)]
19+
final class PollingStartCommandTest extends TestCase
20+
{
21+
private MockObject&MaxBotManager $botManagerMock;
22+
private PollingStartCommand $command;
23+
24+
protected function setUp(): void
25+
{
26+
parent::setUp();
27+
28+
$this->botManagerMock = $this->createMock(MaxBotManager::class);
29+
$this->container->instance(MaxBotManager::class, $this->botManagerMock);
30+
$this->container->alias(MaxBotManager::class, 'maxbot.manager');
31+
32+
$this->command = new PollingStartCommand();
33+
$this->command->setLaravel($this->container);
34+
35+
$application = new ConsoleApplication();
36+
$application->add($this->command);
37+
$commandInApp = $application->find('maxbot:polling:start');
38+
$this->tester = new CommandTester($commandInApp);
39+
}
40+
41+
#[Test]
42+
public function handleSuccessfullyCallsManagerWithCustomTimeout(): void
43+
{
44+
$timeout = 60;
45+
46+
$this->botManagerMock
47+
->expects($this->once())
48+
->method('startLongPolling')
49+
->with($timeout);
50+
51+
$this->tester->execute(['--timeout' => $timeout]);
52+
$this->tester->assertCommandIsSuccessful();
53+
54+
$output = $this->tester->getDisplay();
55+
$this->assertStringContainsString("Starting long polling with a timeout of $timeout seconds...", $output);
56+
}
57+
58+
#[Test]
59+
public function handleSuccessfullyUsesDefaultTimeout(): void
60+
{
61+
$defaultTimeout = 90;
62+
63+
$this->botManagerMock
64+
->expects($this->once())
65+
->method('startLongPolling')
66+
->with($defaultTimeout);
67+
68+
$this->tester->execute([]);
69+
$this->tester->assertCommandIsSuccessful();
70+
71+
$output = $this->tester->getDisplay();
72+
$this->assertStringContainsString(
73+
"Starting long polling with a timeout of $defaultTimeout seconds...",
74+
$output
75+
);
76+
}
77+
78+
#[Test]
79+
public function handleCatchesExceptionAndLogsError(): void
80+
{
81+
$exceptionMessage = 'Something went wrong';
82+
$exception = new \RuntimeException($exceptionMessage);
83+
84+
$this->botManagerMock
85+
->expects($this->once())
86+
->method('startLongPolling')
87+
->willThrowException($exception);
88+
89+
Log::shouldReceive('error')
90+
->once()
91+
->with(
92+
"Long polling failed to start or crashed: $exceptionMessage",
93+
['exception' => $exception],
94+
);
95+
96+
$statusCode = $this->tester->execute([]);
97+
98+
$this->assertSame(1, $statusCode, 'Command should return a failure exit code.');
99+
100+
$output = $this->tester->getDisplay();
101+
$this->assertStringContainsString("❌ Long polling failed: $exceptionMessage", $output);
102+
}
103+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace BushlanovDev\MaxMessengerBot\Tests\Laravel\Commands;
6+
7+
use Illuminate\Container\Container;
8+
use Illuminate\Support\Facades\Facade;
9+
use PHPUnit\Framework\TestCase as TestCaseOriginal;
10+
use Psr\Log\LoggerInterface;
11+
use Symfony\Component\Console\Tester\CommandTester;
12+
13+
abstract class TestCase extends TestCaseOriginal
14+
{
15+
protected Container $container;
16+
protected CommandTester $tester;
17+
18+
protected function setUp(): void
19+
{
20+
parent::setUp();
21+
22+
$this->container = new TestApplicationContainer();
23+
Container::setInstance($this->container);
24+
Facade::setFacadeApplication($this->container);
25+
26+
$loggerMock = $this->createMock(LoggerInterface::class);
27+
$this->container->instance('log', $loggerMock);
28+
}
29+
30+
protected function tearDown(): void
31+
{
32+
Container::setInstance(null);
33+
Facade::clearResolvedInstances();
34+
35+
if (class_exists(\Mockery::class)) {
36+
\Mockery::close();
37+
}
38+
parent::tearDown();
39+
}
40+
}
41+
42+
class TestApplicationContainer extends Container
43+
{
44+
public function runningUnitTests(): bool
45+
{
46+
return true;
47+
}
48+
}

0 commit comments

Comments
 (0)