Some checks failed
CodeQL / Analyze (push) Waiting to run
Docker Build & Push Simapp (main) / docker-build (push) Waiting to run
golangci-lint / lint (push) Waiting to run
Tests / Code Coverage / build (amd64) (push) Waiting to run
Tests / Code Coverage / build (arm64) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[additional-args:-tags="test_e2e" name:e2e path:./e2e]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:08-wasm path:./modules/light-clients/08-wasm]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:ibc-go path:.]) (push) Waiting to run
Deploy to GitHub Pages / Deploy to GitHub Pages (push) Has been cancelled
Buf-Push / push (push) Has been cancelled
163 lines
5.5 KiB
Go
163 lines
5.5 KiB
Go
package diagnostics
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
ospath "path"
|
|
"strings"
|
|
"testing"
|
|
|
|
dockertypes "github.com/docker/docker/api/types"
|
|
mobycli "github.com/moby/moby/client"
|
|
|
|
"github.com/cosmos/ibc-go/e2e/dockerutil"
|
|
"github.com/cosmos/ibc-go/e2e/internal/directories"
|
|
)
|
|
|
|
const (
|
|
dockerInspectFileName = "docker-inspect.json"
|
|
defaultFilePerm = 0o750
|
|
)
|
|
|
|
// Collect can be used in `t.Cleanup` and will copy all the of the container logs and relevant files
|
|
// into e2e/<test-suite>/<test-name>.log. These log files will be uploaded to GH upon test failure.
|
|
func Collect(t *testing.T, dc *mobycli.Client, debugModeEnabled bool, suiteName string, chainNames ...string) {
|
|
t.Helper()
|
|
|
|
if !debugModeEnabled {
|
|
// when we are not forcing log collection, we only upload upon test failing.
|
|
if !t.Failed() {
|
|
t.Logf("test passed, not uploading logs")
|
|
return
|
|
}
|
|
}
|
|
|
|
t.Logf("writing logs for test: %s", t.Name())
|
|
|
|
ctx := context.TODO()
|
|
e2eDir, err := directories.E2E()
|
|
if err != nil {
|
|
t.Logf("failed finding log directory: %s", err)
|
|
return
|
|
}
|
|
|
|
logsDir := fmt.Sprintf("%s/diagnostics", e2eDir)
|
|
|
|
if err := os.MkdirAll(fmt.Sprintf("%s/%s", logsDir, t.Name()), defaultFilePerm); err != nil {
|
|
t.Logf("failed creating logs directory in test cleanup: %s", err)
|
|
return
|
|
}
|
|
|
|
testContainers, err := dockerutil.GetTestContainers(ctx, suiteName, dc)
|
|
if err != nil {
|
|
t.Logf("failed listing containers during test cleanup: %s", err)
|
|
return
|
|
}
|
|
|
|
for _, container := range testContainers {
|
|
containerName := getContainerName(t, container)
|
|
containerDir := fmt.Sprintf("%s/%s/%s", logsDir, t.Name(), containerName)
|
|
if err := os.MkdirAll(containerDir, defaultFilePerm); err != nil {
|
|
t.Logf("failed creating logs directory for container %s: %s", containerDir, err)
|
|
continue
|
|
}
|
|
|
|
logsBz, err := dockerutil.GetContainerLogs(ctx, dc, container.ID)
|
|
if err != nil {
|
|
t.Logf("failed reading logs in test cleanup: %s", err)
|
|
continue
|
|
}
|
|
|
|
logFile := fmt.Sprintf("%s/%s.log", containerDir, containerName)
|
|
if err := os.WriteFile(logFile, logsBz, defaultFilePerm); err != nil {
|
|
continue
|
|
}
|
|
|
|
t.Logf("successfully wrote log file %s", logFile)
|
|
|
|
var diagnosticFiles []string
|
|
for _, chainName := range chainNames {
|
|
diagnosticFiles = append(diagnosticFiles, chainDiagnosticAbsoluteFilePaths(chainName)...)
|
|
}
|
|
diagnosticFiles = append(diagnosticFiles, relayerDiagnosticAbsoluteFilePaths()...)
|
|
|
|
for _, absoluteFilePathInContainer := range diagnosticFiles {
|
|
localFilePath := ospath.Join(containerDir, ospath.Base(absoluteFilePathInContainer))
|
|
if err := fetchAndWriteDiagnosticsFile(ctx, dc, container.ID, localFilePath, absoluteFilePathInContainer); err != nil {
|
|
continue
|
|
}
|
|
t.Logf("successfully wrote diagnostics file %s", absoluteFilePathInContainer)
|
|
}
|
|
|
|
localFilePath := ospath.Join(containerDir, dockerInspectFileName)
|
|
if err := fetchAndWriteDockerInspectOutput(ctx, dc, container.ID, localFilePath); err != nil {
|
|
continue
|
|
}
|
|
t.Logf("successfully wrote docker inspect output")
|
|
}
|
|
}
|
|
|
|
// getContainerName returns an either the ID of the container or stripped down human-readable
|
|
// version of the name if the name is non-empty.
|
|
//
|
|
// Note: You should still always use the ID when interacting with the docker client.
|
|
func getContainerName(t *testing.T, container dockertypes.Container) string {
|
|
t.Helper()
|
|
// container will always have an id, by may not have a name.
|
|
containerName := container.ID
|
|
if len(container.Names) > 0 {
|
|
containerName = container.Names[0]
|
|
// remove the test name from the container as the folder structure will provide this
|
|
// information already.
|
|
containerName = strings.TrimRight(containerName, "-"+t.Name())
|
|
containerName = strings.TrimLeft(containerName, "/")
|
|
}
|
|
return containerName
|
|
}
|
|
|
|
// fetchAndWriteDiagnosticsFile fetches the contents of a single file from the given container id and writes
|
|
// the contents of the file to a local path provided.
|
|
func fetchAndWriteDiagnosticsFile(ctx context.Context, dc *mobycli.Client, containerID, localPath, absoluteFilePathInContainer string) error {
|
|
fileBz, err := dockerutil.GetFileContentsFromContainer(ctx, dc, containerID, absoluteFilePathInContainer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.WriteFile(localPath, fileBz, defaultFilePerm)
|
|
}
|
|
|
|
// fetchAndWriteDockerInspectOutput writes the contents of docker inspect to the specified file.
|
|
func fetchAndWriteDockerInspectOutput(ctx context.Context, dc *mobycli.Client, containerID, localPath string) error {
|
|
containerJSON, err := dc.ContainerInspect(ctx, containerID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fileBz, err := json.MarshalIndent(containerJSON, "", "\t")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.WriteFile(localPath, fileBz, defaultFilePerm)
|
|
}
|
|
|
|
// chainDiagnosticAbsoluteFilePaths returns a slice of absolute file paths (in the containers) which are the files that should be
|
|
// copied locally when fetching diagnostics.
|
|
func chainDiagnosticAbsoluteFilePaths(chainName string) []string {
|
|
return []string{
|
|
fmt.Sprintf("/var/cosmos-chain/%s/config/genesis.json", chainName),
|
|
fmt.Sprintf("/var/cosmos-chain/%s/config/app.toml", chainName),
|
|
fmt.Sprintf("/var/cosmos-chain/%s/config/config.toml", chainName),
|
|
fmt.Sprintf("/var/cosmos-chain/%s/config/client.toml", chainName),
|
|
}
|
|
}
|
|
|
|
// relayerDiagnosticAbsoluteFilePaths returns a slice of absolute file paths (in the containers) which are the files that should be
|
|
// copied locally when fetching diagnostics.
|
|
func relayerDiagnosticAbsoluteFilePaths() []string {
|
|
return []string{
|
|
"/home/hermes/.hermes/config.toml",
|
|
}
|
|
}
|