Skip to content

Commit

Permalink
chore: refactor after discussion and initial review
Browse files Browse the repository at this point in the history
  • Loading branch information
IronCore864 committed Sep 11, 2024
1 parent e0bb83b commit 574fa49
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 175 deletions.
10 changes: 1 addition & 9 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,11 @@
## Run Tests

```bash
go test -tags=integration ./tests/
go test -count=1 -tags=integration ./tests/
```

## Developing

### Clean Test Cache

If you are adding tests and debugging, remember to clean test cache:

```bash
go clean -testcache && go test -v -tags=integration ./tests/
```

### Visual Studio Code Settings

For the VSCode Go extention to work properly with files with build tags, add the following:
Expand Down
116 changes: 85 additions & 31 deletions tests/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,55 +14,109 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package tests_test
package tests

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

. "github.com/canonical/pebble/tests"
"github.com/canonical/pebble/internals/servicelog"
)

// TestMain does extra setup before executing tests.
// TestMain builds the pebble binary before running the integration tests.
func TestMain(m *testing.M) {
goBuild := exec.Command("go", "build", "-o", "../pebble", "../cmd/pebble")
if err := goBuild.Run(); err != nil {
fmt.Println("Setup failed with error:", err)
fmt.Println("Cannot build pebble binary:", err)
os.Exit(1)
}

exitVal := m.Run()
os.Exit(exitVal)
exitCode := m.Run()
os.Exit(exitCode)
}

func TestPebbleRunNormal(t *testing.T) {
pebbleDir := t.TempDir()

layerYAML := `
services:
demo-service:
override: replace
command: sleep 1000
startup: enabled
demo-service2:
override: replace
command: sleep 1000
startup: enabled
`[1:]

CreateLayer(t, pebbleDir, "001-simple-layer.yaml", layerYAML)

logsCh := PebbleRun(t, pebbleDir)
expected := []string{
"Started daemon",
"Service \"demo-service\" starting",
"Service \"demo-service2\" starting",
"Started default services with change",
func createLayer(t *testing.T, pebbleDir string, layerFileName string, layerYAML string) {
t.Helper()

layersDir := filepath.Join(pebbleDir, "layers")
err := os.MkdirAll(layersDir, 0o755)
if err != nil {
t.Fatalf("Cannot create layers directory: pipe: %v", err)
}

layerPath := filepath.Join(layersDir, layerFileName)
err = os.WriteFile(layerPath, []byte(layerYAML), 0o755)
if err != nil {
t.Fatalf("Error creating layers file: %v", err)
}
}

func pebbleRun(t *testing.T, pebbleDir string, args ...string) <-chan servicelog.Entry {
t.Helper()

logsCh := make(chan servicelog.Entry)

cmd := exec.Command("../pebble", append([]string{"run"}, args...)...)
cmd.Env = append(os.Environ(), "PEBBLE="+pebbleDir)

t.Cleanup(func() {
err := cmd.Process.Signal(os.Interrupt)
if err != nil {
t.Errorf("Error sending SIGINT/Ctrl+C to pebble: %v", err)
}
cmd.Wait()
})

stderrPipe, err := cmd.StderrPipe()
if err != nil {
t.Fatalf("Error creating stderr pipe: %v", err)
}
if err := WaitForLogs(logsCh, expected, time.Second*3); err != nil {
t.Errorf("Error waiting for logs: %v", err)

err = cmd.Start()
if err != nil {
t.Fatalf("Error starting 'pebble run': %v", err)
}

go func() {
defer close(logsCh)
parser := servicelog.NewParser(stderrPipe, 4*1024)
for parser.Next() {
if err := parser.Err(); err != nil {
t.Errorf("Cannot parse Pebble logs: %v", err)
}
logsCh <- parser.Entry()
}
}()

return logsCh
}

func waitForServices(t *testing.T, pebbleDir string, expectedServices []string, timeout time.Duration) {
for _, service := range expectedServices {
waitForService(t, pebbleDir, service, timeout)
}
}

func waitForService(t *testing.T, pebbleDir string, service string, timeout time.Duration) {
serviceFilePath := filepath.Join(pebbleDir, service)
timeoutCh := time.After(timeout)
ticker := time.NewTicker(time.Millisecond)
for {
select {
case <-timeoutCh:
t.Errorf("timeout waiting for service %s", service)
return

case <-ticker.C:
stat, err := os.Stat(serviceFilePath)
if err == nil && stat.Mode().IsRegular() {
os.Remove(serviceFilePath)
return
}
}
}
}
52 changes: 52 additions & 0 deletions tests/run_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//go:build integration

// Copyright (c) 2024 Canonical Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 3 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package tests

import (
"fmt"
"path/filepath"
"strings"
"testing"
"time"
)

func TestPebbleRunNormal(t *testing.T) {
pebbleDir := t.TempDir()

layerYAML := `
services:
svc1:
override: replace
command: {{.svc1Cmd}}
startup: enabled
svc2:
override: replace
command: {{.svc2Cmd}}
startup: enabled
`
svc1Cmd := fmt.Sprintf("touch %s ; sleep 1000", filepath.Join(pebbleDir, "svc1"))
svc2Cmd := fmt.Sprintf("touch %s ; sleep 1000", filepath.Join(pebbleDir, "svc2"))
layerYAML = strings.Replace(layerYAML, "{{.svc1Cmd}}", svc1Cmd, -1)
layerYAML = strings.Replace(layerYAML, "{{.svc2Cmd}}", svc2Cmd, -1)

createLayer(t, pebbleDir, "001-simple-layer.yaml", layerYAML)

_ = pebbleRun(t, pebbleDir)

expectedServices := []string{"svc1", "svc2"}
waitForServices(t, pebbleDir, expectedServices, time.Second*3)
}
135 changes: 0 additions & 135 deletions tests/utils.go

This file was deleted.

0 comments on commit 574fa49

Please sign in to comment.