diff --git a/worker/context.go b/worker/context.go new file mode 100644 index 0000000..7a240a7 --- /dev/null +++ b/worker/context.go @@ -0,0 +1,61 @@ +package worker + +// Context object aims to store runtime configurations + +import "errors" + +// A Context object is a layered key-value storage +// when enters a context, the changes to the storage would be stored +// in a new layer and when exits, the top layer poped and the storage +// returned to the state before entering this context +type Context struct { + parent *Context + store map[string]interface{} +} + +// NewContext returns a new context object +func NewContext() *Context { + return &Context{ + parent: nil, + store: make(map[string]interface{}), + } +} + +// Enter generates a new layer of context +func (ctx *Context) Enter() *Context { + + return &Context{ + parent: ctx, + store: make(map[string]interface{}), + } + +} + +// Exit return the upper layer of context +func (ctx *Context) Exit() (*Context, error) { + if ctx.parent == nil { + return nil, errors.New("Cannot exit the bottom layer context") + } + return ctx.parent, nil +} + +// Get returns the value corresponding to key, if it's +// not found in the current layer, return the lower layer +// context's value +func (ctx *Context) Get(key string) (interface{}, bool) { + if ctx.parent == nil { + if value, ok := ctx.store[key]; ok { + return value, true + } + return nil, false + } + if value, ok := ctx.store[key]; ok { + return value, true + } + return ctx.parent.Get(key) +} + +// Set sets the value to the key at current layer +func (ctx *Context) Set(key string, value interface{}) { + ctx.store[key] = value +} diff --git a/worker/context_test.go b/worker/context_test.go new file mode 100644 index 0000000..f11c0ab --- /dev/null +++ b/worker/context_test.go @@ -0,0 +1,64 @@ +package worker + +import ( + "testing" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestContext(t *testing.T) { + Convey("Context should work", t, func() { + + ctx := NewContext() + So(ctx, ShouldNotBeNil) + So(ctx.parent, ShouldBeNil) + + ctx.Set("logdir1", "logdir_value_1") + ctx.Set("logdir2", "logdir_value_2") + logdir, ok := ctx.Get("logdir1") + So(ok, ShouldBeTrue) + So(logdir, ShouldEqual, "logdir_value_1") + + Convey("When entering a new context", func() { + ctx = ctx.Enter() + logdir, ok = ctx.Get("logdir1") + So(ok, ShouldBeTrue) + So(logdir, ShouldEqual, "logdir_value_1") + + ctx.Set("logdir1", "new_value_1") + + logdir, ok = ctx.Get("logdir1") + So(ok, ShouldBeTrue) + So(logdir, ShouldEqual, "new_value_1") + + logdir, ok = ctx.Get("logdir2") + So(ok, ShouldBeTrue) + So(logdir, ShouldEqual, "logdir_value_2") + + Convey("When accesing invalid key", func() { + logdir, ok = ctx.Get("invalid_key") + So(ok, ShouldBeFalse) + So(logdir, ShouldBeNil) + }) + + Convey("When exiting the new context", func() { + ctx, err := ctx.Exit() + So(err, ShouldBeNil) + + logdir, ok = ctx.Get("logdir1") + So(ok, ShouldBeTrue) + So(logdir, ShouldEqual, "logdir_value_1") + + logdir, ok = ctx.Get("logdir2") + So(ok, ShouldBeTrue) + So(logdir, ShouldEqual, "logdir_value_2") + + Convey("When exiting from top bottom context", func() { + ctx, err := ctx.Exit() + So(err, ShouldNotBeNil) + So(ctx, ShouldBeNil) + }) + }) + }) + }) +} diff --git a/worker/provider.go b/worker/provider.go new file mode 100644 index 0000000..410e93a --- /dev/null +++ b/worker/provider.go @@ -0,0 +1,13 @@ +// mirror provider is the wrapper of mirror jobs + +package worker + +// a mirrorProvider instance +type mirrorProvider interface { + // run mirror job + Run() + // terminate mirror job + Terminate() + // get context + Context() +}