Skip to content

Commit

Permalink
Merge pull request #347 from ysugimoto/feat/hotreload
Browse files Browse the repository at this point in the history
add watch option for incremental testing
  • Loading branch information
ysugimoto authored Sep 16, 2024
2 parents 7473a96 + d244d1b commit db0b902
Show file tree
Hide file tree
Showing 28 changed files with 118 additions and 11 deletions.
1 change: 1 addition & 0 deletions cmd/falco/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ Flags:
-request : Override request config
--max_backends : Override max backends limitation
--max_acls : Override max acls limitation
--watch : Watch VCL file changes and run test
Local testing example:
falco test -I . -I ./tests /path/to/vcl/main.vcl
Expand Down
85 changes: 84 additions & 1 deletion cmd/falco/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ import (
"fmt"
"math"
"os"
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"strings"
"syscall"
"time"

"encoding/json"

"github.com/fatih/color"
"github.com/fsnotify/fsnotify"
"github.com/kyokomi/emoji"
"github.com/mattn/go-colorable"
"github.com/pkg/errors"
Expand Down Expand Up @@ -161,7 +166,12 @@ func main() {
var exitErr error
switch action {
case subcommandTest:
exitErr = runTest(runner, v)
// test can accept watch
if c.Testing.Watch {
exitErr = watchRunTest(runner, v)
} else {
exitErr = runTest(runner, v)
}
case subcommandSimulate:
exitErr = runSimulate(runner, v)
case subcommandStats:
Expand Down Expand Up @@ -279,6 +289,79 @@ func runStats(runner *Runner, rslv resolver.Resolver) error {
return nil
}

func watchRunTest(runner *Runner, rslv resolver.Resolver) error {
watcher, err := fsnotify.NewWatcher()
if err != nil {
writeln(red, err.Error())
return ErrExit
}
defer watcher.Close()

doneCh := make(chan struct{})
errCh := make(chan error)

clearTerminal := func() {
if runtime.GOOS == "windows" {
// Clear terminal, we're not sure Window could clear termina by following command...
exec.Command("cmd", "/c", "cls").Run() // nolint:errcheck
} else {
// Darwin, Linux could clear by sending escape sequence
fmt.Print("\033[H\033[2J")
}
}

go func() {
clearTerminal()
// Run test at least once
runTest(runner, rslv) // nolint:errcheck

writeln(cyan, "waiting for file changes...")
for {
select {
case event, ok := <-watcher.Events:
if !ok {
doneCh <- struct{}{}
return
}
switch event.Op {
case fsnotify.Create, fsnotify.Rename:
clearTerminal()
runTest(runner, rslv) // nolint:errcheck
writeln(cyan, "waiting for file changes...")
}
case err, ok := <-watcher.Errors:
if !ok {
doneCh <- struct{}{}
return
}
writeln(red, err.Error())
errCh <- ErrExit
return
}
}
}()
go func() {
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)

<-sig
doneCh <- struct{}{}
}()

for _, p := range rslv.IncludePaths() {
if err := watcher.Add(p); err != nil {
return ErrExit
}
}

select {
case err := <-errCh:
return err
case <-doneCh:
return nil
}
}

func runTest(runner *Runner, rslv resolver.Resolver) error {
factory, err := runner.Test(rslv)
if err != nil {
Expand Down
12 changes: 6 additions & 6 deletions cmd/falco/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,37 +324,37 @@ func TestTester(t *testing.T) {
}{
{
name: "table manipulation test",
main: "../../examples/testing/table_manipulation.vcl",
main: "../../examples/testing/table_manipulation/table_manipulation.vcl",
filter: "*table_*.test.vcl",
passes: 2,
},
{
name: "empty and notset value test",
main: "../../examples/testing/default_values.vcl",
main: "../../examples/testing/default_values/default_values.vcl",
filter: "*values.test.vcl",
passes: 16,
},
{
name: "assertions test",
main: "../../examples/testing/assertion.vcl",
main: "../../examples/testing/assertion/assertion.vcl",
filter: "*assertion.test.vcl",
passes: 5,
},
{
name: "grouping test",
main: "../../examples/testing/group.vcl",
main: "../../examples/testing/group/group.vcl",
filter: "*group.test.vcl",
passes: 3,
},
{
name: "mockging test",
main: "../../examples/testing/mock_subroutine.vcl",
main: "../../examples/testing/mock_subroutine/mock_subroutine.vcl",
filter: "*mock_subroutine.test.vcl",
passes: 6,
},
{
name: "overriding variables test",
main: "../../examples/testing/override_variables.vcl",
main: "../../examples/testing/override_variables/override_variables.vcl",
filter: "*override_variables.test.vcl",
passes: 6,
},
Expand Down
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type TestConfig struct {
Filter string `cli:"f,filter" default:"*.test.vcl"`
IncludePaths []string // Copy from root field
OverrideHost string `yaml:"host"`
Watch bool `cli:"watch"` // Enable only in CLI option

// Override Request configuration
OverrideRequest *RequestConfig
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ require (
require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gdamore/encoding v1.0.0 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.6.0 h1:OKbluoP9VYmJwZwq/iLb4BxwKcwGthaa1YNBJIyCySg=
Expand Down
4 changes: 4 additions & 0 deletions linter/linter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,10 @@ func (m *mockResolver) Name() string {
return ""
}

func (m *mockResolver) IncludePaths() []string {
return []string{}
}

func TestResolveRootIncludeStatement(t *testing.T) {
mock := &mockResolver{
dependency: map[string]string{
Expand Down
3 changes: 2 additions & 1 deletion resolver/empty.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ func (e *EmptyResolver) Resolve(stmt *ast.IncludeStatement) (*VCL, error) {
return nil, errors.New("Empty Resolver returns error")
}

func (e *EmptyResolver) Name() string { return "__EMPTY__" }
func (e *EmptyResolver) Name() string { return "__EMPTY__" }
func (e *EmptyResolver) IncludePaths() []string { return []string{} }
4 changes: 4 additions & 0 deletions resolver/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ func (f *FileResolver) Name() string {
return ""
}

func (f *FileResolver) IncludePaths() []string {
return f.includePaths
}

func getVCL(file string) (*VCL, error) {
if _, err := os.Stat(file); err != nil {
return nil, err
Expand Down
4 changes: 4 additions & 0 deletions resolver/glob.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ func (g *GlobResolver) Name() string {
return ""
}

func (g *GlobResolver) IncludePaths() []string {
return []string{}
}

func (g *GlobResolver) MainVCL() (*VCL, error) {
return getVCL(g.main)
}
Expand Down
1 change: 1 addition & 0 deletions resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Resolver interface {
MainVCL() (*VCL, error)
Resolve(stmt *ast.IncludeStatement) (*VCL, error)
Name() string
IncludePaths() []string
// TODO: implement
// ResolveScopeSnippet(scope string) (*VCL, error)
}
3 changes: 2 additions & 1 deletion resolver/static.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ func (s *StaticResolver) Resolve(stmt *ast.IncludeStatement) (*VCL, error) {
return nil, errors.New("Static Resolver returns error")
}

func (s *StaticResolver) Name() string { return "__STATIC__" }
func (s *StaticResolver) Name() string { return "__STATIC__" }
func (s *StaticResolver) IncludePaths() []string { return []string{} }
4 changes: 4 additions & 0 deletions resolver/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ func (s *TerraformResolver) Name() string {
return s.ServiceName
}

func (s *TerraformResolver) IncludePaths() []string {
return []string{}
}

func (s *TerraformResolver) MainVCL() (*VCL, error) {
return s.Main, nil
}
Expand Down
4 changes: 2 additions & 2 deletions tester/tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ func New(c *config.TestConfig, opts []icontext.Option) *Tester {
// Note that:
// - Test files must have ".test.vcl" extension e.g default.test.vcl
// - Tester finds files from all include paths
func (t *Tester) listTestFiles(mainVCL string) ([]string, error) {
func (t *Tester) listTestFiles(main string) ([]string, error) {
// correct include paths
searchDirs := []string{filepath.Dir(mainVCL)}
searchDirs := []string{filepath.Dir(main)}
searchDirs = append(searchDirs, t.config.IncludePaths...)

var testFiles []string
Expand Down

0 comments on commit db0b902

Please sign in to comment.