Skip to content

Conversation

@AlexSkrypnyk
Copy link
Member

@AlexSkrypnyk AlexSkrypnyk commented Feb 8, 2026

Summary

  • Added collectSutArtifacts() method to FunctionalTestCase::tearDown() that copies SUT .logs/ to .vortex/tests/.logs/sut/{testName}/ before workspace cleanup
  • On test failure, first syncs artifacts from the still-running Docker container via syncToHost(), then copies to the persistent location
  • Added "Upload test artifacts" step with if: always() to the vortex-test-workflow CI job to upload .vortex/tests/.logs/ (includes both PHPUnit runner's junit.xml and SUT artifacts)

Closes #1976

Test plan

  • Verify that on test failure, SUT artifacts (PHPUnit results, Behat screenshots) appear in the uploaded GitHub Actions artifacts under sut/{testName}/
  • Verify that on test success, the upload step completes without error (no artifacts to upload is acceptable via if-no-files-found: ignore)
  • Verify that existing coverage report upload is unaffected

Summary by CodeRabbit

  • Chores
    • CI now always uploads test artifacts (including hidden logs) after test runs, ensuring logs are archived even when tests fail and making troubleshooting easier.
    • Functional test suite now preserves and centralizes SUT diagnostic logs for failed tests, creating uniquely named copies for later inspection without altering pass-case behavior.

@coderabbitai
Copy link

coderabbitai bot commented Feb 8, 2026

Walkthrough

Adds collection of SUT test logs during PHPUnit tearDown and a GitHub Actions step to always upload collected test artifacts (including hidden files) from CI after tests run.

Changes

Cohort / File(s) Summary
Workflow Configuration
\.github/workflows/vortex-test-common.yml
Adds an "Upload test artifacts" step (actions/upload-artifact@v7) that always runs and uploads the .vortex/tests/.logs directory (include-hidden-files, ignore if no files).
Test Artifact Collection
\.vortex/tests/phpunit/Functional/FunctionalTestCase.php
Adds collectSutArtifacts(bool $test_failed) and calls it from tearDown. On failure, attempts to sync container .logs to host (errors swallowed) and copies any SUT .logs into .logs/sut/{test_id} for centralized archival.

Sequence Diagram(s)

sequenceDiagram
  participant PHPUnit as "PHPUnit Test"
  participant SUT as "SUT Container"
  participant Host as "Host FS (.vortex/tests/.logs)"
  participant Actions as "GitHub Actions (upload-artifact)"

  PHPUnit->>SUT: run test (may produce .logs)
  PHPUnit->>PHPUnit: tearDown() calls collectSutArtifacts(test_failed)
  alt test_failed
    PHPUnit->>SUT: try sync `.logs` -> Host (errors ignored)
  end
  SUT-->>Host: `.logs` available on host
  PHPUnit->>Host: copy `.logs` -> `.logs/sut/{test_id}`
  Actions->>Host: workflow step always runs
  Actions->>Actions: upload `.vortex/tests/.logs` (include hidden files)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐇 I hopped through logs both day and night,

Pulled SUT whispers into softer light,
Packaged them neatly for CI to keep,
No more lost traces in quiet sleep,
Hooray — artifacts safe in one warm heap!

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: uploading SUT test artifacts in the CI workflow, with issue reference for context.
Linked Issues check ✅ Passed The PR implements all core requirements from issue #1976: collects SUT artifacts in FunctionalTestCase, uploads via actions/upload-artifact with if: always() and include-hidden-files: true, and handles no-files-found.
Out of Scope Changes check ✅ Passed All changes are directly related to the linked issue objective of capturing and uploading SUT test artifacts; no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/1976-sut-test-artifacts

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.vortex/tests/phpunit/Functional/FunctionalTestCase.php:
- Around line 102-103: The current artifact destination uses only $this->name(),
risking collisions and unsafe characters; update the destination construction in
FunctionalTestCase so it includes the test class name (e.g., get_class($this) or
static::class) and a sanitized test identifier, then ensure uniqueness (append a
timestamp or uniqid()) and strip or replace filesystem-unsafe characters
(spaces, slashes, colons, non-alphanumerics) before calling File::copy with the
resulting $dest. Target the code that sets $dest and the call to File::copy to
perform the sanitization and uniqueness logic.

@AlexSkrypnyk
Copy link
Member Author

Code Coverage Report:
  2026-02-08 03:14:44

 Summary:
  Classes:  0.00% (0/1)
  Methods:  0.00% (0/2)
  Lines:   93.92% (170/181)

@github-actions

This comment has been minimized.

@github-actions
Copy link

github-actions bot commented Feb 8, 2026

Code Coverage Report:
  2026-02-08 03:23:09

 Summary:
  Classes:  0.00% (0/1)
  Methods:  0.00% (0/2)
  Lines:   93.92% (170/181)

@AlexSkrypnyk
Copy link
Member Author

Code Coverage Report:
  2026-02-08 03:23:34

 Summary:
  Classes:  0.00% (0/1)
  Methods:  0.00% (0/2)
  Lines:   93.92% (170/181)

@AlexSkrypnyk
Copy link
Member Author

Code Coverage Report:
  2026-02-08 03:26:34

 Summary:
  Classes:  0.00% (0/1)
  Methods:  0.00% (0/2)
  Lines:   93.92% (170/181)

@AlexSkrypnyk
Copy link
Member Author

Code Coverage Report:
  2026-02-08 03:27:00

 Summary:
  Classes:  0.00% (0/1)
  Methods:  0.00% (0/2)
  Lines:   93.92% (170/181)

@codecov
Copy link

codecov bot commented Feb 8, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.22%. Comparing base (35cb270) to head (6dd3a48).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2255      +/-   ##
==========================================
- Coverage   76.85%   76.22%   -0.63%     
==========================================
  Files         112      105       -7     
  Lines        5846     5687     -159     
  Branches       44        0      -44     
==========================================
- Hits         4493     4335     -158     
+ Misses       1353     1352       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.vortex/tests/phpunit/Functional/FunctionalTestCase.php:
- Around line 102-109: In tearDown() where $dest is built and
File::copy($sut_logs, $dest) is called, ensure the destination directory exists
(create dirname($dest) with appropriate permissions) before copying, and wrap
the File::copy call in a try/catch that catches the FileException (or
\Exception) so copy failures are logged via $this->logNote or a warning but not
rethrown (so they don't mask test results); reference the $dest variable,
File::copy, the surrounding tearDown() method and $this->logNote when making
this change.

Comment on lines +102 to +109
$class_name = (new \ReflectionClass($this))->getShortName();
$test_id = $class_name . '_' . $this->name() . '_' . uniqid();
$test_id = (string) preg_replace('/[^a-zA-Z0-9_-]/', '_', $test_id);

$dest = dirname(__DIR__, 2) . '/.logs/sut/' . $test_id;
File::copy($sut_logs, $dest);

$this->logNote('SUT test artifacts copied to: ' . $dest);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

# Find the File class being used
rg 'class File' --type php -A 5 | head -50

Repository: drevops/vortex

Length of output: 40


🏁 Script executed:

# Look for File class imports or usage
rg 'use.*File' .vortex/tests/phpunit/Functional/FunctionalTestCase.php

Repository: drevops/vortex

Length of output: 85


🏁 Script executed:

# Search for File::copy definition
rg 'function copy\(' --type php

Repository: drevops/vortex

Length of output: 40


🏁 Script executed:

# Check if File class is from a composer package
cat composer.json | jq '.require, .require-dev' 2>/dev/null || find . -name "composer.json" -type f -exec cat {} \; | head -100

Repository: drevops/vortex

Length of output: 4691


🌐 Web query:

alexskrypnyk/file 0.19.0 File::copy() documentation

💡 Result:

For alexskrypnyk/file v0.19.0 (released 2025-12-23), the README documents AlexSkrypnyk\File\File::copy() as a static utility to copy a file or a directory (the example shows copying a directory recursively). It’s intended to be used inside a try/catch for FileException. [1]

Example (from the v0.19.0 README):

use AlexSkrypnyk\File\Exception\FileException;
use AlexSkrypnyk\File\File;

try {
  File::copy('/path/to/source', '/path/to/destination');
} catch (FileException $e) {
  echo $e->getMessage();
}
``` [1]

**Where it’s listed:**
- “Available Methods” table: **`copy()` — Copy file or directory.** [1]

**Source:** Packagist README for `alexskrypnyk/file` **0.19.0**. [1]

References:  
[1] https://packagist.org/packages/alexskrypnyk/file

---

🌐 Web query:

`github AlexSkrypnyk file php copy method parent directories`

💡 Result:

I couldn’t find a specific `File.php` (or a `copy()` implementation) in an `AlexSkrypnyk` GitHub repo from that query, but in plain PHP the key point is: **`copy($from, $to)` will fail if the destination directory doesn’t exist**—it does not create parent directories for you. [1]

Create the parent dirs first (recursively), then copy:

```php
$from = $src;
$to   = $dst;

$dir = dirname($to);
if (!is_dir($dir)) {
  mkdir($dir, 0777, true); // recursive parent directories
}

if (!copy($from, $to)) {
  throw new RuntimeException("Failed to copy $from to $to");
}
  • mkdir(..., $recursive=true) creates nested/parent directories. [2]
  • copy() copies/overwrites the destination file, but won’t create missing directories. [1]

Sources: [1] [2]


Defensive directory creation + copy error handling.

The .logs/sut directory must be created explicitly before copying, and File::copy() throws FileException on failure. In tearDown(), artifact logging failures should not mask test results. Ensure the destination directory exists and handle copy exceptions gracefully.

♻️ Suggested hardening
-    $dest = dirname(__DIR__, 2) . '/.logs/sut/' . $test_id;
-    File::copy($sut_logs, $dest);
+    $dest_root = dirname(__DIR__, 2) . '/.logs/sut';
+    if (!is_dir($dest_root) && !mkdir($dest_root, 0777, TRUE) && !is_dir($dest_root)) {
+      $this->logNote('Unable to create SUT artifacts directory: ' . $dest_root);
+      return;
+    }
+    $dest = $dest_root . '/' . $test_id;
+    try {
+      File::copy($sut_logs, $dest);
+    }
+    catch (\Throwable $e) {
+      $this->logNote('Failed to copy SUT artifacts: ' . $e->getMessage());
+      return;
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$class_name = (new \ReflectionClass($this))->getShortName();
$test_id = $class_name . '_' . $this->name() . '_' . uniqid();
$test_id = (string) preg_replace('/[^a-zA-Z0-9_-]/', '_', $test_id);
$dest = dirname(__DIR__, 2) . '/.logs/sut/' . $test_id;
File::copy($sut_logs, $dest);
$this->logNote('SUT test artifacts copied to: ' . $dest);
$class_name = (new \ReflectionClass($this))->getShortName();
$test_id = $class_name . '_' . $this->name() . '_' . uniqid();
$test_id = (string) preg_replace('/[^a-zA-Z0-9_-]/', '_', $test_id);
$dest_root = dirname(__DIR__, 2) . '/.logs/sut';
if (!is_dir($dest_root) && !mkdir($dest_root, 0777, TRUE) && !is_dir($dest_root)) {
$this->logNote('Unable to create SUT artifacts directory: ' . $dest_root);
return;
}
$dest = $dest_root . '/' . $test_id;
try {
File::copy($sut_logs, $dest);
}
catch (\Throwable $e) {
$this->logNote('Failed to copy SUT artifacts: ' . $e->getMessage());
return;
}
$this->logNote('SUT test artifacts copied to: ' . $dest);
🤖 Prompt for AI Agents
In @.vortex/tests/phpunit/Functional/FunctionalTestCase.php around lines 102 -
109, In tearDown() where $dest is built and File::copy($sut_logs, $dest) is
called, ensure the destination directory exists (create dirname($dest) with
appropriate permissions) before copying, and wrap the File::copy call in a
try/catch that catches the FileException (or \Exception) so copy failures are
logged via $this->logNote or a warning but not rethrown (so they don't mask test
results); reference the $dest variable, File::copy, the surrounding tearDown()
method and $this->logNote when making this change.

@AlexSkrypnyk AlexSkrypnyk merged commit 57e225e into main Feb 8, 2026
28 checks passed
@AlexSkrypnyk AlexSkrypnyk deleted the feature/1976-sut-test-artifacts branch February 8, 2026 03:51
@github-project-automation github-project-automation bot moved this from BACKLOG to Release queue in Vortex Feb 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Release queue

Development

Successfully merging this pull request may close these issues.

Dev CI vortex-test-workflow does not upload artifacts produced by SUT tests

1 participant