diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..4e7e916 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,49 @@ +linters: + # please, do not use `enable-all`: it's deprecated and will be removed soon. + # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint + disable-all: true + enable: + - bodyclose + - depguard + - dogsled + - dupl + - gochecknoinits + - goconst + - gocritic + - gocyclo + - gofmt + - goimports + # - golint + - goprintffuncname + # - gosec + # - gosimple + - govet + - ineffassign + - interfacer + - misspell + - nakedret + - nolintlint + - rowserrcheck + - scopelint + - staticcheck + - structcheck + - stylecheck + - typecheck + - unconvert + - unparam + # - unused + - varcheck + - whitespace + + # don't enable: + # - asciicheck + # - gochecknoglobals + # - gocognit + # - godot + # - godox + # - goerr113 + # - maligned + # - nestif + # - prealloc + # - testpackage + # - wsl diff --git a/calculate_deps.go b/calculate_deps.go index 13b3d69..d2f9050 100644 --- a/calculate_deps.go +++ b/calculate_deps.go @@ -70,7 +70,7 @@ func (c *Cascade) addEdges() error { /* Add the dependencies (if) which this vertex needs to init Information we know at this step is: - 1. VertexId + 1. vertexID 2. Vertex structure value (interface) 3. Provided type 4. Provided type String name @@ -171,10 +171,7 @@ func (c *Cascade) addDependersDeps(vertexID string, vertex interface{}) error { func (c *Cascade) addInitDeps(vertexID string, initMethod reflect.Method) error { // S2 init args - initArgs, err := functionParameters(initMethod) - if err != nil { - return err - } + initArgs := functionParameters(initMethod) // iterate over all function parameters for _, initArg := range initArgs { @@ -196,7 +193,7 @@ func (c *Cascade) addInitDeps(vertexID string, initMethod reflect.Method) error } tmpIsRef := isReference(initArg) tmpValue := reflect.ValueOf(c.graph.Vertices[i].Iface) - err = c.graph.Vertices[i].AddProvider(removePointerAsterisk(initArg.String()), tmpValue, tmpIsRef, initArg.Kind()) + err := c.graph.Vertices[i].AddProvider(removePointerAsterisk(initArg.String()), tmpValue, tmpIsRef, initArg.Kind()) if err != nil { return err } @@ -204,7 +201,7 @@ func (c *Cascade) addInitDeps(vertexID string, initMethod reflect.Method) error } } - err = c.graph.AddDep(vertexID, removePointerAsterisk(initArg.String()), structures.Init, isReference(initArg), initArg.Kind()) + err := c.graph.AddDep(vertexID, removePointerAsterisk(initArg.String()), structures.Init, isReference(initArg), initArg.Kind()) if err != nil { return err } diff --git a/cascade.go b/cascade.go index 73c90a6..c44ccfb 100644 --- a/cascade.go +++ b/cascade.go @@ -3,7 +3,10 @@ package cascade import ( "errors" "net/http" + + // pprof enabled in debug mode _ "net/http/pprof" + "reflect" "sync" "time" @@ -187,12 +190,12 @@ func (c *Cascade) Register(vertex interface{}) error { ok := t.Implements(reflect.TypeOf((*Service)(nil)).Elem()) if !ok { - return typeNotImplementError + return errTypeNotImplementError } /* Depender the type Information we know at this step is: - 1. VertexId + 1. vertexID 2. Vertex structure value (interface) And we fill vertex with this information */ @@ -203,7 +206,7 @@ func (c *Cascade) Register(vertex interface{}) error { order++ /* Add the types, which (if) current vertex provides Information we know at this step is: - 1. VertexId + 1. vertexID 2. Vertex structure value (interface) 3. Provided type 4. Provided type String name @@ -254,7 +257,7 @@ func (c *Cascade) Init() error { return nil } -func (c *Cascade) Serve() (error, <-chan *Result) { +func (c *Cascade) Serve() (<-chan *Result, error) { c.rwMutex.Lock() defer c.rwMutex.Unlock() c.startMainThread() @@ -264,8 +267,8 @@ func (c *Cascade) Serve() (error, <-chan *Result) { for nCopy != nil { err := c.configure(nCopy) if err != nil { - c.logger.Error("backoff failed", zap.String("vertex id", nCopy.Vertex.Id), zap.Error(err)) - return err, nil + c.logger.Error("backoff failed", zap.String("vertex id", nCopy.Vertex.ID), zap.Error(err)) + return nil, err } nCopy = nCopy.Next @@ -275,11 +278,11 @@ func (c *Cascade) Serve() (error, <-chan *Result) { for nCopy != nil { err := c.serve(nCopy) if err != nil { - return err, nil + return nil, err } nCopy = nCopy.Next } - return nil, c.userResultsCh + return c.userResultsCh, nil } func (c *Cascade) Stop() error { @@ -319,18 +322,18 @@ func (c *Cascade) startMainThread() { return } - c.logger.Debug("processing error in the main thread", zap.String("vertex id", res.vertexId)) + c.logger.Debug("processing error in the main thread", zap.String("vertex id", res.vertexID)) if c.checkLeafErrorTime(res) { - c.logger.Debug("error processing skipped because vertex already restartedTime by the root", zap.String("vertex id", res.vertexId)) + c.logger.Debug("error processing skipped because vertex already restartedTime by the root", zap.String("vertex id", res.vertexID)) c.sendResultToUser(res) c.rwMutex.Unlock() continue } // get vertex from the graph - vertex := c.graph.GetVertex(res.vertexId) + vertex := c.graph.GetVertex(res.vertexID) if vertex == nil { - c.logger.Error("failed to get vertex from the graph, vertex is nil", zap.String("vertex id from the handleErrorCh channel", res.vertexId)) + c.logger.Error("failed to get vertex from the graph, vertex is nil", zap.String("vertex id from the handleErrorCh channel", res.vertexID)) c.userResultsCh <- &Result{ Error: FailedToGetTheVertex, VertexID: "", @@ -341,12 +344,12 @@ func (c *Cascade) startMainThread() { // reset vertex and dependencies to the initial state // NumOfDeps and Visited/Visiting - vertices := c.resetVertices(vertex) + vertices := c.graph.Reset(vertex) // Topologically sort the graph sorted := structures.TopologicalSort(vertices) if sorted == nil { - c.logger.Error("sorted list should not be nil", zap.String("vertex id from the handleErrorCh channel", res.vertexId)) + c.logger.Error("sorted list should not be nil", zap.String("vertex id from the handleErrorCh channel", res.vertexID)) c.userResultsCh <- &Result{ Error: FailedToSortTheGraph, VertexID: "", @@ -377,10 +380,10 @@ func (c *Cascade) startMainThread() { for headCopy != nil { berr := backoff.Retry(c.backoffInit(headCopy.Vertex), b) if berr != nil { - c.logger.Error("backoff failed", zap.String("vertex id", headCopy.Vertex.Id), zap.Error(berr)) + c.logger.Error("backoff failed", zap.String("vertex id", headCopy.Vertex.ID), zap.Error(berr)) c.userResultsCh <- &Result{ Error: ErrorDuringInit, - VertexID: headCopy.Vertex.Id, + VertexID: headCopy.Vertex.ID, } c.rwMutex.Unlock() return @@ -396,9 +399,9 @@ func (c *Cascade) startMainThread() { if berr != nil { c.userResultsCh <- &Result{ Error: ErrorDuringInit, - VertexID: headCopy.Vertex.Id, + VertexID: headCopy.Vertex.ID, } - c.logger.Error("backoff failed", zap.String("vertex id", headCopy.Vertex.Id), zap.Error(berr)) + c.logger.Error("backoff failed", zap.String("vertex id", headCopy.Vertex.ID), zap.Error(berr)) c.rwMutex.Unlock() return } @@ -413,9 +416,9 @@ func (c *Cascade) startMainThread() { if err != nil { c.userResultsCh <- &Result{ Error: ErrorDuringServe, - VertexID: headCopy.Vertex.Id, + VertexID: headCopy.Vertex.ID, } - c.logger.Error("fatal error during the serve in the main thread", zap.String("vertex id", headCopy.Vertex.Id), zap.Error(err)) + c.logger.Error("fatal error during the serve in the main thread", zap.String("vertex id", headCopy.Vertex.ID), zap.Error(err)) c.rwMutex.Unlock() return } diff --git a/container.go b/container.go index 0f7f079..947b323 100644 --- a/container.go +++ b/container.go @@ -26,7 +26,7 @@ type result struct { // error from the channel err error // unique vertex id - vertexId string + vertexID string // signal to the vertex goroutine to exit exit chan struct{} // internal exit, used to notify main thread to release resources @@ -34,13 +34,14 @@ type result struct { } type ( - // TODO namings + // used to gracefully stop and configure the plugins Graceful interface { // Configure is used when we need to make preparation and wait for all services till Serve Configure() error // Close frees resources allocated by the service Close() error } + // this is the main service interface with should implement every plugin Service interface { // Serve Serve() chan error @@ -48,8 +49,14 @@ type ( Stop() error } - Container interface { - Serve() (error, <-chan *Result) + // Name of the service + Named interface { + Name() string + } + + // internal container interface + container interface { + Serve() (<-chan *Result, error) Stop() error restart() error Register(service interface{}) error diff --git a/errors.go b/errors.go index 839d2ec..8d1c8dd 100644 --- a/errors.go +++ b/errors.go @@ -43,6 +43,6 @@ var ErrorDuringServe = Error{ Stack: debug.Stack(), } -var typeNotImplementError = errors.New("type should implement Service interface") -var vertexAlreadyExists = func(name string) error { return fmt.Errorf("vertex `%s` already exists", name) } -var unknownErrorOccurred = errors.New("unknown error occurred during the function call") +var errTypeNotImplementError = errors.New("type should implement Service interface") +var errVertexAlreadyExists = func(name string) error { return fmt.Errorf("vertex `%s` already exists", name) } +var errUnknownErrorOccurred = errors.New("unknown error occurred during the function call") diff --git a/examples/db_http_logger/go.mod b/examples/db_http_logger/go.mod index 5c94827..9a71dfe 100644 --- a/examples/db_http_logger/go.mod +++ b/examples/db_http_logger/go.mod @@ -8,4 +8,4 @@ require ( github.com/rs/cors v1.7.0 github.com/spiral/cascade v1.0.0-beta4 go.etcd.io/bbolt v1.3.5 -) +) \ No newline at end of file diff --git a/examples/db_http_logger/main.go b/examples/db_http_logger/main.go index 63ede82..d4d86c0 100644 --- a/examples/db_http_logger/main.go +++ b/examples/db_http_logger/main.go @@ -43,7 +43,7 @@ func main() { panic(err) } - err, errCh := container.Serve() + errCh, err := container.Serve() if err != nil { panic(err) } diff --git a/examples/db_http_logger/modules/db/db_layer.go b/examples/db_http_logger/modules/db/db_layer.go index 62387d6..814a6ce 100644 --- a/examples/db_http_logger/modules/db/db_layer.go +++ b/examples/db_http_logger/modules/db/db_layer.go @@ -50,6 +50,10 @@ func (db *DB) Stop() error { return nil } +func (db *DB) Name() string { + return "super DATABASE service" +} + /////////////// DB LAYER ///////////////// diff --git a/examples/db_http_logger/modules/gzip/gzip.go b/examples/db_http_logger/modules/gzip/gzip.go index f048d2c..b315b2e 100644 --- a/examples/db_http_logger/modules/gzip/gzip.go +++ b/examples/db_http_logger/modules/gzip/gzip.go @@ -29,3 +29,7 @@ func (gz *Gzip) Middleware(f http.Handler) http.HandlerFunc { gziphandler.GzipHandler(f).ServeHTTP(w, r) } } + +func (gz *Gzip) Name() string { + return "super Gzip middleware" +} \ No newline at end of file diff --git a/examples/db_http_logger/modules/headers/headers.go b/examples/db_http_logger/modules/headers/headers.go index 588c7b3..d16944e 100644 --- a/examples/db_http_logger/modules/headers/headers.go +++ b/examples/db_http_logger/modules/headers/headers.go @@ -33,4 +33,8 @@ func (h *Headers) Middleware(f http.Handler) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { f.ServeHTTP(w, r) } +} + +func (h *Headers) Name() string { + return "super Headers middleware" } \ No newline at end of file diff --git a/examples/db_http_logger/modules/http/http_layer.go b/examples/db_http_logger/modules/http/http_layer.go index 9780593..45d87ca 100644 --- a/examples/db_http_logger/modules/http/http_layer.go +++ b/examples/db_http_logger/modules/http/http_layer.go @@ -145,3 +145,7 @@ func (h *Http) insert(writer http.ResponseWriter, request *http.Request) { h.db.Insert() writer.WriteHeader(http.StatusOK) } + +func (h *Http) Name() string { + return "super http service" +} \ No newline at end of file diff --git a/examples/db_http_logger/modules/logger/logger.go b/examples/db_http_logger/modules/logger/logger.go index 255f32e..7d0d971 100644 --- a/examples/db_http_logger/modules/logger/logger.go +++ b/examples/db_http_logger/modules/logger/logger.go @@ -2,6 +2,8 @@ package logger import ( "fmt" + + "github.com/spiral/cascade" ) type Logger struct { @@ -29,3 +31,13 @@ func (l *Logger) Stop() error { return nil } +func (l *Logger) Provides() []interface{} { + return []interface{}{ + l.LoggerInstance, + } +} + +func (l *Logger) LoggerInstance(name cascade.Named) (*Logger, error) { + println(name.Name() + " invoke " + "logger") + return l, nil +} \ No newline at end of file diff --git a/internal.go b/internal.go index 915b596..fc0fdb6 100644 --- a/internal.go +++ b/internal.go @@ -14,14 +14,14 @@ import ( Traverse the DLL in the forward direction */ -func (c *Cascade) init(v *structures.Vertex) error { +func (c *Cascade) init(vertex *structures.Vertex) error { // we already checked the Interface satisfaction // at this step absence of Init() is impoosssibruuu - init, _ := reflect.TypeOf(v.Iface).MethodByName(InitMethodName) + initMethod, _ := reflect.TypeOf(vertex.Iface).MethodByName(InitMethodName) - err := c.callInitFn(init, v) + err := c.callInitFn(initMethod, vertex) if err != nil { - c.logger.Error("error occurred during the call INIT function", zap.String("vertex id", v.Id), zap.Error(err)) + c.logger.Error("error occurred during the call INIT function", zap.String("vertex id", vertex.ID), zap.Error(err)) return err } @@ -29,19 +29,20 @@ func (c *Cascade) init(v *structures.Vertex) error { } func (c *Cascade) callInitFn(init reflect.Method, vertex *structures.Vertex) error { - in := c.findInitParameters(vertex) - + in, err := c.findInitParameters(vertex) + if err != nil { + return err + } // Iterate over dependencies // And search in Vertices for the provided types ret := init.Func.Call(in) rErr := ret[0].Interface() if rErr != nil { if e, ok := rErr.(error); ok && e != nil { - c.logger.Error("error calling init", zap.String("vertex id", vertex.Id), zap.Error(e)) + c.logger.Error("error calling init", zap.String("vertex id", vertex.ID), zap.Error(e)) return e - } else { - return unknownErrorOccurred } + return errUnknownErrorOccurred } // just to be safe here @@ -54,31 +55,25 @@ func (c *Cascade) callInitFn(init reflect.Method, vertex *structures.Vertex) err */ err := vertex.AddProvider(removePointerAsterisk(in[0].Type().String()), in[0], isReference(in[0].Type()), in[0].Kind()) if err != nil { + c.logger.Debug("value added successfully", zap.String("vertex id", vertex.ID), zap.String("parameter", in[0].Type().String())) return err } - c.logger.Debug("value added successfully", zap.String("vertex id", vertex.Id), zap.String("parameter", in[0].Type().String())) - } else { - c.logger.Error("0 or less parameters for Init", zap.String("vertex id", vertex.Id)) + c.logger.Error("0 or less parameters for Init", zap.String("vertex id", vertex.ID)) return errors.New("0 or less parameters for Init") } - err := c.traverseCallProvider(vertex, []reflect.Value{reflect.ValueOf(vertex.Iface)}) - if err != nil { - return err - } - if len(vertex.Meta.DepsList) > 0 { for i := 0; i < len(vertex.Meta.DepsList); i++ { // Interface dependency if vertex.Meta.DepsList[i].Kind == reflect.Interface { - err = c.traverseCallDependersInterface(vertex) + err := c.traverseCallDependersInterface(vertex) if err != nil { return err } } else { // structure dependence - err = c.traverseCallDependers(vertex) + err := c.traverseCallDependers(vertex) if err != nil { return err } @@ -91,9 +86,9 @@ func (c *Cascade) callInitFn(init reflect.Method, vertex *structures.Vertex) err func (c *Cascade) traverseCallDependersInterface(vertex *structures.Vertex) error { for i := 0; i < len(vertex.Meta.DepsList); i++ { // get dependency id (vertex id) - depId := vertex.Meta.DepsList[i].Name + depID := vertex.Meta.DepsList[i].Name // find vertex which provides dependency - providers := c.graph.FindProviders(depId) + providers := c.graph.FindProviders(depID) // Depend from interface /* @@ -108,7 +103,7 @@ func (c *Cascade) traverseCallDependersInterface(vertex *structures.Vertex) erro // vertexKey is for example foo.DB // vertexValue is value for that key for vertexKey, vertexVal := range providers[j].Provides { - if depId != vertexKey { + if depID != vertexKey { continue } // init @@ -117,14 +112,16 @@ func (c *Cascade) traverseCallDependersInterface(vertex *structures.Vertex) erro inInterface = append(inInterface, reflect.ValueOf(vertex.Iface)) // if type provides needed type // value - reference and init dep also reference - if *vertexVal.IsReference == *vertex.Meta.DepsList[i].IsReference { + + switch { + case *vertexVal.IsReference == *vertex.Meta.DepsList[i].IsReference: inInterface = append(inInterface, *vertexVal.Value) - } else if *vertexVal.IsReference { + case *vertexVal.IsReference: // same type, but difference in the refs // Init needs to be a value // But Vertex provided reference inInterface = append(inInterface, vertexVal.Value.Elem()) - } else if !*vertexVal.IsReference { + case !*vertexVal.IsReference: // vice versa // Vertex provided value // but Init needs to be a reference @@ -156,23 +153,23 @@ func (c *Cascade) traverseCallDependers(vertex *structures.Vertex) error { for i := 0; i < len(vertex.Meta.DepsList); i++ { // get dependency id (vertex id) - depId := vertex.Meta.DepsList[i].Name + depID := vertex.Meta.DepsList[i].Name // find vertex which provides dependency - providers := c.graph.FindProviders(depId) + providers := c.graph.FindProviders(depID) // search for providers for j := 0; j < len(providers); j++ { - for vertexId, val := range providers[j].Provides { + for vertexID, val := range providers[j].Provides { // if type provides needed type - if vertexId == depId { - // value - reference and init dep also reference - if *val.IsReference == *vertex.Meta.DepsList[i].IsReference { + if vertexID == depID { + switch { + case *val.IsReference == *vertex.Meta.DepsList[i].IsReference: in = append(in, *val.Value) - } else if *val.IsReference { + case *val.IsReference: // same type, but difference in the refs // Init needs to be a value // But Vertex provided reference in = append(in, val.Value.Elem()) - } else if !*val.IsReference { + case !*val.IsReference: // vice versa // Vertex provided value // but Init needs to be a reference @@ -206,7 +203,7 @@ func (c *Cascade) callDependerFns(vertex *structures.Vertex, in []reflect.Value) for k := 0; k < len(vertex.Meta.FnsDependerToInvoke); k++ { m, ok := reflect.TypeOf(vertex.Iface).MethodByName(vertex.Meta.FnsDependerToInvoke[k]) if !ok { - c.logger.Error("type has missing method in FnsDependerToInvoke", zap.String("vertex id", vertex.Id), zap.String("method", vertex.Meta.FnsDependerToInvoke[k])) + c.logger.Error("type has missing method in FnsDependerToInvoke", zap.String("vertex id", vertex.ID), zap.String("method", vertex.Meta.FnsDependerToInvoke[k])) return errors.New("type has missing method in FnsDependerToInvoke") } @@ -217,11 +214,10 @@ func (c *Cascade) callDependerFns(vertex *structures.Vertex, in []reflect.Value) rErr := ret[len(ret)-1].Interface() if rErr != nil { if e, ok := rErr.(error); ok && e != nil { - c.logger.Error("error calling Registers", zap.String("vertex id", vertex.Id), zap.Error(e)) + c.logger.Error("error calling Registers", zap.String("vertex id", vertex.ID), zap.Error(e)) return e - } else { - return unknownErrorOccurred } + return errUnknownErrorOccurred } } else { return errors.New("depender should return Value and error types") @@ -232,7 +228,7 @@ func (c *Cascade) callDependerFns(vertex *structures.Vertex, in []reflect.Value) return nil } -func (c *Cascade) findInitParameters(vertex *structures.Vertex) []reflect.Value { +func (c *Cascade) findInitParameters(vertex *structures.Vertex) ([]reflect.Value, error) { in := make([]reflect.Value, 0, 2) // add service itself @@ -241,28 +237,37 @@ func (c *Cascade) findInitParameters(vertex *structures.Vertex) []reflect.Value // add dependencies if len(vertex.Meta.InitDepsList) > 0 { for i := 0; i < len(vertex.Meta.InitDepsList); i++ { - depId := vertex.Meta.InitDepsList[i].Name - v := c.graph.FindProviders(depId) - - in = c.traverseProviders(vertex.Meta.InitDepsList, v[0], depId, i, in) + depID := vertex.Meta.InitDepsList[i].Name + v := c.graph.FindProviders(depID) + var err error + in, err = c.traverseProviders(vertex.Meta.InitDepsList[i], v[0], depID, vertex.ID, in) + if err != nil { + return nil, err + } } } - return in + return in, nil } -func (c *Cascade) traverseProviders(list []structures.DepsEntry, depVertex *structures.Vertex, depId string, i int, in []reflect.Value) []reflect.Value { - for vertexId, val := range depVertex.Provides { - if vertexId == depId { - // value - reference and init dep also reference - if *val.IsReference == *list[i].IsReference { +func (c *Cascade) traverseProviders(depsEntry structures.DepsEntry, depVertex *structures.Vertex, depID string, calleeID string, in []reflect.Value) ([]reflect.Value, error) { + // we need to call all providers first + err := c.traverseCallProvider(depVertex, []reflect.Value{reflect.ValueOf(depVertex.Iface)}, calleeID) + if err != nil { + return nil, err + } + + // to index function name in defer + for providerID, val := range depVertex.Provides { + if providerID == depID { + switch { + case *val.IsReference == *depsEntry.IsReference: in = append(in, *val.Value) - } else if *val.IsReference { + case *val.IsReference: // same type, but difference in the refs // Init needs to be a value // But Vertex provided reference - in = append(in, val.Value.Elem()) - } else if !*val.IsReference { + case !*val.IsReference: // vice versa // Vertex provided value // but Init needs to be a reference @@ -278,10 +283,25 @@ func (c *Cascade) traverseProviders(list []structures.DepsEntry, depVertex *stru } } - return in + return in, nil } -func (c *Cascade) traverseCallProvider(v *structures.Vertex, in []reflect.Value) error { +type TmpStr struct { + N string +} + +func (t TmpStr) Name() string { + return t.N +} + +func (c *Cascade) traverseCallProvider(v *structures.Vertex, in []reflect.Value, callerID string) error { + // to index function name in defer + i := 0 + defer func() { + if r := recover(); r != nil { + c.logger.Error("panic during the function call", zap.String("function name", v.Meta.FnsProviderToInvoke[i]), zap.String("error", fmt.Sprint(r))) + } + }() // type implements Provider interface if reflect.TypeOf(v.Iface).Implements(reflect.TypeOf((*Provider)(nil)).Elem()) { // if type implements Provider() it should has FnsProviderToInvoke @@ -289,23 +309,63 @@ func (c *Cascade) traverseCallProvider(v *structures.Vertex, in []reflect.Value) // go over all function to invoke // invoke it // and save its return values - for i := 0; i < len(v.Meta.FnsProviderToInvoke); i++ { + for i = 0; i < len(v.Meta.FnsProviderToInvoke); i++ { m, ok := reflect.TypeOf(v.Iface).MethodByName(v.Meta.FnsProviderToInvoke[i]) if !ok { - panic("method Provides should be") + c.logger.Panic("should implement the Provider interface", zap.String("function name", v.Meta.FnsProviderToInvoke[i])) } - ret := m.Func.Call(in) + /* + think about better solution here TODO + We copy IN params here because only in slice is constant + */ + inCopy := make([]reflect.Value, len(in)) + copy(inCopy, in) + + /* + cases when func NumIn can be more than one + is that function accepts some other type except of receiver + at the moment we assume, that this "other type" is Name interface + */ + if m.Func.Type().NumIn() > 1 { + /* + here we should add type which implement Named interface + at the moment we seek for implementation in the callerID only + */ + + callerV := c.graph.GetVertex(callerID) + if callerV == nil { + return errors.New("caller vertex is nil") + } + + // skip function receiver + for j := 1; j < m.Func.Type().NumIn(); j++ { + // current function IN type (interface) + t := m.Func.Type().In(j) + if t.Kind() != reflect.Interface { + c.logger.Panic("Provider accepts only interfaces", zap.String("function name", v.Meta.FnsProviderToInvoke[i])) + } + + // if Caller struct implements interface -- ok, add it to the inCopy list + // else panic + if reflect.TypeOf(callerV.Iface).Implements(t) == false { + c.logger.Panic("Caller should implement callee interface", zap.String("function name", v.Meta.FnsProviderToInvoke[i])) + } + + inCopy = append(inCopy, reflect.ValueOf(callerV.Iface)) + } + } + + ret := m.Func.Call(inCopy) // handle error if len(ret) > 1 { rErr := ret[1].Interface() if rErr != nil { if e, ok := rErr.(error); ok && e != nil { - c.logger.Error("error occurred in the traverseCallProvider", zap.String("vertex id", v.Id)) + c.logger.Error("error occurred in the traverseCallProvider", zap.String("vertex id", v.ID)) return e - } else { - return unknownErrorOccurred } + return errUnknownErrorOccurred } // add the value to the Providers @@ -340,7 +400,7 @@ func (c *Cascade) callServeFn(vertex *structures.Vertex, in []reflect.Value) *re return &result{ errCh: e, exit: make(chan struct{}, 2), - vertexId: vertex.Id, + vertexID: vertex.ID, } } } @@ -360,7 +420,7 @@ func (c *Cascade) callConfigureFn(vertex *structures.Vertex, in []reflect.Value) if e, ok := res.(error); ok && e != nil { return e } - return unknownErrorOccurred + return errUnknownErrorOccurred } return nil } @@ -373,16 +433,14 @@ func (c *Cascade) callStopFn(vertex *structures.Vertex, in []reflect.Value) erro if rErr != nil { if e, ok := rErr.(error); ok && e != nil { return e - } else { - return unknownErrorOccurred } + return errUnknownErrorOccurred } return nil - } -func (c *Cascade) stop(vId string) error { - vertex := c.graph.GetVertex(vId) +func (c *Cascade) stop(vID string) error { + vertex := c.graph.GetVertex(vID) in := make([]reflect.Value, 0, 1) // add service itself @@ -390,13 +448,15 @@ func (c *Cascade) stop(vId string) error { err := c.callStopFn(vertex, in) if err != nil { - c.logger.Error("error occurred during the stop", zap.String("vertex id", vertex.Id)) + c.logger.Error("error occurred during the stop", zap.String("vertex id", vertex.ID)) + return err } if reflect.TypeOf(vertex.Iface).Implements(reflect.TypeOf((*Graceful)(nil)).Elem()) { - err = c.close(vertex.Id, in) + err = c.close(vertex.ID, in) if err != nil { - c.logger.Error("error occurred during the close", zap.String("vertex id", vertex.Id)) + c.logger.Error("error occurred during the close", zap.String("vertex id", vertex.ID)) + return err } } @@ -404,8 +464,8 @@ func (c *Cascade) stop(vId string) error { } // TODO add stack to the all of the log events -func (c *Cascade) close(vId string, in []reflect.Value) error { - v := c.graph.GetVertex(vId) +func (c *Cascade) close(vID string, in []reflect.Value) error { + v := c.graph.GetVertex(vID) // Call Close() method, which returns only error (or nil) m, _ := reflect.TypeOf(v.Iface).MethodByName(CloseMethodName) ret := m.Func.Call(in) @@ -413,9 +473,8 @@ func (c *Cascade) close(vId string, in []reflect.Value) error { if rErr != nil { if e, ok := rErr.(error); ok && e != nil { return e - } else { - return unknownErrorOccurred } + return errUnknownErrorOccurred } return nil } @@ -423,15 +482,15 @@ func (c *Cascade) close(vId string, in []reflect.Value) error { func (c *Cascade) sendExitSignal(sorted []*structures.Vertex) { for _, v := range sorted { // get result by vertex ID - tmp := c.results[v.Id] + tmp := c.results[v.ID] if tmp == nil { continue } // send exit signal to the goroutine in sorted order - c.logger.Debug("sending exit signal to the vertex from the main thread", zap.String("vertex id", tmp.vertexId)) + c.logger.Debug("sending exit signal to the vertex from the main thread", zap.String("vertex id", tmp.vertexID)) tmp.exit <- struct{}{} - c.results[v.Id] = nil + c.results[v.ID] = nil } } @@ -442,21 +501,21 @@ func (c *Cascade) sendResultToUser(res *result) { Code: 0, Stack: nil, }, - VertexID: res.vertexId, + VertexID: res.vertexID, } } func (c *Cascade) shutdown(n *structures.DllNode) { nCopy := n for nCopy != nil { - err := c.stop(nCopy.Vertex.Id) + err := c.stop(nCopy.Vertex.ID) if err != nil { // TODO do not return until finished // just log the errors // stack it in slice and if slice is not empty, print it ?? - c.logger.Error("error occurred during the services stopping", zap.String("vertex id", nCopy.Vertex.Id), zap.Error(err)) + c.logger.Error("error occurred during the services stopping", zap.String("vertex id", nCopy.Vertex.ID), zap.Error(err)) } - if channel, ok := c.results[nCopy.Vertex.Id]; ok && channel != nil { + if channel, ok := c.results[nCopy.Vertex.ID]; ok && channel != nil { channel.exit <- struct{}{} } @@ -474,25 +533,25 @@ func (c *Cascade) serve(n *structures.DllNode) error { res := c.callServeFn(n.Vertex, in) if res != nil { - c.results[res.vertexId] = res + c.results[res.vertexID] = res } else { - c.logger.Error("nil result returned from the vertex", zap.String("vertex id", n.Vertex.Id)) - return errors.New(fmt.Sprintf("nil result returned from the vertex, vertex id: %s", n.Vertex.Id)) + c.logger.Error("nil result returned from the vertex", zap.String("vertex id", n.Vertex.ID)) + return fmt.Errorf("nil result returned from the vertex, vertex id: %s", n.Vertex.ID) } c.poll(res) - if c.restartedTime[n.Vertex.Id] != nil { - *c.restartedTime[n.Vertex.Id] = time.Now() + if c.restartedTime[n.Vertex.ID] != nil { + *c.restartedTime[n.Vertex.ID] = time.Now() } else { tmp := time.Now() - c.restartedTime[n.Vertex.Id] = &tmp + c.restartedTime[n.Vertex.ID] = &tmp } return nil } func (c *Cascade) checkLeafErrorTime(res *result) bool { - return c.restartedTime[res.vertexId] != nil && (*c.restartedTime[res.vertexId]).After(*c.errorTime[res.vertexId]) + return c.restartedTime[res.vertexID] != nil && c.restartedTime[res.vertexID].After(*c.errorTime[res.vertexID]) } // poll is used to poll the errors from the vertex @@ -507,15 +566,15 @@ func (c *Cascade) poll(r *result) { if e != nil { // set error time c.rwMutex.Lock() - if c.errorTime[res.vertexId] != nil { - *c.errorTime[res.vertexId] = time.Now() + if c.errorTime[res.vertexID] != nil { + *c.errorTime[res.vertexID] = time.Now() } else { tmp := time.Now() - c.errorTime[res.vertexId] = &tmp + c.errorTime[res.vertexID] = &tmp } c.rwMutex.Unlock() - c.logger.Error("error processed in poll", zap.String("vertex id", res.vertexId), zap.Error(e)) + c.logger.Error("error processed in poll", zap.String("vertex id", res.vertexID), zap.Error(e)) // set the error res.err = e @@ -526,10 +585,10 @@ func (c *Cascade) poll(r *result) { // exit from the goroutine case <-res.exit: c.rwMutex.Lock() - c.logger.Info("got exit signal", zap.String("vertex id", res.vertexId)) - err := c.stop(res.vertexId) + c.logger.Info("got exit signal", zap.String("vertex id", res.vertexID)) + err := c.stop(res.vertexID) if err != nil { - c.logger.Error("error during exit signal", zap.String("error while stopping the vertex:", res.vertexId), zap.Error(err)) + c.logger.Error("error during exit signal", zap.String("error while stopping the vertex:", res.vertexID), zap.Error(err)) c.rwMutex.Unlock() } c.rwMutex.Unlock() @@ -539,40 +598,10 @@ func (c *Cascade) poll(r *result) { }(rr) } -// TODO graph responsibility, not Cascade -func (c *Cascade) resetVertices(vertex *structures.Vertex) []*structures.Vertex { - // restore number of dependencies for the root - vertex.NumOfDeps = len(vertex.Dependencies) - vertex.Visiting = false - vertex.Visited = false - vertices := make([]*structures.Vertex, 0, 5) - vertices = append(vertices, vertex) - - tmp := make(map[string]*structures.Vertex) - - c.dfs(vertex.Dependencies, tmp) - - for _, v := range tmp { - vertices = append(vertices, v) - } - return vertices -} - -// TODO graph responsibility, not Cascade -func (c *Cascade) dfs(deps []*structures.Vertex, tmp map[string]*structures.Vertex) { - for i := 0; i < len(deps); i++ { - deps[i].Visited = false - deps[i].Visiting = false - deps[i].NumOfDeps = len(deps) - tmp[deps[i].Id] = deps[i] - c.dfs(deps[i].Dependencies, tmp) - } -} - func (c *Cascade) register(name string, vertex interface{}, order int) error { // check the vertex if c.graph.HasVertex(name) { - return vertexAlreadyExists(name) + return errVertexAlreadyExists(name) } meta := structures.Meta{ @@ -593,7 +622,7 @@ func (c *Cascade) backoffInit(v *structures.Vertex) func() error { err := c.callInitFn(init, v) if err != nil { - c.logger.Error("error occurred during the call INIT function", zap.String("vertex id", v.Id), zap.Error(err)) + c.logger.Error("error occurred during the call INIT function", zap.String("vertex id", v.ID), zap.Error(err)) return err } @@ -629,7 +658,7 @@ func (c *Cascade) backoffConfigure(n *structures.DllNode) func() error { if reflect.TypeOf(n.Vertex.Iface).Implements(reflect.TypeOf((*Graceful)(nil)).Elem()) { err := c.callConfigureFn(n.Vertex, in) if err != nil { - c.logger.Error("error configuring the vertex", zap.String("vertex id", n.Vertex.Id), zap.Error(err)) + c.logger.Error("error configuring the vertex", zap.String("vertex id", n.Vertex.ID), zap.Error(err)) return err } } @@ -670,7 +699,7 @@ func (c *Cascade) restart() error { for nCopy != nil { err := c.configure(nCopy) if err != nil { - c.logger.Error("backoff failed", zap.String("vertex id", nCopy.Vertex.Id), zap.Error(err)) + c.logger.Error("backoff failed", zap.String("vertex id", nCopy.Vertex.ID), zap.Error(err)) return err } diff --git a/plugins/config/config_provider.go b/plugins/config/config_provider.go index 4801b36..d707557 100644 --- a/plugins/config/config_provider.go +++ b/plugins/config/config_provider.go @@ -1,7 +1,6 @@ package config type Provider struct { - } func (p *Provider) Init() error { diff --git a/plugins/logger/logger_provider.go b/plugins/logger/logger_provider.go index 9f4ba5a..88830b7 100644 --- a/plugins/logger/logger_provider.go +++ b/plugins/logger/logger_provider.go @@ -1,8 +1,6 @@ package logger - type Provider struct { - } func (p *Provider) Init() error { diff --git a/reflect.go b/reflect.go index c4ddb48..f35aba2 100644 --- a/reflect.go +++ b/reflect.go @@ -39,7 +39,7 @@ func argType(m interface{}) ([]reflect.Type, error) { return out, nil } -func functionParameters(r reflect.Method) ([]reflect.Type, error) { +func functionParameters(r reflect.Method) []reflect.Type { args := make([]reflect.Type, 0) // NumIn returns a function type's input parameter count. // It panics if the type's Kind is not Func. @@ -50,7 +50,7 @@ func functionParameters(r reflect.Method) ([]reflect.Type, error) { args = append(args, r.Type.In(i)) } - return args, nil + return args } func getFunctionName(i interface{}) string { diff --git a/structures/linked_list.go b/structures/linked_list.go index d2a8455..95897f0 100644 --- a/structures/linked_list.go +++ b/structures/linked_list.go @@ -89,7 +89,6 @@ func (dll *DoublyLinkedList) InsertAfter(node, nodeToInsert *DllNode) { node.Next = nodeToInsert } - func (dll *DoublyLinkedList) Remove(node *DllNode) { if node == dll.Head { dll.Head = dll.Head.Next diff --git a/structures/service_graph.go b/structures/service_graph.go index 67ce4e3..e1b232a 100644 --- a/structures/service_graph.go +++ b/structures/service_graph.go @@ -1,6 +1,7 @@ package structures import ( + "errors" "fmt" "reflect" ) @@ -51,7 +52,7 @@ type DepsEntry struct { // since we can have cyclic dependencies // when we traverse the VerticesMap, we should mark nodes as Visited or not to detect cycle type Vertex struct { - Id string + ID string // Vertex Iface interface{} // Meta information about current Vertex @@ -135,7 +136,7 @@ func (g *Graph) HasVertex(name string) bool { AddDepRev doing the following: 1. Get a vertexID (foo2.S2 for example) 2. Get a depID --> could be vertexID of vertex dep ID like foo2.DB -3. Need to find VertexID to provide dependency. Example foo2.DB is actually foo2.S2 vertex +3. Need to find vertexID to provide dependency. Example foo2.DB is actually foo2.S2 vertex */ func (g *Graph) AddDep(vertexID, depID string, method Kind, isRef bool, typeKind reflect.Kind) error { switch typeKind { @@ -178,8 +179,8 @@ func (g *Graph) addInterfaceDep(vertexID, depID string, method Kind, isRef bool) //append depID vertex for j := 0; j < len(depVertices[i].Dependencies); j++ { - tmpId := depVertices[i].Dependencies[i].Id - if tmpId == vertex.Id { + tmpID := depVertices[i].Dependencies[i].ID + if tmpID == vertex.ID { return nil } } @@ -231,16 +232,18 @@ func (g *Graph) addStructDep(vertexID, depID string, method Kind, isRef bool) er // vertex should always present vertex := g.GetVertex(vertexID) if vertex == nil { - panic("vertex should be in the graph") + return errors.New("vertex should be in the graph") } // but depVertex can be represented like foo2.S2 (vertexID) or like foo2.DB (vertex foo2.S2, dependency foo2.DB) depVertex := g.GetVertex(depID) if depVertex == nil { - // here can be only 1 Dep for the struct, or PANIC!!! - depVertex = g.FindProviders(depID)[0] - } - if depVertex == nil { - return fmt.Errorf("can't find dep: %s for the vertex: %s", depID, vertexID) + tmp := g.FindProviders(depID) + if len(tmp) > 0 { + // here can be only 1 Dep for the struct, or PANIC!!! + depVertex = g.FindProviders(depID)[0] + } else { + return fmt.Errorf("can't find dep: %s for the vertex: %s", depID, vertexID) + } } // add Dependency into the List @@ -250,8 +253,8 @@ func (g *Graph) addStructDep(vertexID, depID string, method Kind, isRef bool) er // append depID vertex for i := 0; i < len(depVertex.Dependencies); i++ { - tmpId := depVertex.Dependencies[i].Id - if tmpId == vertex.Id { + tmpID := depVertex.Dependencies[i].ID + if tmpID == vertex.ID { return nil } } @@ -261,25 +264,55 @@ func (g *Graph) addStructDep(vertexID, depID string, method Kind, isRef bool) er return nil } -func (g *Graph) AddVertex(vertexId string, vertexIface interface{}, meta Meta) { - g.VerticesMap[vertexId] = &Vertex{ - Id: vertexId, +// reset vertices to initial state +func (g *Graph) Reset(vertex *Vertex) []*Vertex { + // restore number of dependencies for the root + vertex.NumOfDeps = len(vertex.Dependencies) + vertex.Visiting = false + vertex.Visited = false + vertices := make([]*Vertex, 0, 5) + vertices = append(vertices, vertex) + + tmp := make(map[string]*Vertex) + + g.depthFirstSearch(vertex.Dependencies, tmp) + + for _, v := range tmp { + vertices = append(vertices, v) + } + return vertices +} + +// actually this is DFS just to reset all vertices to initial state after topological sort +func (g *Graph) depthFirstSearch(deps []*Vertex, tmp map[string]*Vertex) { + for i := 0; i < len(deps); i++ { + deps[i].Visited = false + deps[i].Visiting = false + deps[i].NumOfDeps = len(deps) + tmp[deps[i].ID] = deps[i] + g.depthFirstSearch(deps[i].Dependencies, tmp) + } +} + +func (g *Graph) AddVertex(vertexID string, vertexIface interface{}, meta Meta) { + g.VerticesMap[vertexID] = &Vertex{ + ID: vertexID, Iface: vertexIface, Meta: meta, Dependencies: nil, } - g.Vertices = append(g.Vertices, g.VerticesMap[vertexId]) + g.Vertices = append(g.Vertices, g.VerticesMap[vertexID]) } func (g *Graph) GetVertex(id string) *Vertex { return g.VerticesMap[id] } -func (g *Graph) FindProviders(depId string) []*Vertex { +func (g *Graph) FindProviders(depID string) []*Vertex { ret := make([]*Vertex, 0, 2) for i := 0; i < len(g.Vertices); i++ { - for providerId := range g.Vertices[i].Provides { - if depId == providerId { + for providerID := range g.Vertices[i].Provides { + if depID == providerID { ret = append(ret, g.Vertices[i]) } } diff --git a/tests/cascade_test.go b/tests/cascade_test.go index 6dc21c6..10690de 100644 --- a/tests/cascade_test.go +++ b/tests/cascade_test.go @@ -10,6 +10,9 @@ import ( "github.com/spiral/cascade/tests/foo7" "github.com/spiral/cascade/tests/foo8" "github.com/spiral/cascade/tests/foo9" + "github.com/spiral/cascade/tests/registers/named/randominterface" + "github.com/spiral/cascade/tests/registers/named/registers" + "github.com/spiral/cascade/tests/registers/named/registersfail" "github.com/stretchr/testify/assert" "github.com/spiral/cascade" @@ -31,7 +34,7 @@ func TestCascade_Init_OK(t *testing.T) { assert.NoError(t, c.Register(&foo6.S6Interface{})) assert.NoError(t, c.Init()) - err, res := c.Serve() + res, err := c.Serve() assert.NoError(t, err) go func() { @@ -60,7 +63,7 @@ func TestCascade_Interfaces_OK(t *testing.T) { t.Fatal(err) } - err, res := c.Serve() + res, err := c.Serve() assert.NoError(t, err) go func() { @@ -85,7 +88,7 @@ func TestCascade_Init_1_Element(t *testing.T) { assert.NoError(t, c.Register(&foo1.S1One{})) assert.NoError(t, c.Init()) - err, res := c.Serve() + res, err := c.Serve() assert.NoError(t, err) go func() { @@ -111,7 +114,7 @@ func TestCascade_ProvidedValueButNeedPointer(t *testing.T) { assert.NoError(t, c.Register(&foo4.S4V{})) assert.NoError(t, c.Init()) - err, res := c.Serve() + res, err := c.Serve() assert.NoError(t, err) go func() { @@ -152,7 +155,7 @@ func TestCascade_Serve_Err(t *testing.T) { t.Fatal(err) } - err, res := c.Serve() + res, err := c.Serve() if err != nil { t.Fatal(err) } @@ -192,7 +195,7 @@ func TestCascade_Serve_Retry_Err(t *testing.T) { assert.NoError(t, c.Register(&foo1.S1ServeErr{})) // should produce an error during the Serve assert.NoError(t, c.Init()) - err, res := c.Serve() + res, err := c.Serve() assert.NoError(t, err) // we can't be sure, what node will be processed first @@ -243,7 +246,7 @@ func TestCascade_Serve_Retry_100_Err(t *testing.T) { assert.NoError(t, c.Register(&foo1.S1ServeErr{})) // should produce an error during the Serve assert.NoError(t, c.Init()) - err, res := c.Serve() + res, err := c.Serve() assert.NoError(t, err) // we can't be sure, what node will be processed first @@ -291,7 +294,7 @@ func TestCascade_Serve_Retry_100_With_Random_Err(t *testing.T) { assert.NoError(t, c.Register(&foo1.S1ServeErr{})) // should produce an error during the Serve assert.NoError(t, c.Init()) - err, res := c.Serve() + res, err := c.Serve() assert.NoError(t, err) // we can't be sure, what node will be processed first @@ -339,7 +342,6 @@ func TestCascade_PrimitiveType_Err(t *testing.T) { assert.NoError(t, c.Stop()) } - func TestCascade_InterfacesDepends_Ok(t *testing.T) { c, err := cascade.NewContainer(cascade.DebugLevel) assert.NoError(t, err) @@ -350,9 +352,58 @@ func TestCascade_InterfacesDepends_Ok(t *testing.T) { assert.NoError(t, c.Init()) - err, _ = c.Serve() + _, err = c.Serve() + assert.NoError(t, err) + + assert.NoError(t, c.Stop()) +} + +func TestCascade_NamedProvides_Ok(t *testing.T) { + c, err := cascade.NewContainer(cascade.DebugLevel) assert.NoError(t, err) + assert.NoError(t, c.Register(®isters.Foo11{})) + assert.NoError(t, c.Register(®isters.Foo10{})) + + assert.NoError(t, c.Init()) + + _, err = c.Serve() + assert.NoError(t, err) assert.NoError(t, c.Stop()) -} \ No newline at end of file +} + +func TestCascade_NamedProvides_NotImplement_Ok(t *testing.T) { + c, err := cascade.NewContainer(cascade.DebugLevel) + assert.NoError(t, err) + + assert.NoError(t, c.Register(&randominterface.Foo1{})) + assert.NoError(t, c.Register(&randominterface.Foo{})) + + assert.NoError(t, c.Init()) + + _, err = c.Serve() + assert.NoError(t, err) + + assert.NoError(t, c.Stop()) +} + +func TestCascade_NamedProvides_WrongType_Fail(t *testing.T) { + defer func() { + if r := recover(); r != nil { + println("test should panic") + } + }() + c, err := cascade.NewContainer(cascade.DebugLevel) + assert.NoError(t, err) + + assert.NoError(t, c.Register(®istersfail.Foo1{})) + assert.NoError(t, c.Register(®istersfail.Foo{})) + + assert.Error(t, c.Init()) + + _, err = c.Serve() + assert.NoError(t, err) + + assert.NoError(t, c.Stop()) +} diff --git a/tests/foo1/foo1_init_err.go b/tests/foo1/foo1_init_err.go index b6d6ad1..1f7644e 100644 --- a/tests/foo1/foo1_init_err.go +++ b/tests/foo1/foo1_init_err.go @@ -9,13 +9,11 @@ import ( type S1Err struct { } - // No deps func (s *S1Err) Init(s2 *foo2.S2Err) error { return errors.New("s1 test init error") } - func (s *S1Err) Serve() chan error { errCh := make(chan error, 1) return errCh @@ -23,4 +21,4 @@ func (s *S1Err) Serve() chan error { func (s *S1Err) Stop() error { return nil -} \ No newline at end of file +} diff --git a/tests/foo1/foo1_serve_error.go b/tests/foo1/foo1_serve_error.go index b8f4e71..959c645 100644 --- a/tests/foo1/foo1_serve_error.go +++ b/tests/foo1/foo1_serve_error.go @@ -8,7 +8,6 @@ import ( type S1ServeErr struct { } - // No deps func (s *S1ServeErr) Init(s2 *foo2.S2, db *foo4.DB) error { return nil diff --git a/tests/foo2/foo2.go b/tests/foo2/foo2.go index 67f5539..de54a42 100644 --- a/tests/foo2/foo2.go +++ b/tests/foo2/foo2.go @@ -37,4 +37,4 @@ func (s2 *S2) Serve() chan error { func (s2 *S2) Stop() error { return nil -} \ No newline at end of file +} diff --git a/tests/foo3/foo3.go b/tests/foo3/foo3.go index 6b77524..51a54fe 100644 --- a/tests/foo3/foo3.go +++ b/tests/foo3/foo3.go @@ -30,4 +30,4 @@ func (s3 *S3) Serve() chan error { func (s3 *S3) Stop() error { return nil -} \ No newline at end of file +} diff --git a/tests/foo3/foo3_serve_error.go b/tests/foo3/foo3_serve_error.go index c5b0999..025961e 100644 --- a/tests/foo3/foo3_serve_error.go +++ b/tests/foo3/foo3_serve_error.go @@ -30,4 +30,4 @@ func (s3 *S3ServeError) Serve() chan error { func (s3 *S3ServeError) Stop() error { return nil -} \ No newline at end of file +} diff --git a/tests/foo4/foo4.go b/tests/foo4/foo4.go index c20a720..fd64ccd 100644 --- a/tests/foo4/foo4.go +++ b/tests/foo4/foo4.go @@ -19,12 +19,12 @@ func (s *S4) Init(foo5 foo5.S5) error { // But provide some func (s *S4) Provides() []interface{} { return []interface{}{ - s.CreateAnotherDb, + s.CreateAnotherDB, } } // this is the same type but different packages -func (s *S4) CreateAnotherDb() (*DB, error) { +func (s *S4) CreateAnotherDB() (*DB, error) { return &DB{ Name: "", }, nil diff --git a/tests/foo4/foo4ServeError.go b/tests/foo4/foo4ServeError.go index 55c117d..142e469 100644 --- a/tests/foo4/foo4ServeError.go +++ b/tests/foo4/foo4ServeError.go @@ -10,7 +10,6 @@ import ( type S4ServeError struct { } - // No deps func (s *S4ServeError) Init(s5 foo5.S5) error { return nil @@ -19,12 +18,12 @@ func (s *S4ServeError) Init(s5 foo5.S5) error { // But provide some func (s *S4ServeError) Provides() []interface{} { return []interface{}{ - s.CreateAnotherDb, + s.CreateAnotherDB, } } // this is the same type but different packages -func (s *S4ServeError) CreateAnotherDb() (*DB, error) { +func (s *S4ServeError) CreateAnotherDB() (*DB, error) { return &DB{ Name: "", }, nil diff --git a/tests/foo4/foo4_value.go b/tests/foo4/foo4_value.go index 1af2328..e4c8105 100644 --- a/tests/foo4/foo4_value.go +++ b/tests/foo4/foo4_value.go @@ -15,12 +15,12 @@ func (s *S4V) Init() error { // But provide some func (s *S4V) Provides() []interface{} { return []interface{}{ - s.CreateAnotherDb, + s.CreateAnotherDB, } } // this is the same type but different packages -func (s *S4V) CreateAnotherDb() (DBV, error) { +func (s *S4V) CreateAnotherDB() (DBV, error) { return DBV{ Name: "", }, nil diff --git a/tests/foo5/foo5.go b/tests/foo5/foo5.go index ddedbe0..d1cef73 100644 --- a/tests/foo5/foo5.go +++ b/tests/foo5/foo5.go @@ -12,8 +12,6 @@ func (s *S5) Init() error { return nil } - - func (s *S5) Configure() error { return nil } @@ -29,4 +27,4 @@ func (s *S5) Close() error { func (s *S5) Stop() error { return nil -} \ No newline at end of file +} diff --git a/tests/foo5/foo5_interfaces.go b/tests/foo5/foo5_interfaces.go index d0223a9..2c4d33f 100644 --- a/tests/foo5/foo5_interfaces.go +++ b/tests/foo5/foo5_interfaces.go @@ -11,8 +11,6 @@ func (s *S5Interface) Init(fooer foo6.FooReader) error { return nil } - - func (s *S5Interface) Configure() error { return nil } @@ -28,4 +26,4 @@ func (s *S5Interface) Close() error { func (s *S5Interface) Stop() error { return nil -} \ No newline at end of file +} diff --git a/tests/foo7/foo7_plugin.go b/tests/foo7/foo7_plugin.go index a1df091..9ba450f 100644 --- a/tests/foo7/foo7_plugin.go +++ b/tests/foo7/foo7_plugin.go @@ -3,7 +3,6 @@ package foo7 import "net/http" type Foo7 struct { - } func (f7 *Foo7) Init() error { @@ -23,4 +22,4 @@ func (f7 *Foo7) AddMiddleware(handler http.Handler) http.HandlerFunc { return func(writer http.ResponseWriter, request *http.Request) { handler.ServeHTTP(writer, request) } -} \ No newline at end of file +} diff --git a/tests/foo8/foo8_plugin.go b/tests/foo8/foo8_plugin.go index deb3577..c672d98 100644 --- a/tests/foo8/foo8_plugin.go +++ b/tests/foo8/foo8_plugin.go @@ -3,7 +3,6 @@ package foo8 import "net/http" type Foo8 struct { - } func (f8 *Foo8) Init() error { @@ -23,4 +22,4 @@ func (f8 *Foo8) AddMiddleware(handler http.Handler) http.HandlerFunc { return func(writer http.ResponseWriter, request *http.Request) { handler.ServeHTTP(writer, request) } -} \ No newline at end of file +} diff --git a/tests/foo9/foo9_http.go b/tests/foo9/foo9_http.go index 8d0ea5b..49ab605 100644 --- a/tests/foo9/foo9_http.go +++ b/tests/foo9/foo9_http.go @@ -5,10 +5,10 @@ import ( ) type Foo9 struct { - mdwr []HttpMiddleware + mdwr []HTTPMiddleware } -type HttpMiddleware interface { +type HTTPMiddleware interface { AddMiddleware(h http.Handler) http.HandlerFunc } @@ -36,7 +36,7 @@ func (f9 *Foo9) Depends() []interface{} { } } -func (f9 *Foo9) AddMiddleware(m HttpMiddleware) error { +func (f9 *Foo9) AddMiddleware(m HTTPMiddleware) error { f9.mdwr = append(f9.mdwr, m) return nil } diff --git a/tests/named_registers/foo10.go b/tests/named_registers/foo10.go deleted file mode 100644 index 2c60f60..0000000 --- a/tests/named_registers/foo10.go +++ /dev/null @@ -1,19 +0,0 @@ -package named_registers - -type Foo10 struct { - -} - -func (f *Foo10) Init() error { - return nil -} - -func (f *Foo10) Serve() chan error { - errCh := make(chan error) - return errCh -} - -func (f *Foo10) Stop() error { - return nil -} - diff --git a/tests/named_registers/foo11.go b/tests/named_registers/foo11.go deleted file mode 100644 index 59d0e06..0000000 --- a/tests/named_registers/foo11.go +++ /dev/null @@ -1,19 +0,0 @@ -package named_registers - -type Foo11 struct { - -} - -func (f *Foo11) Init() error { - return nil -} - -func (f *Foo11) Serve() chan error { - errCh := make(chan error) - return errCh -} - -func (f *Foo11) Stop() error { - return nil -} - diff --git a/tests/registers/named/randominterface/foo.go b/tests/registers/named/randominterface/foo.go new file mode 100644 index 0000000..4e51800 --- /dev/null +++ b/tests/registers/named/randominterface/foo.go @@ -0,0 +1,26 @@ +package randominterface + +type Foo struct { +} + +type SuperInterface interface { + Super() string +} + +func (f *Foo) Init(db DB) error { + println(db.Name) + return nil +} + +func (f *Foo) Serve() chan error { + errCh := make(chan error) + return errCh +} + +func (f *Foo) Stop() error { + return nil +} + +func (f *Foo) Super() string { + return "SUPER -> " +} diff --git a/tests/registers/named/randominterface/foo1.go b/tests/registers/named/randominterface/foo1.go new file mode 100644 index 0000000..1586cbf --- /dev/null +++ b/tests/registers/named/randominterface/foo1.go @@ -0,0 +1,37 @@ +package randominterface + +type Foo1 struct { +} + +type DB struct { + Name string +} + +func (f *Foo1) Init() error { + return nil +} + +func (f *Foo1) Serve() chan error { + errCh := make(chan error) + return errCh +} + +func (f *Foo1) Stop() error { + return nil +} + +// But provide some +func (f *Foo1) Provides() []interface{} { + return []interface{}{ + f.ProvideDB, + } +} + +// this is the same type but different packages +// foo10 invokes foo11 +// foo11 should get the foo10 name or provide vertex id +func (f *Foo1) ProvideDB(super SuperInterface) (*DB, error) { + return &DB{ + Name: super.Super() + "ME", + }, nil +} diff --git a/tests/registers/named/registers/foo10.go b/tests/registers/named/registers/foo10.go new file mode 100644 index 0000000..6bdd687 --- /dev/null +++ b/tests/registers/named/registers/foo10.go @@ -0,0 +1,23 @@ +package registers + +type Foo10 struct { +} + +func (f *Foo10) Init(db DB, db2 DB2) error { + println(db.Name) + println(db2.Name) + return nil +} + +func (f *Foo10) Serve() chan error { + errCh := make(chan error) + return errCh +} + +func (f *Foo10) Stop() error { + return nil +} + +func (f *Foo10) Name() string { + return "My name is Foo10, friend!" +} diff --git a/tests/registers/named/registers/foo11.go b/tests/registers/named/registers/foo11.go new file mode 100644 index 0000000..0052de0 --- /dev/null +++ b/tests/registers/named/registers/foo11.go @@ -0,0 +1,53 @@ +package registers + +import "github.com/spiral/cascade" + +type Foo11 struct { +} + +type DB struct { + Name string +} + +type DB2 struct { + Name string +} + +func (f *Foo11) Init() error { + return nil +} + +func (f *Foo11) Serve() chan error { + errCh := make(chan error) + return errCh +} + +func (f *Foo11) Stop() error { + return nil +} + +// But provide some +func (f *Foo11) Provides() []interface{} { + return []interface{}{ + f.ProvideDB, + f.ProvideDB2, + } +} + +// this is the same type but different packages +// foo10 invokes foo11 +// foo11 should get the foo10 name or provide vertex id +func (f *Foo11) ProvideDB(name cascade.Named) (*DB, error) { + return &DB{ + Name: name.Name(), + }, nil +} + +// this is the same type but different packages +// foo10 invokes foo11 +// foo11 should get the foo10 name or provide vertex id +func (f *Foo11) ProvideDB2(name cascade.Named, name2 cascade.Named) (*DB2, error) { + return &DB2{ + Name: name.Name() + "; " + name2.Name(), + }, nil +} diff --git a/tests/registers/named/registersfail/foo.go b/tests/registers/named/registersfail/foo.go new file mode 100644 index 0000000..0ee7d6e --- /dev/null +++ b/tests/registers/named/registersfail/foo.go @@ -0,0 +1,18 @@ +package registersfail + +type Foo struct { +} + +func (f *Foo) Init(db DB) error { + println(db.Name) + return nil +} + +func (f *Foo) Serve() chan error { + errCh := make(chan error) + return errCh +} + +func (f *Foo) Stop() error { + return nil +} diff --git a/tests/registers/named/registersfail/foo1.go b/tests/registers/named/registersfail/foo1.go new file mode 100644 index 0000000..ba698e7 --- /dev/null +++ b/tests/registers/named/registersfail/foo1.go @@ -0,0 +1,40 @@ +package registersfail + +type Foo1 struct { +} + +type S struct { +} + +type DB struct { + Name string +} + +func (f *Foo1) Init() error { + return nil +} + +func (f *Foo1) Serve() chan error { + errCh := make(chan error) + return errCh +} + +func (f *Foo1) Stop() error { + return nil +} + +// But provide some +func (f *Foo1) Provides() []interface{} { + return []interface{}{ + f.ProvideDB, + } +} + +// this is the same type but different packages +// foo10 invokes foo11 +// foo11 should get the foo10 name or provide vertex id +func (f *Foo1) ProvideDB(s S) (*DB, error) { + return &DB{ + Name: "", + }, nil +}