Example #1
0
func TestStream_Open_WithOp(t *testing.T) {
	src := newStrSrc([]string{"HELLO", "WORLD", "HOW", "ARE", "YOU"})
	snk := newStrSink()
	op1 := api.UnFunc(func(ctx context.Context, data interface{}) interface{} {
		str := data.(string)
		return len(str)
	})

	var m sync.RWMutex
	runeCount := 0
	op2 := api.UnFunc(func(ctx context.Context, data interface{}) interface{} {
		length := data.(int)
		m.Lock()
		runeCount += length
		m.Unlock()
		return nil
	})

	strm := New().From(src).Transform(op1).Transform(op2).To(snk)
	select {
	case err := <-strm.Open():
		if err != nil {
			t.Fatal(err)
		}
	case <-time.After(50 * time.Millisecond):
		t.Fatal("Waited too long ...")
	}
	m.RLock()
	if runeCount != 19 {
		t.Fatal("Data not streaming, runeCount 19, got ", runeCount)
	}
	m.RUnlock()
}
Example #2
0
func TestUnaryOp_Params(t *testing.T) {
	o := NewUnaryOp(context.Background())
	op := api.UnFunc(func(ctx context.Context, data interface{}) interface{} {
		return nil
	})
	in := make(chan interface{})

	o.SetOperation(op)
	if o.op == nil {
		t.Fatal("process Elem not set")
	}

	o.SetConcurrency(4)
	if o.concurrency != 4 {
		t.Fatal("Concurrency not being set")
	}

	o.SetInput(in)
	if o.input == nil {
		t.Fatal("Input not being set")
	}

	if o.GetOutput == nil {
		t.Fatal("Output not set")
	}
}
Example #3
0
func BenchmarkUnaryOp_Exec(b *testing.B) {
	ctx := context.Background()
	o := NewUnaryOp(ctx)
	N := b.N

	chanSize := func() int {
		if N == 1 {
			return N
		}
		return int(float64(0.5) * float64(N))
	}()

	in := make(chan interface{}, chanSize)
	o.SetInput(in)
	go func() {
		for i := 0; i < N; i++ {
			in <- testutil.GenWord()
		}
		close(in)
	}()

	counter := 0
	var m sync.RWMutex

	op := api.UnFunc(func(ctx context.Context, data interface{}) interface{} {
		m.Lock()
		counter++
		m.Unlock()
		return data
	})
	o.SetOperation(op)

	// process output
	done := make(chan struct{})
	go func() {
		defer close(done)
		for _ = range o.GetOutput() {
		}
	}()

	if err := o.Exec(); err != nil {
		b.Fatal("Error during execution:", err)
	}

	select {
	case <-done:
	case <-time.After(time.Second * 60):
		b.Fatal("Took too long")
	}
	m.RLock()
	b.Logf("Input %d, counted %d", N, counter)
	if counter != N {
		b.Fatalf("Expected %d items processed,  got %d", N, counter)
	}
	m.RUnlock()
}
Example #4
0
func TestStream_InitGraph(t *testing.T) {
	src := newStrSrc([]string{"Hello", "World"})
	snk := newStrSink()
	op1 := api.UnFunc(func(ctx context.Context, data interface{}) interface{} {
		return nil
	})
	op2 := api.UnFunc(func(ctx context.Context, data interface{}) interface{} {
		return nil
	})

	strm := New().From(src).To(snk)

	if err := strm.initGraph(); err != nil {
		t.Fatal(err)
	}

	if src.GetOutput() != snk.input {
		t.Fatal("Source not link to sink when no ops are present")
	}

	strm = New().From(src).Transform(op1).Transform(op2).To(snk)
	if err := strm.initGraph(); err != nil {
		t.Fatal(err)
	}

	if len(strm.ops) != 2 {
		t.Fatal("Not adding operations to stream")
	}

	if src.GetOutput() == snk.input {
		t.Fatal("Graph invalid, source skipping ops, linked to sink!")
	}

	if strm.ops[1].GetOutput() != snk.input {
		t.Fatal("Sink not linked to last element in graph")
	}

}
Example #5
0
// Process is used to express general processing operation of incoming stream
// elements.  Function must be of the form "func(input)output", anything else
// will cause painic.
func (s *Stream) Process(f interface{}) *Stream {
	fntype := reflect.TypeOf(f)
	if err := s.isUnaryFuncForm(fntype); err != nil {
		panic(fmt.Sprintf("Op Process() failed: %s", err))
	}

	fnval := reflect.ValueOf(f)

	op := api.UnFunc(func(ctx context.Context, data interface{}) interface{} {
		arg0 := reflect.ValueOf(data)
		result := fnval.Call([]reflect.Value{arg0})[0]
		return result.Interface()
	})

	return s.Transform(op)
}
Example #6
0
func TestUnaryOp_Exec(t *testing.T) {
	ctx, _ := context.WithCancel(context.Background())
	o := NewUnaryOp(ctx)

	op := api.UnFunc(func(ctx context.Context, data interface{}) interface{} {
		values := data.([]string)
		t.Logf("Processing data %v, sending %d", values, len(values))
		return len(values)
	})
	o.SetOperation(op)

	in := make(chan interface{})
	go func() {
		in <- []string{"A", "B", "C"}
		in <- []string{"D", "E"}
		in <- []string{"G"}
		close(in)
	}()
	o.SetInput(in)

	wait := make(chan struct{})
	go func() {
		defer close(wait)
		for data := range o.GetOutput() {
			val, ok := data.(int)
			t.Logf("Got value %v", val)
			if !ok {
				t.Fatalf("Expecting type int, got %T, value %v", val, val)
			}
			if val != 3 && val != 2 && val != 1 {
				t.Fatalf("Expecting values 3, 2, or 1, but got %d", val)
			}
		}
	}()

	if err := o.Exec(); err != nil {
		t.Fatal(err)
	}

	select {
	case <-wait:
	case <-time.After(50 * time.Millisecond):
		t.Fatal("Took too long...")
	}
}
Example #7
0
// FlatMap similar to Map, however, expected to return a slice of values
// to downstream operators.  The operator will flatten the slice and emit
// individually onto the stream. The FlatMap function must have the form
// "func(intput)[]output", anything else will be rejected
func (s *Stream) FlatMap(f interface{}) *Stream {
	fntype := reflect.TypeOf(f)
	if err := s.isUnaryFuncForm(fntype); err != nil {
		panic(fmt.Sprintf("Op FlatMap() failed: %s", err))
	}
	if fntype.Out(0).Kind() != reflect.Slice {
		panic(fmt.Sprintf("Op FlatMap() expects to return a slice of values"))
	}

	fnval := reflect.ValueOf(f)

	op := api.UnFunc(func(ctx context.Context, data interface{}) interface{} {
		arg0 := reflect.ValueOf(data)
		result := fnval.Call([]reflect.Value{arg0})[0]
		return result.Interface()
	})

	s.Transform(op) // add flatmap as unary op
	s.ReStream()    // add streamop to unpack flatmap result
	return s
}
Example #8
0
func TestStream_BuilderMethods(t *testing.T) {
	op := api.UnFunc(func(ctx context.Context, data interface{}) interface{} {
		return nil
	})

	st := New()
	st.
		From(newStrSrc([]string{"Hello", "World", "!!"})).
		To(newStrSink()).
		Transform(op)

	if st.source == nil {
		t.Fatal("From() not setting source")
	}
	if st.sink == nil {
		t.Fatal("To() not setting sink")
	}
	if len(st.ops) != 1 {
		t.Fatal("Operation not added to ops slice")
	}
}
Example #9
0
// Filter takes a predicate func that filters the stream.
// Function must be of form "func(input)bool", anything else causes panic.
// If func returns true, current item continues downstream.
func (s *Stream) Filter(f interface{}) *Stream {
	fntype := reflect.TypeOf(f)
	if err := s.isUnaryFuncForm(fntype); err != nil {
		panic(fmt.Sprintf("Op Filter() failed :%s", err))
	}
	// ensure bool ret type
	if fntype.Out(0).Kind() != reflect.Bool {
		panic("Op Filter() must return a bool")
	}

	fnval := reflect.ValueOf(f)

	op := api.UnFunc(func(ctx context.Context, data interface{}) interface{} {
		arg0 := reflect.ValueOf(data)
		result := fnval.Call([]reflect.Value{arg0})[0]
		predicate := result.Bool()
		if !predicate {
			return nil
		}
		return data
	})
	return s.Transform(op)
}