Skip to content

Commit

Permalink
Push repo instead of building executable (smartcontractkit#457)
Browse files Browse the repository at this point in the history
* Push repo instead of building executable

* cleanup linting

* go get and tidy latest chainlink-env
  • Loading branch information
tateexon authored Oct 24, 2022
1 parent 4e86278 commit 7fc9036
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 107 deletions.
206 changes: 102 additions & 104 deletions actions/soak_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
package actions

import (
"bufio"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"time"

"github.com/pkg/errors"
"github.com/rs/zerolog/log"
Expand All @@ -14,156 +17,151 @@ import (
"github.com/smartcontractkit/chainlink-testing-framework/logging"
)

// BuildGoTests builds the go tests using native go cross-compilation to run, and returns a path to the test executable
// along with its size in bytes.
//
// Note: currentProjectRootPath and currentSoakTestRootPath are not interchangeable with utils.ProjectRoot and utils.SoakRoot
// when running in outside repositories. Keep an eye on when you need paths leading to this go package vs the current running project.
func BuildGoTests(executablePath, testsPath, projectRootPath string) (string, int64, error) {
logging.Init()
absExecutablePath, err := filepath.Abs(executablePath)
if err != nil {
return "", 0, err
}
absTestsPath, err := filepath.Abs(testsPath)
if err != nil {
return "", 0, err
}
absProjectRootPath, err := filepath.Abs(projectRootPath)
if err != nil {
return "", 0, err
}
log.Info().
Str("Test Directory", absTestsPath).
Str("Executable Path", absExecutablePath).
Str("Project Root Path", absProjectRootPath).
Msg("Compiling tests")

exeFile := filepath.Join(absExecutablePath, "remote.test")
compileCmd := exec.Command("go", "test", "-ldflags=-s -w", "-c", absTestsPath, "-o", exeFile) // #nosec G204
compileCmd.Env = os.Environ()
compileCmd.Env = append(compileCmd.Env, "CGO_ENABLED=0", "GOOS=linux", "GOARCH=amd64")

compileOut, err := compileCmd.CombinedOutput()
log.Debug().
Str("Output", string(compileOut)).
Str("Command", compileCmd.String()).
Msg("Ran command")
if err != nil {
return "", 0, fmt.Errorf("Env: %s\nCommand: %s\nCommand Output: %s, %w",
compileCmd.Env, compileCmd.String(), string(compileOut), err)
}
const containerName = "remote-test-runner"
const tarFileName = "ztarrepo.tar.gz"

exeFileInfo, err := os.Stat(exeFile)
if err != nil {
return "", 0, fmt.Errorf("Expected '%s' to exist, %w", exeFile, err)
// BasicRunnerValuesSetup Basic values needed to run a soak test in the remote runner
func BasicRunnerValuesSetup(focus, namespace, testDirectory string) map[string]interface{} {
return map[string]interface{}{
"focus": focus,
"env_namespace": namespace,
"test_dir": testDirectory,
}
log.Info().Str("Path", exeFile).Int64("File Size (bytes)", exeFileInfo.Size()).Msg("Compiled tests")
return exeFile, exeFileInfo.Size(), nil
}

// TriggerRemoteTest copies the executable to the remote-test-runner and starts the run
func TriggerRemoteTest(exePath string, testEnvironment *environment.Environment) error {
func TriggerRemoteTest(repoSourcePath string, testEnvironment *environment.Environment) error {
logging.Init()

// Leaving commented out for now since it may be useful for the final solution to compiling cosmwasm into the tests
// Add gcompat package, required by libwasmvm
// _, _, err := testEnvironment.Client.ExecuteInPod(testEnvironment.Cfg.Namespace, "remote-test-runner", "remote-test-runner", []string{"apk", "add", "gcompat"})
// _, _, err := testEnvironment.Client.ExecuteInPod(testEnvironment.Cfg.Namespace, containerName, containerName, []string{"apk", "add", "gcompat"})
// if err != nil {
// return errors.Wrap(err, "Error adding gcompat")
// }
// Copy libwasmvm dependency of chainlink core
// _, _, errOut, err := testEnvironment.Client.CopyToPod(
// testEnvironment.Cfg.Namespace,
// os.Getenv("GOPATH")+"/pkg/mod/github.com/!cosm!wasm/[email protected]/api/libwasmvm.x86_64.so",
// fmt.Sprintf("%s/%s:/usr/lib/libwasmvm.x86_64.so", testEnvironment.Cfg.Namespace, "remote-test-runner"),
// fmt.Sprintf("%s/%s:/usr/lib/libwasmvm.x86_64.so", testEnvironment.Cfg.Namespace, containerName),
// "remote-test-runner")
// if err != nil {
// return errors.Wrap(err, errOut.String())
// }

// tar the repo
tarPath, _, err := tarRepo(repoSourcePath)
if err != nil {
return err
}
log.Debug().Str("Path", tarPath).Msg("Tar file to copy to pod")

// copy the repo containing the test to the pod
_, _, errOut, err := testEnvironment.Client.CopyToPod(
testEnvironment.Cfg.Namespace,
exePath,
fmt.Sprintf("%s/%s:/root/remote.test", testEnvironment.Cfg.Namespace, "remote-test-runner"),
"remote-test-runner")
tarPath,
fmt.Sprintf("%s/%s:/root/", testEnvironment.Cfg.Namespace, containerName),
containerName)
if err != nil {
return errors.Wrap(err, errOut.String())
}
log.Info().Str("Namespace", testEnvironment.Cfg.Namespace).Msg("Remote Test Triggered on 'remote-test-runner'")

// create start file in pod to start the test
_, _, err = testEnvironment.Client.ExecuteInPod(
testEnvironment.Cfg.Namespace,
containerName,
containerName,
[]string{
"touch",
"/root/start.txt",
},
)
if err != nil {
return err
}

log.Info().Str("Namespace", testEnvironment.Cfg.Namespace).Msg(fmt.Sprintf("Remote Test Triggered on '%s'", containerName))
return nil
}

/** This gets complicated with recent refactoring. Seeing how it's a niche use case, we'll remove it for now.
BuildGoTestsWithDocker builds the go tests to run using docker, and returns a path to the test executable, along with
remote config options. This version usually takes longer to run, but eliminates issues with cross-compilation.
Note: executablePath and projectRootPath are not interchangeable with utils.ProjectRoot and utils.SoakRoot
when running in outside repositories. Keep an eye on when you need paths leading to this go package vs the current running project.
func BuildGoTestsWithDocker(executablePath, testsPath, projectRootPath string) (fs.FileInfo, error) {
dockerfilePath, err := filepath.Abs("./Dockerfile.compiler")
// tarRep Uses the gnu tar command from a docker image to consistently compress the code
// using .gitingore and some other excludes to reduce the file size
func tarRepo(repoRootPath string) (string, int64, error) {
absRepoRootPath, err := filepath.Abs(repoRootPath)
if err != nil {
return "", 0, err
}
err = os.Chdir(absRepoRootPath)
if err != nil {
return nil, err
return "", 0, err
}
testTargetDir := filepath.Join(executablePath, "generated_test_dir")
finalTestDestination := filepath.Join(executablePath, "remote.test")

absTarFilePath := filepath.Join(absRepoRootPath, tarFileName)
// Clean up old test files if they're around
if _, err := os.Stat(finalTestDestination); err == nil {
if err = os.Remove(finalTestDestination); err != nil {
return nil, err
if _, err := os.Stat(absTarFilePath); err == nil {
if err = os.Remove(absTarFilePath); err != nil {
return "", 0, err
}
}

// Get the relative paths to directories needed by docker
relativeTestDirectoryToRootPath, err := filepath.Rel(executablePath, testsPath)
dockerBuildCmd := exec.Command("docker",
"run",
"--rm",
"-v",
fmt.Sprintf("%s:/usr/src", absRepoRootPath),
"tateexon/tar@sha256:093ca3ba5dbdd906d03425cbec3296705a6aa316db2071f4c8b487504de9e129",
fmt.Sprintf("--exclude=%s", tarFileName),
"--exclude=.git",
"--exclude-vcs-ignores",
"--ignore-failed-read",
"-czvf",
fmt.Sprintf("/usr/src/%s", tarFileName),
"/usr/src/",
) // #nosec G204
dockerBuildCmd.Env = os.Environ()
log.Info().Str("cmd", dockerBuildCmd.String()).Msg("Docker command")
stderr, err := dockerBuildCmd.StderrPipe()
if err != nil {
return nil, err
return "", 0, err
}
log.Info().Str("path", relativeTestDirectoryToRootPath).Msg("docker build arg testDirectory")
relativeProjectRootPathToRunningTest, err := filepath.Rel(projectRootPath, executablePath)
stdout, err := dockerBuildCmd.StdoutPipe()
if err != nil {
return nil, err
return "", 0, err
}
log.Info().Str("path", relativeProjectRootPathToRunningTest).Msg("docker build arg projectRootPath")

// TODO: Docker has a Go API, but it was oddly complicated and not at all documented, and kept failing.
// So for now, we're doing the tried and true method of plain commands.
dockerBuildCmd := exec.Command("docker",
"build",
"-t",
"test-compiler",
"--build-arg",
fmt.Sprintf("testDirectory=./%s", relativeTestDirectoryToRootPath),
"--build-arg",
fmt.Sprintf("projectRootPath=./%s", relativeProjectRootPathToRunningTest),
"-f",
dockerfilePath,
"--output",
testTargetDir,
executablePath) // #nosec G204
dockerBuildCmd.Env = os.Environ()
log.Info().Str("Docker File", dockerfilePath).Msg("Compiling tests using Docker")
compileOut, err := dockerBuildCmd.CombinedOutput()
log.Debug().
Str("Output", string(compileOut)).
Str("Command", dockerBuildCmd.String()).
Msg("Ran command")
// start the command and wrap stderr and stdout
started := time.Now()
err = dockerBuildCmd.Start()
if err != nil {
return nil, err
return "", 0, err
}
go readStdPipeDocker(stderr, "Error")
go readStdPipeDocker(stdout, "Output")

err = os.Rename(filepath.Join(testTargetDir, "remote.test"), finalTestDestination)
// wait for the command to finish
err = dockerBuildCmd.Wait()
if err != nil {
return nil, err
log.Info().Err(err).Msg("Ignoring error since it always fails for directory changing.")
}
err = os.Remove(testTargetDir)

finished := time.Now()
log.Info().Str("total", fmt.Sprintf("%v", finished.Sub(started))).Msg("Docker Command Run Time")

tarFileInfo, err := os.Stat(absTarFilePath)
if err != nil {
return nil, err
return "", 0, fmt.Errorf("expected '%s' to exist, %w", absTarFilePath, err)
}
log.Info().Str("Path", absTarFilePath).Int64("File Size (bytes)", tarFileInfo.Size()).Msg("Compiled tests")

exeFileInfo, err := os.Stat(finalTestDestination)
if err != nil {
return nil, fmt.Errorf("Expected '%s' to exist, %w", finalTestDestination, err)
return absTarFilePath, tarFileInfo.Size(), nil
}

// readStdPipeDocker continuously read a pipe from the docker command
func readStdPipeDocker(writer io.ReadCloser, prependOutput string) {
reader := bufio.NewReader(writer)
line, err := reader.ReadString('\n')
for err == nil {
log.Info().Str(prependOutput, line).Msg("Docker")
line, err = reader.ReadString('\n')
}
return exeFileInfo, nil
}
**/
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ require (
github.com/prometheus/common v0.37.0
github.com/rs/zerolog v1.28.0
github.com/slack-go/slack v0.11.3
github.com/smartcontractkit/chainlink-env v0.2.41
github.com/smartcontractkit/chainlink-env v0.2.43
github.com/stretchr/testify v1.8.0
go.uber.org/ratelimit v0.2.0
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -547,8 +547,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/slack-go/slack v0.11.3 h1:GN7revxEMax4amCc3El9a+9SGnjmBvSUobs0QnO6ZO8=
github.com/slack-go/slack v0.11.3/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
github.com/smartcontractkit/chainlink-env v0.2.41 h1:4Eh2er9t43M5scxevPR9kLkuC7k/noTthdhq1e3urSg=
github.com/smartcontractkit/chainlink-env v0.2.41/go.mod h1:QbD84f6yyME/lWlOJ9LF7sZ4bt2i8UvUht3UdjM6tek=
github.com/smartcontractkit/chainlink-env v0.2.43 h1:SrfMFrCacKpHATYOW7Cq1xnXBPRmF1BonxfgUFeSY8M=
github.com/smartcontractkit/chainlink-env v0.2.43/go.mod h1:QbD84f6yyME/lWlOJ9LF7sZ4bt2i8UvUht3UdjM6tek=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
Expand Down

0 comments on commit 7fc9036

Please sign in to comment.