github.com/MontFerret/ferret@v0.18.0/pkg/runtime/expressions/waitfor_event_test.go (about) 1 package expressions_test 2 3 import ( 4 "context" 5 "sync" 6 "testing" 7 "time" 8 9 "github.com/MontFerret/ferret/pkg/runtime/core" 10 "github.com/MontFerret/ferret/pkg/runtime/events" 11 "github.com/MontFerret/ferret/pkg/runtime/expressions" 12 "github.com/MontFerret/ferret/pkg/runtime/expressions/literals" 13 14 . "github.com/smartystreets/goconvey/convey" 15 16 "github.com/MontFerret/ferret/pkg/runtime/values" 17 ) 18 19 type MockedObservable struct { 20 *values.Object 21 22 subscribers map[string]*MockedEventStream 23 24 Args map[string][]*values.Object 25 } 26 27 type MockedEventStream struct { 28 mu sync.Mutex 29 ch chan events.Message 30 closed bool 31 } 32 33 func NewMockedEventStream(ch chan events.Message) *MockedEventStream { 34 es := new(MockedEventStream) 35 es.ch = ch 36 37 return es 38 } 39 40 func (m *MockedEventStream) Close(ctx context.Context) error { 41 m.mu.Lock() 42 defer m.mu.Unlock() 43 44 close(m.ch) 45 m.closed = true 46 47 return nil 48 } 49 50 func (m *MockedEventStream) Read(_ context.Context) <-chan events.Message { 51 m.mu.Lock() 52 defer m.mu.Unlock() 53 54 return m.ch 55 } 56 57 func (m *MockedEventStream) Write(ctx context.Context, evt events.Message) { 58 m.mu.Lock() 59 defer m.mu.Unlock() 60 61 if ctx.Err() != nil { 62 return 63 } 64 65 m.ch <- evt 66 } 67 68 func (m *MockedEventStream) IsClosed() bool { 69 m.mu.Lock() 70 defer m.mu.Unlock() 71 72 return m.closed 73 } 74 75 func NewMockedObservable() *MockedObservable { 76 return &MockedObservable{ 77 Object: values.NewObject(), 78 subscribers: make(map[string]*MockedEventStream), 79 Args: make(map[string][]*values.Object), 80 } 81 } 82 83 func (m *MockedObservable) Emit(ctx context.Context, eventName string, args core.Value, err error, timeout int64) { 84 es, ok := m.subscribers[eventName] 85 86 if !ok { 87 return 88 } 89 90 go func() { 91 <-time.After(time.Millisecond * time.Duration(timeout)) 92 93 if ctx.Err() != nil { 94 return 95 } 96 97 if es.IsClosed() { 98 return 99 } 100 101 if err == nil { 102 es.Write(ctx, events.WithValue(args)) 103 } else { 104 es.Write(ctx, events.WithErr(err)) 105 } 106 }() 107 } 108 109 func (m *MockedObservable) Subscribe(_ context.Context, sub events.Subscription) (events.Stream, error) { 110 calls, found := m.Args[sub.EventName] 111 112 if !found { 113 calls = make([]*values.Object, 0, 10) 114 m.Args[sub.EventName] = calls 115 } 116 117 es, found := m.subscribers[sub.EventName] 118 119 if !found { 120 es = NewMockedEventStream(make(chan events.Message)) 121 m.subscribers[sub.EventName] = es 122 } 123 124 m.Args[sub.EventName] = append(calls, sub.Options) 125 126 return es, nil 127 } 128 129 func TestWaitForEventExpression(t *testing.T) { 130 SkipConvey("Should create a return expression", t, func() { 131 variable, err := expressions.NewVariableExpression(core.NewSourceMap("test", 1, 10), "test") 132 133 So(err, ShouldBeNil) 134 135 sourceMap := core.NewSourceMap("test", 2, 10) 136 expression, err := expressions.NewWaitForEventExpression( 137 sourceMap, 138 literals.NewStringLiteral("test"), 139 variable, 140 ) 141 So(err, ShouldBeNil) 142 So(expression, ShouldNotBeNil) 143 }) 144 145 SkipConvey("Should wait for an event", t, func() { 146 mock := NewMockedObservable() 147 eventName := "foobar" 148 variable, err := expressions.NewVariableExpression( 149 core.NewSourceMap("test", 1, 10), 150 "observable", 151 ) 152 153 So(err, ShouldBeNil) 154 155 sourceMap := core.NewSourceMap("test", 2, 10) 156 expression, err := expressions.NewWaitForEventExpression( 157 sourceMap, 158 literals.NewStringLiteral(eventName), 159 variable, 160 ) 161 162 So(err, ShouldBeNil) 163 164 scope, _ := core.NewRootScope() 165 So(scope.SetVariable("observable", mock), ShouldBeNil) 166 167 mock.Emit(context.Background(), eventName, values.None, nil, 100) 168 _, err = expression.Exec(context.Background(), scope) 169 So(err, ShouldBeNil) 170 }) 171 172 SkipConvey("Should receive opts", t, func() { 173 mock := NewMockedObservable() 174 eventName := "foobar" 175 variable, err := expressions.NewVariableExpression( 176 core.NewSourceMap("test", 1, 10), 177 "observable", 178 ) 179 180 So(err, ShouldBeNil) 181 182 prop, err := literals.NewObjectPropertyAssignment( 183 literals.NewStringLiteral("value"), 184 literals.NewStringLiteral("bar"), 185 ) 186 187 So(err, ShouldBeNil) 188 189 sourceMap := core.NewSourceMap("test", 2, 10) 190 expression, err := expressions.NewWaitForEventExpression( 191 sourceMap, 192 literals.NewStringLiteral(eventName), 193 variable, 194 ) 195 196 So(err, ShouldBeNil) 197 198 So(expression.SetOptions(literals.NewObjectLiteralWith(prop)), ShouldBeNil) 199 200 scope, _ := core.NewRootScope() 201 So(scope.SetVariable("observable", mock), ShouldBeNil) 202 203 mock.Emit(context.Background(), eventName, values.None, nil, 100) 204 _, err = expression.Exec(context.Background(), scope) 205 So(err, ShouldBeNil) 206 207 opts := mock.Args[eventName][0] 208 So(opts, ShouldNotBeNil) 209 }) 210 211 SkipConvey("Should return event arg", t, func() { 212 mock := NewMockedObservable() 213 eventName := "foobar" 214 variable, err := expressions.NewVariableExpression( 215 core.NewSourceMap("test", 1, 10), 216 "observable", 217 ) 218 219 So(err, ShouldBeNil) 220 221 sourceMap := core.NewSourceMap("test", 2, 10) 222 expression, err := expressions.NewWaitForEventExpression( 223 sourceMap, 224 literals.NewStringLiteral(eventName), 225 variable, 226 ) 227 228 So(err, ShouldBeNil) 229 230 scope, _ := core.NewRootScope() 231 So(scope.SetVariable("observable", mock), ShouldBeNil) 232 233 arg := values.NewString("foo") 234 mock.Emit(context.Background(), eventName, arg, nil, 100) 235 out, err := expression.Exec(context.Background(), scope) 236 So(err, ShouldBeNil) 237 So(out.String(), ShouldEqual, arg.String()) 238 }) 239 240 SkipConvey("Should timeout", t, func() { 241 mock := NewMockedObservable() 242 eventName := "foobar" 243 variable, err := expressions.NewVariableExpression( 244 core.NewSourceMap("test", 1, 10), 245 "observable", 246 ) 247 248 So(err, ShouldBeNil) 249 250 sourceMap := core.NewSourceMap("test", 2, 10) 251 expression, err := expressions.NewWaitForEventExpression( 252 sourceMap, 253 literals.NewStringLiteral(eventName), 254 variable, 255 ) 256 257 So(err, ShouldBeNil) 258 259 scope, _ := core.NewRootScope() 260 So(scope.SetVariable("observable", mock), ShouldBeNil) 261 262 _, err = expression.Exec(context.Background(), scope) 263 So(err, ShouldNotBeNil) 264 }) 265 266 SkipConvey("Should filter", t, func() { 267 mock := NewMockedObservable() 268 eventName := "foobar" 269 270 eventNameExp, err := expressions.NewVariableExpression( 271 core.NewSourceMap("test", 1, 10), 272 "observable", 273 ) 274 275 So(err, ShouldBeNil) 276 277 sourceMap := core.NewSourceMap("test", 2, 10) 278 279 expression, err := expressions.NewWaitForEventExpression( 280 sourceMap, 281 literals.NewStringLiteral(eventName), 282 eventNameExp, 283 ) 284 285 So(err, ShouldBeNil) 286 287 evtVar := "CURRENT" 288 289 err = expression.SetFilter(core.SourceMap{}, evtVar, core.AsExpression(func(ctx context.Context, scope *core.Scope) (core.Value, error) { 290 out, err := scope.GetVariable(evtVar) 291 292 if err != nil { 293 return nil, err 294 } 295 296 num := values.ToInt(out) 297 298 return values.NewBoolean(int64(num) > 2), nil 299 })) 300 301 So(err, ShouldBeNil) 302 ctx := context.Background() 303 mock.Emit(ctx, eventName, values.NewInt(0), nil, 0) 304 mock.Emit(ctx, eventName, values.NewInt(1), nil, 0) 305 mock.Emit(ctx, eventName, values.NewInt(2), nil, 0) 306 mock.Emit(ctx, eventName, values.NewInt(3), nil, 0) 307 308 scope, _ := core.NewRootScope() 309 So(scope.SetVariable("observable", mock), ShouldBeNil) 310 out, err := expression.Exec(context.Background(), scope) 311 312 So(err, ShouldBeNil) 313 So(int64(out.(values.Int)), ShouldEqual, 3) 314 }) 315 }