From 0e1f492227b579494293f17402f123864c65a2f6 Mon Sep 17 00:00:00 2001 From: dapeng Date: Thu, 30 May 2024 19:41:17 +0800 Subject: [PATCH 1/6] feat: update test function --- heaven.go | 8 ++++---- test.go | 42 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/heaven.go b/heaven.go index a8a5b74..2c2f545 100644 --- a/heaven.go +++ b/heaven.go @@ -1,6 +1,7 @@ package gone import ( + "errors" "os" "os/signal" "reflect" @@ -96,9 +97,7 @@ func (h *heaven) GetHeavenStopSignal() <-chan struct{} { func (h *heaven) burial() { for _, priest := range h.priests { err := priest(h.cemetery) - if err != nil { - panic(err) - } + h.panicOnError(err) } } @@ -135,7 +134,8 @@ func (h *heaven) panicOnError(err error) { if err == nil { return } - if iErr, ok := err.(InnerError); ok { + var iErr InnerError + if errors.As(err, &iErr) { h.Errorf("%s\n", iErr.Error()) } panic(err) diff --git a/test.go b/test.go index d2362cb..68d4e07 100644 --- a/test.go +++ b/test.go @@ -90,14 +90,44 @@ func TestKit[T Goner](fn func(T)) TestHeaven[T] { return &testHeaven[T]{testFn: fn} } -// Test 用于编写测试用例,参考[示例](https://github.com/gone-io/gone/blob/main/example/test/goner_test.go) -func Test[T Goner](fn func(T), priests ...Priest) { - TestKit(fn).WithPriest(priests...).Run() +//// Test 用于编写测试用例,参考[示例](https://github.com/gone-io/gone/blob/main/example/test/goner_test.go) +//func Test[T Goner](fn func(T), priests ...Priest) { +// TestKit(fn).WithPriest(priests...).Run() +//} +// +//// TestAt 用于编写测试用例,测试某个特定ID的Goner +//func TestAt[T Goner](id GonerId, fn func(T), priests ...Priest) { +// TestKit(fn).WithId(id).WithPriest(priests...).Run() +//} + +func Test[T Goner](fn func(goner T), priests ...Priest) { + Prepare(priests...).Run(func(in struct { + cemetery Cemetery `gone:"*"` + }) { + ft := reflect.TypeOf(fn) + t := ft.In(0).Elem() + theTombs := in.cemetery.GetTomByType(t) + if len(theTombs) == 0 { + panic(CannotFoundGonerByTypeError(t)) + } + fn(theTombs[0].GetGoner().(T)) + }) } -// TestAt 用于编写测试用例,测试某个特定ID的Goner -func TestAt[T Goner](id GonerId, fn func(T), priests ...Priest) { - TestKit(fn).WithId(id).WithPriest(priests...).Run() +func TestAt[T Goner](id GonerId, fn func(goner T), priests ...Priest) { + Prepare(priests...).Run(func(in struct { + cemetery Cemetery `gone:"*"` + }) { + theTomb := in.cemetery.GetTomById(id) + if theTomb == nil { + panic(CannotFoundGonerByIdError(id)) + } + g, ok := theTomb.GetGoner().(T) + if !ok { + panic(NotCompatibleError(reflect.TypeOf(g).Elem(), reflect.TypeOf(theTomb.GetGoner()).Elem())) + } + fn(g) + }) } type BuryMockCemetery struct { From 701ca461a1e9a9b536039adcf681629dd2a65e0b Mon Sep 17 00:00:00 2001 From: dapeng Date: Thu, 30 May 2024 19:53:00 +0800 Subject: [PATCH 2/6] feat: update test function --- cemetery.go | 10 ------ interface.go | 7 ---- test.go | 98 ++-------------------------------------------------- test_test.go | 8 ----- 4 files changed, 2 insertions(+), 121 deletions(-) diff --git a/cemetery.go b/cemetery.go index beed965..a045f71 100644 --- a/cemetery.go +++ b/cemetery.go @@ -321,16 +321,6 @@ func (c *cemetery) reviveSpecialTypeFields(field reflect.StructField, v reflect. return } -func (c *cemetery) reviveDependence(tomb Tomb) (deps []Tomb, err error) { - deps, err = c.reviveOneAndItsDeps(tomb) - if err != nil { - return - } - - err = c.prophesy(append(deps, tomb)...) - return -} - func (c *cemetery) reviveOneAndItsDeps(tomb Tomb) (deps []Tomb, err error) { deps, err = c.reviveOneFromTomb(tomb) if err != nil { diff --git a/interface.go b/interface.go index 86e0690..d00ef0c 100644 --- a/interface.go +++ b/interface.go @@ -53,12 +53,8 @@ type DefaultLogger interface { // Cemetery which is for burying and reviving Goner type Cemetery interface { - //DefaultLogger - Goner - //bury(goner Goner, ids ...GonerId) Tomb - //Bury a Goner to the Cemetery Bury(Goner, ...GonerOption) Cemetery @@ -74,9 +70,6 @@ type Cemetery interface { //ReviveAllFromTombs Revive all Goner from the Cemetery ReviveAllFromTombs() error - //reviveOneFromTomb(tomb Tomb) (deps []Tomb, err error) - reviveDependence(tomb Tomb) (deps []Tomb, err error) - //GetTomById return the Tomb by the GonerId GetTomById(GonerId) Tomb diff --git a/test.go b/test.go index 68d4e07..4a614d6 100644 --- a/test.go +++ b/test.go @@ -4,102 +4,7 @@ import ( "reflect" ) -type TestHeaven[T Goner] interface { - Heaven - WithId(id GonerId) TestHeaven[T] - WithPriest(priests ...Priest) TestHeaven[T] - Run() -} - -type testHeaven[T Goner] struct { - *heaven - testFn func(T) - testGonerId GonerId -} - -func (h *testHeaven[T]) WithId(id GonerId) TestHeaven[T] { - h.testGonerId = id - return h -} - -func (h *testHeaven[T]) WithPriest(priests ...Priest) TestHeaven[T] { - h.heaven = New(priests...).(*heaven) - return h -} - -func (h *testHeaven[T]) installAngelHook(deps []Tomb) { - angleTombs := Tombs(deps).GetTomByType(getAngelType()) - for _, tomb := range angleTombs { - angel := tomb.GetGoner().(Angel) - h.BeforeStart(angel.Start) - h.BeforeStop(angel.Stop) - } -} - -func (h *testHeaven[T]) run(tomb Tomb, fn func(T)) { - deps, err := h.cemetery.reviveDependence(tomb) - if err != nil { - panic(err) - } - deps = append(deps, tomb) - h.installAngelHook(deps) - h.startFlow() - fn(tomb.GetGoner().(T)) - h.stopFlow() -} - -func (h *testHeaven[T]) getTestGonerType() reflect.Type { - t := new(T) - return reflect.TypeOf(t).Elem() -} - -func (h *testHeaven[T]) Run() { - //将自己安葬了,便于其他组件引用 和 感知自己在TestKit - h.cemetery.Bury(h, IdGoneTestKit) - - h.burial() - - paramType := h.getTestGonerType() - var tomb Tomb = nil - if h.testGonerId != "" { - tomb = h.cemetery.GetTomById(h.testGonerId) - if tomb == nil { - panic(CannotFoundGonerByIdError(h.testGonerId)) - } - if tomb != nil && !isCompatible(paramType, tomb.GetGoner()) { - panic(NotCompatibleError(paramType, reflect.TypeOf(tomb.GetGoner()).Elem())) - } - } else { - list := h.cemetery.GetTomByType(paramType) - if len(list) > 0 { - if len(list) > 1 { - h.Warnf("more than one Goner found by type") - } - tomb = list[0] - } - - if tomb == nil { - panic(CannotFoundGonerByTypeError(paramType)) - } - } - h.run(tomb, h.testFn) - return -} - -func TestKit[T Goner](fn func(T)) TestHeaven[T] { - return &testHeaven[T]{testFn: fn} -} - -//// Test 用于编写测试用例,参考[示例](https://github.com/gone-io/gone/blob/main/example/test/goner_test.go) -//func Test[T Goner](fn func(T), priests ...Priest) { -// TestKit(fn).WithPriest(priests...).Run() -//} -// -//// TestAt 用于编写测试用例,测试某个特定ID的Goner -//func TestAt[T Goner](id GonerId, fn func(T), priests ...Priest) { -// TestKit(fn).WithId(id).WithPriest(priests...).Run() -//} - +// Test Use for writing test cases, refer to [example](https://github.com/gone-io/gone/blob/main/example/test/goner_test.go) func Test[T Goner](fn func(goner T), priests ...Priest) { Prepare(priests...).Run(func(in struct { cemetery Cemetery `gone:"*"` @@ -114,6 +19,7 @@ func Test[T Goner](fn func(goner T), priests ...Priest) { }) } +// TestAt Use for writing test cases, test a specific ID of Goner func TestAt[T Goner](id GonerId, fn func(goner T), priests ...Priest) { Prepare(priests...).Run(func(in struct { cemetery Cemetery `gone:"*"` diff --git a/test_test.go b/test_test.go index fbc2dfe..2eefec6 100644 --- a/test_test.go +++ b/test_test.go @@ -188,14 +188,6 @@ func Test_TestAt(t *testing.T) { }) } -func Test_testHeaven_WithId(t *testing.T) { - test := &testHeaven[*Point]{} - result := test.WithId("point-a") - assert.Equal(t, test, result) - - assert.Equal(t, "point-a", string(test.testGonerId)) -} - type angel struct { Flag x int From 8e86cb3ee5915119ade6e7bf625f6251e6e7135b Mon Sep 17 00:00:00 2001 From: dapeng Date: Thu, 30 May 2024 20:03:07 +0800 Subject: [PATCH 3/6] feat: update test tool --- test.go | 70 ++++++++++----------------------------------------------- 1 file changed, 12 insertions(+), 58 deletions(-) diff --git a/test.go b/test.go index 4a614d6..c6b53af 100644 --- a/test.go +++ b/test.go @@ -36,65 +36,19 @@ func TestAt[T Goner](id GonerId, fn func(goner T), priests ...Priest) { }) } -type BuryMockCemetery struct { - Cemetery - m map[GonerId]Goner -} - -func (c *BuryMockCemetery) Bury(g Goner, options ...GonerOption) Cemetery { - for _, option := range options { - if id, ok := option.(GonerId); ok { - c.m[id] = g - return c - } - } - id := GetGoneDefaultId(g) - c.m[id] = g - return c -} - -func (c *BuryMockCemetery) GetTomById(id GonerId) Tomb { - goner := c.m[id] - if goner == nil { - return nil - } - return NewTomb(goner) -} - -func (c *BuryMockCemetery) GetTomByType(t reflect.Type) (list []Tomb) { - for _, g := range c.m { - if reflect.TypeOf(g).Elem() == t { - list = append(list, NewTomb(g)) - } - } - return list -} - -func (c *BuryMockCemetery) BuryOnce(goner Goner, options ...GonerOption) Cemetery { - var id GonerId - - for _, option := range options { - switch option.(type) { - case GonerId: - id = option.(GonerId) - } - } - if id == "" { - panic(NewInnerError("GonerId is empty, must have gonerId option", MustHaveGonerId)) - } - - if nil == c.GetTomById(id) { - c.Bury(goner, options...) - } - return c -} - func NewBuryMockCemeteryForTest() Cemetery { - c := BuryMockCemetery{} - c.m = make(map[GonerId]Goner) - return &c -} - + return newCemetery() +} + +// Test Use for writing test cases +// example: +// +// gone.Prepare(priests...).Test(func(in struct{ +// cemetery Cemetery `gone:"*"` +// }) { +// +// // test code +// }) func (p *Preparer) Test(fn any) { p.AfterStart(fn).Run() } From 9d05f5b090e3cba8a63ced09f44d68af8fba5ff3 Mon Sep 17 00:00:00 2001 From: dapeng Date: Thu, 30 May 2024 20:26:10 +0800 Subject: [PATCH 4/6] test: add test code for cemetery.go --- cemetery.go | 41 ++++++++++++++++++++++------------------- cemetery_test.go | 19 +++++++++++++++++++ 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/cemetery.go b/cemetery.go index a045f71..eaf24b7 100644 --- a/cemetery.go +++ b/cemetery.go @@ -183,7 +183,7 @@ func isCompatible(t reflect.Type, goner Goner) bool { } } -func (c *cemetery) setFieldValue(v reflect.Value, ref any) error { +func (c *cemetery) setFieldValue(v reflect.Value, ref any) { t := v.Type() switch t.Kind() { @@ -192,7 +192,7 @@ func (c *cemetery) setFieldValue(v reflect.Value, ref any) error { default: v.Set(reflect.ValueOf(ref).Elem()) } - return nil + return } func (c *cemetery) reviveFieldById(tag string, field reflect.StructField, v reflect.Value) (deps []Tomb, suc bool, err error) { @@ -207,8 +207,8 @@ func (c *cemetery) reviveFieldById(tag string, field reflect.StructField, v refl goner := tomb.GetGoner() if isCompatible(field.Type, goner) { - err = c.setFieldValue(v, goner) - suc = err == nil + c.setFieldValue(v, goner) + suc = true return } @@ -225,14 +225,23 @@ func (c *cemetery) reviveFieldById(tag string, field reflect.StructField, v refl return } +func (c *cemetery) checkRevive(tomb Tomb) error { + if !tomb.GonerIsRevive() { + _, err := c.reviveOneAndItsDeps(tomb) + if err != nil { + return err + } + } + return nil +} + func (c *cemetery) reviveByVampire(goner Goner, tomb Tomb, extConfig string, v reflect.Value) (suc bool, err error) { if builder, ok := goner.(Vampire); ok { - if !tomb.GonerIsRevive() { - _, err = c.reviveOneAndItsDeps(tomb) - if err != nil { - return - } + err = c.checkRevive(tomb) + if err != nil { + return } + err = builder.Suck(extConfig, v) return err == nil, err } @@ -241,11 +250,9 @@ func (c *cemetery) reviveByVampire(goner Goner, tomb Tomb, extConfig string, v r func (c *cemetery) reviveByVampire2(goner Goner, tomb Tomb, extConfig string, v reflect.Value, field reflect.StructField) (suc bool, err error) { if builder, ok := goner.(Vampire2); ok { - if !tomb.GonerIsRevive() { - _, err = c.reviveOneAndItsDeps(tomb) - if err != nil { - return - } + err = c.checkRevive(tomb) + if err != nil { + return } err = builder.Suck(extConfig, v, field) return err == nil, err @@ -271,10 +278,7 @@ func (c *cemetery) reviveFieldByType(field reflect.StructField, v reflect.Value, } } - err = c.setFieldValue(v, container.GetGoner()) - if err != nil { - return - } + c.setFieldValue(v, container.GetGoner()) suc = true deps = append(deps, container) } @@ -316,7 +320,6 @@ func (c *cemetery) reviveSpecialTypeFields(field reflect.StructField, v reflect. v.Set(m) suc = true } - default: } return } diff --git a/cemetery_test.go b/cemetery_test.go index 961a297..123d86a 100644 --- a/cemetery_test.go +++ b/cemetery_test.go @@ -443,3 +443,22 @@ func Test_cemetery_reviveFieldById(t *testing.T) { }).Run() } + +func Test_cemetery_checkRevive(t *testing.T) { + type Line struct { + Flag + PointA *Point `gone:"point-a"` + PointB *Point `gone:"point-b"` + } + + test := NewBuryMockCemeteryForTest() + test. + Bury(&Point{x: 1, y: 2, Index: 1}, GonerId("point-a")). + Bury(&Point{x: 1, y: 2, Index: 2}, GonerId("point-b")). + Bury(&Line{}, GonerId("line")) + + theTomb := test.GetTomById(GonerId("line")) + + err := test.(*cemetery).checkRevive(theTomb) + assert.Nil(t, err) +} From 7046d2f56e1e07275999dd927743ac82c4f4345a Mon Sep 17 00:00:00 2001 From: dapeng Date: Thu, 30 May 2024 20:45:31 +0800 Subject: [PATCH 5/6] test: test kit --- interface.go | 2 -- test.go | 22 +++++++++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/interface.go b/interface.go index d00ef0c..d410e47 100644 --- a/interface.go +++ b/interface.go @@ -112,8 +112,6 @@ type Heaven interface { //AfterStop add a hook function which will execute after stop AfterStop(Process) Heaven - - //DefaultLogger } type AfterReviveError error diff --git a/test.go b/test.go index c6b53af..e1629fd 100644 --- a/test.go +++ b/test.go @@ -4,9 +4,13 @@ import ( "reflect" ) +func testRun(fn any, priests ...Priest) { + Prepare(priests...).testKit().Run(fn) +} + // Test Use for writing test cases, refer to [example](https://github.com/gone-io/gone/blob/main/example/test/goner_test.go) func Test[T Goner](fn func(goner T), priests ...Priest) { - Prepare(priests...).Run(func(in struct { + testRun(func(in struct { cemetery Cemetery `gone:"*"` }) { ft := reflect.TypeOf(fn) @@ -16,12 +20,12 @@ func Test[T Goner](fn func(goner T), priests ...Priest) { panic(CannotFoundGonerByTypeError(t)) } fn(theTombs[0].GetGoner().(T)) - }) + }, priests...) } // TestAt Use for writing test cases, test a specific ID of Goner func TestAt[T Goner](id GonerId, fn func(goner T), priests ...Priest) { - Prepare(priests...).Run(func(in struct { + testRun(func(in struct { cemetery Cemetery `gone:"*"` }) { theTomb := in.cemetery.GetTomById(id) @@ -33,13 +37,21 @@ func TestAt[T Goner](id GonerId, fn func(goner T), priests ...Priest) { panic(NotCompatibleError(reflect.TypeOf(g).Elem(), reflect.TypeOf(theTomb.GetGoner()).Elem())) } fn(g) - }) + }, priests...) } func NewBuryMockCemeteryForTest() Cemetery { return newCemetery() } +func (p *Preparer) testKit() *Preparer { + type Kit struct { + Flag + } + p.heaven.(*heaven).cemetery.Bury(&Kit{}, IdGoneTestKit) + return p +} + // Test Use for writing test cases // example: // @@ -50,5 +62,5 @@ func NewBuryMockCemeteryForTest() Cemetery { // // test code // }) func (p *Preparer) Test(fn any) { - p.AfterStart(fn).Run() + p.testKit().AfterStart(fn).Run() } From 564fe8d6a0ba33b2f98e14db73b7d466daad3019 Mon Sep 17 00:00:00 2001 From: dapeng Date: Thu, 30 May 2024 21:01:45 +0800 Subject: [PATCH 6/6] feat: AfterStopSignalWaitSecond as an Attribute add to heaven --- h_test.go | 2 +- heaven.go | 61 ++++++++++++++-------------------------------------- interface.go | 2 ++ prepare.go | 18 +++++++++++++++- 4 files changed, 36 insertions(+), 47 deletions(-) diff --git a/h_test.go b/h_test.go index f4265de..c72df50 100644 --- a/h_test.go +++ b/h_test.go @@ -76,7 +76,7 @@ func TestNew(t *testing.T) { } func TestServe(t *testing.T) { - gone.AfterStopSignalWaitSecond = 0 + gone.AfterStopSignalWaitSecond = 1 gone.Serve(func(cemetery gone.Cemetery) error { go func() { tom := cemetery.GetTomById(gone.IdGoneHeaven) diff --git a/heaven.go b/heaven.go index 2c2f545..c2d6951 100644 --- a/heaven.go +++ b/heaven.go @@ -9,51 +9,16 @@ import ( "time" ) -// Run 开始运行一个Gone程序;`gone.Run` 和 `gone.Serve` 的区别是: -// 1. gone.Serve启动的程序,主协程会调用 Heaven.WaitEnd 挂起等待停机信号,可以用于服务程序的开发 -// 2. gone.Run启动的程序,主协程则不会挂起,运行完就结束,适合开发一致性运行的代码 -// -// // 定义加载服务的Priest函数 -// func LoadServer(c Cemetery) error { -// c.Bury(goneXorm.New()) -// c.Bury(goneGin.New()) -// return nil -// } -// -// // 加载组件的Priest函数 -// func LoadComponent(c Cemetery) error { -// c.Bury(componentA.New()) -// c.Bury(componentB.New()) -// } -// -// -// gone.Run(LoadServer, LoadComponent)//开始运行 -func Run(priests ...Priest) { - AfterStopSignalWaitSecond = 0 - New(priests...). - Install(). - Start(). - Stop() -} - -// Serve 开始服务,参考[Run](#Run) -func Serve(priests ...Priest) { - New(priests...). - Install(). - Start(). - WaitEnd(). - Stop() -} - // New 新建Heaven; Heaven 代表了一个应用程序; func New(priests ...Priest) Heaven { cemetery := newCemetery() h := heaven{ - SimpleLogger: &defaultLogger{}, - cemetery: cemetery, - priests: priests, - signal: make(chan os.Signal), - stopSignal: make(chan struct{}), + SimpleLogger: &defaultLogger{}, + cemetery: cemetery, + priests: priests, + signal: make(chan os.Signal), + stopSignal: make(chan struct{}), + afterStopSignalWaitSecond: AfterStopSignalWaitSecond, } h. @@ -78,6 +43,12 @@ type heaven struct { signal chan os.Signal stopSignal chan struct{} + + afterStopSignalWaitSecond int +} + +func (h *heaven) SetAfterStopSignalWaitSecond(sec int) { + h.afterStopSignalWaitSecond = sec } func getAngelType() reflect.Type { @@ -186,11 +157,11 @@ func (h *heaven) Stop() Heaven { h.stopFlow() close(h.stopSignal) - if AfterStopSignalWaitSecond > 0 { - h.Infof("WAIT %d SECOND TO STOP!!", AfterStopSignalWaitSecond) + if h.afterStopSignalWaitSecond > 0 { + h.Infof("WAIT %d SECOND TO STOP!!", h.afterStopSignalWaitSecond) } - for i := 0; i < AfterStopSignalWaitSecond; i++ { - h.Infof("Stop in %d seconds.", AfterStopSignalWaitSecond-i) + for i := 0; i < h.afterStopSignalWaitSecond; i++ { + h.Infof("Stop in %d seconds.", h.afterStopSignalWaitSecond-i) <-time.After(time.Second) } return h diff --git a/interface.go b/interface.go index d410e47..dae0f50 100644 --- a/interface.go +++ b/interface.go @@ -112,6 +112,8 @@ type Heaven interface { //AfterStop add a hook function which will execute after stop AfterStop(Process) Heaven + + SetAfterStopSignalWaitSecond(sec int) } type AfterReviveError error diff --git a/prepare.go b/prepare.go index 82a6ec7..f4c8dec 100644 --- a/prepare.go +++ b/prepare.go @@ -24,8 +24,12 @@ func (p *Preparer) AfterStop(fn any) *Preparer { return p } +func (p *Preparer) SetAfterStopSignalWaitSecond(sec int) { + p.heaven.SetAfterStopSignalWaitSecond(sec) +} + func (p *Preparer) Run(fns ...any) { - AfterStopSignalWaitSecond = 0 + p.SetAfterStopSignalWaitSecond(0) for _, fn := range fns { p.AfterStart(fn) } @@ -53,3 +57,15 @@ func Prepare(priests ...Priest) *Preparer { heaven: h, } } + +// Run 开始运行一个Gone程序;`gone.Run` 和 `gone.Serve` 的区别是: +// 1. gone.Serve启动的程序,主协程会调用 Heaven.WaitEnd 挂起等待停机信号,可以用于服务程序的开发 +// 2. gone.Run启动的程序,主协程则不会挂起,运行完就结束,适合开发一致性运行的代码 +func Run(priests ...Priest) { + Prepare(priests...).Run() +} + +// Serve 开始服务,参考[Run](#Run) +func Serve(priests ...Priest) { + Prepare(priests...).Serve() +}