Create a unit test for construct I am using Mockery for the mocking and I am unable to test these three methods. I am using phpseclib3 as a third-party package and I am always getting phpseclib3\Exception\NoKeyLoadedException : Unable to read key. I am trying to mock this class but always fail.
<?php
namespace App\Services;
use phpseclib3\Crypt\Common\AsymmetricKey;
use phpseclib3\Crypt\PublicKeyLoader;
use phpseclib3\Net\SFTP;
class SftpService
{
public SFTP $sftp;
protected string $customer;
protected string $adminUsername;
public function __construct(SFTP $sftp)
{
$this->sftp = $sftp;
$this->customer = 'customer-name';
$this->adminUsername = config('sftp.username');
$this->sftpLogin();
}
protected function sftpLogin(): void
{
if (!$this->sftp->login(config('sftp.username'), $this->loadPrivateKey())) {
throw new \Exception('SFTP login failed due to invalid credentials.');
}
}
protected function loadPrivateKey(): AsymmetricKey
{
return PublicKeyLoader::load(base64_decode(config('sftp.private_key')));
}
public function createSftpUser(): bool
{
$created = false;
if (!$this->userExist()) {
$this->sftp->exec('sudo useradd -m ' . $this->customer);
$created = true;
}
return $created;
}
public function sftpServiceStatus(): bool
{
if ($this->sftp->ping()) {
return true;
}
return false;
}
protected function directoryExist(string $path): bool
{
if ($this->sftp->exec('sudo test -d "/home/' . $path . '" && echo "true" || echo "false"') == 'true') {
return true;
}
return false;
}
protected function userExist(): bool
{
if ($this->sftp->exec("getent passwd | grep -c '^" . $this->customer . ":'") == 1) {
return true;
}
return false;
}
public function setPublicSSHKey(string $key): bool
{
try {
$this->createSSHDirectoryWithAdminPermissions();
$this->sftp->exec('echo ' . $key . ' > /home/' . $this->customer . '/.ssh/authorized_keys');
$this->setUserPermissions();
return true;
} catch (\Exception $exception) {
return false;
} finally {
$this->sftp->disconnect();
}
}
protected function createSSHDirectoryWithAdminPermissions(): void
{
$this->sftp->exec('sudo chgrp ' . $this->adminUsername . ' /home/' . $this->customer);
if (!$this->directoryExist($this->customer . '/.ssh')) {
$this->sftp->exec('sudo mkdir -p /home/' . $this->customer . '/.ssh');
}
$this->sftp->exec('sudo chown ' . $this->adminUsername . ' /home/' . $this->customer . '/.ssh');
}
public function removePublicSSHKey(): bool
{
try {
$this->createSSHDirectoryWithAdminPermissions();
$this->sftp->exec('rm /home/' . $this->customer . '/.ssh/authorized_keys');
$this->setUserPermissions();
return true;
} catch (\Exception $exception) {
return false;
} finally {
$this->sftp->disconnect();
}
}
protected function setUserPermissions(): void
{
$this->sftp->exec('sudo chgrp -R ' . $this->customer . ' /home/' . $this->customer);
$this->sftp->exec('sudo chown -R ' . $this->customer . ' /home/' . $this->customer );
}
public function getFileDetails(): array
{
$this->createSSHDirectoryWithAdminPermissions();
if (!$this->sftp->file_exists('/home/' . $this->customer . '/.ssh/authorized_keys')) {
return [];
}
$fileDetails = [
'fingerprint' => $this->sftp->exec('sudo ssh-keygen -E md5 -lf "/home/spend-cloud/.ssh/authorized_keys" | awk \'{ print }\' | cut -c 5-'),
'created_date' => $this->sftp->exec('stat --printf="%z" /home/' . $this->customer . '/.ssh/authorized_keys'),
];
$this->setUserPermissions();
return $fileDetails;
}
}
Can you show the test as well?
@Sinnbeck I tried this for that trow an exception if not valid
public function testConstruct(){
$sftp = \Mockery::mock(SFTP::class)->makePartial();
$key = '-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----';
\Config::set('sftp.private_key', base64_encode($key));
\Config::set('sftp.username', 'sftp-user');
$this->service->shouldReceive('loadPrivateKey')->withNoArgs()->andReturn('key');
$this->service->shouldReceive('sftpLogin')->andThrow(\Exception::class);
}
@wipflash what is $this->service? I assume it's a mock set somewhere else?
And are you just trying to mock all classes? So no actual classes are getting called?
@Sinnbeck I am sorry I forgot to add this part.
protected SftpService $service;
protected function setUp(): void
{
$this->service = \Mockery::mock(SftpService::class)
->makePartial()
->shouldAllowMockingProtectedMethods();
parent::setUp();
}
@wipflash Ok so what are you planning on testing if you just mock everything ? I only see mocks, no actual tests. In this case I would assume that the service is real..
@Sinnbeck I am completely new to this and have no idea where or what to start. Here is a complete class on what I want to write tests.
<?php
namespace App\Services;
use phpseclib3\Crypt\Common\AsymmetricKey;
use phpseclib3\Crypt\PublicKeyLoader;
use phpseclib3\Net\SFTP;
class SftpService
{
public SFTP $sftp;
protected string $customer;
protected string $adminUsername;
public function __construct(SFTP $sftp)
{
$this->sftp = $sftp;
$this->customer = 'customer-name';
$this->adminUsername = config('sftp.username');
$this->sftpLogin();
}
protected function sftpLogin(): void
{
if (!$this->sftp->login(config('sftp.username'), $this->loadPrivateKey())) {
throw new \Exception('SFTP login failed due to invalid credentials.');
}
}
protected function loadPrivateKey(): AsymmetricKey
{
return PublicKeyLoader::load(base64_decode(config('sftp.private_key')));
}
public function createSftpUser(): bool
{
$created = false;
if (!$this->userExist()) {
$this->sftp->exec('sudo useradd -m ' . $this->customer);
$created = true;
}
return $created;
}
public function sftpServiceStatus(): bool
{
if ($this->sftp->ping()) {
return true;
}
return false;
}
protected function directoryExist(string $path): bool
{
if ($this->sftp->exec('sudo test -d "/home/' . $path . '" && echo "true" || echo "false"') == 'true') {
return true;
}
return false;
}
protected function userExist(): bool
{
if ($this->sftp->exec("getent passwd | grep -c '^" . $this->customer . ":'") == 1) {
return true;
}
return false;
}
public function setPublicSSHKey(string $key): bool
{
try {
$this->createSSHDirectoryWithAdminPermissions();
$this->sftp->exec('echo ' . $key . ' > /home/' . $this->customer . '/.ssh/authorized_keys');
$this->setUserPermissions();
return true;
} catch (\Exception $exception) {
return false;
} finally {
$this->sftp->disconnect();
}
}
protected function createSSHDirectoryWithAdminPermissions(): void
{
$this->sftp->exec('sudo chgrp ' . $this->adminUsername . ' /home/' . $this->customer);
if (!$this->directoryExist($this->customer . '/.ssh')) {
$this->sftp->exec('sudo mkdir -p /home/' . $this->customer . '/.ssh');
}
$this->sftp->exec('sudo chown ' . $this->adminUsername . ' /home/' . $this->customer . '/.ssh');
}
public function removePublicSSHKey(): bool
{
try {
$this->createSSHDirectoryWithAdminPermissions();
$this->sftp->exec('rm /home/' . $this->customer . '/.ssh/authorized_keys');
$this->setUserPermissions();
return true;
} catch (\Exception $exception) {
return false;
} finally {
$this->sftp->disconnect();
}
}
protected function setUserPermissions(): void
{
$this->sftp->exec('sudo chgrp -R ' . $this->customer . ' /home/' . $this->customer);
$this->sftp->exec('sudo chown -R ' . $this->customer . ' /home/' . $this->customer );
}
public function getFileDetails(): array
{
$this->createSSHDirectoryWithAdminPermissions();
if (!$this->sftp->file_exists('/home/' . $this->customer . '/.ssh/authorized_keys')) {
return [];
}
$fileDetails = [
'fingerprint' => $this->sftp->exec('sudo ssh-keygen -E md5 -lf "/home/spend-cloud/.ssh/authorized_keys" | awk \'{ print }\' | cut -c 5-'),
'created_date' => $this->sftp->exec('stat --printf="%z" /home/' . $this->customer . '/.ssh/authorized_keys'),
];
$this->setUserPermissions();
return $fileDetails;
}
}
I have figure out it here is the solution
public function testConstructWithSuccessLogin(){
$sftp = \Mockery::mock(SFTP::class)->makePartial();
$key = '-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----';
\Config::set('sftp.private_key', base64_encode($key));
\Config::set('sftp.username', 'sftp-user');
$this->service->shouldReceive('loadPrivateKey')->withNoArgs()->andReturn('key');
$this->service->shouldReceive('sftpLogin')->andThrow(\Exception::class);
$sftp->shouldReceive('login')->andReturn(true);
$sftpService = new SftpService($sftp);
$this->assertSame($sftp, $sftpService->sftp);
}
Please sign in or create an account to participate in this conversation.