github.com/moleculer-go/moleculer@v0.3.3/broker/broker_internals_test.go (about)

     1  package broker
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  
     7  	"time"
     8  
     9  	"github.com/moleculer-go/cupaloy/v2"
    10  	"github.com/moleculer-go/moleculer"
    11  	"github.com/moleculer-go/moleculer/context"
    12  	"github.com/moleculer-go/moleculer/test"
    13  	"github.com/moleculer-go/moleculer/transit/memory"
    14  	. "github.com/onsi/ginkgo"
    15  	. "github.com/onsi/gomega"
    16  	log "github.com/sirupsen/logrus"
    17  )
    18  
    19  var snap = cupaloy.New(cupaloy.FailOnUpdate(os.Getenv("UPDATE_SNAPSHOTS") == "true"))
    20  
    21  func hasKey(m map[string]moleculer.Payload, k string) bool {
    22  	_, foundKey := m[k]
    23  	return foundKey
    24  }
    25  
    26  var _ = Describe("Broker Internals", func() {
    27  
    28  	Describe("Broker events", func() {
    29  		It("Should trigger Local and remote events", func() {
    30  			logLevel := "ERROR"
    31  			verse := "3 little birds..."
    32  			chorus := "don't worry..."
    33  			mem := &memory.SharedMemory{}
    34  			baseConfig := &moleculer.Config{
    35  				LogLevel: logLevel,
    36  				TransporterFactory: func() interface{} {
    37  					transport := memory.Create(log.WithField("transport", "memory"), mem)
    38  					return &transport
    39  				},
    40  			}
    41  			counters := test.Counter()
    42  
    43  			soundsBroker := New(baseConfig, &moleculer.Config{
    44  				DiscoverNodeID: func() string { return "SoundsBroker" },
    45  			})
    46  			soundsBroker.Publish(moleculer.ServiceSchema{
    47  				Name: "music",
    48  				Actions: []moleculer.Action{
    49  					moleculer.Action{
    50  						Name: "start",
    51  						Handler: func(ctx moleculer.Context, verse moleculer.Payload) interface{} {
    52  							ctx.Logger().Debug(" ** !!! ### music.start ### !!! ** ")
    53  							ctx.Emit("music.verse", verse)
    54  							counters.Inc(ctx.(*context.Context).BrokerDelegates().LocalNode().GetID(), "music.start")
    55  							return nil
    56  						},
    57  					},
    58  					moleculer.Action{
    59  						Name: "end",
    60  						Handler: func(ctx moleculer.Context, chorus moleculer.Payload) interface{} {
    61  							ctx.Emit("music.chorus", chorus)
    62  							counters.Inc(ctx.(*context.Context).BrokerDelegates().LocalNode().GetID(), "music.end")
    63  							return nil
    64  						},
    65  					},
    66  				},
    67  				Events: []moleculer.Event{
    68  					moleculer.Event{
    69  						Name: "music.verse",
    70  						Handler: func(ctx moleculer.Context, verse moleculer.Payload) {
    71  							ctx.Logger().Debug("music.verse --> ", verse.String())
    72  							ctx.Emit("music.chorus", verse)
    73  							counters.Inc(ctx.(*context.Context).BrokerDelegates().LocalNode().GetID(), "music.music.verse")
    74  						},
    75  					},
    76  					moleculer.Event{
    77  						Name: "music.chorus",
    78  						Handler: func(ctx moleculer.Context, chorus moleculer.Payload) {
    79  							ctx.Logger().Debug("music.chorus --> ", chorus.String())
    80  							counters.Inc(ctx.(*context.Context).BrokerDelegates().LocalNode().GetID(), "music.music.chorus")
    81  						},
    82  					},
    83  				},
    84  			})
    85  			djService := moleculer.ServiceSchema{
    86  				Name:         "dj",
    87  				Dependencies: []string{"music"},
    88  				Events: []moleculer.Event{
    89  					moleculer.Event{
    90  						Name: "music.verse",
    91  						Handler: func(ctx moleculer.Context, verse moleculer.Payload) {
    92  							ctx.Logger().Debug("DJ music.verse --> ", verse.String())
    93  							ctx.Emit("music.chorus", verse)
    94  							counters.Inc(ctx.(*context.Context).BrokerDelegates().LocalNode().GetID(), "dj.music.verse")
    95  						},
    96  					},
    97  					moleculer.Event{
    98  						Name: "music.chorus",
    99  						Handler: func(ctx moleculer.Context, chorus moleculer.Payload) {
   100  							ctx.Logger().Debug("DJ  music.chorus --> ", chorus.String())
   101  							counters.Inc(ctx.(*context.Context).BrokerDelegates().LocalNode().GetID(), "dj.music.chorus")
   102  						},
   103  					},
   104  					moleculer.Event{
   105  						Name: "music.tone",
   106  						Handler: func(ctx moleculer.Context, ring moleculer.Payload) {
   107  							ctx.Logger().Debug("DJ  music.tone ring --> ", ring.String())
   108  							counters.Inc(ctx.(*context.Context).BrokerDelegates().LocalNode().GetID(), "dj.music.tone")
   109  						},
   110  					},
   111  				},
   112  			}
   113  			soundsBroker.Publish(djService)
   114  
   115  			// soundsBroker.delegates.EmitEvent = func(context moleculer.BrokerContext) {
   116  			// 	entries := soundsBroker.registry.LoadBalanceEvent(context)
   117  			// 	fmt.Println("entries -> ", entries)
   118  			// 	Expect(snap.SnapshotMulti("entries_1-music.verse_2-music.chorus", entries)).Should(Succeed())
   119  			// }
   120  			soundsBroker.Start()
   121  			Expect(snap.SnapshotMulti("soundsBroker-KnownNodes", soundsBroker.registry.KnownNodes())).Should(Succeed())
   122  
   123  			//Scenario: action music.start will emit music.verse wich emits music.chorus - becuase there are 2 listeners for music.serve
   124  			//there should be too emits to music.chorus
   125  			<-soundsBroker.Call("music.start", verse)
   126  
   127  			Expect(counters.Check("music.music.verse", 1)).ShouldNot(HaveOccurred())
   128  			Expect(counters.Check("dj.music.verse", 1)).ShouldNot(HaveOccurred())
   129  
   130  			Expect(counters.Check("music.music.chorus", 2)).ShouldNot(HaveOccurred()) //failed here
   131  			Expect(counters.Check("dj.music.chorus", 2)).ShouldNot(HaveOccurred())
   132  
   133  			//Scenario: music.end will emit music.chorus once.
   134  			<-soundsBroker.Call("music.end", chorus)
   135  
   136  			Expect(counters.Check("music.music.verse", 1)).ShouldNot(HaveOccurred())
   137  			Expect(counters.Check("dj.music.verse", 1)).ShouldNot(HaveOccurred())
   138  
   139  			Expect(counters.Check("music.music.chorus", 3)).ShouldNot(HaveOccurred())
   140  			Expect(counters.Check("dj.music.chorus", 3)).ShouldNot(HaveOccurred())
   141  
   142  			visualBroker := New(baseConfig, &moleculer.Config{
   143  				DiscoverNodeID: func() string { return "VisualBroker" },
   144  			})
   145  			vjService := moleculer.ServiceSchema{
   146  				Name:         "vj",
   147  				Dependencies: []string{"music", "dj"},
   148  				Events: []moleculer.Event{
   149  					moleculer.Event{
   150  						Name: "music.verse",
   151  						Handler: func(ctx moleculer.Context, verse moleculer.Payload) {
   152  							ctx.Logger().Debug("VJ music.verse --> ", verse.String())
   153  							counters.Inc(ctx.(*context.Context).BrokerDelegates().LocalNode().GetID(), "vj.music.verse")
   154  						},
   155  					},
   156  					moleculer.Event{
   157  						Name: "music.chorus",
   158  						Handler: func(ctx moleculer.Context, chorus moleculer.Payload) {
   159  							ctx.Logger().Debug("VJ  music.chorus --> ", chorus.String())
   160  							counters.Inc(ctx.(*context.Context).BrokerDelegates().LocalNode().GetID(), "vj.music.chorus")
   161  						},
   162  					},
   163  					moleculer.Event{
   164  						Name: "music.tone",
   165  						Handler: func(ctx moleculer.Context, ring moleculer.Payload) {
   166  							ctx.Logger().Debug("VJ  music.tone ring --> ", ring.String())
   167  							counters.Inc(ctx.(*context.Context).BrokerDelegates().LocalNode().GetID(), "vj.music.tone")
   168  						},
   169  					},
   170  				},
   171  			}
   172  			visualBroker.Publish(vjService)
   173  			visualBroker.Publish(moleculer.ServiceSchema{
   174  				Name:         "visualBrokerService",
   175  				Dependencies: []string{"music"},
   176  			})
   177  			visualBroker.Start()
   178  			visualBroker.WaitForNodes("SoundsBroker")
   179  			Expect(snap.SnapshotMulti("visualBroker-KnownNodes", visualBroker.registry.KnownNodes())).Should(Succeed())
   180  
   181  			counters.Clear()
   182  			time.Sleep(time.Millisecond)
   183  			//Scenario: same action music.start as before, but now we added a new broker and new service.
   184  			visualBroker.Call("music.start", verse)
   185  
   186  			time.Sleep(time.Millisecond)
   187  			Expect(counters.Check("music.start", 1)).ShouldNot(HaveOccurred())
   188  			Expect(counters.Check("music.music.verse", 1)).ShouldNot(HaveOccurred())
   189  			Expect(counters.Check("dj.music.verse", 1)).ShouldNot(HaveOccurred())
   190  			Expect(counters.Check("vj.music.verse", 1)).ShouldNot(HaveOccurred())
   191  
   192  			Expect(counters.Check("music.music.chorus", 2)).ShouldNot(HaveOccurred())
   193  			Expect(counters.Check("dj.music.chorus", 2)).ShouldNot(HaveOccurred())
   194  			Expect(counters.Check("vj.music.chorus", 2)).ShouldNot(HaveOccurred())
   195  
   196  			<-visualBroker.Call("music.end", chorus)
   197  
   198  			Expect(counters.Check("music.end", 1)).ShouldNot(HaveOccurred())
   199  			Expect(counters.Check("music.music.verse", 1)).ShouldNot(HaveOccurred())
   200  			Expect(counters.Check("dj.music.verse", 1)).ShouldNot(HaveOccurred())
   201  			Expect(counters.Check("vj.music.verse", 1)).ShouldNot(HaveOccurred())
   202  
   203  			Expect(counters.Check("music.music.chorus", 3)).ShouldNot(HaveOccurred())
   204  			Expect(counters.Check("dj.music.chorus", 3)).ShouldNot(HaveOccurred())
   205  			Expect(counters.Check("vj.music.chorus", 3)).ShouldNot(HaveOccurred())
   206  
   207  			//add a second instance of the vj service, but only one should receive emit events.
   208  			aquaBroker := New(baseConfig, &moleculer.Config{
   209  				DiscoverNodeID: func() string { return "AquaBroker" },
   210  			})
   211  			aquaBroker.Publish(vjService)
   212  			aquaBroker.Publish(moleculer.ServiceSchema{
   213  				Name:         "aquaBrokerService",
   214  				Dependencies: []string{"music", "dj"},
   215  			})
   216  			aquaBroker.Start()
   217  			for {
   218  				if len(aquaBroker.registry.KnownNodes()) == 3 {
   219  					break
   220  				}
   221  				time.Sleep(time.Microsecond)
   222  			}
   223  			Expect(snap.SnapshotMulti("aquaBroker-KnownNodes", aquaBroker.registry.KnownNodes())).Should(Succeed())
   224  			for {
   225  				if len(aquaBroker.registry.KnownEventListeners(true)) == 11 {
   226  					break
   227  				}
   228  				time.Sleep(time.Microsecond)
   229  			}
   230  			Expect(snap.SnapshotMulti("aquaBroker-KnownEventListeners", aquaBroker.registry.KnownEventListeners(true))).Should(Succeed())
   231  
   232  			counters.Clear()
   233  
   234  			aquaBroker.Call("music.start", chorus)
   235  
   236  			Expect(counters.Check("music.start", 1)).ShouldNot(HaveOccurred())
   237  			Expect(counters.Check("music.music.verse", 1)).ShouldNot(HaveOccurred())
   238  			Expect(counters.Check("dj.music.verse", 1)).ShouldNot(HaveOccurred())
   239  			Expect(counters.Check("vj.music.verse", 1)).ShouldNot(HaveOccurred())
   240  
   241  			Expect(counters.Check("music.music.chorus", 2)).ShouldNot(HaveOccurred())
   242  			Expect(counters.Check("dj.music.chorus", 2)).ShouldNot(HaveOccurred()) //failed here
   243  			Expect(counters.Check("vj.music.chorus", 2)).ShouldNot(HaveOccurred())
   244  
   245  			<-visualBroker.Call("music.end", chorus)
   246  
   247  			Expect(counters.Check("music.end", 1)).ShouldNot(HaveOccurred())
   248  			Expect(counters.Check("music.music.verse", 1)).ShouldNot(HaveOccurred())
   249  			Expect(counters.Check("dj.music.verse", 1)).ShouldNot(HaveOccurred())
   250  			Expect(counters.Check("vj.music.verse", 1)).ShouldNot(HaveOccurred())
   251  
   252  			Expect(counters.Check("music.music.chorus", 3)).ShouldNot(HaveOccurred())
   253  			Expect(counters.Check("dj.music.chorus", 3)).ShouldNot(HaveOccurred())
   254  			Expect(counters.Check("vj.music.chorus", 3)).ShouldNot(HaveOccurred())
   255  
   256  			//add a second instance of the dj service
   257  			stormBroker := New(baseConfig, &moleculer.Config{
   258  				DiscoverNodeID: func() string { return "StormBroker" },
   259  			})
   260  			stormBroker.Publish(djService)
   261  			stormBroker.Start()
   262  			for {
   263  				if len(stormBroker.registry.KnownNodes()) == 4 {
   264  					break
   265  				}
   266  				time.Sleep(time.Microsecond)
   267  			}
   268  			Expect(snap.SnapshotMulti("stormBroker-KnownNodes", stormBroker.registry.KnownNodes())).Should(Succeed())
   269  			for {
   270  				if len(stormBroker.registry.KnownEventListeners(true)) == 14 {
   271  					break
   272  				}
   273  				time.Sleep(time.Microsecond)
   274  			}
   275  			Expect(snap.SnapshotMulti("stormBroker-KnownEventListeners", stormBroker.registry.KnownEventListeners(true))).Should(Succeed())
   276  
   277  			counters.Clear()
   278  
   279  			stormBroker.Call("music.start", verse)
   280  
   281  			Expect(counters.Check("music.start", 1)).ShouldNot(HaveOccurred())
   282  			Expect(counters.Check("music.music.verse", 1)).ShouldNot(HaveOccurred())
   283  			Expect(counters.Check("dj.music.verse", 1)).ShouldNot(HaveOccurred())
   284  			Expect(counters.Check("vj.music.verse", 1)).ShouldNot(HaveOccurred())
   285  
   286  			Expect(counters.Check("music.music.chorus", 2)).ShouldNot(HaveOccurred())
   287  			Expect(counters.Check("dj.music.chorus", 2)).ShouldNot(HaveOccurred())
   288  			Expect(counters.Check("vj.music.chorus", 2)).ShouldNot(HaveOccurred())
   289  
   290  			<-stormBroker.Call("music.end", chorus)
   291  
   292  			Expect(counters.Check("music.end", 1)).ShouldNot(HaveOccurred())
   293  			Expect(counters.Check("music.music.verse", 1)).ShouldNot(HaveOccurred())
   294  			Expect(counters.Check("dj.music.verse", 1)).ShouldNot(HaveOccurred())
   295  			Expect(counters.Check("vj.music.verse", 1)).ShouldNot(HaveOccurred())
   296  
   297  			Expect(counters.Check("music.music.chorus", 3)).ShouldNot(HaveOccurred())
   298  			Expect(counters.Check("dj.music.chorus", 3)).ShouldNot(HaveOccurred())
   299  			Expect(counters.Check("vj.music.chorus", 3)).ShouldNot(HaveOccurred())
   300  
   301  			counters.Clear()
   302  
   303  			//now broadcast and every music.tone event listener should receive it.
   304  			stormBroker.Broadcast("music.tone", "broad< storm >cast")
   305  
   306  			Expect(counters.Check("dj.music.tone", 2)).ShouldNot(HaveOccurred())
   307  			Expect(counters.Check("vj.music.tone", 2)).ShouldNot(HaveOccurred())
   308  
   309  			counters.Clear()
   310  
   311  			//emit and only 2 shuold be accounted
   312  			stormBroker.Emit("music.tone", "Emit< storm >cast")
   313  
   314  			Expect(counters.Check("dj.music.tone", 1)).ShouldNot(HaveOccurred())
   315  			Expect(counters.Check("vj.music.tone", 1)).ShouldNot(HaveOccurred())
   316  
   317  			//remove one dj service
   318  			stormBroker.Stop()
   319  			counters.Clear()
   320  			time.Sleep(time.Millisecond)
   321  
   322  			Expect(snap.SnapshotMulti("stormBroker-stopped-aquaBroker-KnownNodes", aquaBroker.registry.KnownNodes())).Should(Succeed())
   323  			Expect(snap.SnapshotMulti("stormBroker-stopped-visualBroker-KnownNodes", visualBroker.registry.KnownNodes())).Should(Succeed())
   324  			Expect(snap.SnapshotMulti("stormBroker-stopped-soundsBroker-KnownNodes", soundsBroker.registry.KnownNodes())).Should(Succeed())
   325  
   326  			aquaBroker.Broadcast("music.tone", "broad< aqua 1 >cast")
   327  
   328  			time.Sleep(time.Millisecond)
   329  			Expect(counters.Check("dj.music.tone", 1)).ShouldNot(HaveOccurred())
   330  			Expect(counters.Check("vj.music.tone", 2)).ShouldNot(HaveOccurred())
   331  
   332  			//remove the other dj service
   333  			soundsBroker.Stop()
   334  			counters.Clear()
   335  
   336  			Expect(snap.SnapshotMulti("soundsBroker-Stopped-aquaBroker-KnownNodes", aquaBroker.registry.KnownNodes())).Should(Succeed())
   337  			Expect(snap.SnapshotMulti("soundsBroker-Stopped-visualBroker-KnownNodes", visualBroker.registry.KnownNodes())).Should(Succeed())
   338  
   339  			aquaBroker.Broadcast("music.tone", "broad< aqua 2 >cast")
   340  
   341  			Expect(counters.Check("dj.music.tone", 0)).ShouldNot(HaveOccurred())
   342  			Expect(counters.Check("vj.music.tone", 2)).ShouldNot(HaveOccurred())
   343  
   344  			counters.Clear()
   345  			aquaBroker.Emit("music.tone", "Emit< aqua >cast")
   346  
   347  			Expect(counters.Check("dj.music.tone", 0)).ShouldNot(HaveOccurred())
   348  			Expect(counters.Check("vj.music.tone", 1)).ShouldNot(HaveOccurred())
   349  
   350  			visualBroker.Stop()
   351  			aquaBroker.Stop()
   352  
   353  		})
   354  	})
   355  
   356  	//TODO: MCalls current implementation works ?most of the time" :( ... enought to continue
   357  	//the dev of other features that need it.. but it need to be refactored so the tests pass everytime.. or maybe the issue is with the testing.
   358  	Describe("Broker.MCall", func() {
   359  
   360  		It("MCall on $node service actions with all params false", func() {
   361  			MCallTimeout := 20 * time.Second
   362  			actionHandler := func(result string) func(moleculer.Context, moleculer.Payload) interface{} {
   363  				return func(ctx moleculer.Context, param moleculer.Payload) interface{} {
   364  					result := fmt.Sprint("input: (", param.String(), " ) -> output: ( ", result, " )")
   365  					//fmt.Println("MCALL Action --> ", result)
   366  					return result
   367  				}
   368  			}
   369  			logLevel := "FATAL"
   370  			mem := &memory.SharedMemory{}
   371  			bkr1 := New(
   372  				&moleculer.Config{
   373  					MCallTimeout:   MCallTimeout,
   374  					LogLevel:       logLevel,
   375  					DiscoverNodeID: func() string { return "test-broker1" },
   376  					TransporterFactory: func() interface{} {
   377  						transport := memory.Create(log.WithField("transport", "memory"), mem)
   378  						return &transport
   379  					},
   380  				},
   381  			)
   382  			bkr1.Publish(moleculer.ServiceSchema{
   383  				Name: "music",
   384  				Actions: []moleculer.Action{
   385  					moleculer.Action{
   386  						Name:    "start",
   387  						Handler: actionHandler("start result"),
   388  					},
   389  					moleculer.Action{
   390  						Name:    "end",
   391  						Handler: actionHandler("end result"),
   392  					},
   393  				},
   394  			})
   395  
   396  			bkr2 := New(
   397  				&moleculer.Config{
   398  					MCallTimeout:   MCallTimeout,
   399  					LogLevel:       logLevel,
   400  					DiscoverNodeID: func() string { return "test-broker2" },
   401  					TransporterFactory: func() interface{} {
   402  						transport := memory.Create(log.WithField("transport", "memory"), mem)
   403  						return &transport
   404  					},
   405  				},
   406  			)
   407  			bkr2.Publish(moleculer.ServiceSchema{
   408  				Name:         "food",
   409  				Dependencies: []string{"music"},
   410  				Actions: []moleculer.Action{
   411  					moleculer.Action{
   412  						Name:    "lunch",
   413  						Handler: actionHandler("lunch result"),
   414  					},
   415  					moleculer.Action{
   416  						Name:    "dinner",
   417  						Handler: actionHandler("dinner result"),
   418  					},
   419  				},
   420  			})
   421  
   422  			bkr1.Start()
   423  			bkr2.Start()
   424  
   425  			mParams := map[string]map[string]interface{}{
   426  				"food-lunch": map[string]interface{}{
   427  					"action": "food.lunch",
   428  					"params": "lunch param",
   429  				},
   430  				"food-dinner": map[string]interface{}{
   431  					"action": "food.dinner",
   432  					"params": "dinner param",
   433  				},
   434  				"music-start": map[string]interface{}{
   435  					"action": "music.start",
   436  					"params": "start param",
   437  				},
   438  				"music-end": map[string]interface{}{
   439  					"action": "music.end",
   440  					"params": "end param",
   441  				},
   442  			}
   443  
   444  			mcallResults := <-bkr2.MCall(mParams)
   445  			Expect(hasKey(mcallResults, "music-start")).Should(BeTrue())
   446  			Expect(hasKey(mcallResults, "music-end")).Should(BeTrue())
   447  			Expect(hasKey(mcallResults, "food-dinner")).Should(BeTrue())
   448  			Expect(hasKey(mcallResults, "food-lunch")).Should(BeTrue())
   449  
   450  			mcallResults = <-bkr1.MCall(mParams)
   451  			Expect(hasKey(mcallResults, "music-start")).Should(BeTrue())
   452  			Expect(hasKey(mcallResults, "music-end")).Should(BeTrue())
   453  			Expect(hasKey(mcallResults, "food-dinner")).Should(BeTrue())
   454  			Expect(hasKey(mcallResults, "food-lunch")).Should(BeTrue())
   455  
   456  			bkr1.Stop()
   457  			bkr2.Stop()
   458  		})
   459  
   460  		// }
   461  
   462  		// orderResults := func(values map[string]moleculer.Payload) interface{} {
   463  		// 	result := make(map[string][]map[string]interface{})
   464  		// 	for key, payload := range values {
   465  		// 		orderBy := "name"
   466  		// 		if key == "nodes" {
   467  		// 			orderBy = "id"
   468  		// 		}
   469  		// 		result[key] = test.OrderMapArray(payload.MapArray(), orderBy)
   470  		// 	}
   471  		// 	return result
   472  		// }
   473  
   474  		// It("MCall on $node service actions with all params false",
   475  		// 	harness("all-false",
   476  		// 		map[string]interface{}{
   477  		// 			"withServices":  false,
   478  		// 			"withActions":   false,
   479  		// 			"onlyAvailable": false,
   480  		// 			"withEndpoints": false,
   481  		// 			"skipInternal":  false,
   482  		// 		}, orderResults))
   483  
   484  		// It("MCall on $node service actions with all params true",
   485  		// 	harness("all-true",
   486  		// 		map[string]interface{}{
   487  		// 			"withServices":  true,
   488  		// 			"withActions":   true,
   489  		// 			"onlyAvailable": true,
   490  		// 			"withEndpoints": true,
   491  		// 			"skipInternal":  true,
   492  		// 		}, orderResults))
   493  
   494  	})
   495  
   496  	Context("Middlewares", func() {
   497  
   498  		It("Should register user middlewares", func() {
   499  
   500  			config := moleculer.Config{DisableInternalMiddlewares: true}
   501  			bkr := New(&config)
   502  			Expect(bkr.middlewares.Has("Config")).Should(BeFalse())
   503  
   504  			config = moleculer.Config{
   505  				DisableInternalMiddlewares: true,
   506  				Middlewares: []moleculer.Middlewares{
   507  					map[string]moleculer.MiddlewareHandler{
   508  						"Config": func(params interface{}, next func(...interface{})) {
   509  							next()
   510  						},
   511  					},
   512  				},
   513  			}
   514  			bkr = New(&config)
   515  			Expect(bkr.middlewares.Has("Config")).Should(BeTrue())
   516  			Expect(bkr.middlewares.Has("anotherOne")).Should(BeFalse())
   517  		})
   518  
   519  		It("Should call Config middleware on Start and not change the config", func() {
   520  
   521  			ConfigCalls := 0
   522  			config := moleculer.Config{
   523  				DontWaitForNeighbours:      true,
   524  				DisableInternalMiddlewares: true,
   525  				Middlewares: []moleculer.Middlewares{
   526  					map[string]moleculer.MiddlewareHandler{
   527  						"Config": func(params interface{}, next func(...interface{})) {
   528  							ConfigCalls++
   529  							next()
   530  						},
   531  					},
   532  				},
   533  			}
   534  			bkr := New(&config)
   535  			Expect(bkr.middlewares.Has("Config")).Should(BeTrue())
   536  			bkr.Start()
   537  			Expect(ConfigCalls).Should(Equal(1))
   538  			bkr.Stop()
   539  		})
   540  
   541  		It("Should call Config middleware on Start and not change the config", func() {
   542  
   543  			ConfigCalls := 0
   544  			config := moleculer.Config{
   545  				DontWaitForNeighbours: true,
   546  				Metrics:               true,
   547  				Middlewares: []moleculer.Middlewares{
   548  					map[string]moleculer.MiddlewareHandler{
   549  						"Config": func(params interface{}, next func(...interface{})) {
   550  							Config := params.(moleculer.Config)
   551  							Config.Metrics = false
   552  							ConfigCalls++
   553  							next(Config)
   554  						},
   555  					},
   556  				},
   557  			}
   558  			Expect(config.Metrics).Should(BeTrue())
   559  			bkr := New(&config)
   560  			bkr.Start()
   561  			Expect(ConfigCalls).Should(Equal(1))
   562  			Expect(bkr.config.Metrics).Should(BeFalse())
   563  			bkr.Stop()
   564  		})
   565  
   566  	})
   567  
   568  	Describe("Publish()services...interface{}", func() {
   569  		It("should panic when passing invalid service", func() {
   570  			bkr := New()
   571  			Expect(func() {
   572  				bkr.Publish("some string")
   573  			}).Should(Panic())
   574  			Expect(func() {
   575  				bkr.Publish(10)
   576  			}).Should(Panic())
   577  			Expect(func() {
   578  				bkr.Publish(invalidObj{})
   579  			}).Should(Panic())
   580  			Expect(func() {
   581  				bkr.Publish(validService{})
   582  			}).ShouldNot(Panic())
   583  		})
   584  
   585  		It("should add service strict obj to broker when valid", func() {
   586  			bkr := New()
   587  			Expect(len(bkr.services)).Should(Equal(0))
   588  			bkr.Publish(validService{})
   589  			Expect(len(bkr.services)).Should(Equal(1))
   590  		})
   591  
   592  		It("should add service schema obj to broker", func() {
   593  			bkr := New()
   594  			Expect(len(bkr.services)).Should(Equal(0))
   595  			bkr.Publish(moleculer.ServiceSchema{Name: "service from schema"})
   596  			Expect(len(bkr.services)).Should(Equal(1))
   597  		})
   598  	})
   599  
   600  })
   601  
   602  type invalidObj struct {
   603  }
   604  
   605  type validService struct {
   606  }
   607  
   608  func (s validService) Name() string {
   609  	return "validService"
   610  }