Skip to content

Commit a946ca2

Browse files
committed
Add unit and integration tests for some components
1 parent f5dc6e5 commit a946ca2

10 files changed

Lines changed: 1029 additions & 0 deletions

File tree

tests/joy/ConfigCommandTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace joy;
6+
7+
use Symfony\Component\Console\Output\OutputInterface;
8+
9+
class ConfigCommandTest extends JoyTest
10+
{
11+
protected function recipe(): string
12+
{
13+
return <<<'PHP'
14+
<?php
15+
namespace Deployer;
16+
localhost('web')
17+
->set('deploy_path', '/var/www');
18+
PHP;
19+
}
20+
21+
protected function depConfig(string $format): int
22+
{
23+
$recipe = \__TEMP_DIR__ . '/' . get_called_class() . '.php';
24+
file_put_contents($recipe, $this->recipe());
25+
$this->init($recipe);
26+
return $this->tester->run([
27+
'config',
28+
'selector' => ['all'],
29+
'--file' => $recipe,
30+
'--format' => $format,
31+
], [
32+
'verbosity' => OutputInterface::VERBOSITY_VERBOSE,
33+
'interactive' => false,
34+
]);
35+
}
36+
37+
public function testConfigOutputYaml(): void
38+
{
39+
$this->depConfig('yaml');
40+
$display = $this->tester->getDisplay();
41+
self::assertEquals(0, $this->tester->getStatusCode(), $display);
42+
self::assertStringContainsString('web:', $display);
43+
self::assertStringContainsString('deploy_path', $display);
44+
}
45+
46+
public function testConfigOutputJson(): void
47+
{
48+
$this->depConfig('json');
49+
$display = $this->tester->getDisplay();
50+
self::assertEquals(0, $this->tester->getStatusCode(), $display);
51+
self::assertStringContainsString('"web"', $display);
52+
self::assertStringContainsString('deploy_path', $display);
53+
}
54+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Deployer\Command;
6+
7+
use Deployer\Deployer;
8+
use Deployer\Task\Task;
9+
use PHPUnit\Framework\Attributes\Group;
10+
use PHPUnit\Framework\TestCase;
11+
use Symfony\Component\Console\Application;
12+
use Symfony\Component\Console\Input\Input;
13+
use Symfony\Component\Console\Output\Output;
14+
use Symfony\Component\Console\Tester\CommandTester;
15+
16+
#[Group('unit')]
17+
class TreeCommandTest extends TestCase
18+
{
19+
private Deployer $deployer;
20+
private Application $console;
21+
22+
protected function setUp(): void
23+
{
24+
$this->console = new Application();
25+
$input = $this->createStub(Input::class);
26+
$output = $this->createStub(Output::class);
27+
28+
$this->deployer = new Deployer($this->console);
29+
$this->deployer['input'] = $input;
30+
$this->deployer['output'] = $output;
31+
}
32+
33+
protected function tearDown(): void
34+
{
35+
unset($this->deployer);
36+
}
37+
38+
public function testTreeForSimpleTask(): void
39+
{
40+
$this->deployer->tasks->set('deploy', new Task('deploy', function () {}));
41+
42+
$command = new TreeCommand($this->deployer);
43+
$this->console->addCommand($command);
44+
45+
$tester = new CommandTester($command);
46+
$tester->execute(['task' => 'deploy']);
47+
48+
$display = $tester->getDisplay();
49+
self::assertStringContainsString('deploy', $display);
50+
self::assertStringContainsString('task-tree', $display);
51+
}
52+
53+
public function testTreeForTaskWithBeforeAndAfter(): void
54+
{
55+
$mainTask = new Task('deploy', function () {});
56+
$beforeTask = new Task('prepare', function () {});
57+
$afterTask = new Task('cleanup', function () {});
58+
59+
$mainTask->addBefore('prepare');
60+
$mainTask->addAfter('cleanup');
61+
62+
$this->deployer->tasks->set('deploy', $mainTask);
63+
$this->deployer->tasks->set('prepare', $beforeTask);
64+
$this->deployer->tasks->set('cleanup', $afterTask);
65+
66+
$command = new TreeCommand($this->deployer);
67+
$this->console->addCommand($command);
68+
69+
$tester = new CommandTester($command);
70+
$tester->execute(['task' => 'deploy']);
71+
72+
$display = $tester->getDisplay();
73+
self::assertStringContainsString('deploy', $display);
74+
self::assertStringContainsString('prepare', $display);
75+
self::assertStringContainsString('cleanup', $display);
76+
self::assertStringContainsString('before deploy', $display);
77+
self::assertStringContainsString('after deploy', $display);
78+
}
79+
}

tests/src/Executor/PlannerTest.php

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Deployer\Executor;
6+
7+
use Deployer\Deployer;
8+
use Deployer\Host\Localhost;
9+
use Deployer\Task\Task;
10+
use PHPUnit\Framework\Attributes\Group;
11+
use PHPUnit\Framework\TestCase;
12+
use Symfony\Component\Console\Application;
13+
use Symfony\Component\Console\Input\Input;
14+
use Symfony\Component\Console\Output\BufferedOutput;
15+
use Symfony\Component\Console\Output\Output;
16+
17+
#[Group('unit')]
18+
class PlannerTest extends TestCase
19+
{
20+
private Deployer $deployer;
21+
22+
protected function setUp(): void
23+
{
24+
$console = new Application();
25+
$input = $this->createStub(Input::class);
26+
$output = $this->createStub(Output::class);
27+
28+
$this->deployer = new Deployer($console);
29+
$this->deployer['input'] = $input;
30+
$this->deployer['output'] = $output;
31+
}
32+
33+
protected function tearDown(): void
34+
{
35+
unset($this->deployer);
36+
}
37+
38+
public function testCommitMarksMatchingHosts(): void
39+
{
40+
$output = new BufferedOutput();
41+
42+
$host1 = new Localhost('web');
43+
$host2 = new Localhost('db');
44+
45+
$planner = new Planner($output, [$host1, $host2]);
46+
47+
$task = new Task('deploy', function () {});
48+
$planner->commit([$host1], $task);
49+
$planner->render();
50+
51+
$result = $output->fetch();
52+
self::assertStringContainsString('deploy', $result);
53+
self::assertStringContainsString('-', $result);
54+
}
55+
56+
public function testCommitAllHosts(): void
57+
{
58+
$output = new BufferedOutput();
59+
60+
$host1 = new Localhost('web');
61+
$host2 = new Localhost('db');
62+
63+
$planner = new Planner($output, [$host1, $host2]);
64+
65+
$task = new Task('deploy', function () {});
66+
$planner->commit([$host1, $host2], $task);
67+
$planner->render();
68+
69+
$result = $output->fetch();
70+
// Both hosts should show the task name, no "-"
71+
self::assertStringContainsString('deploy', $result);
72+
}
73+
74+
public function testMultipleCommits(): void
75+
{
76+
$output = new BufferedOutput();
77+
78+
$host1 = new Localhost('web');
79+
$host2 = new Localhost('db');
80+
81+
$planner = new Planner($output, [$host1, $host2]);
82+
83+
$task1 = new Task('prepare', function () {});
84+
$task2 = new Task('deploy', function () {});
85+
86+
$planner->commit([$host1, $host2], $task1);
87+
$planner->commit([$host1], $task2);
88+
$planner->render();
89+
90+
$result = $output->fetch();
91+
self::assertStringContainsString('prepare', $result);
92+
self::assertStringContainsString('deploy', $result);
93+
}
94+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Deployer\Executor;
6+
7+
use PHPUnit\Framework\Attributes\Group;
8+
use PHPUnit\Framework\TestCase;
9+
10+
#[Group('unit')]
11+
class ResponseTest extends TestCase
12+
{
13+
public function testGetters(): void
14+
{
15+
$response = new Response(200, ['key' => 'value']);
16+
self::assertSame(200, $response->getStatus());
17+
self::assertSame(['key' => 'value'], $response->getBody());
18+
}
19+
20+
public function testNullBody(): void
21+
{
22+
$response = new Response(404, null);
23+
self::assertSame(404, $response->getStatus());
24+
self::assertNull($response->getBody());
25+
}
26+
27+
public function testStringBody(): void
28+
{
29+
$response = new Response(200, 'hello');
30+
self::assertSame('hello', $response->getBody());
31+
}
32+
}

tests/src/Executor/WorkerTest.php

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Deployer\Executor;
6+
7+
use Deployer\Deployer;
8+
use Deployer\Exception\GracefulShutdownException;
9+
use Deployer\Exception\RunException;
10+
use Deployer\Host\Host;
11+
use Deployer\Host\Localhost;
12+
use Deployer\Logger\Logger;
13+
use Deployer\Task\Task;
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Console\Application;
16+
use Symfony\Component\Console\Input\Input;
17+
use PHPUnit\Framework\Attributes\Group;
18+
use Symfony\Component\Console\Output\Output;
19+
20+
#[Group('unit')]
21+
class WorkerTest extends TestCase
22+
{
23+
private Deployer $deployer;
24+
private Logger $logger;
25+
private Worker $worker;
26+
27+
protected function setUp(): void
28+
{
29+
$console = new Application();
30+
$input = $this->createStub(Input::class);
31+
$output = $this->createStub(Output::class);
32+
33+
$this->deployer = new Deployer($console);
34+
$this->deployer['input'] = $input;
35+
$this->deployer['output'] = $output;
36+
37+
$this->logger = $this->createMock(Logger::class);
38+
$this->deployer['logger'] = $this->logger;
39+
40+
$this->worker = new Worker($this->deployer);
41+
}
42+
43+
protected function tearDown(): void
44+
{
45+
unset($this->deployer);
46+
}
47+
48+
public function testExecuteSuccessReturnsZero(): void
49+
{
50+
$host = new Localhost('test-host');
51+
$task = new Task('deploy', function () {});
52+
53+
$this->logger->expects($this->once())
54+
->method('endOnHost')
55+
->with($host);
56+
57+
$exitCode = $this->worker->execute($task, $host);
58+
self::assertSame(0, $exitCode);
59+
}
60+
61+
public function testExecuteSkipsLoggerForConnectTask(): void
62+
{
63+
$host = new Localhost('test-host');
64+
$task = new Task('connect', function () {});
65+
66+
$this->logger->expects($this->never())
67+
->method('endOnHost');
68+
69+
$exitCode = $this->worker->execute($task, $host);
70+
self::assertSame(0, $exitCode);
71+
}
72+
73+
public function testExecuteGracefulShutdownExceptionReturnsExitCode42(): void
74+
{
75+
$host = new Localhost('test-host');
76+
$task = new Task('deploy', function () {
77+
throw new GracefulShutdownException('graceful shutdown');
78+
});
79+
80+
$this->logger->expects($this->once())
81+
->method('renderException');
82+
83+
$exitCode = $this->worker->execute($task, $host);
84+
self::assertSame(GracefulShutdownException::EXIT_CODE, $exitCode);
85+
}
86+
87+
public function testExecuteRunExceptionReturnsItsExitCode(): void
88+
{
89+
$host = new Localhost('test-host');
90+
$task = new Task('deploy', function () use ($host) {
91+
throw new RunException($host, 'failing-command', 127, '', 'command not found');
92+
});
93+
94+
$this->logger->expects($this->once())
95+
->method('renderException');
96+
97+
$exitCode = $this->worker->execute($task, $host);
98+
self::assertSame(127, $exitCode);
99+
}
100+
101+
public function testExecuteGenericThrowableReturns255(): void
102+
{
103+
$host = new Localhost('test-host');
104+
$task = new Task('deploy', function () {
105+
throw new \RuntimeException('unexpected error');
106+
});
107+
108+
$this->logger->expects($this->once())
109+
->method('renderException');
110+
111+
$exitCode = $this->worker->execute($task, $host);
112+
self::assertSame(255, $exitCode);
113+
}
114+
}

0 commit comments

Comments
 (0)