| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package sampler_test |
| |
| import ( |
| "strings" |
| "testing" |
| "time" |
| |
| "v.io/v23/context" |
| tu "v.io/x/ref/test/testutil" |
| "v.io/x/sensorlog/internal/measure/sampler" |
| "v.io/x/sensorlog/internal/sbmodel" |
| ) |
| |
| // Runs the sampler script and verifies that the callback was called with the |
| // expected value or error. |
| func runSamplerTest(t *testing.T, samDef *sbmodel.SamplerDef) sbmodel.VDataPoint { |
| ctx, cancel := context.RootContext() |
| defer cancel() |
| |
| var gotRes *sampler.MeasureResult |
| start := time.Now() |
| if err := sampler.Run(ctx, samDef, func(res *sampler.MeasureResult) error { |
| gotRes = res |
| return nil |
| }); err != nil { |
| t.Fatal(tu.FormatLogLine(3, "unexpected sampling error: %v", err)) |
| } |
| end := time.Now() |
| |
| if gotRes == nil { |
| t.Fatal(tu.FormatLogLine(3, "sampler callback was not called")) |
| } |
| |
| if gotRes.Time.Before(start) || gotRes.Time.After(end) { |
| t.Error(tu.FormatLogLine(3, "invalid time: %v, expected between %v and %v", gotRes.Time, start, end)) |
| } |
| |
| return gotRes.Data |
| } |
| |
| func runSamplerTestForValue(t *testing.T, samDef *sbmodel.SamplerDef, expectVal float64) { |
| res := runSamplerTest(t, samDef) |
| switch res := res.(type) { |
| case sbmodel.VDataPointValue: |
| if res.Value != expectVal { |
| t.Error(tu.FormatLogLine(2, "unexpected value, got: %v, want: %v", res.Value, expectVal)) |
| } |
| default: |
| t.Error(tu.FormatLogLine(2, "unexpected type, got: %v, want value: %v", res, expectVal)) |
| } |
| } |
| |
| func runSamplerTestForError(t *testing.T, samDef *sbmodel.SamplerDef, expectErrPrefix string) { |
| res := runSamplerTest(t, samDef) |
| switch res := res.(type) { |
| case sbmodel.VDataPointError: |
| if !strings.HasPrefix(res.Value, expectErrPrefix) { |
| t.Error(tu.FormatLogLine(2, "unexpected error, got: %v, want prefix: %v", res.Value, expectErrPrefix)) |
| } |
| default: |
| t.Error(tu.FormatLogLine(2, "unexpected type, got: %v, want error with prefix: %v", res, expectErrPrefix)) |
| } |
| } |
| |
| func TestSamplerRun(t *testing.T) { |
| runSamplerTestForValue(t, &sbmodel.SamplerDef{ |
| Script: `echo 42`, |
| Start: time.Now(), |
| Interval: time.Second, // 7.5M years overflows time.Duration |
| }, 42.0) |
| |
| runSamplerTestForValue(t, &sbmodel.SamplerDef{ |
| Script: ` |
| for i in $(seq 10000); do :; done |
| printf "%f\n" -12.73 |
| exit 0 |
| `, |
| Start: time.Now(), |
| Interval: time.Millisecond, |
| }, -12.73) |
| |
| runSamplerTestForError(t, &sbmodel.SamplerDef{ |
| Script: `echo 42; exit 1`, |
| Start: time.Now(), |
| Interval: time.Second, |
| }, "Script error") |
| |
| runSamplerTestForError(t, &sbmodel.SamplerDef{ |
| Script: `exit 0`, |
| Start: time.Now(), |
| Interval: time.Second, |
| }, "Parse error") |
| |
| runSamplerTestForError(t, &sbmodel.SamplerDef{ |
| Script: `echo 42foo`, |
| Start: time.Now(), |
| Interval: time.Second, |
| }, "Parse error") |
| |
| runSamplerTestForError(t, &sbmodel.SamplerDef{ |
| Script: `echo 42; echo 47`, |
| Start: time.Now(), |
| Interval: time.Second, |
| }, "Parse error") |
| } |
| |
| func TestSamplerCancel(t *testing.T) { |
| ctx, cancel := context.RootContext() |
| defer cancel() |
| |
| // The script sleeps for 10 seconds, not interruptible by SIGINT/SIGTERM. |
| samDef := &sbmodel.SamplerDef{ |
| Script: ` |
| trap 'sleep 10' INT TERM |
| sleep 10 |
| echo 42 |
| `, |
| Start: time.Now(), |
| Interval: time.Second, |
| } |
| // Asynchronously run sampler, cancelling shortly after. |
| done := make(chan error, 1) |
| go func() { |
| done <- sampler.Run(ctx, samDef, func(res *sampler.MeasureResult) error { |
| t.Errorf("worker was cancelled, result callback should not have been called, got: %v", res.Data) |
| return nil |
| }) |
| }() |
| |
| time.Sleep(100 * time.Millisecond) |
| cancelTime := time.Now() |
| cancel() |
| |
| if err := <-done; err != nil { |
| t.Errorf("unexpected sampling error: %v", err) |
| } |
| // Cancel should have killed the script using SIGKILL a short time after the |
| // script failed to exit on SIGINT. |
| if cancelTime.Add(1 * time.Second).Before(time.Now()) { |
| t.Errorf("sampling script took more than a second to stop") |
| } |
| } |