[tests-only] Log requests and responses for the failing tests (#7371)

* log request-response to a file

show logs in ci

move hooks to one place

* preserve logs between suites

* ignore logs

* Refactor and beautify logs

* fix php style

* add log step in ci pipeline

* get expected-failure file from env if available
This commit is contained in:
Sawjan Gurung
2023-10-13 13:22:27 +05:45
committed by GitHub
parent db84a238b3
commit bd955f75ed
6 changed files with 284 additions and 3 deletions
@@ -60,4 +60,3 @@ Feature: Download file in project space
Given user "Alice" has uploaded a file inside space "download file" with content "new content" to "file.txt"
When user "Bob" tries to get version of the file "file.txt" with the index "1" of the space "download file" using the WebDAV API
Then the HTTP status code should be "403"
@@ -27,9 +27,11 @@ use GuzzleHttp\Exception\GuzzleException;
use Helmich\JsonAssert\JsonAssertions;
use rdx\behatvars\BehatVariablesContext;
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
use Behat\Behat\Hook\Scope\AfterScenarioScope;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\TableNode;
use Behat\Testwork\Hook\Scope\BeforeSuiteScope;
use Behat\Testwork\Hook\Scope\AfterSuiteScope;
use GuzzleHttp\Cookie\CookieJar;
use Psr\Http\Message\ResponseInterface;
use PHPUnit\Framework\Assert;
@@ -37,6 +39,7 @@ use TestHelpers\AppConfigHelper;
use TestHelpers\OcsApiHelper;
use TestHelpers\SetupHelper;
use TestHelpers\HttpRequestHelper;
use TestHelpers\HttpLogger;
use TestHelpers\UploadHelper;
use TestHelpers\OcisHelper;
use Laminas\Ldap\Ldap;
@@ -572,6 +575,66 @@ class FeatureContext extends BehatVariablesContext {
$this->originalAdminPassword = $this->adminPassword;
}
/**
* Create log directory if it doesn't exist
*
* @BeforeSuite
*
* @param BeforeSuiteScope $scope
*
* @return void
* @throws Exception
*/
public static function setupLogDir(BeforeSuiteScope $scope): void {
if (!\file_exists(HttpLogger::getLogDir())) {
\mkdir(HttpLogger::getLogDir(), 0777, true);
}
}
/**
*
* @BeforeScenario
*
* @param BeforeScenarioScope $scope
*
* @return void
* @throws Exception
*/
public static function logScenario(BeforeScenarioScope $scope): void {
$scenarioLine = self::getScenarioLine($scope);
if ($scope->getScenario()->getNodeType() === "Example") {
$scenario = "Scenario Outline: " . $scope->getScenario()->getOutlineTitle();
} else {
$scenario = $scope->getScenario()->getNodeType() . ": " . $scope->getScenario()->getTitle();
}
$logMessage = "## $scenario ($scenarioLine)\n";
// Delete previous scenario's log file
if (\file_exists(HttpLogger::getScenarioLogPath())) {
\unlink(HttpLogger::getScenarioLogPath());
}
// Write the scenario log
HttpLogger::writeLog(HttpLogger::getScenarioLogPath(), $logMessage);
}
/**
*
* @BeforeStep
*
* @param BeforeStepScope $scope
*
* @return void
* @throws Exception
*/
public static function logStep(BeforeStepScope $scope): void {
$step = $scope->getStep()->getType() . " " . $scope->getStep()->getText();
$logMessage = "\t### $step\n";
HttpLogger::writeLog(HttpLogger::getScenarioLogPath(), $logMessage);
}
/**
* @param string $appTestCodeFullPath
*
@@ -3578,4 +3641,80 @@ class FeatureContext extends BehatVariablesContext {
throw new Exception(__METHOD__ . " accounts-list is empty");
}
}
/**
*
* @AfterSuite
*
* @return void
* @throws Exception
*/
public static function clearScenarioLog(): void {
if (\file_exists(HttpLogger::getScenarioLogPath())) {
\unlink(HttpLogger::getScenarioLogPath());
}
}
/**
* Log request and response logs if scenario fails
*
* @AfterScenario
*
* @param AfterScenarioScope $scope
*
* @return void
* @throws Exception
*/
public static function checkScenario(AfterScenarioScope $scope): void {
if (($scope->getTestResult()->getResultCode() !== 0)
&& (!self::isExpectedToFail(self::getScenarioLine($scope)))
) {
$logs = \file_get_contents(HttpLogger::getScenarioLogPath());
// add new lines
$logs = \rtrim($logs, "\n") . "\n\n\n";
HttpLogger::writeLog(HttpLogger::getFailedLogPath(), $logs);
}
}
/**
* @param BeforeScenarioScope|AfterScenarioScope $scope
*
* @return string
*/
public static function getScenarioLine($scope): string {
$feature = $scope->getFeature()->getFile();
$feature = \explode('/', $feature);
$feature = \array_slice($feature, -2);
$feature = \implode('/', $feature);
$scenarioLine = $scope->getScenario()->getLine();
// Example: apiGraph/createUser.feature:24
return $feature . ':' . $scenarioLine;
}
/**
* @param string $scenarioLine
*
* @return bool
*/
public static function isExpectedToFail(string $scenarioLine): bool {
$expectedFailFile = \getenv('EXPECTED_FAILURES_FILE');
if (!$expectedFailFile) {
$expectedFailFile = __DIR__ . '/../../expected-failures-localAPI-on-OCIS-storage.md';
if (\strpos($scenarioLine, "coreApi") === 0) {
$expectedFailFile = __DIR__ . '/../../expected-failures-API-on-OCIS-storage.md';
}
}
$reader = \fopen($expectedFailFile, 'r');
if ($reader) {
while (($line = \fgets($reader)) !== false) {
if (\strpos($line, $scenarioLine) !== false) {
\fclose($reader);
return true;
}
}
\fclose($reader);
}
return false;
}
}