github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/aagent/watchers/expressionwatcher/expression_test.go (about) 1 // Copyright (c) 2024, R.I. Pienaar and the Choria Project contributors 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package expressionwatcher 6 7 import ( 8 "fmt" 9 "testing" 10 "time" 11 12 "github.com/choria-io/go-choria/aagent/model" 13 "github.com/choria-io/go-choria/aagent/watchers/event" 14 "github.com/golang/mock/gomock" 15 . "github.com/onsi/ginkgo/v2" 16 . "github.com/onsi/gomega" 17 ) 18 19 func TestMachine(t *testing.T) { 20 RegisterFailHandler(Fail) 21 RunSpecs(t, "AAgent/Watchers/ExpressionsWatcher") 22 } 23 24 var _ = Describe("AAgent/Watchers/ExpressionsWatcher", func() { 25 var ( 26 w *Watcher 27 machine *model.MockMachine 28 mockctl *gomock.Controller 29 td string 30 err error 31 ) 32 33 BeforeEach(func() { 34 td = GinkgoT().TempDir() 35 36 mockctl = gomock.NewController(GinkgoT()) 37 38 machine = model.NewMockMachine(mockctl) 39 machine.EXPECT().Directory().Return(td).AnyTimes() 40 machine.EXPECT().SignerKey().Return("").AnyTimes() 41 42 var wi any 43 wi, err = New(machine, "ginkgo_machine", nil, "FAIL_EVENT", "SUCCESS_EVENT", "1m", time.Hour, map[string]any{ 44 "success_when": "true", 45 }) 46 Expect(err).ToNot(HaveOccurred()) 47 w = wi.(*Watcher) 48 }) 49 50 AfterEach(func() { 51 mockctl.Finish() 52 }) 53 54 Describe("handleCheck", func() { 55 var now time.Time 56 57 BeforeEach(func() { 58 now = time.Now() 59 machine.EXPECT().Identity().Return("ginkgo.example.net").AnyTimes() 60 machine.EXPECT().InstanceID().Return("123").AnyTimes() 61 machine.EXPECT().Version().Return("1.0.0").AnyTimes() 62 machine.EXPECT().TimeStampSeconds().Return(now.Unix()).AnyTimes() 63 machine.EXPECT().Name().Return("ginkgo").AnyTimes() 64 }) 65 66 It("Should handle SuccessWhen", func() { 67 w.previous = Skipped 68 69 machine.EXPECT().Infof(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() 70 machine.EXPECT().Infof(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() 71 machine.EXPECT().NotifyWatcherState("ginkgo_machine", gomock.Eq(&StateNotification{ 72 Event: event.New(w.name, wtype, version, w.machine), 73 PreviousOutcome: stateNames[SuccessWhen], 74 })).Times(2) 75 76 // noce only since second time would be a flip-flop 77 machine.EXPECT().Transition("SUCCESS_EVENT").Times(1) 78 79 err := w.handleCheck(SuccessWhen, nil) 80 Expect(err).ToNot(HaveOccurred()) 81 Expect(w.previous).To(Equal(SuccessWhen)) 82 83 err = w.handleCheck(SuccessWhen, nil) 84 Expect(err).ToNot(HaveOccurred()) 85 Expect(w.previous).To(Equal(SuccessWhen)) 86 }) 87 88 It("Should handle FailWhen", func() { 89 w.previous = Skipped 90 91 machine.EXPECT().Infof(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() 92 machine.EXPECT().Infof(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() 93 machine.EXPECT().NotifyWatcherState("ginkgo_machine", gomock.Eq(&StateNotification{ 94 Event: event.New(w.name, wtype, version, w.machine), 95 PreviousOutcome: stateNames[FailWhen], 96 })).Times(2) 97 98 // noce only since second time would be a flip-flop 99 machine.EXPECT().Transition("FAIL_EVENT").Times(1) 100 101 err := w.handleCheck(FailWhen, nil) 102 Expect(err).ToNot(HaveOccurred()) 103 Expect(w.previous).To(Equal(FailWhen)) 104 105 err = w.handleCheck(FailWhen, nil) 106 Expect(err).ToNot(HaveOccurred()) 107 Expect(w.previous).To(Equal(FailWhen)) 108 }) 109 110 It("Should handle Error", func() { 111 machine.EXPECT().Errorf("ginkgo_machine", gomock.Any(), gomock.Any()).Times(1) 112 machine.EXPECT().NotifyWatcherState("ginkgo_machine", gomock.Eq(&StateNotification{ 113 Event: event.New(w.name, wtype, version, w.machine), 114 PreviousOutcome: stateNames[Error], 115 })).Times(1) 116 117 err := w.handleCheck(Error, fmt.Errorf("simulated")) 118 Expect(err).ToNot(HaveOccurred()) 119 }) 120 }) 121 122 Describe("watch", func() { 123 BeforeEach(func() { 124 machine.EXPECT().Data().Return(map[string]any{"test": 1}).AnyTimes() 125 machine.EXPECT().Facts().Return([]byte(`{"fqdn":"ginkgo.example.net"}`)).AnyTimes() 126 machine.EXPECT().Identity().Return("ginkgo.example.net").AnyTimes() 127 128 w.properties.FailWhen = "" 129 w.properties.SuccessWhen = "" 130 }) 131 132 It("Should handle success_when expressions", func() { 133 machine.EXPECT().Debugf(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() 134 w.properties.SuccessWhen = "data.test == 1" 135 state, err := w.watch() 136 Expect(err).ToNot(HaveOccurred()) 137 Expect(state).To(Equal(SuccessWhen)) 138 139 w.properties.SuccessWhen = "data.test == 2" 140 state, err = w.watch() 141 Expect(err).ToNot(HaveOccurred()) 142 Expect(state).To(Equal(NoMatch)) 143 144 w.properties.SuccessWhen = "1" 145 state, err = w.watch() 146 Expect(err).To(MatchError("expected bool, but got int")) 147 Expect(state).To(Equal(Error)) 148 }) 149 150 It("Should handle fail_when expressions", func() { 151 machine.EXPECT().Debugf(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() 152 w.properties.FailWhen = "data.test == 1" 153 state, err := w.watch() 154 Expect(err).ToNot(HaveOccurred()) 155 Expect(state).To(Equal(FailWhen)) 156 157 w.properties.FailWhen = "data.test == 2" 158 state, err = w.watch() 159 Expect(err).ToNot(HaveOccurred()) 160 Expect(state).To(Equal(NoMatch)) 161 162 w.properties.FailWhen = "1" 163 state, err = w.watch() 164 Expect(err).To(MatchError("expected bool, but got int")) 165 Expect(state).To(Equal(Error)) 166 }) 167 }) 168 169 Describe("setProperties", func() { 170 It("Should validate the interval", func() { 171 w.interval = time.Millisecond 172 Expect(w.setProperties(nil)).To(MatchError("interval should be more than 1 second: 1ms")) 173 }) 174 175 It("Should require one expressions", func() { 176 w.properties.FailWhen = "" 177 w.properties.SuccessWhen = "" 178 179 Expect(w.setProperties(nil)).To(MatchError("success_when or fail_when is required")) 180 181 w.properties.FailWhen = "true" 182 Expect(w.setProperties(nil)).ToNot(HaveOccurred()) 183 184 w.properties.FailWhen = "" 185 w.properties.SuccessWhen = "true" 186 Expect(w.setProperties(nil)).ToNot(HaveOccurred()) 187 }) 188 }) 189 })