func (fm *FileMgr) setupNatsOptions() { if !fm.certs.skipTLS { err := fm.certs.certLoad() if err != nil { panic(err) } } o := []nats.Option{} o = append(o, nats.MaxReconnects(-1)) // -1 => keep trying forever o = append(o, nats.ReconnectWait(2*time.Second)) o = append(o, nats.Name("archiver")) o = append(o, nats.ErrorHandler(func(c *nats.Conn, s *nats.Subscription, e error) { fm.NatsAsyncErrCh <- asyncErr{conn: c, sub: s, err: e} })) o = append(o, nats.DisconnectHandler(func(conn *nats.Conn) { fm.NatsConnDisconCh <- conn })) o = append(o, nats.ReconnectHandler(func(conn *nats.Conn) { fm.NatsConnReconCh <- conn })) o = append(o, nats.ClosedHandler(func(conn *nats.Conn) { fm.NatsConnClosedCh <- conn })) if !fm.certs.skipTLS { o = append(o, nats.Secure(&fm.certs.tlsConfig)) o = append(o, fm.certs.rootCA) } fm.opts = o }
func TestCallbacksOrder(t *testing.T) { authS, authSOpts := RunServerWithConfig("./configs/tls.conf") defer authS.Shutdown() s := RunDefaultServer() defer s.Shutdown() firstDisconnect := true dtime1 := time.Time{} dtime2 := time.Time{} rtime := time.Time{} atime1 := time.Time{} atime2 := time.Time{} ctime := time.Time{} cbErrors := make(chan error, 20) reconnected := make(chan bool) closed := make(chan bool) asyncErr := make(chan bool, 2) recvCh := make(chan bool, 2) recvCh1 := make(chan bool) recvCh2 := make(chan bool) dch := func(nc *nats.Conn) { if err := isRunningInAsyncCBDispatcher(); err != nil { cbErrors <- err return } time.Sleep(100 * time.Millisecond) if firstDisconnect { firstDisconnect = false dtime1 = time.Now() } else { dtime2 = time.Now() } } rch := func(nc *nats.Conn) { if err := isRunningInAsyncCBDispatcher(); err != nil { cbErrors <- err reconnected <- true return } time.Sleep(50 * time.Millisecond) rtime = time.Now() reconnected <- true } ech := func(nc *nats.Conn, sub *nats.Subscription, err error) { if err := isRunningInAsyncCBDispatcher(); err != nil { cbErrors <- err asyncErr <- true return } if sub.Subject == "foo" { time.Sleep(20 * time.Millisecond) atime1 = time.Now() } else { atime2 = time.Now() } asyncErr <- true } cch := func(nc *nats.Conn) { if err := isRunningInAsyncCBDispatcher(); err != nil { cbErrors <- err closed <- true return } ctime = time.Now() closed <- true } url := net.JoinHostPort(authSOpts.Host, strconv.Itoa(authSOpts.Port)) url = "nats://" + url + "," + nats.DefaultURL nc, err := nats.Connect(url, nats.DisconnectHandler(dch), nats.ReconnectHandler(rch), nats.ClosedHandler(cch), nats.ErrorHandler(ech), nats.ReconnectWait(50*time.Millisecond), nats.DontRandomize()) if err != nil { t.Fatalf("Unable to connect: %v\n", err) } defer nc.Close() ncp, err := nats.Connect(nats.DefaultURL, nats.ReconnectWait(50*time.Millisecond)) if err != nil { t.Fatalf("Unable to connect: %v\n", err) } defer ncp.Close() // Wait to make sure that if we have closed (incorrectly) the // asyncCBDispatcher during the connect process, this is caught here. time.Sleep(time.Second) s.Shutdown() s = RunDefaultServer() defer s.Shutdown() if err := Wait(reconnected); err != nil { t.Fatal("Did not get the reconnected callback") } var sub1 *nats.Subscription var sub2 *nats.Subscription recv := func(m *nats.Msg) { // Signal that one message is received recvCh <- true // We will now block if m.Subject == "foo" { <-recvCh1 } else { <-recvCh2 } m.Sub.Unsubscribe() } sub1, err = nc.Subscribe("foo", recv) if err != nil { t.Fatalf("Unable to create subscription: %v\n", err) } sub1.SetPendingLimits(1, 100000) sub2, err = nc.Subscribe("bar", recv) if err != nil { t.Fatalf("Unable to create subscription: %v\n", err) } sub2.SetPendingLimits(1, 100000) nc.Flush() ncp.Publish("foo", []byte("test")) ncp.Publish("bar", []byte("test")) ncp.Flush() // Wait notification that message were received err = Wait(recvCh) if err == nil { err = Wait(recvCh) } if err != nil { t.Fatal("Did not receive message") } for i := 0; i < 2; i++ { ncp.Publish("foo", []byte("test")) ncp.Publish("bar", []byte("test")) } ncp.Flush() if err := Wait(asyncErr); err != nil { t.Fatal("Did not get the async callback") } if err := Wait(asyncErr); err != nil { t.Fatal("Did not get the async callback") } close(recvCh1) close(recvCh2) nc.Close() if err := Wait(closed); err != nil { t.Fatal("Did not get the close callback") } if len(cbErrors) > 0 { t.Fatalf("%v", <-cbErrors) } if (dtime1 == time.Time{}) || (dtime2 == time.Time{}) || (rtime == time.Time{}) || (atime1 == time.Time{}) || (atime2 == time.Time{}) || (ctime == time.Time{}) { t.Fatalf("Some callbacks did not fire:\n%v\n%v\n%v\n%v\n%v\n%v", dtime1, rtime, atime1, atime2, dtime2, ctime) } if rtime.Before(dtime1) || dtime2.Before(rtime) || atime2.Before(atime1) || ctime.Before(atime2) { t.Fatalf("Wrong callback order:\n%v\n%v\n%v\n%v\n%v\n%v", dtime1, rtime, atime1, atime2, dtime2, ctime) } }
func Test003ArchiverAcknowledgesStorage(t *testing.T) { cv.Convey("given a running gnatsd, the archiver should store messages to disk and acknowledge their storage on the 'servicename.storage-ack.(hostname)' subject.", t, func() { user := "******" pw := "password" host := "127.0.0.1" port := 4444 serverList := fmt.Sprintf("nats://%v:%v@%v:%v", user, pw, host, port) // start yourself an embedded gnatsd server opts := server.Options{ Host: host, Port: port, Username: user, Password: pw, Trace: true, Debug: true, //NoLog: true, //NoSigs: true, } gnats := gnatsd.RunServer(&opts) gnats.SetLogger(&Logger{}, true, true) //logger := log.New(os.Stderr, "gnatsd: ", log.LUTC|log.Ldate|log.Ltime|log.Lmicroseconds|log.Llongfile) defer func() { p("calling gnats.Shutdown()") gnats.Shutdown() // when done }() addr := fmt.Sprintf("%v:%v", host, port) if !PortIsBound(addr) { panic("port not bound " + addr) } // start client asyncHandler := nats.ErrorHandler(func(c *nats.Conn, s *nats.Subscription, e error) { fmt.Printf("\n *** async error handler sees error: '%s'\n", e) panic(e) }) p("about to connect with client") nc, err := nats.Connect(serverList, asyncHandler) panicOn(err) defer nc.Close() // prep data p("prepping data") streamName := "test" data1 := []byte("data1") tm1, err := time.Parse(time.RFC3339, "2016-01-01T00:00:00Z") panicOn(err) frame1, err := ts.NewFrame(tm1, ts.EvUtf8, 0, 0, data1) panicOn(err) framed, err := frame1.Marshal(nil) panicOn(err) // subscribe to reply in advance of publishing archive request gotAck := make(chan *nats.Msg) nc.Subscribe(ServiceName+".storage-ack.>", func(msgNats *nats.Msg) { p(ServiceName+".storage-ack received msg: '%#v'", msgNats) select { case <-gotAck: // already closed; don't do it again p(ServiceName + ".storage-ack already closed, skipping this time") default: p(ServiceName + ".storage-ack closing gotAck") close(gotAck) } }) // start an archiver to catch our request tmp, err := ioutil.TempDir("", "test-archiver-filemgr") panicOn(err) defer os.RemoveAll(tmp) fm := NewFileMgr(&ArchiverConfig{WriteDir: tmp, ServerList: serverList}) go func() { err := fm.Run() panicOn(err) }() <-fm.Ready p("archiver_test: fm.Ready received") defer fm.Stop() // make the achiving request: write data to server subj := ServiceName + ".archive." + streamName err = nc.Publish(subj, framed) if err != nil { panic(fmt.Errorf("Got an error on nc.Publish(): %+v\n", err)) } nc.Flush() p("Published to subject '%s' %v bytes", subj, len(framed)) reply, err := nc.Request(subj, framed, 1000*time.Millisecond) if err != nil { p("\n ----------->>>>>>> Request got err back: '%s'\n", err) panic(fmt.Errorf("Error in Request: %v\n", err)) } p("003ArchiverAck test sent request, got reply: '%#v' with Data '%s'", reply, string(reply.Data)) cv.So(strings.HasPrefix(reply.Subject, "_INBOX."), cv.ShouldBeTrue) // verify reply or panic after timeout timeout := 2 * time.Second select { case <-gotAck: // cool p("successfully got ack!") case <-time.After(timeout): panic(fmt.Errorf("timeout after %v waiting for reply", timeout)) } }) }