Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"scripts": {
"test": "phpunit"
},
"version": "2.1.5",
"version": "2.1.6",
"config": {
"platform": {
"php": "8.0"
Expand Down
2 changes: 1 addition & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion src/Config/BaseConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public function __construct(string $reporterName, LoggerInterface $logger)
}
}
$this->logger = $logger;

}

public function getReporterName(): string
Expand Down
31 changes: 31 additions & 0 deletions src/Config/ConfigLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ private function loadFromJsonFile(): QaseConfig
if (isset($data['environment'])) $config->setEnvironment($data['environment']);
if (isset($data['rootSuite'])) $config->setRootSuite($data['rootSuite']);
if (isset($data['debug'])) $config->setDebug($data['debug']);
if (isset($data['logging'])) $config->setLogging($data['logging']);

if (isset($data['statusMapping'])) {
$statusMapping = new StatusMapping(new \Qase\PhpCommons\Loggers\Logger(false));
Expand Down Expand Up @@ -131,6 +132,12 @@ private function overrideWithEnvVariables(): void
case "qase_debug":
$this->config->setDebug($value);
break;
case "qase_logging_console":
$this->parseLoggingConsole($value);
break;
case "qase_logging_file":
$this->parseLoggingFile($value);
break;
case "qase_status_mapping":
$this->parseStatusMapping($value);
break;
Expand Down Expand Up @@ -294,6 +301,30 @@ private function parseExternalLinkUrl(string $value): void
}
}

/**
* Parse logging console setting from environment variable
*
* @param string $value Console logging setting (true/false)
*/
private function parseLoggingConsole(string $value): void
{
$logging = $this->config->getLogging() ?? [];
$logging['console'] = filter_var($value, FILTER_VALIDATE_BOOLEAN);
$this->config->setLogging($logging);
}

/**
* Parse logging file setting from environment variable
*
* @param string $value File logging setting (true/false)
*/
private function parseLoggingFile(string $value): void
{
$logging = $this->config->getLogging() ?? [];
$logging['file'] = filter_var($value, FILTER_VALIDATE_BOOLEAN);
$this->config->setLogging($logging);
}

/**
* Parse status mapping from environment variable
* Format: "invalid=failed,skipped=passed"
Expand Down
48 changes: 36 additions & 12 deletions src/Loggers/Logger.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,38 @@ class Logger implements LoggerInterface
'RESET' => "\033[0m", // Reset color
];
private bool $debug;
private bool $consoleEnabled;
private bool $fileEnabled;
private string $logFilePath;

public function __construct(bool $debug = false)
public function __construct(bool $debug = false, ?array $loggingConfig = null)
{
$this->debug = $debug;
$this->logFilePath = getcwd() . '/logs/log_' . date('Y-m-d') . '.log';

if (!is_dir(getcwd() . '/logs')) {
// Set default logging configuration
$this->consoleEnabled = true;
$this->fileEnabled = true;

// Override with config if provided
if ($loggingConfig !== null) {
if (isset($loggingConfig['console'])) {
$this->consoleEnabled = (bool)$loggingConfig['console'];
}
if (isset($loggingConfig['file'])) {
$this->fileEnabled = (bool)$loggingConfig['file'];
}
}

// Create logs directory if file logging is enabled
if ($this->fileEnabled && !is_dir(getcwd() . '/logs')) {
mkdir(getcwd() . '/logs', 0777, true);
}
}

public function info(string $message): void
{
$this->log($message, 'INFO');
$this->writeLog($message, 'INFO');
}

public function debug(string $message): void
Expand All @@ -39,24 +56,31 @@ public function debug(string $message): void
return;
}

$this->log($message, 'DEBUG');
$this->writeLog($message, 'DEBUG');
}

public function error(string $message): void
{
$this->log($message, 'ERROR');
$this->writeLog($message, 'ERROR');
}

private function log(string $message, string $level): void
{
$color = self::LEVEL_COLORS[$level] ?? self::LEVEL_COLORS['RESET'];
$reset = self::LEVEL_COLORS['RESET'];

private function writeLog(string $message, string $level): void
{
$timestamp = date('Y-m-d H:i:s');
$formattedMessage = sprintf("%s %s%s %s %s%s\n", $color, self::PREFIX, $timestamp, $level, $message, $reset);
$logEntry = $timestamp . ' ' . $level . ' ' . $message . PHP_EOL;

echo $formattedMessage;
// Console output
if ($this->consoleEnabled) {
$color = self::LEVEL_COLORS[$level] ?? self::LEVEL_COLORS['RESET'];
$reset = self::LEVEL_COLORS['RESET'];
$formattedMessage = sprintf("%s %s%s %s %s%s\n", $color, self::PREFIX, $timestamp, $level, $message, $reset);
echo $formattedMessage;
}

file_put_contents($this->logFilePath, $timestamp . ' ' . $level . ' ' . $message . PHP_EOL, FILE_APPEND);
// File output
if ($this->fileEnabled) {
file_put_contents($this->logFilePath, $logEntry, FILE_APPEND);
}
}
}
22 changes: 22 additions & 0 deletions src/Models/Config/QaseConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class QaseConfig
public ?string $rootSuite = null;
public bool $debug;
public array $statusMapping = [];
public ?array $logging = null;
public TestopsConfig $testops;
public ReportConfig $report;

Expand All @@ -21,6 +22,7 @@ public function __construct()
$this->mode = Mode::OFF;
$this->fallback = Mode::OFF;
$this->debug = false;
$this->logging = null;
$this->testops = new TestopsConfig();
$this->report = new ReportConfig();
}
Expand Down Expand Up @@ -98,4 +100,24 @@ public function setStatusMapping(array $statusMapping): void
{
$this->statusMapping = $statusMapping;
}

/**
* Get logging configuration
*
* @return array|null
*/
public function getLogging(): ?array
{
return $this->logging;
}

