From 0911242e4fad47bc1a5ea059645597cfb3c01315 Mon Sep 17 00:00:00 2001 From: imago Date: Sat, 2 Mar 2024 18:52:25 +0200 Subject: [PATCH] Cleaning, release prep, tests work --- CHANGELOG.md | 8 ++++++ configured_oper.go | 3 +++ configured_oper_test.go | 57 +++++++++++++++++++++++------------------ configured_oper_work.go | 12 +++------ main.go | 13 +++++++++- main_test.go | 3 +-- 6 files changed, 60 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a215275..39562fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 1.2 +* Upgraded worker pattern to guarantee amount of runs +* Introduced flag retryOnFail + - If set, the task will be retried if it fails + - If set to false, the task will simply be started -n amount of times + - Previous behavoiur were to simply repeat a command -n amonut of times, now the default is to successfully run the task -n amount of times (felt more useful) +* Upgraded progress print to include amount of failures + ## 1.1 * Changed default behaviour of result from STDOUT to HIDDEN * Changed name of REPORT_FILE -> FILE diff --git a/configured_oper.go b/configured_oper.go index 7b28c3f..cfef9ee 100644 --- a/configured_oper.go +++ b/configured_oper.go @@ -33,6 +33,7 @@ type configuredOper struct { amIdleWorkers int amSuccess int workPlanMu *sync.Mutex + retryOnFail bool } type userQuitError string @@ -60,6 +61,7 @@ func New(am, workers int, outputFileMode string, increment bool, resultFlag string, + retryOnFail bool, ) (configuredOper, error) { shouldHaveReportFile := pMode == output.BOTH || pMode == output.FILE || oMode == output.BOTH || oMode == output.FILE @@ -89,6 +91,7 @@ func New(am, workers int, workerWg: &sync.WaitGroup{}, amIdleWorkers: workers, workPlanMu: &sync.Mutex{}, + retryOnFail: retryOnFail, } c.workerWg.Add(workers) diff --git a/configured_oper_test.go b/configured_oper_test.go index d0f4739..3f2fb78 100644 --- a/configured_oper_test.go +++ b/configured_oper_test.go @@ -9,6 +9,7 @@ import ( "strings" "sync" "testing" + "time" "github.com/baalimago/go_away_boilerplate/pkg/testboil" "github.com/baalimago/repeater/internal/output" @@ -32,14 +33,15 @@ func Test_configuredOper(t *testing.T) { testFile := testboil.CreateTestFile(t, "tFile") outputString := "test" co := configuredOper{ - am: 1, - args: []string{"printf", fmt.Sprintf("%v", outputString)}, - color: false, - progress: output.HIDDEN, - output: outputMode, - outputFile: testFile, - workPlanMu: &sync.Mutex{}, - workerWg: &sync.WaitGroup{}, + am: 1, + args: []string{"printf", fmt.Sprintf("%v", outputString)}, + color: false, + progress: output.HIDDEN, + output: outputMode, + outputFile: testFile, + amIdleWorkers: 1, + workPlanMu: &sync.Mutex{}, + workerWg: &sync.WaitGroup{}, } co.workerWg.Add(1) @@ -66,13 +68,14 @@ func Test_configuredOper(t *testing.T) { runTest := func(outputMode output.Mode, wantProgress bool) { testFile := testboil.CreateTestFile(t, "tFile") outputString := "something" - progFormat := "%v/%v" + progFormat := "%v/%v/%v" co := configuredOper{ am: 1, args: []string{"printf", fmt.Sprintf("%v", outputString)}, color: false, progressFormat: progFormat, progress: outputMode, + amIdleWorkers: 1, output: output.HIDDEN, outputFile: testFile, workPlanMu: &sync.Mutex{}, @@ -88,7 +91,7 @@ func Test_configuredOper(t *testing.T) { if err != nil { t.Fatalf("failed to get report file: %v", err) } - wantStr := fmt.Sprintf("%v\n", fmt.Sprintf(progFormat, 0, 1)) + wantStr := fmt.Sprintf("%v", fmt.Sprintf(progFormat, 1, 0, 1)) if got != wantStr && wantProgress { t.Fatalf("for: %s, expected: %v, got: %v", outputMode, wantStr, got) } else if got == wantStr && !wantProgress { @@ -102,12 +105,13 @@ func Test_configuredOper(t *testing.T) { }) t.Run("it should follow format set in progressFormat", func(t *testing.T) { - wantFormat := "lol%vtest%v" + wantFormat := "lol%vtest%vhere%v" testFile := testboil.CreateTestFile(t, "testFile") c := configuredOper{ am: 1, args: []string{"true"}, color: false, + amIdleWorkers: 1, progress: output.FILE, progressFormat: wantFormat, output: output.HIDDEN, @@ -124,7 +128,7 @@ func Test_configuredOper(t *testing.T) { if err != nil { t.Fatalf("failed to get report file: %v", err) } - want := fmt.Sprintf("%v\n", fmt.Sprintf(wantFormat, 0, 1)) + want := fmt.Sprintf("%v", fmt.Sprintf(wantFormat, 1, 0, 1)) if got != want { t.Fatalf("expected: %v, got: %v", want, got) } @@ -136,10 +140,11 @@ func Test_results(t *testing.T) { // This should ouput "test" want := "test" c := configuredOper{ - am: 1, - args: []string{"printf", want}, - workPlanMu: &sync.Mutex{}, - workerWg: &sync.WaitGroup{}, + am: 1, + args: []string{"printf", want}, + workPlanMu: &sync.Mutex{}, + amIdleWorkers: 1, + workerWg: &sync.WaitGroup{}, } c.workerWg.Add(1) @@ -160,12 +165,14 @@ func Test_results(t *testing.T) { c := configuredOper{ am: wantAm, // Date is most likely to exist in most OS's running this test - args: []string{"date"}, - workerWg: &sync.WaitGroup{}, - workPlanMu: &sync.Mutex{}, + args: []string{"date"}, + workerWg: &sync.WaitGroup{}, + workPlanMu: &sync.Mutex{}, + amIdleWorkers: 1, } c.workerWg.Add(1) c.run(context.Background()) + time.Sleep(time.Millisecond) gotLen := len(c.results) // ensure that the correc amount is output if gotLen != wantAm { @@ -186,7 +193,7 @@ func Test_results(t *testing.T) { func Test_configuredOper_New(t *testing.T) { t.Run("it should return incrementConfigError if increment is true and no args contains 'INC'", func(t *testing.T) { args := []string{"test", "abc"} - _, gotErr := New(0, 0, args, output.HIDDEN, "testing", output.HIDDEN, "", "", true, "") + _, gotErr := New(0, 0, args, output.HIDDEN, "testing", output.HIDDEN, "", "", true, "", false) if gotErr == nil { t.Fatal("expected to get error, got nil") } @@ -205,7 +212,7 @@ func Test_configuredOper_New(t *testing.T) { t.Run("it should not return an error if increment is true and one argument is 'INC'", func(t *testing.T) { args := []string{"test", "abc", "INC"} - _, gotErr := New(0, 0, args, output.HIDDEN, "testing", output.HIDDEN, "", "", true, "") + _, gotErr := New(0, 0, args, output.HIDDEN, "testing", output.HIDDEN, "", "", true, "", false) if gotErr != nil { t.Fatalf("expected nil, got: %v", gotErr) } @@ -213,7 +220,7 @@ func Test_configuredOper_New(t *testing.T) { t.Run("it should not return an error if increment is true and one argument contains 'INC'", func(t *testing.T) { args := []string{"test", "abc", "another-argument/INC"} - _, gotErr := New(0, 0, args, output.HIDDEN, "testing", output.HIDDEN, "", "", true, "") + _, gotErr := New(0, 0, args, output.HIDDEN, "testing", output.HIDDEN, "", "", true, "", false) if gotErr != nil { t.Fatalf("expected nil, got: %v", gotErr) } @@ -223,7 +230,7 @@ func Test_configuredOper_New(t *testing.T) { am := 1 workers := 2 args := []string{"test", "abc"} - _, gotErr := New(am, workers, args, output.HIDDEN, "testing", output.HIDDEN, "", "", false, "") + _, gotErr := New(am, workers, args, output.HIDDEN, "testing", output.HIDDEN, "", "", false, "", false) if gotErr == nil { t.Fatal("expected to get error, got nil") } @@ -237,14 +244,14 @@ func Test_configuredOper_New(t *testing.T) { t.Run("it should not return an error if the number of workers is lower than the number of times to repeat the command", func(t *testing.T) { args := []string{"test", "abc"} - _, gotErr := New(2, 1, args, output.HIDDEN, "testing", output.HIDDEN, "", "", false, "") + _, gotErr := New(2, 1, args, output.HIDDEN, "testing", output.HIDDEN, "", "", false, "", false) if gotErr != nil { t.Fatalf("expected nil, got: %v", gotErr) } }) t.Run("it should not return an error if the number of workers is equal to the number of times to repeat the command", func(t *testing.T) { args := []string{"test", "abc"} - _, gotErr := New(2, 2, args, output.HIDDEN, "testing", output.HIDDEN, "", "", false, "") + _, gotErr := New(2, 2, args, output.HIDDEN, "testing", output.HIDDEN, "", "", false, "", false) if gotErr != nil { t.Fatalf("expected nil, got: %v", gotErr) } diff --git a/configured_oper_work.go b/configured_oper_work.go index b3c79f6..0312d63 100644 --- a/configured_oper_work.go +++ b/configured_oper_work.go @@ -64,7 +64,7 @@ func (c *configuredOper) setupWorkers(workCtx context.Context, workChan chan int // The current amount of workers is enough to reach the requested // amount of tasks in parallel so kill off this worker to not overshoot // the amount of repetitions - if workingWorkrs+c.amSuccess >= requestedTasks { + if workingWorkrs+c.amSuccess >= requestedTasks || (!c.retryOnFail && taskIdx >= requestedTasks) { c.workerWg.Done() c.workPlanMu.Unlock() return @@ -121,13 +121,9 @@ func (c *configuredOper) runResultCollector(ctx context.Context, resultChan chan } emptyResChan := func() { - for { - select { - case res := <-resultChan: - handleRes(res) - default: - return - } + for len(resultChan) > 0 { + res := <-resultChan + handleRes(res) } } for { diff --git a/main.go b/main.go index 7eca317..6a71586 100644 --- a/main.go +++ b/main.go @@ -28,6 +28,7 @@ var ( statisticsFlag = flag.Bool("statistics", true, "Set to true if you don't wish to see statistics of the repeated command.") incrementFlag = flag.Bool("increment", false, "Set to true and add an argument 'INC', to have 'INC' be replaced with the iteration. If increment == true && 'INC' is not set, repeater will panic.") resultFlag = flag.String("result", "", "Set this to some filename and get a json-formated output of all the performed tasks. This output is the basis of the statistics.") + retryOnFailFlag = flag.Bool("retryOnFail", false, "Set to true to retry failed commands, effectively making repeate run until all commands are successful.") ) func main() { @@ -39,7 +40,17 @@ func main() { printErr(fmt.Sprintf("error: %v", "you need to supply at least 1 argument\n")) os.Exit(1) } - c, err := New(*amRunsFlag, *workersFlag, args, output.New(progressFlag), *progressFormatFlag, output.New(outputFlag), *fileFlag, *fileModeFlag, *incrementFlag, *resultFlag) + c, err := New( + *amRunsFlag, + *workersFlag, + args, output.New(progressFlag), + *progressFormatFlag, + output.New(outputFlag), + *fileFlag, + *fileModeFlag, + *incrementFlag, + *resultFlag, + *retryOnFailFlag) if *verboseFlag { fmt.Printf("Operation:\n%v\n------\n", &c) diff --git a/main_test.go b/main_test.go index 9fb8a59..5f0bd71 100644 --- a/main_test.go +++ b/main_test.go @@ -34,7 +34,7 @@ func Test_do(t *testing.T) { } }) - for i := 0; i < 1000; i++ { + for i := 0; i < 10; i++ { t.Run("it should run command am amount of times, 10 workers", func(t *testing.T) { expectedCalls := 123 amWorkers := 10 @@ -61,5 +61,4 @@ func Test_do(t *testing.T) { } }) } - }