diff --git a/internal/controllers/referenceaddon/options.go b/internal/controllers/referenceaddon/options.go index eca1e4e4..7dee4b98 100644 --- a/internal/controllers/referenceaddon/options.go +++ b/internal/controllers/referenceaddon/options.go @@ -16,6 +16,10 @@ func (w WithLog) ConfigurePhaseApplyNetworkPolicies(c *PhaseApplyNetworkPolicies c.Log = w.Log } +func (w WithLog) ConfigurePhaseSmokeTestRun(c *PhaseSmokeTestRunConfig) { + c.Log = w.Log +} + func (w WithLog) ConfigurePhaseUninstall(c *PhaseUninstallConfig) { c.Log = w.Log } @@ -115,3 +119,9 @@ type WithSampleURLs []string func (w WithSampleURLs) ConfigurePhaseSendDummyMetrics(c *PhaseSendDummyMetricsConfig) { c.SampleURLs = []string(w) } + +type WithSmokeTester struct{ Tester SmokeTester } + +func (w WithSmokeTester) ConfigurePhaseSmokeTestRun(c *PhaseSmokeTestRunConfig) { + c.SmokeTester = w.Tester +} diff --git a/internal/controllers/referenceaddon/parameter_getter.go b/internal/controllers/referenceaddon/parameter_getter.go index 0483a4f6..5a16b4ad 100644 --- a/internal/controllers/referenceaddon/parameter_getter.go +++ b/internal/controllers/referenceaddon/parameter_getter.go @@ -34,6 +34,7 @@ type SecretParameterGetter struct { const ( applyNetworkPoliciesID = "applynetworkpolicies" + enableSmokeTestID = "enablesmoketest" sizeParameterID = "size" ) @@ -63,6 +64,15 @@ func (s *SecretParameterGetter) GetParameters(ctx context.Context) (PhaseRequest opts = append(opts, WithApplyNetworkPolicies{Value: &b}) } + if val, ok := secret.Data[enableSmokeTestID]; ok { + b, err := parseBool(string(val)) + if err != nil { + return NewPhaseRequestParameters(), fmt.Errorf("parsing 'EnableSmokeTest' value: %w", err) + } + + opts = append(opts, WithEnableSmokeTest{Value: &b}) + } + if val, ok := secret.Data[sizeParameterID]; ok { s := string(val) diff --git a/internal/controllers/referenceaddon/phase.go b/internal/controllers/referenceaddon/phase.go index 9b1854a2..556e3599 100644 --- a/internal/controllers/referenceaddon/phase.go +++ b/internal/controllers/referenceaddon/phase.go @@ -23,12 +23,14 @@ func NewPhaseRequestParameters(opts ...PhaseRequestParametersOption) PhaseReques return PhaseRequestParameters{ applyNetworkPolicies: cfg.ApplyNetworkPolicies, + enableSmokeTest: cfg.EnableSmokeTest, size: cfg.Size, } } type PhaseRequestParameters struct { applyNetworkPolicies *bool + enableSmokeTest *bool size *string } @@ -40,6 +42,14 @@ func (p *PhaseRequestParameters) GetSize() (string, bool) { return *p.size, true } +func (p *PhaseRequestParameters) GetEnableSmokeTest() (bool, bool) { + if p.enableSmokeTest == nil { + return false, false + } + + return *p.enableSmokeTest, true +} + func (p *PhaseRequestParameters) GetApplyNetworkPolicies() (bool, bool) { if p.applyNetworkPolicies == nil { return false, false @@ -50,6 +60,7 @@ func (p *PhaseRequestParameters) GetApplyNetworkPolicies() (bool, bool) { type PhaseRequestParametersConfig struct { ApplyNetworkPolicies *bool + EnableSmokeTest *bool Size *string } @@ -65,6 +76,12 @@ func (w WithApplyNetworkPolicies) ConfigurePhaseRequestParameters(c *PhaseReques c.ApplyNetworkPolicies = w.Value } +type WithEnableSmokeTest struct{ Value *bool } + +func (w WithEnableSmokeTest) ConfigurePhaseRequestParameters(c *PhaseRequestParametersConfig) { + c.EnableSmokeTest = w.Value +} + type WithSize struct{ Value *string } func (w WithSize) ConfigurePhaseRequestParameters(c *PhaseRequestParametersConfig) { diff --git a/internal/controllers/referenceaddon/phase_smoke_test_run.go b/internal/controllers/referenceaddon/phase_smoke_test_run.go new file mode 100644 index 00000000..9e57f8db --- /dev/null +++ b/internal/controllers/referenceaddon/phase_smoke_test_run.go @@ -0,0 +1,70 @@ +package referenceaddon + +import ( + "context" + + "github.com/go-logr/logr" +) + +func NewPhaseSmokeTestRun(opts ...PhaseSmokeTestRunOption) *PhaseSmokeTestRun { + var cfg PhaseSmokeTestRunConfig + + cfg.Option(opts...) + cfg.Default() + + return &PhaseSmokeTestRun{ + cfg: cfg, + } +} + +type PhaseSmokeTestRun struct { + cfg PhaseSmokeTestRunConfig +} + +func (p *PhaseSmokeTestRun) Execute(_ context.Context, req PhaseRequest) PhaseResult { + enableSmokeTest, ok := req.Params.GetEnableSmokeTest() + if !ok { + p.cfg.Log.V(1).Info("'EnableSmokeTest' parameter not set") + + return PhaseResultSuccess() + } + + if enableSmokeTest { + p.cfg.SmokeTester.Enable() + + p.cfg.Log.Info("enabling smoke test") + } else { + p.cfg.SmokeTester.Disable() + + p.cfg.Log.Info("disabling smoke test") + } + + return PhaseResultSuccess() +} + +type PhaseSmokeTestRunConfig struct { + Log logr.Logger + + SmokeTester SmokeTester +} + +func (c *PhaseSmokeTestRunConfig) Option(opts ...PhaseSmokeTestRunOption) { + for _, opt := range opts { + opt.ConfigurePhaseSmokeTestRun(c) + } +} + +func (c *PhaseSmokeTestRunConfig) Default() { + if c.Log.GetSink() == nil { + c.Log = logr.Discard() + } +} + +type PhaseSmokeTestRunOption interface { + ConfigurePhaseSmokeTestRun(*PhaseSmokeTestRunConfig) +} + +type SmokeTester interface { + Enable() + Disable() +} diff --git a/internal/controllers/referenceaddon/phase_smoke_test_run_test.go b/internal/controllers/referenceaddon/phase_smoke_test_run_test.go new file mode 100644 index 00000000..9bdeeb87 --- /dev/null +++ b/internal/controllers/referenceaddon/phase_smoke_test_run_test.go @@ -0,0 +1,83 @@ +package referenceaddon + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func TestPhaseSmokeTestRunInterface(t *testing.T) { + t.Parallel() + + require.Implements(t, new(Phase), new(PhaseSmokeTestRun)) +} + +func TestPhaseSmokeTestRun_Execute(t *testing.T) { + t.Parallel() + + var ( + tr = true + f = false + ) + + for name, tc := range map[string]struct { + EnableSmokeTest *bool + }{ + "enablesmoketest 'nil'": { + EnableSmokeTest: nil, + }, + "enablesmoketest 'false'": { + EnableSmokeTest: &f, + }, + "enablesmoketest 'true'": { + EnableSmokeTest: &tr, + }, + } { + tc := tc + + t.Run(name, func(t *testing.T) { + t.Parallel() + + tester := &SmokeTesterMock{} + + if tc.EnableSmokeTest != nil { + if *tc.EnableSmokeTest { + tester.On("Enable") + } else { + tester.On("Disable") + } + } + + phase := NewPhaseSmokeTestRun( + WithSmokeTester{ + Tester: tester}, + ) + + res := phase.Execute(context.Background(), PhaseRequest{ + Params: NewPhaseRequestParameters( + WithEnableSmokeTest{ + Value: tc.EnableSmokeTest, + }, + ), + }) + + assert.Equal(t, PhaseStatusSuccess, res.Status()) + tester.AssertExpectations(t) + }) + } +} + +type SmokeTesterMock struct { + mock.Mock +} + +func (m *SmokeTesterMock) Enable() { + m.Called() +} + +func (m *SmokeTesterMock) Disable() { + m.Called() +} diff --git a/internal/controllers/referenceaddon/reference_addon_controller.go b/internal/controllers/referenceaddon/reference_addon_controller.go index 444b9753..3311dbb4 100644 --- a/internal/controllers/referenceaddon/reference_addon_controller.go +++ b/internal/controllers/referenceaddon/reference_addon_controller.go @@ -42,6 +42,7 @@ func NewReferenceAddonReconciler(client client.Client, getter ParameterGetter, o var ( phaseLog = cfg.Log.WithName("phase") phaseApplyNetworkPoliciesLog = phaseLog.WithName("applyNetworkPolicies") + PhaseSmokeTestRunLog = phaseLog.WithName("smokeTestRun") phaseUninstallLog = phaseLog.WithName("uninstall") uninstallerLog = phaseUninstallLog.WithName("uninstaller") ) @@ -64,6 +65,12 @@ func NewReferenceAddonReconciler(client client.Client, getter ParameterGetter, o WithAddonNamespace(cfg.AddonNamespace), WithOperatorName(cfg.OperatorName), ), + NewPhaseSmokeTestRun( + WithLog{Log: PhaseSmokeTestRunLog}, + WithSmokeTester{ + Tester: metrics.NewSmokeTester(), + }, + ), NewPhaseSendDummyMetrics( metrics.NewResponseSamplerImpl(), WithSampleURLs{"https://httpstat.us/503", "https://httpstat.us/200"}, diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index eb0df797..c5275985 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -17,26 +17,38 @@ func RegisterMetrics(reg prometheus.Registerer) error { return fmt.Errorf("registering 'responseTime' metric: %w", err) } + if err := reg.Register(smokeTest); err != nil { + return fmt.Errorf("registering 'smokeTest' metric: %w", err) + } + return nil } var ( availability = prometheus.NewGaugeVec( prometheus.GaugeOpts{ - Name: "reference_addon_sample_availability", + Name: metricPrefix + "sample_availability", Help: "external url availability 0-not available and 1-available.", }, []string{"url"}, ) responseTime = prometheus.NewGaugeVec( prometheus.GaugeOpts{ - Name: "reference_addon_sample_response_time", + Name: metricPrefix + "sample_response_time", Help: "external url response time taken.", }, []string{"url"}, ) + smokeTest = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: metricPrefix + "smoke_test", + Help: "smoke test for testing end-to-end metrics flow", + }, + ) ) +const metricPrefix = "reference_addon_" + func NewResponseSamplerImpl() *ResponseSamplerImpl { return &ResponseSamplerImpl{} } @@ -69,3 +81,17 @@ func callExternalURL(externalURL string) (float64, float64) { return float64(status), float64(time.Since(start).Milliseconds()) } + +func NewSmokeTester() *SmokeTester { + return &SmokeTester{} +} + +type SmokeTester struct{} + +func (t *SmokeTester) Enable() { + smokeTest.Set(1) +} + +func (t *SmokeTester) Disable() { + smokeTest.Set(0) +}