From dd58373e3205ce87004103971e99ab2186cb78c6 Mon Sep 17 00:00:00 2001 From: MacRat Date: Fri, 23 Dec 2022 21:19:53 +0900 Subject: [PATCH] feat(scheme/plugin): make sure that plugin records within 1 hours --- README.md | 2 +- internal/scheme/plugin.go | 15 +++++++ internal/scheme/plugin_internal_test.go | 10 +++++ internal/scheme/plugin_test.go | 48 ++++++++++++++++++++- internal/scheme/testdata/ayd-plug-probe | 6 +-- internal/scheme/testdata/ayd-plug-probe.bat | 6 +-- 6 files changed, 79 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f447c9b..eef304e 100644 --- a/README.md +++ b/README.md @@ -416,7 +416,7 @@ For example, if the target URL has the scheme `xxx-yyy:`, Ayd will search these The scheme names that supported by Ayd, `ayd`, and `alert`, are reserved and cannot be used by plugins. The plugin prints result to stdout, in the same format as [log file](#log-file). -Plugins should not report results that are more than 1 hour old. +Plugins should not report future results, or old results more than 1 hour. Ayd expects the output of the plugin to be in UTF-8. However, in Windows, the system's default character encoding can be used. diff --git a/internal/scheme/plugin.go b/internal/scheme/plugin.go index ad4a648..02dc5ff 100644 --- a/internal/scheme/plugin.go +++ b/internal/scheme/plugin.go @@ -14,6 +14,12 @@ import ( api "github.com/macrat/ayd/lib-ayd" ) +var ( + // currentTime returns the current time. + // This function can override for testing. + currentTime = time.Now +) + // PluginScheme is the plugin handler. This implements both of Prober interface and Alerter interface. type PluginScheme struct { target *api.URL @@ -141,6 +147,15 @@ func (p PluginScheme) execute(ctx context.Context, r Reporter, scope string, arg rec.Time = rec.Time.Local() + current := currentTime() + if rec.Time.After(current) { + rec.Time = current + } + min := current.Add(-1 * time.Hour) + if rec.Time.Before(min) { + rec.Time = min + } + count++ r.Report(p.target, rec) } diff --git a/internal/scheme/plugin_internal_test.go b/internal/scheme/plugin_internal_test.go index 64f693e..0226b53 100644 --- a/internal/scheme/plugin_internal_test.go +++ b/internal/scheme/plugin_internal_test.go @@ -4,10 +4,20 @@ import ( "os" "path/filepath" "testing" + "time" "github.com/google/go-cmp/cmp" ) +func SetCurrentTime(t *testing.T, ct time.Time) { + currentTime = func() time.Time { + return ct + } + t.Cleanup(func() { + currentTime = time.Now + }) +} + // PreparePluginPath set PATH to ./testdata/ directory. func PreparePluginPath(t *testing.T) { t.Helper() diff --git a/internal/scheme/plugin_test.go b/internal/scheme/plugin_test.go index 199e6e7..1768283 100644 --- a/internal/scheme/plugin_test.go +++ b/internal/scheme/plugin_test.go @@ -127,12 +127,13 @@ func TestPluginScheme_Probe(t *testing.T) { func TestPluginScheme_Probe_timezone(t *testing.T) { PreparePluginPath(t) t.Setenv("TZ", "UTC") + scheme.SetCurrentTime(t, time.Date(2001, 2, 3, 16, 10, 0, 0, time.UTC)) tests := []struct { URL string Time time.Time }{ - {"plug:+0900", time.Date(2001, 2, 3, 16-9, 5, 6, 0, time.UTC)}, + {"plug:+0900", time.Date(2001, 2, 3, 16, 5, 6, 0, time.UTC)}, {"plug-plus:utc", time.Date(2001, 2, 3, 16, 5, 6, 0, time.UTC)}, } @@ -161,6 +162,51 @@ func TestPluginScheme_Probe_timezone(t *testing.T) { } } +func TestPluginScheme_Probe_trimTime(t *testing.T) { + PreparePluginPath(t) + t.Setenv("TZ", "UTC") + + p, err := scheme.NewProber("plug:") + if err != nil { + t.Fatalf("failed to create plugin: %s", err) + } + + base := time.Date(2001, 2, 3, 16, 5, 6, 0, time.UTC) + + tests := []struct { + Cur time.Time + Out time.Time + }{ + {base, base}, + {base.Add(1 * time.Minute), base}, + {base.Add(50 * time.Minute), base}, + {base.Add(60 * time.Minute), base}, + {base.Add(61 * time.Minute), base.Add(1 * time.Minute)}, + {base.Add(-1 * time.Minute), base.Add(-1 * time.Minute)}, + } + + for i, tt := range tests { + scheme.SetCurrentTime(t, tt.Cur) + + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + + rs := testutil.RunProbe(ctx, p) + + if len(rs) != 1 { + t.Fatalf("%d: %s: unexpected number of results: %d", i, tt.Cur, len(rs)) + } + + if rs[0].Target.String() != "plug:" { + t.Errorf("%d: %s: unexpected target: %s", i, tt.Cur, rs[0].Target) + } + + if !rs[0].Time.Equal(tt.Out) { + t.Errorf("%d: %s: unexpected time: %s", i, tt.Cur, rs[0].Time) + } + } +} + func TestPluginScheme_Alert(t *testing.T) { t.Parallel() PreparePluginPath(t) diff --git a/internal/scheme/testdata/ayd-plug-probe b/internal/scheme/testdata/ayd-plug-probe index 54d8a7a..a064a2d 100755 --- a/internal/scheme/testdata/ayd-plug-probe +++ b/internal/scheme/testdata/ayd-plug-probe @@ -1,11 +1,11 @@ #!/bin/sh if [ "$1" = "plug:change" ]; then - echo '{"time":"2001-02-03T16:05:06+09:00","status":"HEALTHY","latency":123.456,"target":"changed:plug","message":"check changed:plug"}' + echo '{"time":"2001-02-03T17:05:06+01:00","status":"HEALTHY","latency":123.456,"target":"changed:plug","message":"check changed:plug"}' elif [ "$1" = "plug:extra" ]; then - echo '{"time":"2001-02-03T16:05:06+09:00","status":"HEALTHY","latency":123.456,"target":"'${1}'","message":"with extra","hello":"world"}' + echo '{"time":"2001-02-03T17:05:06+01:00","status":"HEALTHY","latency":123.456,"target":"'${1}'","message":"with extra","hello":"world"}' elif [ "$1" != "plug:empty" ]; then - echo '{"time":"2001-02-03T16:05:06+09:00","status":"HEALTHY","latency":123.456,"target":"'${1}'","message":"check '${1}'"}' + echo '{"time":"2001-02-03T17:05:06+01:00","status":"HEALTHY","latency":123.456,"target":"'${1}'","message":"check '${1}'"}' fi if [ "$1" = "plug:invalid-record" ]; then diff --git a/internal/scheme/testdata/ayd-plug-probe.bat b/internal/scheme/testdata/ayd-plug-probe.bat index 17ec33d..e346112 100755 --- a/internal/scheme/testdata/ayd-plug-probe.bat +++ b/internal/scheme/testdata/ayd-plug-probe.bat @@ -1,11 +1,11 @@ @echo off if "%1" == "plug:change" ( - echo {"time":"2001-02-03T16:05:06+09:00","status":"HEALTHY","latency":123.456,"target":"changed:plug","message":"check changed:plug"} + echo {"time":"2001-02-03T17:05:06+01:00","status":"HEALTHY","latency":123.456,"target":"changed:plug","message":"check changed:plug"} ) else if "%1" == "plug:extra" ( - echo {"time":"2001-02-03T16:05:06+09:00","status":"HEALTHY","latency":123.456,"target":"%1","message":"with extra","hello":"world"} + echo {"time":"2001-02-03T17:05:06+01:00","status":"HEALTHY","latency":123.456,"target":"%1","message":"with extra","hello":"world"} ) else if not "%1" == "plug:empty" ( - echo {"time":"2001-02-03T16:05:06+09:00","status":"HEALTHY","latency":123.456,"target":"%1","message":"check %1"} + echo {"time":"2001-02-03T17:05:06+01:00","status":"HEALTHY","latency":123.456,"target":"%1","message":"check %1"} ) if "%1" == "plug:invalid-record" (