From 78b0ade526775553a0d155c2f86d24c584359bb1 Mon Sep 17 00:00:00 2001 From: Victor Yves Crispim <rotcivyves@hotmail.com> Date: Wed, 15 Nov 2023 16:18:03 -0300 Subject: [PATCH] test: remove Rust binary dependency So far, tests of the Service struct assumed that the "cartesi-rollups-graphql-server" binary had been built already and then used it internally. This commit creates a "fake-service" binary for this purpose, eliminating the dependency. Also adds new tests for Service. --- .gitignore | 7 +- internal/services/service.go | 4 +- internal/services/service_test.go | 124 +++++++++++++++++++++++++----- test/fakeservice/main.go | 10 +++ 4 files changed, 120 insertions(+), 25 deletions(-) create mode 100644 test/fakeservice/main.go diff --git a/.gitignore b/.gitignore index f22a3ae7c..cc73ca4cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ -.vscode -.env +**/.idea/ .DS_Store +.env +.vscode build/deployments -**/.idea/ +build/fake-service diff --git a/internal/services/service.go b/internal/services/service.go index a57148f28..8bc873d07 100644 --- a/internal/services/service.go +++ b/internal/services/service.go @@ -46,8 +46,8 @@ func (s Service) Start(ctx context.Context) error { <-ctx.Done() logger.Debug.Printf("%v: %v\n", s.String(), ctx.Err()) if err := cmd.Process.Signal(syscall.SIGTERM); err != nil { - msg := "%v: failed to send SIGTERM to %v\n" - logger.Error.Printf(msg, s.String(), s.name) + msg := "failed to send SIGTERM to %v: %v" + logger.Warning.Printf(msg, s.name, err) } }() diff --git a/internal/services/service_test.go b/internal/services/service_test.go index 8ef7a9fa5..06220e071 100644 --- a/internal/services/service_test.go +++ b/internal/services/service_test.go @@ -5,10 +5,10 @@ package services import ( "context" + "fmt" "os" "os/exec" "path/filepath" - "syscall" "testing" "time" @@ -16,45 +16,129 @@ import ( ) func setup() { - logger.Init("warning", false) - setRustBinariesPath() + logger.Init("debug", false) + buildFakeService() } func TestService(t *testing.T) { + setup() t.Run("it stops when the context is cancelled", func(t *testing.T) { - setup() service := Service{ - name: "graphql-server", - binaryName: "cartesi-rollups-graphql-server", + name: "fake-service", + binaryName: "fake-service", } ctx, cancel := context.WithCancel(context.Background()) - exit := make(chan error) + defer cancel() + startErr := make(chan error) + success := make(chan struct{}) go func() { if err := service.Start(ctx); err != nil { - exit <- err + startErr <- err } + success <- struct{}{} }() <-time.After(100 * time.Millisecond) cancel() - err := <-exit - exitError, ok := err.(*exec.ExitError) - if !ok || !assertExitErrorWasCausedBy(exitError, syscall.SIGTERM) { - t.Logf("service exited for the wrong reason: %v", err) - t.FailNow() + select { + case err := <-startErr: + t.Errorf("service exited for the wrong reason: %v", err) + case <-success: + return + } + }) + + t.Run("it stops when timeout is reached and it isn't ready yet", func(t *testing.T) { + service := Service{ + name: "fake-service", + binaryName: "fake-service", + healthcheckPort: "0000", //wrong port + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + startErr := make(chan error, 1) + go func() { + if err := service.Start(ctx); err != nil { + startErr <- err + } + }() + + readyErr := make(chan error, 1) + success := make(chan struct{}, 1) + timeoutCtx, timeoutCancel := context.WithTimeout(ctx, 1*time.Second) + defer timeoutCancel() + go func() { + if err := service.Ready(timeoutCtx); err == nil { + readyErr <- fmt.Errorf("expected service to timeout") + } + success <- struct{}{} + }() + + select { + case err := <-startErr: + t.Errorf("service failed to start: %v", err) + case err := <-readyErr: + t.Error(err) + case <-success: + return } }) -} -func setRustBinariesPath() { - rustBinPath, _ := filepath.Abs("../../offchain/target/debug") - os.Setenv("PATH", os.Getenv("PATH")+":"+rustBinPath) + t.Run("it becomes ready soon after being started", func(t *testing.T) { + service := Service{ + name: "fake-service", + binaryName: "fake-service", + healthcheckPort: "8090", + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + startErr := make(chan error, 1) + go func() { + if err := service.Start(ctx); err != nil { + startErr <- err + } + }() + + readyErr := make(chan error, 1) + success := make(chan struct{}, 1) + timeoutCtx, timeoutCancel := context.WithTimeout(ctx, 5*time.Second) + defer timeoutCancel() + go func() { + if err := service.Ready(timeoutCtx); err != nil { + readyErr <- err + } + success <- struct{}{} + }() + + select { + case err := <-startErr: + t.Errorf("service failed to start: %v", err) + case err := <-readyErr: + t.Errorf("service wasn't ready in time. %v", err) + case <-success: + return + } + }) } -func assertExitErrorWasCausedBy(err *exec.ExitError, signal syscall.Signal) bool { - status := err.Sys().(syscall.WaitStatus) - return status.Signal() == signal +// Builds the fake-service binary and adds it to PATH +func buildFakeService() { + rootDir, err := filepath.Abs("../../") + if err != nil { + panic(err) + } + + cmd := exec.Command("go", "build", "-o", "build/fake-service", "test/fakeservice/main.go") + cmd.Dir = rootDir + if err := cmd.Run(); err != nil { + panic(err) + } + + execPath := filepath.Join(rootDir, "build") + os.Setenv("PATH", os.Getenv("PATH")+":"+execPath) } diff --git a/test/fakeservice/main.go b/test/fakeservice/main.go new file mode 100644 index 000000000..95756d545 --- /dev/null +++ b/test/fakeservice/main.go @@ -0,0 +1,10 @@ +// This file creates a dummy webserver with the sole pupose of being used +// as a binary to test the services.Service struct +package main + +import "net/http" + +func main() { + err := http.ListenAndServe(":8090", nil) + panic(err) +}