Skip to content

Commit 728f413

Browse files
committed
Some unit tests added
1 parent ed35b18 commit 728f413

6 files changed

Lines changed: 365 additions & 17 deletions

File tree

tests/BoilerplateTest.php

Lines changed: 0 additions & 14 deletions
This file was deleted.

tests/HelpersTest.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php namespace NumenCode\SyncOps\Tests;
2+
3+
use PluginTestCase;
4+
5+
class HelpersTest extends PluginTestCase
6+
{
7+
/**
8+
* Test function: format_path
9+
* Test formatting a normal directory path without trailing slash.
10+
*/
11+
public function testFormatPathWithoutTrailingSlash(): void
12+
{
13+
$result = format_path('/var/www/html');
14+
15+
// Assert a trailing slash was added
16+
$this->assertEquals('/var/www/html/', $result);
17+
}
18+
19+
/**
20+
* Test function: format_path
21+
* Test formatting a directory path that already has a trailing slash.
22+
*/
23+
public function testFormatPathWithTrailingSlash(): void
24+
{
25+
$result = format_path('/var/www/html/');
26+
27+
// Assert the path remains unchanged
28+
$this->assertEquals('/var/www/html/', $result);
29+
}
30+
31+
/**
32+
* Test function: format_path
33+
* Test formatting a directory path with multiple trailing slashes.
34+
*/
35+
public function testFormatPathWithMultipleTrailingSlashes(): void
36+
{
37+
$result = format_path('/var/www/html///');
38+
39+
// Assert only one trailing slash remains
40+
$this->assertEquals('/var/www/html/', $result);
41+
}
42+
43+
/**
44+
* Test function: format_path
45+
* Test formatting when the input is null.
46+
*/
47+
public function testFormatPathWithNull(): void
48+
{
49+
$result = format_path(null);
50+
51+
// Assert null is returned for null input
52+
$this->assertNull($result);
53+
}
54+
55+
/**
56+
* Test function: format_path
57+
* Test formatting an empty string input.
58+
*/
59+
public function testFormatPathWithEmptyString(): void
60+
{
61+
$result = format_path('');
62+
63+
// Assert null is returned for empty string
64+
$this->assertNull($result);
65+
}
66+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php namespace NumenCode\SyncOps\Tests\Support;
2+
3+
use PluginTestCase;
4+
use NumenCode\SyncOps\Support\MysqlCommandBuilder;
5+
6+
class MysqlCommandBuilderTest extends PluginTestCase
7+
{
8+
protected array $config;
9+
10+
public function setUp(): void
11+
{
12+
parent::setUp();
13+
14+
$this->config = [
15+
'username' => 'testuser',
16+
'password' => 'secret',
17+
'database' => 'mydb',
18+
];
19+
}
20+
21+
/**
22+
* Test function: dump
23+
* Test building a basic dump command with gzip enabled.
24+
*/
25+
public function testDumpWithGzip(): void
26+
{
27+
$command = MysqlCommandBuilder::dump($this->config, '/backups/db.sql.gz');
28+
29+
// Assert command contains mysqldump with correct credentials and database
30+
$this->assertStringContainsString('mysqldump --skip-comments --replace -u"testuser" -p\'secret\' "mydb"', $command);
31+
32+
// Assert command includes gzip output redirection
33+
$this->assertStringContainsString('| gzip > "/backups/db.sql.gz"', $command);
34+
}
35+
36+
/**
37+
* Test function: dump
38+
* Test building a dump command without gzip enabled.
39+
*/
40+
public function testDumpWithoutGzip(): void
41+
{
42+
$command = MysqlCommandBuilder::dump($this->config, '/backups/db.sql', false);
43+
44+
// Assert command contains mysqldump with correct credentials and database
45+
$this->assertStringContainsString('mysqldump --skip-comments --replace -u"testuser" -p\'secret\' "mydb"', $command);
46+
47+
// Assert command includes plain file output redirection
48+
$this->assertStringContainsString('> "/backups/db.sql"', $command);
49+
50+
// Assert gzip is not included
51+
$this->assertStringNotContainsString('gzip', $command);
52+
}
53+
54+
/**
55+
* Test function: dump
56+
* Test building a dump command with limited tables.
57+
*/
58+
public function testDumpWithSpecificTables(): void
59+
{
60+
$command = MysqlCommandBuilder::dump($this->config, '/backups/tables.sql', true, ['users', 'orders']);
61+
62+
// Assert both tables are included and shell-escaped
63+
$this->assertStringContainsString('"users"', $command);
64+
$this->assertStringContainsString('"orders"', $command);
65+
}
66+
67+
/**
68+
* Test function: import
69+
* Test building an import command with normalized file path.
70+
*/
71+
public function testImportCommand(): void
72+
{
73+
$command = MysqlCommandBuilder::import($this->config, 'C:\\backups\\db.sql.gz');
74+
75+
// Assert correct username and password
76+
$this->assertStringContainsString('mysql -utestuser -psecret', $command);
77+
78+
// Assert database name has 'test' suffix and is escaped with double quotes
79+
$this->assertStringContainsString('"mydbtest"', $command);
80+
81+
// Assert Windows path is normalized to forward slashes
82+
$this->assertStringContainsString('C:/backups/db.sql.gz', $command);
83+
}
84+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php namespace NumenCode\SyncOps\Tests\Traits;
2+
3+
use PluginTestCase;
4+
use NumenCode\SyncOps\Traits\RunsLocalCommands;
5+
use Symfony\Component\Process\Exception\ProcessFailedException;
6+
use Symfony\Component\Process\Exception\ProcessTimedOutException;
7+
8+
class RunsLocalCommandsTest extends PluginTestCase
9+
{
10+
protected RunsLocalCommandsTestHelper $runner;
11+
12+
public function setUp(): void
13+
{
14+
parent::setUp();
15+
16+
$this->runner = new RunsLocalCommandsTestHelper();
17+
}
18+
19+
/**
20+
* Test function: runLocalCommand
21+
* Test running a successful shell command.
22+
*/
23+
public function testRunLocalCommandSuccess(): void
24+
{
25+
$output = $this->runner->runLocalCommand('echo "Hello World"');
26+
27+
// Assert the command output is as expected
28+
$this->assertStringContainsString('Hello World', $output);
29+
}
30+
31+
/**
32+
* Test function: runLocalCommand
33+
* Test running a failing shell command throws an exception.
34+
*/
35+
public function testRunLocalCommandFailure(): void
36+
{
37+
$this->expectException(ProcessFailedException::class);
38+
39+
// Run a guaranteed invalid command
40+
$this->runner->runLocalCommand('nonexistent_command_12345');
41+
}
42+
43+
/**
44+
* Test function: runLocalCommand
45+
* Test that a custom timeout value can be set.
46+
*/
47+
public function testRunLocalCommandWithCustomTimeout(): void
48+
{
49+
$output = $this->runner->runLocalCommand('echo "Timeout Test"', 5);
50+
51+
// Assert the command output is as expected
52+
$this->assertStringContainsString('Timeout Test', $output);
53+
}
54+
55+
/**
56+
* Test function: runLocalCommand
57+
* Test that a process exceeding the timeout throws an exception.
58+
*/
59+
public function testRunLocalCommandTimeout(): void
60+
{
61+
$this->expectException(ProcessTimedOutException::class);
62+
63+
// Run with timeout shorter than sleep duration
64+
$this->runner->runLocalCommand('sleep 2', 1);
65+
}
66+
}
67+
68+
/**
69+
* Helper class to expose the protected runLocalCommand method.
70+
*/
71+
class RunsLocalCommandsTestHelper
72+
{
73+
use RunsLocalCommands {
74+
runLocalCommand as traitRunLocalCommand;
75+
}
76+
77+
public function runLocalCommand(string $command, int $timeout = 60): string
78+
{
79+
return $this->traitRunLocalCommand($command, $timeout);
80+
}
81+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<?php namespace NumenCode\SyncOps\Tests\Traits;
2+
3+
use Mockery;
4+
use PluginTestCase;
5+
use NumenCode\SyncOps\Classes\SshExecutor;
6+
use NumenCode\SyncOps\Traits\RunsRemoteCommands;
7+
8+
class RunsRemoteCommandsTest extends PluginTestCase
9+
{
10+
protected RunsRemoteCommandsTestHelper $runner;
11+
protected $sshMock;
12+
13+
public function setUp(): void
14+
{
15+
parent::setUp();
16+
17+
$this->runner = new RunsRemoteCommandsTestHelper();
18+
19+
// Create mock for SshExecutor
20+
$this->sshMock = Mockery::mock(SshExecutor::class);
21+
22+
// Inject mock into helper
23+
$this->runner->setSshExecutor($this->sshMock);
24+
}
25+
26+
/**
27+
* Test function: runRemote
28+
* Test running a remote command using runAndGet.
29+
*/
30+
public function testRunRemote(): void
31+
{
32+
$this->sshMock->shouldReceive('runAndGet')
33+
->once()
34+
->with(['ls', '-la'])
35+
->andReturn("mocked output");
36+
37+
$output = $this->runner->runRemote('my-server', ['ls', '-la']);
38+
39+
// Assert mocked output is returned
40+
$this->assertEquals("mocked output", $output);
41+
}
42+
43+
/**
44+
* Test function: runRemoteAndPrint
45+
* Test running remote commands using runAndPrint.
46+
*/
47+
public function testRunRemoteAndPrint(): void
48+
{
49+
$this->sshMock->shouldReceive('runAndPrint')
50+
->once()
51+
->with(['echo', 'hello'])
52+
->andReturn("printed hello");
53+
54+
$output = $this->runner->runRemoteAndPrint('my-server', ['echo', 'hello']);
55+
56+
// Assert mocked output is returned
57+
$this->assertEquals("printed hello", $output);
58+
}
59+
60+
/**
61+
* Test function: runRemoteRaw
62+
* Test running a raw remote command using runRawCommand.
63+
*/
64+
public function testRunRemoteRaw(): void
65+
{
66+
$this->sshMock->shouldReceive('runRawCommand')
67+
->once()
68+
->with('uptime')
69+
->andReturn("raw uptime");
70+
71+
$output = $this->runner->runRemoteRaw('my-server', 'uptime');
72+
73+
// Assert mocked output is returned
74+
$this->assertEquals("raw uptime", $output);
75+
}
76+
77+
/**
78+
* Test function: ssh
79+
* Test that ssh() caches the executor instance once created or injected.
80+
*/
81+
public function testSshCaching(): void
82+
{
83+
// Inject our mock once
84+
$this->runner->setSshExecutor($this->sshMock);
85+
86+
// First call should return the injected mock
87+
$first = $this->runner->ssh('server1');
88+
89+
// Second call with a different server should still return the same mock
90+
$second = $this->runner->ssh('server2');
91+
92+
$this->assertSame($first, $second);
93+
}
94+
95+
/**
96+
* Test function: ssh
97+
* Test that manually overwriting sshExecutor replaces the cached instance.
98+
*/
99+
public function testSshExecutorCanBeOverwritten(): void
100+
{
101+
$this->runner->setSshExecutor($this->sshMock);
102+
$this->assertSame($this->sshMock, $this->runner->ssh('server1'));
103+
104+
$newMock = Mockery::mock(SshExecutor::class);
105+
$this->runner->setSshExecutor($newMock);
106+
107+
$this->assertSame($newMock, $this->runner->ssh('server2'));
108+
}
109+
110+
public function tearDown(): void
111+
{
112+
Mockery::close();
113+
parent::tearDown();
114+
}
115+
}
116+
117+
/**
118+
* Helper class to expose protected methods of RunsRemoteCommands.
119+
*/
120+
class RunsRemoteCommandsTestHelper
121+
{
122+
use RunsRemoteCommands {
123+
ssh as public;
124+
runRemote as public;
125+
runRemoteAndPrint as public;
126+
runRemoteRaw as public;
127+
}
128+
129+
public function setSshExecutor($executor): void
130+
{
131+
$this->sshExecutor = $executor;
132+
}
133+
}

traits/RunsLocalCommands.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
<?php
2-
3-
namespace NumenCode\SyncOps\Traits;
1+
<?php namespace NumenCode\SyncOps\Traits;
42

53
use Symfony\Component\Process\Process;
64
use Symfony\Component\Process\Exception\ProcessFailedException;

0 commit comments

Comments
 (0)