github.com/moleculer-go/moleculer@v0.3.3/registry/registry_test.go (about)

     1  package registry_test
     2  
     3  import (
     4  	"os"
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/moleculer-go/cupaloy/v2"
     9  	bus "github.com/moleculer-go/goemitter"
    10  	"github.com/moleculer-go/moleculer"
    11  	"github.com/moleculer-go/moleculer/broker"
    12  	"github.com/moleculer-go/moleculer/transit/memory"
    13  	. "github.com/onsi/ginkgo"
    14  	. "github.com/onsi/gomega"
    15  	log "github.com/sirupsen/logrus"
    16  )
    17  
    18  var logLevel = "fatal"
    19  var snap = cupaloy.New(cupaloy.FailOnUpdate(os.Getenv("UPDATE_SNAPSHOTS") == "true"))
    20  
    21  func createPrinterBroker(mem *memory.SharedMemory) broker.ServiceBroker {
    22  	broker := broker.New(&moleculer.Config{
    23  		DiscoverNodeID: func() string { return "node_printerBroker" },
    24  		LogLevel:       logLevel,
    25  		TransporterFactory: func() interface{} {
    26  			transport := memory.Create(log.WithField("transport", "memory"), mem)
    27  			return &transport
    28  		},
    29  	})
    30  
    31  	broker.Publish(moleculer.ServiceSchema{
    32  		Name: "printer",
    33  		Actions: []moleculer.Action{
    34  			{
    35  				Name: "print",
    36  				Handler: func(context moleculer.Context, params moleculer.Payload) interface{} {
    37  					context.Logger().Info("print action invoked. params: ", params)
    38  					return params.Value()
    39  				},
    40  			},
    41  		},
    42  		Events: []moleculer.Event{
    43  			{
    44  				Name: "printed",
    45  				Handler: func(context moleculer.Context, params moleculer.Payload) {
    46  					context.Logger().Info("printer.printed --> ", params.Value())
    47  				},
    48  			},
    49  		},
    50  	})
    51  
    52  	return (*broker)
    53  }
    54  
    55  func createScannerBroker(mem *memory.SharedMemory) broker.ServiceBroker {
    56  	broker := broker.New(&moleculer.Config{
    57  		DiscoverNodeID: func() string { return "node_scannerBroker" },
    58  		LogLevel:       logLevel,
    59  		TransporterFactory: func() interface{} {
    60  			transport := memory.Create(log.WithField("transport", "memory"), mem)
    61  			return &transport
    62  		},
    63  	})
    64  	broker.Publish(moleculer.ServiceSchema{
    65  		Name: "scanner",
    66  		Actions: []moleculer.Action{
    67  			{
    68  				Name: "scan",
    69  				Handler: func(context moleculer.Context, params moleculer.Payload) interface{} {
    70  					context.Logger().Info("scan action invoked!")
    71  
    72  					return params.Value()
    73  				},
    74  			},
    75  		},
    76  		Events: []moleculer.Event{
    77  			{
    78  				Name: "scanned",
    79  				Handler: func(context moleculer.Context, params moleculer.Payload) {
    80  					context.Logger().Info("scanner.scanned --> ", params.Value())
    81  				},
    82  			},
    83  		},
    84  	})
    85  
    86  	return (*broker)
    87  }
    88  
    89  func createCpuBroker(mem *memory.SharedMemory) broker.ServiceBroker {
    90  	broker := broker.New(&moleculer.Config{
    91  		DiscoverNodeID: func() string { return "node_cpuBroker" },
    92  		LogLevel:       logLevel,
    93  		TransporterFactory: func() interface{} {
    94  			transport := memory.Create(log.WithField("transport", "memory"), mem)
    95  			return &transport
    96  		},
    97  	})
    98  	broker.Publish(moleculer.ServiceSchema{
    99  		Name: "cpu",
   100  		Actions: []moleculer.Action{
   101  			{
   102  				Name: "compute",
   103  				Handler: func(context moleculer.Context, params moleculer.Payload) interface{} {
   104  					context.Logger().Debug("compute action invoked!")
   105  
   106  					scanResult := <-context.Call("scanner.scan", params)
   107  
   108  					context.Logger().Debug("scanResult: ", scanResult)
   109  
   110  					printResult := <-context.Call("printer.print", scanResult)
   111  
   112  					return printResult
   113  				},
   114  			},
   115  		},
   116  	})
   117  	broker.Publish(moleculer.ServiceSchema{
   118  		Name: "printer",
   119  		Actions: []moleculer.Action{
   120  			{
   121  				Name: "print",
   122  				Handler: func(context moleculer.Context, params moleculer.Payload) interface{} {
   123  					return params.Value()
   124  				},
   125  			},
   126  		},
   127  		Events: []moleculer.Event{
   128  			{
   129  				Name: "printed",
   130  				Handler: func(context moleculer.Context, params moleculer.Payload) {
   131  					context.Logger().Info("printer.printed --> ", params.Value())
   132  				},
   133  			},
   134  		},
   135  	})
   136  	return (*broker)
   137  }
   138  
   139  func hasNode(list []moleculer.Payload, nodeID string) bool {
   140  	for _, p := range list {
   141  		if p.Get("nodeID").String() == nodeID {
   142  			return true
   143  		}
   144  	}
   145  	return false
   146  }
   147  
   148  var _ = Describe("Registry", func() {
   149  
   150  	Describe("Auto discovery", func() {
   151  		//failed with timeout
   152  		It("3 brokers should auto discovery and perform local and remote Calls", func() {
   153  			mem := &memory.SharedMemory{}
   154  			printerBroker := createPrinterBroker(mem)
   155  			var serviceAdded, serviceRemoved []moleculer.Payload
   156  			events := bus.Construct()
   157  			addedMutex := &sync.Mutex{}
   158  			printerBroker.Publish(moleculer.ServiceSchema{
   159  				Name: "internal-consumer",
   160  				Events: []moleculer.Event{
   161  					moleculer.Event{
   162  						Name: "$registry.service.added",
   163  						Handler: func(ctx moleculer.Context, params moleculer.Payload) {
   164  							addedMutex.Lock()
   165  							defer addedMutex.Unlock()
   166  							serviceAdded = append(serviceAdded, params)
   167  							go events.EmitSync("$registry.service.added", serviceAdded)
   168  						},
   169  					},
   170  					moleculer.Event{
   171  						Name: "$registry.service.removed",
   172  						Handler: func(ctx moleculer.Context, params moleculer.Payload) {
   173  							serviceRemoved = append(serviceRemoved, params)
   174  							go events.EmitSync("$registry.service.removed", serviceRemoved)
   175  						},
   176  					},
   177  				},
   178  			})
   179  			onEvent := func(event string, callback func(list []moleculer.Payload, cancel func())) {
   180  				events.On(event, func(v ...interface{}) {
   181  					list := v[0].([]moleculer.Payload)
   182  					callback(list, func() {
   183  						events = bus.Construct()
   184  					})
   185  				})
   186  			}
   187  
   188  			Expect(printerBroker.LocalNode().GetID()).Should(Equal("node_printerBroker"))
   189  
   190  			scannerBroker := createScannerBroker(mem)
   191  			Expect(scannerBroker.LocalNode().GetID()).Should(Equal("node_scannerBroker"))
   192  
   193  			cpuBroker := createCpuBroker(mem)
   194  			Expect(cpuBroker.LocalNode().GetID()).Should(Equal("node_cpuBroker"))
   195  
   196  			printerBroker.Start()
   197  
   198  			printText := "TEXT TO PRINT"
   199  			printResult := <-printerBroker.Call("printer.print", printText)
   200  			Expect(printResult.Error()).Should(BeNil())
   201  			Expect(printResult.Value()).Should(Equal(printText))
   202  
   203  			scanText := "TEXT TO SCAN"
   204  
   205  			scanResult := <-printerBroker.Call("scanner.scan", printText)
   206  			Expect(scanResult.IsError()).Should(BeTrue())
   207  
   208  			step := make(chan bool)
   209  			onEvent("$registry.service.added", func(list []moleculer.Payload, cancel func()) {
   210  				if hasNode(serviceAdded, "node_scannerBroker") {
   211  					cancel()
   212  					step <- true
   213  				}
   214  			})
   215  			scannerBroker.Start()
   216  			<-step
   217  
   218  			scanResult = <-scannerBroker.Call("scanner.scan", scanText)
   219  			Expect(scanResult.IsError()).ShouldNot(Equal(true))
   220  			Expect(scanResult.Value()).Should(Equal(scanText))
   221  
   222  			scanResult = <-printerBroker.Call("scanner.scan", scanText)
   223  			Expect(scanResult.IsError()).ShouldNot(Equal(true))
   224  			Expect(scanResult.Value()).Should(Equal(scanText))
   225  
   226  			serviceAdded = []moleculer.Payload{}
   227  			step = make(chan bool)
   228  			onEvent("$registry.service.added", func(list []moleculer.Payload, cancel func()) {
   229  				if hasNode(serviceAdded, "node_cpuBroker") {
   230  					cancel()
   231  					step <- true
   232  				}
   233  			})
   234  			cpuBroker.Start()
   235  			<-step
   236  
   237  			cpuBroker.WaitForActions("scanner.scan", "printer.print")
   238  			time.Sleep(time.Millisecond)
   239  
   240  			contentToCompute := "Some long long text ..."
   241  			computeResult := <-printerBroker.Call("cpu.compute", contentToCompute)
   242  			Expect(computeResult.Error()).Should(Succeed())
   243  			Expect(computeResult.Value()).Should(Equal(contentToCompute))
   244  
   245  			step = make(chan bool)
   246  			onEvent("$registry.service.removed", func(list []moleculer.Payload, cancel func()) {
   247  				if hasNode(serviceRemoved, "node_scannerBroker") {
   248  					cancel()
   249  					step <- true
   250  				}
   251  			})
   252  
   253  			//stopping broker B
   254  			scannerBroker.Stop()
   255  
   256  			//wait services from node node_scannerBroker to be removed
   257  			<-step
   258  
   259  			Expect(func() {
   260  				<-scannerBroker.Call("scanner.scan", scanText)
   261  			}).Should(Panic()) //broker B is stopped ... so it should panic
   262  
   263  		})
   264  	})
   265  
   266  	Describe("Namespace", func() {
   267  
   268  		It("Services across namespaces cannos see each other", func() {
   269  
   270  			mem := &memory.SharedMemory{}
   271  
   272  			devBroker := broker.New(&moleculer.Config{
   273  				DiscoverNodeID: func() string { return "node1_devBroker" },
   274  				LogLevel:       logLevel,
   275  				Namespace:      "dev",
   276  				TransporterFactory: func() interface{} {
   277  					transport := memory.Create(log.WithField("transport", "memory"), mem)
   278  					return &transport
   279  				},
   280  				RequestTimeout: 1 * time.Second,
   281  			})
   282  
   283  			stageBroker := broker.New(&moleculer.Config{
   284  				DiscoverNodeID: func() string { return "node1_stageBroker" },
   285  				LogLevel:       logLevel,
   286  				Namespace:      "stage",
   287  				TransporterFactory: func() interface{} {
   288  					transport := memory.Create(log.WithField("transport", "memory"), mem)
   289  					return &transport
   290  				},
   291  				RequestTimeout: 1 * time.Second,
   292  			})
   293  
   294  			stage2Broker := broker.New(&moleculer.Config{
   295  				DiscoverNodeID: func() string { return "node1_stage2Broker" },
   296  				LogLevel:       logLevel,
   297  				Namespace:      "stage",
   298  				TransporterFactory: func() interface{} {
   299  					transport := memory.Create(log.WithField("transport", "memory"), mem)
   300  					return &transport
   301  				},
   302  				RequestTimeout: 1 * time.Second,
   303  			})
   304  
   305  			//alarm service - prints the alarm and return the namespace :)
   306  			alarmService := func(namemspace string) moleculer.ServiceSchema {
   307  				return moleculer.ServiceSchema{
   308  					Name: "alarm",
   309  					Actions: []moleculer.Action{
   310  						{
   311  							Name: "bell",
   312  							Handler: func(context moleculer.Context, params moleculer.Payload) interface{} {
   313  								context.Logger().Info("alarm.bell ringing !!! namemspace: ", namemspace)
   314  								return namemspace
   315  							},
   316  						},
   317  					},
   318  				}
   319  			}
   320  
   321  			//available in the dev namespace only
   322  			devOnlyService := moleculer.ServiceSchema{
   323  				Name: "devOnly",
   324  				Actions: []moleculer.Action{
   325  					{
   326  						Name: "code",
   327  						Handler: func(context moleculer.Context, params moleculer.Payload) interface{} {
   328  							return "🧠"
   329  						},
   330  					},
   331  				},
   332  			}
   333  
   334  			devBroker.Publish(alarmService("dev"))
   335  			devBroker.Publish(devOnlyService)
   336  			devBroker.Start()
   337  
   338  			stageBroker.Start()
   339  			stage2Broker.Publish(moleculer.ServiceSchema{
   340  				Name: "stage2",
   341  				Actions: []moleculer.Action{
   342  					{
   343  						Name: "where",
   344  						Handler: func(context moleculer.Context, params moleculer.Payload) interface{} {
   345  							return "🌏"
   346  						},
   347  					},
   348  				},
   349  			})
   350  			stage2Broker.Start()
   351  
   352  			devAlarm := <-devBroker.Call("alarm.bell", nil)
   353  			Expect(devAlarm.IsError()).Should(BeFalse())
   354  			Expect(devAlarm.String()).Should(Equal("dev"))
   355  
   356  			code := <-devBroker.Call("devOnly.code", nil)
   357  			Expect(code.IsError()).Should(BeFalse())
   358  			Expect(code.String()).Should(Equal("🧠"))
   359  
   360  			//alarm.bell should not be accessible to the stage broker
   361  			stageAlarm := <-stageBroker.Call("alarm.bell", nil)
   362  			Expect(stageAlarm.IsError()).Should(BeTrue())
   363  			Expect(stageAlarm.Error().Error()).Should(Equal("Registry - endpoint not found for actionName: alarm.bell namespace: stage"))
   364  
   365  			stageBroker.Publish(alarmService("stage"))
   366  			stageAlarm = <-stageBroker.Call("alarm.bell", nil)
   367  			Expect(stageAlarm.IsError()).Should(BeFalse())
   368  			Expect(stageAlarm.String()).Should(Equal("stage"))
   369  
   370  			code = <-stageBroker.Call("good.code", nil)
   371  			Expect(code.IsError()).Should(BeTrue())
   372  			Expect(code.Error().Error()).Should(Equal("Registry - endpoint not found for actionName: good.code namespace: stage"))
   373  
   374  			time.Sleep(time.Second)
   375  			//make sure 2 brokers on the same namespace can talk to each other
   376  			msg := <-stageBroker.Call("stage2.where", nil)
   377  			Expect(msg.String()).Should(Equal("🌏"))
   378  
   379  			devBroker.Stop()
   380  			stageBroker.Stop()
   381  			stage2Broker.Stop()
   382  
   383  		})
   384  	})
   385  })