예제 #1
0
func TestDingoAmqpMultiAppSuite(t *testing.T) {
	suite.Run(t, &amqpMultiAppTestSuite{
		DingoMultiAppTestSuite{
			CountOfCallers: 3,
			CountOfWorkers: 3,
			GenCaller: func() (app *dingo.App, err error) {
				app, err = dingo.NewApp("remote", nil)
				if err != nil {
					return
				}
				brk, err := dgamqp.NewBroker(dgamqp.DefaultAmqpConfig())
				if err != nil {
					return
				}
				_, _, err = app.Use(brk, dingo.ObjT.Producer)
				if err != nil {
					return
				}
				bkd, err := dgamqp.NewBackend(dgamqp.DefaultAmqpConfig())
				if err != nil {
					return
				}
				_, _, err = app.Use(bkd, dingo.ObjT.Store)
				if err != nil {
					return
				}

				return
			},
			GenWorker: func() (app *dingo.App, err error) {
				app, err = dingo.NewApp("remote", nil)
				if err != nil {
					return
				}
				brk, err := dgamqp.NewBroker(dgamqp.DefaultAmqpConfig())
				if err != nil {
					return
				}
				_, _, err = app.Use(brk, dingo.ObjT.NamedConsumer)
				if err != nil {
					return
				}
				bkd, err := dgamqp.NewBackend(dgamqp.DefaultAmqpConfig())
				if err != nil {
					return
				}
				_, _, err = app.Use(bkd, dingo.ObjT.Reporter)
				if err != nil {
					return
				}

				return
			},
		},
	})
}
예제 #2
0
func TestDingoAmqpSingleAppSuite(t *testing.T) {
	suite.Run(t, &amqpSingleAppTestSuite{
		DingoSingleAppTestSuite{
			GenApp: func() (app *dingo.App, err error) {
				app, err = dingo.NewApp("remote", nil)
				if err != nil {
					return
				}
				brk, err := dgamqp.NewBroker(dgamqp.DefaultAmqpConfig())
				if err != nil {
					return
				}
				_, _, err = app.Use(brk, dingo.ObjT.Default)
				if err != nil {
					return
				}

				bkd, err := dgamqp.NewBackend(dgamqp.DefaultAmqpConfig())
				if err != nil {
					return
				}
				_, _, err = app.Use(bkd, dingo.ObjT.Default)
				if err != nil {
					return
				}

				return
			},
		},
	})
}
예제 #3
0
func (me *localSingleAppTestSuite) SetupTest() {
	// reset the 'virtual wire' for every test
	me.wireBroker, me.wireBackend = make(chan []byte, 10), make(chan *dingo.ReportEnvelope, 10)

	me.GenApp = func() (app *dingo.App, err error) {
		app, err = dingo.NewApp("remote", nil)
		if err != nil {
			return
		}

		brk, err := dingo.NewLocalBroker(dingo.DefaultConfig(), me.wireBroker)
		if err != nil {
			return
		}
		_, _, err = app.Use(brk, dingo.ObjT.Default)
		if err != nil {
			return
		}

		bkd, err := dingo.NewLocalBackend(dingo.DefaultConfig(), me.wireBackend)
		if err != nil {
			return
		}
		_, _, err = app.Use(bkd, dingo.ObjT.Default)
		if err != nil {
			return
		}

		return
	}

	me.DingoSingleAppTestSuite.SetupTest()
}
예제 #4
0
func ExampleApp_local() {
	// this example demonstrates a job queue runs in background

	var err error
	defer func() {
		if err != nil {
			fmt.Printf("%v\n", err)
		}
	}()

	// a App in local mode
	app, err := dingo.NewApp("local", nil)
	if err != nil {
		return
	}

	// register a worker function murmur
	err = app.Register("murmur", func(msg string, repeat int, interval time.Duration) {
		for ; repeat > 0; repeat-- {
			select {
			case <-time.After(interval):
				fmt.Printf("%v\n", msg)
			}
		}
	})
	if err != nil {
		return
	}

	// allocate 5 workers, sharing 1 report channel
	_, err = app.Allocate("murmur", 5, 1)
	if err != nil {
		return
	}

	results := []*dingo.Result{}
	// invoke 10 tasks
	for i := 0; i < 10; i++ {
		results = append(
			results,
			dingo.NewResult(
				// name, option, parameter#1, parameter#2, parameter#3...
				app.Call("murmur", nil, fmt.Sprintf("this is %d speaking", i), 10, 100*time.Millisecond),
			))
	}

	// wait until those tasks are done
	for _, v := range results {
		err = v.Wait(0)
		if err != nil {
			return
		}
	}

	// release resource
	err = app.Close()
	if err != nil {
		return
	}
}
예제 #5
0
func TestDingoLocalModeTestSuite(t *testing.T) {
	suite.Run(t, &localModeTestSuite{
		DingoSingleAppTestSuite{
			GenApp: func() (*dingo.App, error) {
				return dingo.NewApp("local", nil)
			},
		},
	})
}
예제 #6
0
func TestDingoEventFromBackendAndBroker(t *testing.T) {
	// make sure events from backend/broker are published
	ass := assert.New(t)
	app, err := dingo.NewApp("remote", nil)
	ass.Nil(err)
	if err != nil {
		return
	}

	// prepare a caller
	_, _, err = app.Use(&testFakeProducer{make(chan *dingo.Event, 10)}, dingo.ObjT.Producer)
	ass.Nil(err)
	if err != nil {
		return
	}
	_, _, err = app.Use(&testFakeStore{make(chan *dingo.Event, 10)}, dingo.ObjT.Store)
	ass.Nil(err)
	if err != nil {
		return
	}

	// register a task
	err = app.Register("TestDingoEvent", func() {})
	ass.Nil(err)
	if err != nil {
		return
	}

	// there should be 2 events
	_, events, err := app.Listen(dingo.ObjT.All, dingo.EventLvl.Info, 0)
	ass.Nil(err)
	if err != nil {
		return
	}

	// send a task
	_, err = app.Call("TestDingoEvent", nil)
	ass.Nil(err)
	if err != nil {
		return
	}

	// exactly two event should be received.
	e1 := <-events
	e2 := <-events
	ass.True(e1.Origin|e2.Origin == dingo.ObjT.Producer|dingo.ObjT.Store)
	ass.True(e1.Level == dingo.EventLvl.Info)
	ass.True(e2.Level == dingo.EventLvl.Info)
	ass.True(e1.Payload.(string) == "Send" || e2.Payload.(string) == "Send")
	ass.True(e1.Payload.(string) == "Poll" || e2.Payload.(string) == "Poll")

	// release resource
	ass.Nil(app.Close())
}
예제 #7
0
func TestDingoUse(t *testing.T) {
	var (
		err error
		ass = assert.New(t)
	)
	defer func() {
		ass.Nil(err)
	}()

	app, err := dingo.NewApp("remote", nil)
	if err != nil {
		return
	}
	defer func() {
		ass.Nil(app.Close())
	}()

	// new a fake object, whose event channel is accessible
	obj := &testFakeObject{}
	chk := func(id int, used int, err error) {
		ass.Equal(0, used)
		ass.NotNil(err)
	}

	// attach it with different types
	chk(app.Use(obj, dingo.ObjT.Producer))
	chk(app.Use(obj, dingo.ObjT.Consumer))
	chk(app.Use(obj, dingo.ObjT.NamedConsumer))
	chk(app.Use(obj, dingo.ObjT.Reporter))
	chk(app.Use(obj, dingo.ObjT.Store))

	err = app.Register("TestDingoUse", func() {})
	if err != nil {
		return
	}

	remain, err2 := app.Allocate("TestDingoUse", 10, 1)
	ass.Equal(10, remain)
	ass.NotNil(err2)

	reports, err2 := app.Call("TestDingoUse", nil)
	ass.Nil(reports)
	ass.NotNil(err2)
}
예제 #8
0
func BenchmarkLocal(b *testing.B) {
	var (
		err   error
		count = 1
		msg   = "test string"
	)
	defer func() {
		if err != nil {
			b.Fatalf("failed: %v\n", err)
		}
	}()

	app, err := dingo.NewApp("local", nil)
	if err != nil {
		return
	}

	err = app.Register("myWork", testWork)
	if err != nil {
		return
	}

	_, err = app.Allocate("myWork", 10, 3)
	if err != nil {
		return
	}

	// setup for invoker
	err = app.AddMarshaller(101, &struct {
		dingo.GobMarshaller
		testMyInvoker
	}{
		dingo.GobMarshaller{},
		testMyInvoker{},
	})
	if err != nil {
		return
	}
	err = app.SetMarshaller("myWork", 101, 101)
	if err != nil {
		return
	}

	// setup for idmaker
	err = app.AddIDMaker(101, &dingo.SeqIDMaker{})
	if err != nil {
		return
	}
	err = app.SetIDMaker("myWork", 101)
	if err != nil {
		return
	}

	// reset timer for preparation
	b.ResetTimer()

	var result *dingo.Result
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			result = dingo.NewResult(app.Call("myWork", nil, count, msg))
			result.Wait(0)
		}
	})
}
예제 #9
0
func TestDingoEventOrigin(t *testing.T) {
	var (
		err error
		ass = assert.New(t)
	)
	defer func() {
		ass.Nil(err)
	}()

	app, err := dingo.NewApp("remote", nil)
	if err != nil {
		return
	}
	defer func() {
		ass.Nil(app.Close())
	}()

	// new a fake object, whose event channel is accessible
	obj := &testFakeObject{events: make(chan *dingo.Event, 1)}
	_, _, err = app.Use(obj, 0)
	if err != nil {
		return
	}

	chk := func(ch <-chan *dingo.Event, origin int) {
		e := <-ch
		ass.Equal(origin, e.Origin)
	}

	// subscribe bridge event
	idBridge, chBridge, err := app.Listen(dingo.ObjT.Bridge, dingo.EventLvl.Debug, 0)
	if err != nil {
		return
	}

	// subscribe all event
	idAll, chAll, err := app.Listen(dingo.ObjT.All, dingo.EventLvl.Debug, 0)
	if err != nil {
		return
	}

	// send a mapper event
	obj.events <- dingo.NewEvent(dingo.ObjT.Mapper, dingo.EventLvl.Error, 0, "mapper")
	chk(chAll, dingo.ObjT.Mapper)

	// send a bridge event
	obj.events <- dingo.NewEvent(dingo.ObjT.Bridge, dingo.EventLvl.Error, 0, "bridge")
	chk(chAll, dingo.ObjT.Bridge)
	chk(chBridge, dingo.ObjT.Bridge)

	// send a mapper | bridge event
	obj.events <- dingo.NewEvent(dingo.ObjT.Bridge|dingo.ObjT.Mapper, dingo.EventLvl.Error, 0, "bridge")
	chk(chAll, dingo.ObjT.Bridge|dingo.ObjT.Mapper)
	chk(chBridge, dingo.ObjT.Bridge|dingo.ObjT.Mapper)

	err = app.StopListen(idBridge)
	if err != nil {
		return
	}

	err = app.StopListen(idAll)
	if err != nil {
		return
	}
}
예제 #10
0
func TestDingoEventLevel(t *testing.T) {
	var (
		err error
		ass = assert.New(t)
	)
	defer func() {
		ass.Nil(err)
	}()

	// attach a fake object
	app, err := dingo.NewApp("local", nil)
	if err != nil {
		return
	}
	defer func() {
		ass.Nil(app.Close())
	}()

	// allocate channels slice
	chs := make([]<-chan *dingo.Event, 4)
	Debug, Info, Warning, Error := 0, 1, 2, 3
	idDebug, idInfo, idWarning, idError := 0, 1, 2, 3
	recv := func(which, lvl int) {
		e := <-chs[which]
		ass.Equal(lvl, e.Level)
	}

	// new a fake object, whose event channel is accessible
	obj := &testFakeObject{events: make(chan *dingo.Event, 1)}
	_, _, err = app.Use(obj, 0)
	if err != nil {
		return
	}

	// subscribe a Debug channel
	idDebug, chs[Debug], err = app.Listen(dingo.ObjT.All, dingo.EventLvl.Debug, 0)
	if err != nil {
		return
	}

	// subscribe an Info channel
	idInfo, chs[Info], err = app.Listen(dingo.ObjT.All, dingo.EventLvl.Info, 0)
	if err != nil {
		return
	}

	// subscribe a Warning channel
	idWarning, chs[Warning], err = app.Listen(dingo.ObjT.All, dingo.EventLvl.Warning, 0)
	if err != nil {
		return
	}

	// subscribe an Error channel
	idError, chs[Error], err = app.Listen(dingo.ObjT.All, dingo.EventLvl.Error, 0)
	if err != nil {
		return
	}

	// send an error event
	obj.events <- dingo.NewEvent(dingo.ObjT.Bridge, dingo.EventLvl.Error, 0, "error")
	recv(Error, dingo.EventLvl.Error)
	recv(Warning, dingo.EventLvl.Error)
	recv(Info, dingo.EventLvl.Error)
	recv(Debug, dingo.EventLvl.Error)

	// send a warning event
	obj.events <- dingo.NewEvent(dingo.ObjT.Bridge, dingo.EventLvl.Warning, 0, "warning")
	recv(Warning, dingo.EventLvl.Warning)
	recv(Info, dingo.EventLvl.Warning)
	recv(Debug, dingo.EventLvl.Warning)

	// send an info event
	obj.events <- dingo.NewEvent(dingo.ObjT.Bridge, dingo.EventLvl.Info, 0, "info")
	recv(Info, dingo.EventLvl.Info)
	recv(Debug, dingo.EventLvl.Info)

	// send a debug event
	obj.events <- dingo.NewEvent(dingo.ObjT.Bridge, dingo.EventLvl.Debug, 0, "debug")
	recv(Debug, dingo.EventLvl.Debug)

	// stop debug channel, and send an debug event
	err = app.StopListen(idDebug)
	if err != nil {
		return
	}

	// stop info channel, and send an info event
	err = app.StopListen(idInfo)
	if err != nil {
		return
	}

	// stop warning channel, and send an warning event
	err = app.StopListen(idWarning)
	if err != nil {
		return
	}

	// stop error channel, and send an error event
	err = app.StopListen(idError)
	if err != nil {
		return
	}
}
예제 #11
0
func (me *localMultiAppTestSuite) SetupTest() {
	// reset the 'virtual wire' for every test
	me.wireBroker, me.wireBackend = make(chan []byte, 10), make(chan *dingo.ReportEnvelope, 10)

	me.GenCaller = func() (app *dingo.App, err error) {
		app, err = dingo.NewApp("remote", nil)
		me.Nil(err)
		if err != nil {
			return
		}

		brk, err := dingo.NewLocalBroker(dingo.DefaultConfig(), me.wireBroker)
		me.Nil(err)
		if err != nil {
			return
		}
		_, _, err = app.Use(brk, dingo.ObjT.Producer)
		me.Nil(err)
		if err != nil {
			return
		}

		bkd, err := dingo.NewLocalBackend(dingo.DefaultConfig(), me.wireBackend)
		me.Nil(err)
		if err != nil {
			return
		}
		_, _, err = app.Use(bkd, dingo.ObjT.Store)
		me.Nil(err)
		if err != nil {
			return
		}

		return
	}

	me.GenWorker = func() (app *dingo.App, err error) {
		app, err = dingo.NewApp("remote", nil)
		me.Nil(err)
		if err != nil {
			return
		}

		brk, err := dingo.NewLocalBroker(dingo.DefaultConfig(), me.wireBroker)
		me.Nil(err)
		if err != nil {
			return
		}
		_, _, err = app.Use(brk, dingo.ObjT.Consumer)
		me.Nil(err)
		if err != nil {
			return
		}

		bkd, err := dingo.NewLocalBackend(dingo.DefaultConfig(), me.wireBackend)
		me.Nil(err)
		if err != nil {
			return
		}
		_, _, err = app.Use(bkd, dingo.ObjT.Reporter)
		me.Nil(err)
		if err != nil {
			return
		}

		return
	}

	me.DingoMultiAppTestSuite.SetupTest()
}
예제 #12
0
func ExampleApp_Use_caller() {
	/*
		import (
			"fmt"
			"time"

			"github.com/mission-liao/dingo"
			"github.com/mission-liao/dingo/amqp"
		)
	*/
	// this example demostrate a caller based on AMQP, used along with ExampleApp_Use_worker
	// make sure you install a rabbitmq server locally.
	var err error
	defer func() {
		if err != nil {
			fmt.Printf("%v\n", err)
		}
	}()

	// an App in remote mode
	app, err := dingo.NewApp("remote", nil)
	if err != nil {
		return
	}

	// attach an AMQP producer to publish your tasks
	broker, err := dgamqp.NewBroker(dgamqp.DefaultAmqpConfig())
	if err != nil {
		return
	}
	_, _, err = app.Use(broker, dingo.ObjT.Producer)
	if err != nil {
		return
	}

	// attach an AMQP store to receive reports from datastores.
	backend, err := dgamqp.NewBackend(dgamqp.DefaultAmqpConfig())
	if err != nil {
		return
	}
	_, _, err = app.Use(backend, dingo.ObjT.Store)
	if err != nil {
		return
	}

	// register a work function that murmur
	err = app.Register("murmur", func(speech *struct {
		Prologue string
		Script   []string
	}, interval time.Duration) (countOfSentence int) {
		// speak the prologue
		fmt.Printf("%v:\n", speech.Prologue)
		countOfSentence++

		// speak the script
		for _, v := range speech.Script {
			<-time.After(interval)
			fmt.Printf("%v\n", v)
			countOfSentence++
		}

		// return the total sentence we talked
		return
	})
	if err != nil {
		return
	}

	// compose a script to talk
	script := &struct {
		Prologue string
		Script   []string
	}{
		Script: []string{
			"Today, I'm announcing this library.",
			"It should be easy to use, ",
			"and fun to play with.",
			"Merry X'mas.",
		},
	}

	// invoke 20 tasks
	results := []*dingo.Result{}
	for i := 0; i < 20; i++ {
		script.Prologue = fmt.Sprintf("this is %d speaking", i)
		results = append(results,
			dingo.NewResult(
				// name, option, parameter#1, parameter#2 ...
				app.Call("murmur", nil, script, 100*time.Millisecond),
			))
	}

	// wait until those tasks are done
	for _, v := range results {
		err = v.Wait(0)
		if err != nil {
			return
		}

		// result is accessible
		fmt.Printf("one worker spoke %v sentences\n", v.Last.Return()[0].(int))
	}

	// release resource
	err = app.Close()
	if err != nil {
		return
	}
}
예제 #13
0
func ExampleCustomMarshaller() {
	/*
		import (
			"encoding/json"
			"fmt"

			"github.com/mission-liao/dingo"
		)
	*/
	// this example demonstrate the usage of using a
	// customized marshaller by encoding every parameter
	// in JSON.
	// And invoke it with customized invoker
	var err error
	defer func() {
		if err != nil {
			fmt.Printf("%v\n", err)
		}
	}()

	// an App in remote mode, with local backend/broker
	app, err := dingo.NewApp("remote", nil)
	if err != nil {
		return
	}

	// attach a local broker.
	broker, err := dingo.NewLocalBroker(dingo.DefaultConfig(), nil)
	if err != nil {
		return
	}
	_, _, err = app.Use(broker, dingo.ObjT.Default)
	// attach a local backend
	backend, err := dingo.NewLocalBackend(dingo.DefaultConfig(), nil)
	if err != nil {
		return
	}
	_, _, err = app.Use(backend, dingo.ObjT.Default)
	if err != nil {
		return
	}

	// register customize marshaller & invoker
	err = app.AddMarshaller(101, &struct {
		testMyInvoker3
		dingo.CustomMarshaller
	}{
		testMyInvoker3{},
		dingo.CustomMarshaller{Codec: &testCustomMarshallerCodec{}},
	})
	if err != nil {
		return
	}

	// register worker function
	err = app.Register("concat", func(words []string) (ret string) {
		for _, v := range words {
			ret = ret + v
		}
		return
	})
	if err != nil {
		return
	}

	// change marshaller of worker function
	err = app.SetMarshaller("concat", 101, 101)
	if err != nil {
		return
	}

	// allocate workers
	_, err = app.Allocate("concat", 1, 1)
	if err != nil {
		return
	}

	// trigger the fire...
	result := dingo.NewResult(app.Call("concat", nil, []string{"Merry ", "X", "'mas"}))
	err = result.Wait(0)
	if err != nil {
		return
	}
	result.OnOK(func(ret string) {
		fmt.Printf("%v\n", ret)
	})

	err = app.Close()
	if err != nil {
		return
	}
}
예제 #14
0
func ExampleApp_Use_worker() {
	/*
		import (
			"fmt"
			"os"
			"time"

			"github.com/mission-liao/dingo"
			"github.com/mission-liao/dingo/amqp"
		)
	*/
	// this example demonstrate a worker based on AMQP, used along with ExampleApp_Use_caller
	// make sure you install a rabbitmq server locally.
	var err error
	defer func() {
		if err != nil {
			fmt.Printf("%v\n", err)
		}
	}()

	// an App in remote mode
	app, err := dingo.NewApp("remote", nil)
	if err != nil {
		return
	}

	// attach an AMQP consumer to receive tasks
	broker, err := dgamqp.NewBroker(dgamqp.DefaultAmqpConfig())
	if err != nil {
		return
	}
	_, _, err = app.Use(broker, dingo.ObjT.NamedConsumer)
	if err != nil {
		return
	}

	// attach an AMQP reporter to publish reports
	backend, err := dgamqp.NewBackend(dgamqp.DefaultAmqpConfig())
	if err != nil {
		return
	}
	_, _, err = app.Use(backend, dingo.ObjT.Reporter)
	if err != nil {
		return
	}

	// register a work function that murmur
	err = app.Register("murmur", func(speech *struct {
		Prologue string
		Script   []string
	}, interval time.Duration) (countOfSentence int) {
		// speak the prologue
		fmt.Printf("%v:\n", speech.Prologue)
		countOfSentence++

		// speak the script
		for _, v := range speech.Script {
			<-time.After(interval)
			fmt.Printf("%v\n", v)
			countOfSentence++
		}

		// return the total sentence we talked
		return
	})
	if err != nil {
		return
	}

	// allocate 1 workers, sharing 1 report channel
	_, err = app.Allocate("murmur", 1, 1)
	if err != nil {
		return
	}

	// wait until a key stroke
	var stroke []byte = make([]byte, 100)
	fmt.Println("waiting for tasks...stop waiting by pressing enter")
	os.Stdin.Read(stroke)

	// release resource
	err = app.Close()
	if err != nil {
		return
	}
}