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  }