func TestSendRouteInfoOnConnect(t *testing.T) { s, opts := runRouteServer(t) defer s.Shutdown() rc := createRouteConn(t, opts.Cluster.Host, opts.Cluster.Port) defer rc.Close() routeSend, routeExpect := setupRoute(t, rc, opts) buf := routeExpect(infoRe) info := server.Info{} if err := json.Unmarshal(buf[4:], &info); err != nil { t.Fatalf("Could not unmarshal route info: %v", err) } if !info.AuthRequired { t.Fatal("Expected to see AuthRequired") } if info.Port != opts.Cluster.Port { t.Fatalf("Received wrong information for port, expected %d, got %d", info.Port, opts.Cluster.Port) } // Need to send a different INFO than the one received, otherwise the server // will detect as a "cycle" and close the connection. info.ID = "RouteID" b, err := json.Marshal(info) if err != nil { t.Fatalf("Could not marshal test route info: %v", err) } infoJSON := fmt.Sprintf("INFO %s\r\n", b) routeSend(infoJSON) routeSend("PING\r\n") routeExpect(pongRe) }
func TestRouteResendsLocalSubsOnReconnect(t *testing.T) { s, opts := runRouteServer(t) defer s.Shutdown() client := createClientConn(t, opts.Host, opts.Port) defer client.Close() clientSend, clientExpect := setupConn(t, client) // Setup a local subscription, make sure it reaches. clientSend("SUB foo 1\r\n") clientSend("PING\r\n") clientExpect(pongRe) route := createRouteConn(t, opts.Cluster.Host, opts.Cluster.Port) defer route.Close() routeSend, routeExpect := setupRouteEx(t, route, opts, "ROUTE:4222") // Expect to see the local sub echoed through after we send our INFO. time.Sleep(50 * time.Millisecond) buf := routeExpect(infoRe) // Generate our own INFO so we can send one to trigger the local subs. info := server.Info{} if err := json.Unmarshal(buf[4:], &info); err != nil { t.Fatalf("Could not unmarshal route info: %v", err) } info.ID = "ROUTE:4222" b, err := json.Marshal(info) if err != nil { t.Fatalf("Could not marshal test route info: %v", err) } infoJSON := fmt.Sprintf("INFO %s\r\n", b) // Trigger the send of local subs. routeSend(infoJSON) routeExpect(subRe) // Close and then re-open route.Close() route = createRouteConn(t, opts.Cluster.Host, opts.Cluster.Port) defer route.Close() routeSend, routeExpect = setupRouteEx(t, route, opts, "ROUTE:4222") routeExpect(infoRe) routeSend(infoJSON) routeExpect(subRe) }
func TestRouteSendAsyncINFOToClients(t *testing.T) { f := func(opts *server.Options) { s := RunServer(opts) defer s.Shutdown() clientURL := net.JoinHostPort(opts.Host, strconv.Itoa(opts.Port)) oldClient := createClientConn(t, opts.Host, opts.Port) defer oldClient.Close() oldClientSend, oldClientExpect := setupConn(t, oldClient) oldClientSend("PING\r\n") oldClientExpect(pongRe) newClient := createClientConn(t, opts.Host, opts.Port) defer newClient.Close() newClientSend, newClientExpect := setupConnWithProto(t, newClient, clientProtoInfo) newClientSend("PING\r\n") newClientExpect(pongRe) // Check that even a new client does not receive an async INFO at this point // since there is no route created yet. expectNothing(t, newClient) routeID := "Server-B" createRoute := func() (net.Conn, sendFun, expectFun) { rc := createRouteConn(t, opts.Cluster.Host, opts.Cluster.Port) routeSend, routeExpect := setupRouteEx(t, rc, opts, routeID) buf := routeExpect(infoRe) info := server.Info{} if err := json.Unmarshal(buf[4:], &info); err != nil { t.Fatalf("Could not unmarshal route info: %v", err) } if len(info.ClientConnectURLs) == 0 { t.Fatal("Expected a list of URLs, got none") } if info.ClientConnectURLs[0] != clientURL { t.Fatalf("Expected ClientConnectURLs to be %q, got %q", clientURL, info.ClientConnectURLs[0]) } return rc, routeSend, routeExpect } sendRouteINFO := func(routeSend sendFun, routeExpect expectFun, urls []string) { routeInfo := server.Info{} routeInfo.ID = routeID routeInfo.Host = "localhost" routeInfo.Port = 5222 routeInfo.ClientConnectURLs = urls b, err := json.Marshal(routeInfo) if err != nil { t.Fatalf("Could not marshal test route info: %v", err) } infoJSON := fmt.Sprintf("INFO %s\r\n", b) routeSend(infoJSON) routeSend("PING\r\n") routeExpect(pongRe) } checkINFOReceived := func(client net.Conn, clientExpect expectFun, expectedURLs []string) { if opts.Cluster.NoAdvertise { expectNothing(t, client) return } buf := clientExpect(infoRe) info := server.Info{} if err := json.Unmarshal(buf[4:], &info); err != nil { t.Fatalf("Could not unmarshal route info: %v", err) } if !reflect.DeepEqual(info.ClientConnectURLs, expectedURLs) { t.Fatalf("Expected ClientConnectURLs to be %v, got %v", expectedURLs, info.ClientConnectURLs) } } // Create a route rc, routeSend, routeExpect := createRoute() defer rc.Close() // Send an INFO with single URL routeConnectURLs := []string{"localhost:5222"} sendRouteINFO(routeSend, routeExpect, routeConnectURLs) // Expect nothing for old clients expectNothing(t, oldClient) // Expect new client to receive an INFO (unless disabled) checkINFOReceived(newClient, newClientExpect, routeConnectURLs) // Disconnect and reconnect the route. rc.Close() rc, routeSend, routeExpect = createRoute() defer rc.Close() // Resend the same route INFO json, since there is no new URL, // no client should receive an INFO sendRouteINFO(routeSend, routeExpect, routeConnectURLs) // Expect nothing for old clients expectNothing(t, oldClient) // Expect nothing for new clients as well (no real update) expectNothing(t, newClient) // Now stop the route and restart with an additional URL rc.Close() rc, routeSend, routeExpect = createRoute() defer rc.Close() // Create a client not sending the CONNECT until after route is added clientNoConnect := createClientConn(t, opts.Host, opts.Port) defer clientNoConnect.Close() // Create a client that does not send the first PING yet clientNoPing := createClientConn(t, opts.Host, opts.Port) defer clientNoPing.Close() clientNoPingSend, clientNoPingExpect := setupConnWithProto(t, clientNoPing, clientProtoInfo) // The route now has an additional URL routeConnectURLs = append(routeConnectURLs, "localhost:7777") // This causes the server to add the route and send INFO to clients sendRouteINFO(routeSend, routeExpect, routeConnectURLs) // Expect nothing for old clients expectNothing(t, oldClient) // Expect new client to receive an INFO, and verify content as expected. checkINFOReceived(newClient, newClientExpect, routeConnectURLs) // Expect nothing yet for client that did not send the PING expectNothing(t, clientNoPing) // Now send the first PING clientNoPingSend("PING\r\n") // Should receive PONG followed by INFO // Receive PONG only first pongBuf := make([]byte, len("PONG\r\n")) clientNoPing.SetReadDeadline(time.Now().Add(2 * time.Second)) n, err := clientNoPing.Read(pongBuf) clientNoPing.SetReadDeadline(time.Time{}) if n <= 0 && err != nil { t.Fatalf("Error reading from conn: %v\n", err) } if !pongRe.Match(pongBuf) { t.Fatalf("Response did not match expected: \n\tReceived:'%q'\n\tExpected:'%s'\n", pongBuf, pongRe) } checkINFOReceived(clientNoPing, clientNoPingExpect, routeConnectURLs) // Have the client that did not send the connect do it now clientNoConnectSend, clientNoConnectExpect := setupConnWithProto(t, clientNoConnect, clientProtoInfo) // Send the PING clientNoConnectSend("PING\r\n") // Should receive PONG followed by INFO // Receive PONG only first clientNoConnect.SetReadDeadline(time.Now().Add(2 * time.Second)) n, err = clientNoConnect.Read(pongBuf) clientNoConnect.SetReadDeadline(time.Time{}) if n <= 0 && err != nil { t.Fatalf("Error reading from conn: %v\n", err) } if !pongRe.Match(pongBuf) { t.Fatalf("Response did not match expected: \n\tReceived:'%q'\n\tExpected:'%s'\n", pongBuf, pongRe) } checkINFOReceived(clientNoConnect, clientNoConnectExpect, routeConnectURLs) // Create a client connection and verify content of initial INFO contains array // (but empty if no advertise option is set) cli := createClientConn(t, opts.Host, opts.Port) defer cli.Close() buf := expectResult(t, cli, infoRe) js := infoRe.FindAllSubmatch(buf, 1)[0][1] var sinfo server.Info err = json.Unmarshal(js, &sinfo) if err != nil { t.Fatalf("Could not unmarshal INFO json: %v\n", err) } if opts.Cluster.NoAdvertise { if len(sinfo.ClientConnectURLs) != 0 { t.Fatalf("Expected ClientConnectURLs to be empty, got %v", sinfo.ClientConnectURLs) } } else if !reflect.DeepEqual(sinfo.ClientConnectURLs, routeConnectURLs) { t.Fatalf("Expected ClientConnectURLs to be %v, got %v", routeConnectURLs, sinfo.ClientConnectURLs) } } opts := LoadConfig("./configs/cluster.conf") for i := 0; i < 2; i++ { if i == 1 { opts.Cluster.NoAdvertise = true } f(opts) } }