You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

99 lines
2.9 KiB

//go:build integration
package test
import (
"context"
"fmt"
"os"
"path/filepath"
"testing"
"time"
)
// LogCollector is implemented by any target that can provide a log file.
type LogCollector interface {
CollectLog() (string, error)
}
// ArtifactCollector gathers diagnostic info on test failure.
type ArtifactCollector struct {
dir string // base artifacts directory
node *Node // initiator node for dmesg/lsblk
}
// NewArtifactCollector creates a collector rooted at the given directory.
func NewArtifactCollector(dir string, node *Node) *ArtifactCollector {
return &ArtifactCollector{
dir: dir,
node: node,
}
}
// Collect gathers diagnostics for a failed test. Call from t.Cleanup().
// Pass any LogCollector (Target or WeedTarget) for the correct log file.
func (a *ArtifactCollector) Collect(t *testing.T, tgt LogCollector) {
a.CollectLabeled(t, tgt, "target")
}
// CollectLabeled is like Collect but uses the given label for the log filename
// (e.g. "primary" -> "primary.log"). Use this when collecting logs from
// multiple targets in the same test to avoid overwriting.
func (a *ArtifactCollector) CollectLabeled(t *testing.T, tgt LogCollector, label string) {
if !t.Failed() {
return
}
ts := time.Now().Format("20060102-150405")
testDir := filepath.Join(a.dir, ts, t.Name())
if err := os.MkdirAll(testDir, 0755); err != nil {
t.Logf("artifacts: mkdir failed: %v", err)
return
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// Target log (from the test's own target instance)
if tgt != nil {
if log, err := tgt.CollectLog(); err == nil && log != "" {
writeArtifact(t, filepath.Join(testDir, label+".log"), log)
}
}
// iSCSI session state
if stdout, _, _, err := a.node.RunRoot(ctx, "iscsiadm -m session 2>&1"); err == nil {
writeArtifact(t, filepath.Join(testDir, "iscsi-session.txt"), stdout)
}
// Kernel messages (iSCSI errors)
if stdout, _, _, err := a.node.RunRoot(ctx, "dmesg | tail -200"); err == nil {
writeArtifact(t, filepath.Join(testDir, "dmesg.txt"), stdout)
}
// Block devices
if stdout, _, _, err := a.node.Run(ctx, "lsblk 2>&1"); err == nil {
writeArtifact(t, filepath.Join(testDir, "lsblk.txt"), stdout)
}
t.Logf("artifacts saved to %s", testDir)
}
func writeArtifact(t *testing.T, path, content string) {
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
t.Logf("artifacts: write %s: %v", path, err)
} else {
t.Logf("artifacts: wrote %s (%d bytes)", filepath.Base(path), len(content))
}
}
// CollectPerf saves performance results to a timestamped JSON file.
func (a *ArtifactCollector) CollectPerf(t *testing.T, name string, data string) {
ts := time.Now().Format("20060102-150405")
path := filepath.Join(a.dir, fmt.Sprintf("perf-%s-%s.json", name, ts))
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
t.Logf("artifacts: mkdir failed: %v", err)
return
}
writeArtifact(t, path, data)
}