Browse Source

feature(worker): context object to store runtime configurations

bigeagle 9 năm trước cách đây
mục cha
commit
f95a0f9a6f
3 tập tin đã thay đổi với 138 bổ sung0 xóa
  1. 61 0
      worker/context.go
  2. 64 0
      worker/context_test.go
  3. 13 0
      worker/provider.go

+ 61 - 0
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
+}

+ 64 - 0
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)
+				})
+			})
+		})
+	})
+}

+ 13 - 0
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()
+}