mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-24 02:58:43 +02:00
call cron asynchronously + tests
This commit is contained in:
@@ -976,7 +976,7 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
|
||||
protected function AssertLastErrorLogEntryContains(string $sNeedle, string $sMessage = ''): void
|
||||
{
|
||||
$aLastLines = self::ReadTail(APPROOT.'/log/error.log');
|
||||
$aLastLines = Utils::ReadTail(APPROOT.'/log/error.log');
|
||||
$this->assertStringContainsString($sNeedle, $aLastLines[0], $sMessage);
|
||||
}
|
||||
|
||||
@@ -1470,4 +1470,21 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
@chmod($sConfigPath, 0440);
|
||||
@unlink($this->sConfigTmpBackupFile);
|
||||
}
|
||||
|
||||
protected function AddLoginModeAndSaveConfiguration($sLoginMode)
|
||||
{
|
||||
$aAllowedLoginTypes = $this->oiTopConfig->GetAllowedLoginTypes();
|
||||
if (!in_array($sLoginMode, $aAllowedLoginTypes)) {
|
||||
$aAllowedLoginTypes[] = $sLoginMode;
|
||||
$this->oiTopConfig->SetAllowedLoginTypes($aAllowedLoginTypes);
|
||||
$this->SaveItopConfFile();
|
||||
}
|
||||
}
|
||||
|
||||
private function SaveItopConfFile()
|
||||
{
|
||||
@chmod($this->oiTopConfig->GetLoadedFile(), 0770);
|
||||
$this->oiTopConfig->WriteToFile();
|
||||
@chmod($this->oiTopConfig->GetLoadedFile(), 0440);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ use SetupUtils;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
use Utils;
|
||||
|
||||
use const DEBUG_BACKTRACE_IGNORE_ARGS;
|
||||
|
||||
/**
|
||||
@@ -89,7 +91,7 @@ abstract class ItopTestCase extends KernelTestCase
|
||||
|
||||
if (method_exists('utils', 'GetConfig')) {
|
||||
// Reset the config by forcing the load from disk
|
||||
$oConfig = \utils::GetConfig(true);
|
||||
$oConfig = utils::GetConfig(true);
|
||||
if (method_exists('MetaModel', 'SetConfig')) {
|
||||
\MetaModel::SetConfig($oConfig);
|
||||
}
|
||||
@@ -625,32 +627,7 @@ abstract class ItopTestCase extends KernelTestCase
|
||||
*/
|
||||
protected static function ReadTail($sFilename, $iLines = 1)
|
||||
{
|
||||
$handle = fopen($sFilename, "r");
|
||||
$iLineCounter = $iLines;
|
||||
$iPos = -2;
|
||||
$bBeginning = false;
|
||||
$aLines = [];
|
||||
while ($iLineCounter > 0) {
|
||||
$sChar = " ";
|
||||
while ($sChar != "\n") {
|
||||
if (fseek($handle, $iPos, SEEK_END) == -1) {
|
||||
$bBeginning = true;
|
||||
break;
|
||||
}
|
||||
$sChar = fgetc($handle);
|
||||
$iPos--;
|
||||
}
|
||||
$iLineCounter--;
|
||||
if ($bBeginning) {
|
||||
rewind($handle);
|
||||
}
|
||||
$aLines[$iLines - $iLineCounter - 1] = fgets($handle);
|
||||
if ($bBeginning) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose($handle);
|
||||
return array_reverse($aLines);
|
||||
return Utils::ReadTail($sFilename, $iLines);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Combodo\iTop\Test\UnitTest\Webservices;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use Exception;
|
||||
use iTopMutex;
|
||||
use MetaModel;
|
||||
use utils;
|
||||
|
||||
@@ -17,8 +18,8 @@ class CronTest extends ItopDataTestCase
|
||||
public const USE_TRANSACTION = false;
|
||||
public const CREATE_TEST_ORG = false;
|
||||
|
||||
private static $sLogin;
|
||||
private static $sPassword = "Iuytrez9876543ç_è-(";
|
||||
public static $sLogin;
|
||||
public static $sPassword = "Iuytrez9876543ç_è-(";
|
||||
|
||||
/**
|
||||
* This method is called before the first test of this test class is run (in the current process).
|
||||
@@ -36,20 +37,43 @@ class CronTest extends ItopDataTestCase
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
public function ModeProvider()
|
||||
{
|
||||
$aModes = ['form', 'url', 'basic'];
|
||||
$aUsecases = [];
|
||||
foreach ($aModes as $sMode) {
|
||||
$aUsecases[$sMode] = [$sMode];
|
||||
}
|
||||
|
||||
return $aUsecases;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->BackupConfiguration();
|
||||
|
||||
static::$sLogin = "rest-user-".date('dmYHis');
|
||||
static::$sLogin = "rest-user-";//.date('dmYHis');
|
||||
|
||||
$this->CreateTestOrganization();
|
||||
}
|
||||
|
||||
public function testListOperationsAndJSONPCallback()
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
$this->ReleaseCronIfBusy();
|
||||
|
||||
}
|
||||
|
||||
public function testRestWithFormMode()
|
||||
{
|
||||
$this->AddLoginModeAndSaveConfiguration('form');
|
||||
$this->CreateUserWithProfiles([self::$aURP_Profiles['Administrator'], self::$aURP_Profiles['REST Services User']]);
|
||||
$aPostFields = [
|
||||
'version' => '1.3',
|
||||
@@ -58,27 +82,206 @@ class CronTest extends ItopDataTestCase
|
||||
'json_data' => '{"operation": "list_operations"}',
|
||||
];
|
||||
|
||||
// Test regular JSON result
|
||||
$sJSONResult = $this->CallItopUri("/webservices/rest.php", $aPostFields);
|
||||
|
||||
$sExpected = <<<JSON
|
||||
{"code":0,"message":"Operations: 7","version":"1.3","operations":[{"verb":"core\/create","description":"Create an object","extension":"CoreServices"},{"verb":"core\/update","description":"Update an object","extension":"CoreServices"},{"verb":"core\/apply_stimulus","description":"Apply a stimulus to change the state of an object","extension":"CoreServices"},{"verb":"core\/get","description":"Search for objects","extension":"CoreServices"},{"verb":"core\/delete","description":"Delete objects","extension":"CoreServices"},{"verb":"core\/get_related","description":"Get related objects through the specified relation","extension":"CoreServices"},{"verb":"core\/check_credentials","description":"Check user credentials","extension":"CoreServices"}]}
|
||||
JSON;
|
||||
|
||||
$this->assertEquals($sExpected, $sJSONResult);
|
||||
$this->assertEquals($this->GetExpectedRestResponse(), $sJSONResult);
|
||||
}
|
||||
|
||||
private function CreateUserWithProfiles(array $aProfileIds): void
|
||||
public function testRestWithBasicMode()
|
||||
{
|
||||
$this->AddLoginModeAndSaveConfiguration('basic');
|
||||
$this->CreateUserWithProfiles([self::$aURP_Profiles['Administrator'], self::$aURP_Profiles['REST Services User']]);
|
||||
$aPostFields = [
|
||||
'version' => '1.3',
|
||||
'json_data' => '{"operation": "list_operations"}',
|
||||
];
|
||||
|
||||
$sToken = base64_encode(sprintf("%s:%s", static::$sLogin, static::$sPassword));
|
||||
$aCurlOptions = [
|
||||
CURLOPT_HTTPHEADER => ["Authorization: Basic $sToken"],
|
||||
];
|
||||
|
||||
// Test regular JSON result
|
||||
$sJSONResult = $this->CallItopUri("/webservices/rest.php", $aPostFields, $aCurlOptions);
|
||||
|
||||
$this->assertEquals($this->GetExpectedRestResponse(), $sJSONResult);
|
||||
}
|
||||
|
||||
public function testRestWithUrlMode()
|
||||
{
|
||||
$this->AddLoginModeAndSaveConfiguration('url');
|
||||
$this->CreateUserWithProfiles([self::$aURP_Profiles['Administrator'], self::$aURP_Profiles['REST Services User']]);
|
||||
$aPostFields = [
|
||||
'version' => '1.3',
|
||||
'json_data' => '{"operation": "list_operations"}',
|
||||
];
|
||||
|
||||
$aGetFields = [
|
||||
'auth_user' => static::$sLogin,
|
||||
'auth_pwd' => static::$sPassword,
|
||||
];
|
||||
$sJSONResult = $this->CallItopUri("/webservices/rest.php?".http_build_query($aGetFields), $aPostFields);
|
||||
|
||||
$this->assertEquals($this->GetExpectedRestResponse(), $sJSONResult);
|
||||
}
|
||||
|
||||
public function testLaunchCronWithFormModeFailWhenNotAdmin()
|
||||
{
|
||||
$this->ForceCronBusyError();
|
||||
|
||||
$this->AddLoginModeAndSaveConfiguration('form');
|
||||
$this->CreateUserWithProfiles([self::$aURP_Profiles['REST Services User']]);
|
||||
|
||||
$sLogFileName = "crontest_".uniqid();
|
||||
$aPostFields = [
|
||||
'version' => '1.3',
|
||||
'auth_user' => static::$sLogin,
|
||||
'auth_pwd' => static::$sPassword,
|
||||
'verbose' => 1,
|
||||
'debug' => 1,
|
||||
'cron_log_file' => $sLogFileName,
|
||||
];
|
||||
|
||||
$sJSONResult = $this->CallItopUri("/webservices/launch_cron_asynchronously.php", $aPostFields);
|
||||
|
||||
$this->assertEquals($this->GetExpectedCronResponse(), $sJSONResult);
|
||||
$sLogFile = $this->CheckLogFileIsGeneratedAndGetFullPath($sLogFileName);
|
||||
$this->CheckAdminAccessIssueWithCron($sLogFile);
|
||||
}
|
||||
|
||||
public function testLaunchCronWithBasicModeFailWhenNotAdmin()
|
||||
{
|
||||
$this->ForceCronBusyError();
|
||||
|
||||
$this->AddLoginModeAndSaveConfiguration('basic');
|
||||
$this->CreateUserWithProfiles([self::$aURP_Profiles['REST Services User']]);
|
||||
|
||||
$sLogFileName = "crontest_".uniqid();
|
||||
$aPostFields = [
|
||||
'version' => '1.3',
|
||||
'verbose' => 1,
|
||||
'debug' => 1,
|
||||
'cron_log_file' => $sLogFileName,
|
||||
];
|
||||
|
||||
$sToken = base64_encode(sprintf("%s:%s", static::$sLogin, static::$sPassword));
|
||||
$aCurlOptions = [
|
||||
CURLOPT_HTTPHEADER => ["Authorization: Basic $sToken"],
|
||||
];
|
||||
|
||||
$sJSONResult = $this->CallItopUri("/webservices/launch_cron_asynchronously.php", $aPostFields, $aCurlOptions);
|
||||
|
||||
$this->assertEquals($this->GetExpectedCronResponse(), $sJSONResult);
|
||||
$sLogFile = $this->CheckLogFileIsGeneratedAndGetFullPath($sLogFileName);
|
||||
$this->CheckAdminAccessIssueWithCron($sLogFile);
|
||||
}
|
||||
|
||||
public function testLaunchCronWithUrlModeFailWhenNotAdmin()
|
||||
{
|
||||
$this->ForceCronBusyError();
|
||||
|
||||
$this->AddLoginModeAndSaveConfiguration('url');
|
||||
$this->CreateUserWithProfiles([self::$aURP_Profiles['REST Services User']]);
|
||||
|
||||
$sLogFileName = "crontest_".uniqid();
|
||||
$aPostFields = [
|
||||
'version' => '1.3',
|
||||
'verbose' => 1,
|
||||
'debug' => 1,
|
||||
'cron_log_file' => $sLogFileName,
|
||||
];
|
||||
|
||||
$aGetFields = [
|
||||
'auth_user' => static::$sLogin,
|
||||
'auth_pwd' => static::$sPassword,
|
||||
];
|
||||
|
||||
$sJSONResult = $this->CallItopUri("/webservices/launch_cron_asynchronously.php?".http_build_query($aGetFields), $aPostFields);
|
||||
|
||||
$this->assertEquals($this->GetExpectedCronResponse(), $sJSONResult);
|
||||
$sLogFile = $this->CheckLogFileIsGeneratedAndGetFullPath($sLogFileName);
|
||||
$this->CheckAdminAccessIssueWithCron($sLogFile);
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ModeProvider
|
||||
*/
|
||||
public function testGetUserLoginWithFormMode($sMode)
|
||||
{
|
||||
$this->AddLoginModeAndSaveConfiguration($sMode);
|
||||
$this->CreateUserWithProfiles([self::$aURP_Profiles['Administrator']]);
|
||||
|
||||
$oLoginMode = new \LoginForm();
|
||||
$sUserLogin = $oLoginMode->GetUserLogin([static::$sLogin, static::$sPassword]);
|
||||
$this->assertEquals(static::$sLogin, $sUserLogin);
|
||||
}
|
||||
|
||||
private ?iTopMutex $oMutex = null;
|
||||
private function ForceCronBusyError(): void
|
||||
{
|
||||
try {
|
||||
$oMutex = new iTopMutex('cron');
|
||||
if ($oMutex->TryLock()) {
|
||||
$this->oMutex = $oMutex;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
private function ReleaseCronIfBusy(): void
|
||||
{
|
||||
try {
|
||||
if (! is_null($this->oMutex)) {
|
||||
$this->oMutex->Unlock();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
private function CreateUserWithProfiles(array $aProfileIds): ?string
|
||||
{
|
||||
if (count($aProfileIds) > 0) {
|
||||
$oUser = null;
|
||||
foreach ($aProfileIds as $oProfileId) {
|
||||
foreach ($aProfileIds as $iProfileId) {
|
||||
if (is_null($oUser)) {
|
||||
$oUser = $this->CreateUser(static::$sLogin, $oProfileId, static::$sPassword);
|
||||
$oUser = $this->CreateContactlessUser(static::$sLogin, $iProfileId, static::$sPassword);
|
||||
} else {
|
||||
$this->AddProfileToUser($oUser, $oProfileId);
|
||||
$this->AddProfileToUser($oUser, $iProfileId);
|
||||
}
|
||||
$oUser->DBWrite();
|
||||
}
|
||||
|
||||
return $oUser->GetKey();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function GetExpectedRestResponse(): string
|
||||
{
|
||||
return <<<JSON
|
||||
{"code":0,"message":"Operations: 7","version":"1.3","operations":[{"verb":"core\/create","description":"Create an object","extension":"CoreServices"},{"verb":"core\/update","description":"Update an object","extension":"CoreServices"},{"verb":"core\/apply_stimulus","description":"Apply a stimulus to change the state of an object","extension":"CoreServices"},{"verb":"core\/get","description":"Search for objects","extension":"CoreServices"},{"verb":"core\/delete","description":"Delete objects","extension":"CoreServices"},{"verb":"core\/get_related","description":"Get related objects through the specified relation","extension":"CoreServices"},{"verb":"core\/check_credentials","description":"Check user credentials","extension":"CoreServices"}]}
|
||||
JSON;
|
||||
}
|
||||
|
||||
private function GetExpectedCronResponse(): string
|
||||
{
|
||||
return '{"message":"OK"}';
|
||||
}
|
||||
|
||||
private function CheckLogFileIsGeneratedAndGetFullPath(string $sLogFileName): string
|
||||
{
|
||||
$sLogFile = APPROOT."log/$sLogFileName";
|
||||
$this->assertTrue(is_file($sLogFile));
|
||||
$this->aFileToClean[] = $sLogFile;
|
||||
return $sLogFile;
|
||||
}
|
||||
|
||||
private function CheckAdminAccessIssueWithCron(string $sLogFile)
|
||||
{
|
||||
$aLines = Utils::ReadTail($sLogFile);
|
||||
$sLastLine = array_shift($aLines);
|
||||
$this->assertMatchesRegularExpression('/^Access restricted to administrators/', $sLastLine, "@$sLastLine@");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user