Skip to content

Commit

Permalink
test: remove Rust binary dependency
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
torives committed Nov 16, 2023
1 parent 23baebf commit 78b0ade
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 25 deletions.
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.vscode
.env
**/.idea/
.DS_Store
.env
.vscode
build/deployments
**/.idea/
build/fake-service
4 changes: 2 additions & 2 deletions internal/services/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}()

Expand Down
124 changes: 104 additions & 20 deletions internal/services/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,140 @@ package services

import (
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"syscall"
"testing"
"time"

"github.com/cartesi/rollups-node/internal/logger"
)

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)
}
10 changes: 10 additions & 0 deletions test/fakeservice/main.go
Original file line number Diff line number Diff line change
@@ -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)
}

0 comments on commit 78b0ade

Please sign in to comment.