/**
* Set logging configuration
*
* @param array|null $logging
*/
public function setLogging(?array $logging): void
{
$this->logging = $logging;
}
}
4 changes: 2 additions & 2 deletions src/Reporters/ReporterFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static function create(String $framework = "", String $reporterName = "")
{
$configLoader = new ConfigLoader(new Logger(true));
$config = $configLoader->getConfig();
$logger = new Logger($config->getDebug());
$logger = new Logger($config->getDebug(), $config->getLogging());
$hostInfo = new HostInfo();
$hostData = $hostInfo->getHostInfo($framework, $reporterName);
$logger->debug("Host data: " . json_encode($hostData));
Expand Down Expand Up @@ -55,6 +55,6 @@ private static function createInternalReporter(LoggerInterface $logger, QaseConf
private static function prepareTestopsReporter(LoggerInterface $logger, QaseConfig $config, StateInterface $state): InternalReporterInterface
{
$client = new ApiClientV2($logger, $config->testops);
return new TestOpsReporter($client, $config, $state);
return new TestOpsReporter($client, $config, $state, $logger);
}
}
9 changes: 6 additions & 3 deletions src/Reporters/TestOpsReporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Exception;
use Qase\PhpCommons\Interfaces\ClientInterface;
use Qase\PhpCommons\Interfaces\InternalReporterInterface;
use Qase\PhpCommons\Interfaces\LoggerInterface;
use Qase\PhpCommons\Interfaces\StateInterface;
use Qase\PhpCommons\Models\Config\QaseConfig;

Expand All @@ -16,14 +17,16 @@ class TestOpsReporter implements InternalReporterInterface
private ClientInterface $client;
private QaseConfig $config;
private StateInterface $state;
private LoggerInterface $logger;
private ?int $runId = null;
private ?array $cachedConfigurationGroups = null;

public function __construct(ClientInterface $client, QaseConfig $config, StateInterface $state)
public function __construct(ClientInterface $client, QaseConfig $config, StateInterface $state, LoggerInterface $logger)
{
$this->client = $client;
$this->config = $config;
$this->state = $state;
$this->logger = $logger;
}

/**
Expand Down Expand Up @@ -293,8 +296,8 @@ private function updateExternalIssue(int $runId): void
]
);
} catch (Exception $e) {
// Log error through the client's logger
error_log('Failed to update external issue: ' . $e->getMessage());
// Log error through the centralized logger
$this->logger->error('Failed to update external issue: ' . $e->getMessage());
}
}
}
25 changes: 14 additions & 11 deletions tests/TestOpsReporterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Exception;
use PHPUnit\Framework\TestCase;
use Qase\PhpCommons\Interfaces\ClientInterface;
use Qase\PhpCommons\Interfaces\LoggerInterface;
use Qase\PhpCommons\Interfaces\StateInterface;
use Qase\PhpCommons\Models\Config\QaseConfig;
use Qase\PhpCommons\Reporters\TestOpsReporter;
Expand All @@ -14,12 +15,14 @@ class TestOpsReporterTest extends TestCase
{
private $clientMock;
private $stateMock;
private $loggerMock;
private QaseConfig $config;

protected function setUp(): void
{
$this->clientMock = $this->createMock(ClientInterface::class);
$this->stateMock = $this->createMock(StateInterface::class);
$this->loggerMock = $this->createMock(LoggerInterface::class);
$this->config = $this->getConfig();
}

Expand All @@ -30,7 +33,7 @@ public function testStartRunCreatesNewRunIfRunIdIsNull(): void
$this->stateMock->method('startRun')
->willReturn(123);

$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock);
$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock, $this->loggerMock);
$reporter->startRun();

$this->assertSame(123, $this->getPrivateProperty($reporter, 'runId'));
Expand All @@ -47,7 +50,7 @@ public function testStartRunThrowsExceptionIfRunNotFound(): void
$this->expectException(Exception::class);
$this->expectExceptionMessage('Run with id 123 not found');

$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock);
$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock, $this->loggerMock);
$reporter->startRun();
}

Expand All @@ -59,7 +62,7 @@ public function testStartRunUsesExistingRunId(): void
->with('TEST_PROJECT', 123)
->willReturn(true);

$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock);
$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock, $this->loggerMock);
$reporter->startRun();

$this->assertSame(123, $this->getPrivateProperty($reporter, 'runId'));
Expand All @@ -73,7 +76,7 @@ public function testSendResultsClearsResults(): void
->method('sendResults')
->with('TEST_PROJECT', 123, ['result1', 'result2']);

$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock);
$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock, $this->loggerMock);
$reporter->startRun();

$reporter->addResult('result1');
Expand All @@ -91,7 +94,7 @@ public function testAddResultSendsResultsWhenBatchSizeIsReached(): void
->method('sendResults')
->with('TEST_PROJECT', 123, ['result1', 'result2']);

$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock);
$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock, $this->loggerMock);
$reporter->startRun();

$reporter->addResult('result1');
Expand All @@ -116,7 +119,7 @@ public function testCompleteRunSendsRemainingResults(): void
return is_callable($callback);
}));

$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock);
$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock, $this->loggerMock);
$reporter->startRun();

$reporter->addResult('result1');
Expand All @@ -141,7 +144,7 @@ public function testCompleteRunWithNoResultsDoesNothing(): void
->method('completeRun')
->with($this->isType('callable'));

$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock);
$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock, $this->loggerMock);
$reporter->startRun();
$reporter->completeRun();
}
Expand All @@ -155,7 +158,7 @@ public function testCompleteRunWithCompleteIsFalseDoesNotCompleteTestRun(): void
$this->clientMock->expects($this->never())
->method('completeTestRun');

$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock);
$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock, $this->loggerMock);
$reporter->startRun();
$reporter->completeRun();
}
Expand All @@ -174,7 +177,7 @@ public function testAddResultFiltersOutExcludedStatuses(): void
$this->createResultWithStatus('failed')
]);

$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock);
$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock, $this->loggerMock);
$reporter->startRun();

// Add results with different statuses
Expand Down Expand Up @@ -206,7 +209,7 @@ public function testAddResultIncludesAllResultsWhenNoFilterConfigured(): void
]]
);

$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock);
$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock, $this->loggerMock);
$reporter->startRun();

// Add results with different statuses - all should be included
Expand All @@ -230,7 +233,7 @@ public function testAddResultHandlesResultsWithoutStatus(): void
$this->createResultWithStatus('passed')
]);

$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock);
$reporter = new TestOpsReporter($this->clientMock, $this->config, $this->stateMock, $this->loggerMock);
$reporter->startRun();

// Add results - one without status should be included
Expand Down