From fcb7b4174c3c1e76e2fdcd2673fef7c609b1affb Mon Sep 17 00:00:00 2001 From: dune73 Date: Sun, 30 Oct 2022 15:45:44 +0100 Subject: [PATCH 1/6] feature: look for ~/.ftw.yaml after looking in local folder --- config/config.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/config/config.go b/config/config.go index ad91fa1..23de467 100644 --- a/config/config.go +++ b/config/config.go @@ -26,6 +26,20 @@ func NewConfigFromFile(cfgFile string) error { cfgFile = ".ftw.yaml" } + _, err = os.Stat(cfgFile) + if err != nil { // file does not exist, so we try the home folder + + var home string + + home, err = os.UserHomeDir() + if err != nil { // home folder could not be retrieved + return err + } + + cfgFile = home + "/.ftw.yaml" + + } + _, err = os.Stat(cfgFile) if err != nil { // file exists, so we read it looking for config values return err From e33ec86fdc6e54dee060a290177ced531c56273f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Zipitr=C3=ADa?= <3012076+fzipi@users.noreply.github.com> Date: Sun, 30 Oct 2022 15:49:03 +0100 Subject: [PATCH 2/6] ci: add branch develop (#97) Signed-off-by: Felipe Zipitria --- .github/workflows/codeql-analysis.yml | 4 ++-- .github/workflows/sonar.yaml | 2 +- .github/workflows/test.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 4506e74..46229dd 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,10 +13,10 @@ name: "CodeQL" on: push: - branches: [ main ] + branches: [ main, develop ] pull_request: # The branches below must be a subset of the branches above - branches: [ main ] + branches: [ main, develop ] schedule: - cron: '33 8 * * 4' diff --git a/.github/workflows/sonar.yaml b/.github/workflows/sonar.yaml index 01f7625..97e1d4c 100644 --- a/.github/workflows/sonar.yaml +++ b/.github/workflows/sonar.yaml @@ -1,7 +1,7 @@ name: Sonar on: push: - branches: [ main ] + branches: [ main, develop ] jobs: sonar: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f3bce0b..7ffbdf9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,10 +1,10 @@ name: Test on: pull_request: - branches: [ main ] + branches: [ main, develop ] types: [opened, synchronize, reopened] push: - branches: [ main ] + branches: [ main, develop ] jobs: test: From 48af38fcf31f5c2301b33959c150f22adf6e0c48 Mon Sep 17 00:00:00 2001 From: Max Leske Date: Sun, 30 Oct 2022 15:56:24 +0100 Subject: [PATCH 3/6] fix: properly URL encode data for POST requests (#96) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Felipe Zipitría <3012076+fzipi@users.noreply.github.com> --- check/base.go | 6 +++--- ftwhttp/request.go | 26 +++++--------------------- ftwhttp/request_test.go | 22 ++++++++++++++++++++++ 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/check/base.go b/check/base.go index 765f812..fea8dc2 100644 --- a/check/base.go +++ b/check/base.go @@ -60,7 +60,7 @@ func (c *FTWCheck) SetNoLogContains(contains string) { // ForcedIgnore check if this id need to be ignored from results func (c *FTWCheck) ForcedIgnore(id string) bool { - for re, _ := range c.overrides.Ignore { + for re := range c.overrides.Ignore { if re.MatchString(id) { return true } @@ -70,7 +70,7 @@ func (c *FTWCheck) ForcedIgnore(id string) bool { // ForcedPass check if this id need to be ignored from results func (c *FTWCheck) ForcedPass(id string) bool { - for re, _ := range c.overrides.ForcePass { + for re := range c.overrides.ForcePass { if re.MatchString(id) { return true } @@ -80,7 +80,7 @@ func (c *FTWCheck) ForcedPass(id string) bool { // ForcedFail check if this id need to be ignored from results func (c *FTWCheck) ForcedFail(id string) bool { - for re, _ := range c.overrides.ForceFail { + for re := range c.overrides.ForceFail { if re.MatchString(id) { return true } diff --git a/ftwhttp/request.go b/ftwhttp/request.go index e84c836..23a80d7 100644 --- a/ftwhttp/request.go +++ b/ftwhttp/request.go @@ -183,33 +183,17 @@ func buildRequest(r *Request) ([]byte, error) { return b.Bytes(), err } -// If the values are empty in the map, then don't encode anythin -// This keeps the compatibility with the python implementation -func emptyQueryValues(values url.Values) bool { - for _, v := range values { - val := v - if len(val) > 1 { - return false - } - } - return true -} - // encodeDataParameters url encode parameters in data func encodeDataParameters(h Header, data []byte) ([]byte, error) { var err error if h.Get(ContentTypeHeader) == "application/x-www-form-urlencoded" { - if escapedData, _ := url.QueryUnescape(string(data)); escapedData == string(data) { - queryString, err := url.ParseQuery(string(data)) - if (err != nil && strings.Contains(err.Error(), "invalid semicolon separator in query")) || emptyQueryValues(queryString) { - return data, nil - } - encodedData := queryString.Encode() - if encodedData != string(data) { - // we need to encode data - return []byte(encodedData), nil + if escapedData, err := url.QueryUnescape(string(data)); escapedData == string(data) { + if err != nil { + return nil, errors.New("Failed") } + queryString := url.QueryEscape(string(data)) + return []byte(queryString), nil } } return data, err diff --git a/ftwhttp/request_test.go b/ftwhttp/request_test.go index 2f02d69..2a15966 100644 --- a/ftwhttp/request_test.go +++ b/ftwhttp/request_test.go @@ -226,3 +226,25 @@ func TestRequestURLParseFail(t *testing.T) { err := req.SetData([]byte("test=This&that=but with;;;;;; data now")) assert.NoError(t, err) } + +func TestRequestEncodesPostData(t *testing.T) { + req := generateBaseRequestForTesting() + + h := req.Headers() + h.Add(ContentTypeHeader, "application/x-www-form-urlencoded") + // Test adding semicolons to test parse + err := req.SetData([]byte(`c4= ;c3=t;c2=a;c1=c;a1=/;a2=e;a3=t;a4=c;a5=/;a6=p;a7=a;a8=s;a9=s;a10=w;a11=d;$c1$c2$c3$c4$a1$a2$a3$a4$a5$a6$a7$a8$a9$a10$a11`)) + if err != nil { + t.Errorf("Failed !") + } + result, err := encodeDataParameters(h, req.Data()) + if err != nil { + t.Errorf("Failed to encode %s", req.Data()) + } + + expected := "c4%3D+%3Bc3%3Dt%3Bc2%3Da%3Bc1%3Dc%3Ba1%3D%2F%3Ba2%3De%3Ba3%3Dt%3Ba4%3Dc%3Ba5%3D%2F%3Ba6%3Dp%3Ba7%3Da%3Ba8%3Ds%3Ba9%3Ds%3Ba10%3Dw%3Ba11%3Dd%3B%24c1%24c2%24c3%24c4%24a1%24a2%24a3%24a4%24a5%24a6%24a7%24a8%24a9%24a10%24a11" + actual := string(result) + if actual != expected { + t.Error("Unexpected URL encoded payload") + } +} From 0e1ead6845a682d8cc86bf269e6f644c3b53498f Mon Sep 17 00:00:00 2001 From: Max Leske Date: Sun, 30 Oct 2022 16:00:06 +0100 Subject: [PATCH 4/6] fix: remove obsolete use of tzdata (#95) --- main.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/main.go b/main.go index 51f9f00..9313e84 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,6 @@ package main import ( "fmt" "os" - "time" _ "time/tzdata" "github.com/rs/zerolog" @@ -29,15 +28,6 @@ func main() { // Default level for this example is info, unless debug flag is present zerolog.SetGlobalLevel(zerolog.InfoLevel) - // Load timezone location based on TZ - tzone, _ := time.Now().Zone() - loc, err := time.LoadLocation(tzone) - if err != nil { - log.Info().Msgf("ftw/main: cannot load timezone") - } else { - time.Local = loc // -> set the global timezone - } - cmd.Execute( buildVersion(version, commit, date, builtBy), ) From f29629b62151d9cb35f472248ea01c89d6efb46f Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Wed, 2 Nov 2022 19:30:31 +0900 Subject: [PATCH 5/6] fix: remove most uses of log.Fatal when running (#99) Propagate errors instead of exiting immediately --- cmd/run.go | 5 +++- ftwhttp/client.go | 6 ++--- ftwhttp/client_test.go | 32 ++++++++++++++++---------- ftwhttp/connection.go | 3 ++- ftwhttp/response_test.go | 6 +++-- runner/run.go | 49 +++++++++++++++++++++++++++------------- runner/run_test.go | 45 ++++++++++++++++++++++++------------ waflog/read.go | 3 --- waflog/read_test.go | 15 ++++++++---- waflog/waflog.go | 16 +++++++++---- waflog/waflog_test.go | 3 ++- 11 files changed, 119 insertions(+), 64 deletions(-) diff --git a/cmd/run.go b/cmd/run.go index 6a9aeaa..3019ad6 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -56,7 +56,7 @@ var runCmd = &cobra.Command{ excludeRE = regexp.MustCompile(exclude) } - currentRun := runner.Run(tests, runner.Config{ + currentRun, err := runner.Run(tests, runner.Config{ Include: includeRE, Exclude: excludeRE, ShowTime: showTime, @@ -64,6 +64,9 @@ var runCmd = &cobra.Command{ ConnectTimeout: connectTimeout, ReadTimeout: readTimeout, }) + if err != nil { + log.Fatal().Err(err) + } os.Exit(currentRun.Stats.TotalFailed()) }, diff --git a/ftwhttp/client.go b/ftwhttp/client.go index 729b78b..4d32e2b 100644 --- a/ftwhttp/client.go +++ b/ftwhttp/client.go @@ -21,17 +21,17 @@ func NewClientConfig() ClientConfig { } // NewClient initializes the http client, creating the cookiejar -func NewClient(config ClientConfig) *Client { +func NewClient(config ClientConfig) (*Client, error) { // All users of cookiejar should import "golang.org/x/net/publicsuffix" jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List}) if err != nil { - log.Fatal().Err(err) + return nil, err } c := &Client{ Jar: jar, config: config, } - return c + return c, nil } // NewConnection creates a new Connection based on a Destination diff --git a/ftwhttp/client_test.go b/ftwhttp/client_test.go index 59cf6bb..d58102e 100644 --- a/ftwhttp/client_test.go +++ b/ftwhttp/client_test.go @@ -7,7 +7,8 @@ import ( ) func TestNewClient(t *testing.T) { - c := NewClient(NewClientConfig()) + c, err := NewClient(NewClientConfig()) + assert.NoError(t, err) assert.NotNil(t, c.Jar, "Error creating Client") } @@ -19,9 +20,10 @@ func TestConnectDestinationHTTPS(t *testing.T) { Protocol: "https", } - c := NewClient(NewClientConfig()) + c, err := NewClient(NewClientConfig()) + assert.NoError(t, err) - err := c.NewConnection(*d) + err = c.NewConnection(*d) assert.NoError(t, err, "This should not error") assert.Equal(t, "https", c.Transport.protocol, "Error connecting to example.com using https") } @@ -33,11 +35,12 @@ func TestDoRequest(t *testing.T) { Protocol: "https", } - c := NewClient(NewClientConfig()) + c, err := NewClient(NewClientConfig()) + assert.NoError(t, err) req := generateBaseRequestForTesting() - err := c.NewConnection(*d) + err = c.NewConnection(*d) assert.NoError(t, err, "This should not error") _, err = c.Do(*req) @@ -52,7 +55,8 @@ func TestGetTrackedTime(t *testing.T) { Protocol: "https", } - c := NewClient(NewClientConfig()) + c, err := NewClient(NewClientConfig()) + assert.NoError(t, err) rl := &RequestLine{ Method: "POST", @@ -65,7 +69,7 @@ func TestGetTrackedTime(t *testing.T) { data := []byte(`test=me&one=two&one=twice`) req := NewRequest(rl, h, data, true) - err := c.NewConnection(*d) + err = c.NewConnection(*d) assert.NoError(t, err, "This should not error") c.StartTrackingTime() @@ -90,7 +94,8 @@ func TestClientMultipartFormDataRequest(t *testing.T) { Protocol: "https", } - c := NewClient(NewClientConfig()) + c, err := NewClient(NewClientConfig()) + assert.NoError(t, err) rl := &RequestLine{ Method: "POST", @@ -112,7 +117,7 @@ Some-file-test-here req := NewRequest(rl, h, data, true) - err := c.NewConnection(*d) + err = c.NewConnection(*d) assert.NoError(t, err, "This should not error") c.StartTrackingTime() @@ -127,7 +132,8 @@ Some-file-test-here } func TestNewConnectionCreatesTransport(t *testing.T) { - c := NewClient(NewClientConfig()) + c, err := NewClient(NewClientConfig()) + assert.NoError(t, err) assert.Nil(t, c.Transport, "Transport not expected to initialized yet") server := testServer() @@ -141,7 +147,8 @@ func TestNewConnectionCreatesTransport(t *testing.T) { } func TestNewOrReusedConnectionCreatesTransport(t *testing.T) { - c := NewClient(NewClientConfig()) + c, err := NewClient(NewClientConfig()) + assert.NoError(t, err) assert.Nil(t, c.Transport, "Transport not expected to initialized yet") server := testServer() @@ -155,7 +162,8 @@ func TestNewOrReusedConnectionCreatesTransport(t *testing.T) { } func TestNewOrReusedConnectionReusesTransport(t *testing.T) { - c := NewClient(NewClientConfig()) + c, err := NewClient(NewClientConfig()) + assert.NoError(t, err) assert.Nil(t, c.Transport, "Transport not expected to initialized yet") server := testServer() diff --git a/ftwhttp/connection.go b/ftwhttp/connection.go index f02f333..d273780 100644 --- a/ftwhttp/connection.go +++ b/ftwhttp/connection.go @@ -5,6 +5,7 @@ import ( "bufio" "bytes" "errors" + "fmt" "io" "net" "net/http" @@ -82,7 +83,7 @@ func (c *Connection) Request(request *Request) error { // Build request first, then connect and send, so timers are accurate data, err := buildRequest(request) if err != nil { - log.Fatal().Msgf("ftw/http: fatal error building request: %s", err.Error()) + return fmt.Errorf("ftw/http: fatal error building request: %w", err) } log.Debug().Msgf("ftw/http: sending data:\n%s\n", data) diff --git a/ftwhttp/response_test.go b/ftwhttp/response_test.go index 1503a46..868feb6 100644 --- a/ftwhttp/response_test.go +++ b/ftwhttp/response_test.go @@ -88,7 +88,8 @@ func TestResponse(t *testing.T) { req := generateRequestForTesting(true) - client := NewClient(NewClientConfig()) + client, err := NewClient(NewClientConfig()) + assert.NoError(t, err) err = client.NewConnection(*d) assert.NoError(t, err) @@ -107,7 +108,8 @@ func TestResponseWithCookies(t *testing.T) { assert.NoError(t, err) req := generateRequestForTesting(true) - client := NewClient(NewClientConfig()) + client, err := NewClient(NewClientConfig()) + assert.NoError(t, err) err = client.NewConnection(*d) assert.NoError(t, err) diff --git a/runner/run.go b/runner/run.go index 1671018..4c454ed 100644 --- a/runner/run.go +++ b/runner/run.go @@ -1,6 +1,7 @@ package runner import ( + "errors" "fmt" "regexp" "time" @@ -17,11 +18,16 @@ import ( "github.com/coreruleset/go-ftw/waflog" ) +var errBadTestRequest = errors.New("ftw/run: bad test: choose between data, encoded_request, or raw_request") + // Run runs your tests with the specified Config. Returns error if some test failed -func Run(tests []test.FTWTest, c Config) TestRunContext { +func Run(tests []test.FTWTest, c Config) (TestRunContext, error) { printUnlessQuietMode(c.Quiet, ":rocket:Running go-ftw!\n") - logLines := waflog.NewFTWLogLines(waflog.WithLogFile(config.FTWConfig.LogFile)) + logLines, err := waflog.NewFTWLogLines(waflog.WithLogFile(config.FTWConfig.LogFile)) + if err != nil { + return TestRunContext{}, err + } conf := ftwhttp.NewClientConfig() if c.ConnectTimeout != 0 { @@ -30,7 +36,10 @@ func Run(tests []test.FTWTest, c Config) TestRunContext { if c.ReadTimeout != 0 { conf.ReadTimeout = c.ReadTimeout } - client := ftwhttp.NewClient(conf) + client, err := ftwhttp.NewClient(conf) + if err != nil { + return TestRunContext{}, err + } runContext := TestRunContext{ Include: c.Include, Exclude: c.Exclude, @@ -41,21 +50,23 @@ func Run(tests []test.FTWTest, c Config) TestRunContext { RunMode: config.FTWConfig.RunMode, } - for _, test := range tests { - RunTest(&runContext, test) + for _, tc := range tests { + if err := RunTest(&runContext, tc); err != nil { + return TestRunContext{}, err + } } printSummary(c.Quiet, runContext.Stats) defer cleanLogs(logLines) - return runContext + return runContext, nil } // RunTest runs an individual test. // runContext contains information for the current test run // ftwTest is the test you want to run -func RunTest(runContext *TestRunContext, ftwTest test.FTWTest) { +func RunTest(runContext *TestRunContext, ftwTest test.FTWTest) error { changed := true for _, testCase := range ftwTest.Tests { @@ -78,9 +89,13 @@ func RunTest(runContext *TestRunContext, ftwTest test.FTWTest) { // Iterate over stages for _, stage := range testCase.Stages { ftwCheck := check.NewCheck(config.FTWConfig) - RunStage(runContext, ftwCheck, testCase, stage.Stage) + if err := RunStage(runContext, ftwCheck, testCase, stage.Stage); err != nil { + return err + } } } + + return nil } // RunStage runs an individual test stage. @@ -88,7 +103,7 @@ func RunTest(runContext *TestRunContext, ftwTest test.FTWTest) { // ftwCheck is the current check utility // testCase is the test case the stage belongs to // stage is the stage you want to run -func RunStage(runContext *TestRunContext, ftwCheck *check.FTWCheck, testCase test.Test, stage test.Stage) { +func RunStage(runContext *TestRunContext, ftwCheck *check.FTWCheck, testCase test.Test, stage test.Stage) error { stageStartTime := time.Now() stageID := uuid.NewString() // Apply global overrides initially @@ -101,14 +116,14 @@ func RunStage(runContext *TestRunContext, ftwCheck *check.FTWCheck, testCase tes // Check sanity first if checkTestSanity(testRequest) { - log.Fatal().Msgf("ftw/run: bad test: choose between data, encoded_request, or raw_request") + return errBadTestRequest } // Do not even run test if result is overridden. Just use the override and display the overridden result. if overridden := overriddenTestResult(ftwCheck, testCase.TestTitle); overridden != Failed { addResultToStats(overridden, testCase.TestTitle, &runContext.Stats) displayResult(runContext.Output, overridden, time.Duration(0), time.Duration(0)) - return + return nil } var req *ftwhttp.Request @@ -123,7 +138,7 @@ func RunStage(runContext *TestRunContext, ftwCheck *check.FTWCheck, testCase tes if notRunningInCloudMode(ftwCheck) { startMarker, err := markAndFlush(runContext, dest, stageID) if err != nil && !expectedOutput.ExpectError { - log.Fatal().Caller().Err(err).Msg("Failed to find start marker") + return fmt.Errorf("failed to find start marker: %w", err) } ftwCheck.SetStartMarker(startMarker) } @@ -133,7 +148,7 @@ func RunStage(runContext *TestRunContext, ftwCheck *check.FTWCheck, testCase tes err = runContext.Client.NewConnection(*dest) if err != nil && !expectedOutput.ExpectError { - log.Fatal().Caller().Err(err).Msgf("can't connect to destination %+v", dest) + return fmt.Errorf("can't connect to destination %+v: %w", dest, err) } runContext.Client.StartTrackingTime() @@ -141,13 +156,13 @@ func RunStage(runContext *TestRunContext, ftwCheck *check.FTWCheck, testCase tes runContext.Client.StopTrackingTime() if responseErr != nil && !expectedOutput.ExpectError { - log.Fatal().Caller().Err(responseErr).Msgf("failed sending request to destination %+v", dest) + return fmt.Errorf("failed sending request to destination %+v: %w", dest, responseErr) } if notRunningInCloudMode(ftwCheck) { endMarker, err := markAndFlush(runContext, dest, stageID) if err != nil && !expectedOutput.ExpectError { - log.Fatal().Caller().Err(err).Msg("Failed to find end marker") + return fmt.Errorf("failed to find end marker: %w", err) } ftwCheck.SetEndMarker(endMarker) @@ -171,6 +186,8 @@ func RunStage(runContext *TestRunContext, ftwCheck *check.FTWCheck, testCase tes runContext.Stats.Run++ runContext.Stats.RunTime += stageTime + + return nil } func markAndFlush(runContext *TestRunContext, dest *ftwhttp.Destination, stageID string) ([]byte, error) { @@ -386,6 +403,6 @@ func notRunningInCloudMode(c *check.FTWCheck) bool { func cleanLogs(logLines *waflog.FTWLogLines) { if err := logLines.Cleanup(); err != nil { - log.Fatal().Err(err).Msg("Failed to cleanup log file") + log.Error().Err(err).Msg("Failed to cleanup log file") } } diff --git a/runner/run_test.go b/runner/run_test.go index cf92d3d..f3ed92f 100644 --- a/runner/run_test.go +++ b/runner/run_test.go @@ -417,49 +417,55 @@ func TestRun(t *testing.T) { replaceDestinationInTest(&ftwTest, *dest) t.Run("show time and execute all", func(t *testing.T) { - res := Run([]test.FTWTest{ftwTest}, Config{ + res, err := Run([]test.FTWTest{ftwTest}, Config{ ShowTime: true, Quiet: true, }) + assert.NoError(t, err) assert.Equalf(t, res.Stats.TotalFailed(), 0, "Oops, %d tests failed to run!", res.Stats.TotalFailed()) }) t.Run("be verbose and execute all", func(t *testing.T) { - res := Run([]test.FTWTest{ftwTest}, Config{ + res, err := Run([]test.FTWTest{ftwTest}, Config{ Include: regexp.MustCompile("0*"), ShowTime: true, }) + assert.NoError(t, err) assert.Equal(t, res.Stats.TotalFailed(), 0, "verbose and execute all failed") }) t.Run("don't show time and execute all", func(t *testing.T) { - res := Run([]test.FTWTest{ftwTest}, Config{ + res, err := Run([]test.FTWTest{ftwTest}, Config{ Include: regexp.MustCompile("0*"), }) + assert.NoError(t, err) assert.Equal(t, res.Stats.TotalFailed(), 0, "do not show time and execute all failed") }) t.Run("execute only test 008 but exclude all", func(t *testing.T) { - res := Run([]test.FTWTest{ftwTest}, Config{ + res, err := Run([]test.FTWTest{ftwTest}, Config{ Include: regexp.MustCompile("008"), Exclude: regexp.MustCompile("0*"), }) + assert.NoError(t, err) assert.Equal(t, res.Stats.TotalFailed(), 0, "do not show time and execute all failed") }) t.Run("exclude test 010", func(t *testing.T) { - res := Run([]test.FTWTest{ftwTest}, Config{ + res, err := Run([]test.FTWTest{ftwTest}, Config{ Exclude: regexp.MustCompile("010"), }) + assert.NoError(t, err) assert.Equal(t, res.Stats.TotalFailed(), 0, "failed to exclude test") }) t.Run("test exceptions 1", func(t *testing.T) { - res := Run([]test.FTWTest{ftwTest}, Config{ + res, err := Run([]test.FTWTest{ftwTest}, Config{ Include: regexp.MustCompile("1*"), Exclude: regexp.MustCompile("0*"), Quiet: true, }) + assert.NoError(t, err) assert.Equal(t, res.Stats.TotalFailed(), 0, "failed to test exceptions") }) } @@ -487,9 +493,10 @@ func TestOverrideRun(t *testing.T) { replaceDestinationInTest(&ftwTest, *fakeDestination) - res := Run([]test.FTWTest{ftwTest}, Config{ + res, err := Run([]test.FTWTest{ftwTest}, Config{ Quiet: true, }) + assert.NoError(t, err) assert.LessOrEqual(t, 0, res.Stats.TotalFailed(), "Oops, test run failed!") } @@ -516,9 +523,10 @@ func TestBrokenOverrideRun(t *testing.T) { replaceDestinationInTest(&ftwTest, *fakeDestination) // the test should succeed, despite the unknown override property - res := Run([]test.FTWTest{ftwTest}, Config{ + res, err := Run([]test.FTWTest{ftwTest}, Config{ Quiet: true, }) + assert.NoError(t, err) assert.LessOrEqual(t, 0, res.Stats.TotalFailed(), "Oops, test run failed!") } @@ -547,16 +555,17 @@ func TestBrokenPortOverrideRun(t *testing.T) { replaceDestinationInTest(&ftwTest, *fakeDestination) // the test should succeed, despite the unknown override property - res := Run([]test.FTWTest{ftwTest}, Config{ + res, err := Run([]test.FTWTest{ftwTest}, Config{ Quiet: true, }) + assert.NoError(t, err) assert.LessOrEqual(t, 0, res.Stats.TotalFailed(), "Oops, test run failed!") } func TestDisabledRun(t *testing.T) { t.Cleanup(config.Reset) - err := config.NewConfigFromString(yamlConfig) + err := config.NewConfigFromString(yamlCloudConfig) assert.NoError(t, err) fakeDestination, err := ftwhttp.DestinationFromString("http://example.com:1234") @@ -568,9 +577,10 @@ func TestDisabledRun(t *testing.T) { assert.NoError(t, err) replaceDestinationInTest(&ftwTest, *fakeDestination) - res := Run([]test.FTWTest{ftwTest}, Config{ + res, err := Run([]test.FTWTest{ftwTest}, Config{ Quiet: true, }) + assert.NoError(t, err) assert.LessOrEqual(t, 0, res.Stats.TotalFailed(), "Oops, test run failed!") } @@ -589,9 +599,10 @@ func TestLogsRun(t *testing.T) { assert.NoError(t, err) replaceDestinationInTest(&ftwTest, *dest) - res := Run([]test.FTWTest{ftwTest}, Config{ + res, err := Run([]test.FTWTest{ftwTest}, Config{ Quiet: true, }) + assert.NoError(t, err) assert.LessOrEqual(t, 0, res.Stats.TotalFailed(), "Oops, test run failed!") } @@ -630,12 +641,14 @@ func TestCloudRun(t *testing.T) { replaceDestinationInTest(&ftwTest, *dest) assert.NoError(t, err) + client, err := ftwhttp.NewClient(ftwhttp.NewClientConfig()) + assert.NoError(t, err) runContext := TestRunContext{ Include: nil, Exclude: nil, ShowTime: false, Output: true, - Client: ftwhttp.NewClient(ftwhttp.NewClientConfig()), + Client: client, LogLines: nil, } @@ -662,7 +675,8 @@ func TestFailedTestsRun(t *testing.T) { assert.NoError(t, err) replaceDestinationInTest(&ftwTest, *dest) - res := Run([]test.FTWTest{ftwTest}, Config{}) + res, err := Run([]test.FTWTest{ftwTest}, Config{}) + assert.NoError(t, err) assert.Equal(t, 1, res.Stats.TotalFailed()) } @@ -709,6 +723,7 @@ func TestIgnoredTestsRun(t *testing.T) { replaceDestinationInTest(&ftwTest, *dest) - res := Run([]test.FTWTest{ftwTest}, Config{}) + res, err := Run([]test.FTWTest{ftwTest}, Config{}) + assert.NoError(t, err) assert.Equal(t, res.Stats.TotalFailed(), 1, "Oops, test run failed!") } diff --git a/waflog/read.go b/waflog/read.go index 91186cc..cb5f0eb 100644 --- a/waflog/read.go +++ b/waflog/read.go @@ -83,9 +83,6 @@ func (ll *FTWLogLines) getMarkedLines() [][]byte { // logFile is the file to search // stageID is the ID of the current stage, which is part of the marker line func (ll *FTWLogLines) CheckLogForMarker(stageID string) []byte { - if config.FTWConfig.RunMode == config.DefaultRunMode && ll.logFile == nil { - log.Fatal().Caller().Msg("No log file supplied") - } offset, err := ll.logFile.Seek(0, os.SEEK_END) if err != nil { log.Error().Caller().Err(err).Msgf("failed to seek end of log file") diff --git a/waflog/read_test.go b/waflog/read_test.go index 3a6657c..d5d33c4 100644 --- a/waflog/read_test.go +++ b/waflog/read_test.go @@ -31,7 +31,8 @@ func TestReadCheckLogForMarkerNoMarkerAtEnd(t *testing.T) { config.FTWConfig.LogFile = filename t.Cleanup(func() { os.Remove(filename) }) - ll := NewFTWLogLines(WithStartMarker(bytes.ToLower([]byte(markerLine)))) + ll, err := NewFTWLogLines(WithStartMarker(bytes.ToLower([]byte(markerLine)))) + assert.NoError(t, err) marker := ll.CheckLogForMarker(stageID) assert.Nil(t, marker, "unexpectedly found marker") @@ -54,7 +55,8 @@ func TestReadCheckLogForMarkerWithMarkerAtEnd(t *testing.T) { config.FTWConfig.LogFile = filename t.Cleanup(func() { os.Remove(filename) }) - ll := NewFTWLogLines(WithStartMarker(bytes.ToLower([]byte(markerLine)))) + ll, err := NewFTWLogLines(WithStartMarker(bytes.ToLower([]byte(markerLine)))) + assert.NoError(t, err) marker := ll.CheckLogForMarker(stageID) assert.NotNil(t, marker, "no marker found") @@ -80,9 +82,10 @@ func TestReadGetMarkedLines(t *testing.T) { config.FTWConfig.LogFile = filename t.Cleanup(func() { os.Remove(filename) }) - ll := NewFTWLogLines( + ll, err := NewFTWLogLines( WithStartMarker(bytes.ToLower([]byte(startMarkerLine))), WithEndMarker(bytes.ToLower([]byte(endMarkerLine)))) + assert.NoError(t, err) foundLines := ll.getMarkedLines() // logs are scanned backwards @@ -116,9 +119,10 @@ func TestReadGetMarkedLinesWithTrailingEmptyLines(t *testing.T) { config.FTWConfig.LogFile = filename t.Cleanup(func() { os.Remove(filename) }) - ll := NewFTWLogLines( + ll, err := NewFTWLogLines( WithStartMarker(bytes.ToLower([]byte(startMarkerLine))), WithEndMarker(bytes.ToLower([]byte(endMarkerLine)))) + assert.NoError(t, err) foundLines := ll.getMarkedLines() // logs are scanned backwards @@ -155,9 +159,10 @@ func TestReadGetMarkedLinesWithPrecedingLines(t *testing.T) { config.FTWConfig.LogFile = filename t.Cleanup(func() { os.Remove(filename) }) - ll := NewFTWLogLines( + ll, err := NewFTWLogLines( WithStartMarker(bytes.ToLower([]byte(startMarkerLine))), WithEndMarker(bytes.ToLower([]byte(endMarkerLine)))) + assert.NoError(t, err) foundLines := ll.getMarkedLines() // logs are scanned backwards diff --git a/waflog/waflog.go b/waflog/waflog.go index 7be09e1..da9b5f5 100644 --- a/waflog/waflog.go +++ b/waflog/waflog.go @@ -1,15 +1,17 @@ package waflog import ( + "errors" + "fmt" "os" - "github.com/rs/zerolog/log" - "github.com/coreruleset/go-ftw/config" ) +var errNoLogFile = errors.New("no log file supplied") + // NewFTWLogLines is the base struct for reading the log file -func NewFTWLogLines(opts ...FTWLogOption) *FTWLogLines { +func NewFTWLogLines(opts ...FTWLogOption) (*FTWLogLines, error) { ll := &FTWLogLines{ logFile: nil, FileName: config.FTWConfig.LogFile, @@ -25,10 +27,14 @@ func NewFTWLogLines(opts ...FTWLogOption) *FTWLogLines { } if err := ll.openLogFile(); err != nil { - log.Error().Caller().Msgf("cannot open log file: %s", err) + return nil, fmt.Errorf("cannot open log file: %w", err) + } + + if config.FTWConfig.RunMode == config.DefaultRunMode && ll.logFile == nil { + return nil, errNoLogFile } - return ll + return ll, nil } // WithStartMarker sets the start marker for the log file diff --git a/waflog/waflog_test.go b/waflog/waflog_test.go index 6e7979e..9677d80 100644 --- a/waflog/waflog_test.go +++ b/waflog/waflog_test.go @@ -12,7 +12,8 @@ func TestNewFTWLogLines(t *testing.T) { err := config.NewConfigFromEnv() assert.NoError(t, err) - ll := NewFTWLogLines() + // Don't call NewFTWLogLines to avoid opening the file. + ll := &FTWLogLines{} // Loop through each option for _, opt := range []FTWLogOption{ WithStartMarker([]byte("#")), From 6d0338d6b6593bd225e35b9c8b79df874b1b1904 Mon Sep 17 00:00:00 2001 From: Felipe Zipitria Date: Wed, 2 Nov 2022 15:16:50 +0100 Subject: [PATCH 6/6] ci: setup buildx for release docker builds Signed-off-by: Felipe Zipitria --- .github/workflows/release.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0746e03..6f4ea0d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,6 +14,12 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 - name: Set up Go uses: actions/setup-go@v3