Skip to content

Commit

Permalink
add foremen unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Eslam-Nawara committed Dec 18, 2022
1 parent e7f826d commit 8afa2ca
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 4 deletions.
1 change: 0 additions & 1 deletion cmd/foreman/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ func main() {
flag.Parse()

f, err := foreman.New(*procfilePtr, *verbosePtr)
fmt.Println(*verbosePtr)
if err != nil {
fmt.Println(err)
return
Expand Down
4 changes: 2 additions & 2 deletions foreman.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func New(filePath string, verbose bool) (*Foreman, error) {
// start all services from yaml file
func (foreman *Foreman) Start() error {
var wg sync.WaitGroup
graph := foreman.buildDepGraph()
graph := foreman.BuildDepGraph()

if depgraph.IsCyclic(graph) {
return errors.New("Cyclic dependencies detected")
Expand Down Expand Up @@ -162,7 +162,7 @@ func (foreman *Foreman) runChecker(service parser.Service, stopChecker chan bool
}
}

func (foreman *Foreman) buildDepGraph() map[string][]string {
func (foreman *Foreman) BuildDepGraph() map[string][]string {
graph := make(map[string][]string)
for serviceName, service := range foreman.services {
graph[serviceName] = service.Deps
Expand Down
178 changes: 177 additions & 1 deletion foreman_test.go
Original file line number Diff line number Diff line change
@@ -1,2 +1,178 @@
package foreman
package foreman

import (
"sync"
"testing"

"github.com/Eslam-Nawara/foreman/internal/depgraph"
parser "github.com/Eslam-Nawara/foreman/internal/procparser"
)

const procfile = "./test-procfiles/Procfile"
const testProcfile = "./test-procfiles/Procfile-test"
const testBadProcfile = "./test-procfiles/Procfile-bad-test"
const testCyclicProcfile = "./test-procfiles/Procfile-cyclic-test"

func TestNew(t *testing.T) {
t.Run("Parse existing procfile with correct syntax", func(t *testing.T) {
want := Foreman{
services: map[string]parser.Service{},
servicesMutex: sync.Mutex{},
}
sleeper := parser.Service{
Name: "sleeper",
Process: nil,
Cmd: "sleep infinity",
RunOnce: true,
Deps: []string{"hello"},
Checks: parser.ServiceChecks{
Cmd: "ls",
TcpPorts: []string{"4759", "1865"},
UdpPorts: []string{"4500", "3957"},
},
}
want.services["sleeper"] = sleeper

hello := parser.Service{
Name: "hello",
Process: nil,
Cmd: `echo "hello"`,
RunOnce: true,
Deps: []string{},
}
want.services["hello"] = hello

got, _ := New(testProcfile, false)

assertForeman(t, got, &want)
})

t.Run("Run existing file with bad yml syntax", func(t *testing.T) {
_, err := New(testBadProcfile, false)
if err == nil {
t.Error("Expected error: yaml: unmarshal errors")
}
})

t.Run("Run non-existing file", func(t *testing.T) {
_, err := New("unknown_file", false)
want := "open unknown_file: no such file or directory"
assertError(t, err, want)
})
}

func TestBuildDepGraph(t *testing.T) {
foreman, _ := New(procfile, false)

got := foreman.BuildDepGraph()
want := make(map[string][]string)
want["service_ping"] = []string{"service_redis"}
want["service_sleep"] = []string{"service_ping"}

assertGraph(t, got, want)
}

func TestIsCyclic(t *testing.T) {
t.Run("run cyclic graph", func(t *testing.T) {
foreman, _ := New(testCyclicProcfile, false)
graph := foreman.BuildDepGraph()
got := depgraph.IsCyclic(graph)
if !got {
t.Error("got:true, want:false")
}
})

t.Run("run acyclic graph", func(t *testing.T) {
foreman, _ := New(testProcfile, false)
graph := foreman.BuildDepGraph()
got := depgraph.IsCyclic(graph)
if got {
t.Error("got:false, want:true")
}
})
}

func TestTopSort(t *testing.T) {
foreman, _ := New(procfile, false)
depGraph := foreman.BuildDepGraph()
got := depgraph.TopSort(depGraph)
want := []string{"service_redis", "service_ping", "service_sleep"}
assertList(t, got, want)
}

// Helpers
func assertForeman(t *testing.T, got, want *Foreman) {
t.Helper()

for serviceName, service := range got.services {
assertService(t, service, want.services[serviceName])
}
}

func assertService(t *testing.T, got, want parser.Service) {
t.Helper()

if got.Name != want.Name {
t.Errorf("got:\n%q\nwant:\n%q", got.Name, want.Name)
}

if got.Process != want.Process {
t.Errorf("got:\n%v\nwant:\n%v", got.Process, want.Process)
}

if got.Cmd != want.Cmd {
t.Errorf("got:\n%q\nwant:\n%q", got.Cmd, want.Cmd)
}

if got.RunOnce != want.RunOnce {
t.Errorf("got:\n%t\nwant:\n%t", got.RunOnce, want.RunOnce)
}

assertList(t, got.Deps, want.Deps)
}

func assertChecks(t *testing.T, got, want parser.ServiceChecks) {
t.Helper()

if got.Cmd != want.Cmd {
t.Errorf("got:\n%q\nwant:\n%q", got.Cmd, want.Cmd)
}

assertList(t, got.TcpPorts, want.TcpPorts)
assertList(t, got.UdpPorts, want.UdpPorts)
}

func assertList(t *testing.T, got, want []string) {
t.Helper()

if len(want) != len(got) {
t.Errorf("got:\n%v\nwant:\n%v", got, want)
}

n := len(want)
for i := 0; i < n; i++ {
if got[i] != want[i] {
t.Errorf("got:\n%v\nwant:\n%v", got, want)
}
}
}

func assertError(t *testing.T, err error, want string) {
t.Helper()

if err == nil {
t.Fatal("Expected Error: open unknown_file: no such file or directory")
}

if err.Error() != want {
t.Errorf("got:\n%q\nwant:\n%q", err.Error(), want)
}
}

func assertGraph(t *testing.T, got, want map[string][]string) {
t.Helper()

for key, value := range got {
assertList(t, value, want[key])
}
}

0 comments on commit 8afa2ca

Please sign in to comment.