func TestMissingKey(t *testing.T) { origin, err := Server.Origin() if err != nil { t.Fatalf("Error initializing test server: %#v", err) } conn, deviceId, err := client.Dial(origin) if err != nil { t.Fatalf("Error dialing origin: %#v", err) } defer conn.Close() channelId, endpoint, err := conn.Subscribe() if err != nil { t.Fatalf("Error subscribing to channel: %#v", err) } uri, err := url.ParseRequestURI(endpoint) if err != nil { t.Fatalf("Error parsing push endpoint %#v: %#v", endpoint, err) } keyDevice, keyChannel, ok := endpointIds(uri) if !ok { t.Errorf("Incomplete push endpoint: %#v", endpoint) } if keyDevice != deviceId { t.Errorf("Mismatched device IDs: got %#v; want %#v", keyDevice, deviceId) } if keyChannel != channelId { t.Errorf("Mismatched channel IDs: got %#v; want %#v", keyChannel, channelId) } newURI, _ := uri.Parse(fmt.Sprintf("/update/%s.", keyDevice)) err = client.Notify(newURI.String(), 1) clientErr, ok := err.(client.Error) if !ok { t.Errorf("Type assertion failed for endpoint error: %#v", err) } else if clientErr.Status() != 404 { t.Errorf("Unexpected endpoint status: got %#v; want 404", clientErr.Status()) } }
func roundTrip(conn *client.Conn, deviceId, channelId, endpoint string, version int64) (err error) { stopChan, errChan := make(chan bool), make(chan error) defer close(stopChan) go func() { err := client.Notify(endpoint, version) if err != nil { err = fmt.Errorf("Error sending update %d on channel %q: %s", version, channelId, err) } select { case <-stopChan: case errChan <- err: } }() go func() { var ( pendingAccepts []client.Update err error ) timeout := time.After(15 * time.Second) for ok := true; ok; { var packet client.Packet select { case ok = <-stopChan: case <-timeout: ok = false err = client.ErrTimedOut case packet, ok = <-conn.Packets: if !ok { err = client.ErrChanClosed break } updates, _ := packet.(client.ServerUpdates) if len(updates) == 0 { continue } pendingAccepts = append(pendingAccepts, updates...) var ( update client.Update hasUpdate bool ) for _, update = range updates { if update.ChannelId == channelId && update.Version >= version { hasUpdate = true break } } if !hasUpdate { continue } ok = false if update.Version != version { err = fmt.Errorf("Wrong update version: got %d; want %d", update.Version, version) break } } } if acceptErr := conn.AcceptBatch(pendingAccepts); acceptErr != nil { err = fmt.Errorf("Error acknowledging updates: %s", acceptErr) } select { case <-stopChan: case errChan <- err: } }() for i := 0; i < 2; i++ { if err := <-errChan; err != nil { return err } } return nil }
func TestUnregisterRace(t *testing.T) { origin, err := testServer.Origin() if err != nil { t.Fatalf("Error initializing test server: %#v", err) } socket, err := ws.Dial(origin, "", origin) if err != nil { t.Fatalf("Error dialing origin: %#v", err) } connId, err := id.Generate() if err != nil { t.Fatalf("Error generating connection ID: %#v", err) } // Spool all notifications, including those received on dregistered channels. conn := client.NewConn(socket, connId, true) defer conn.Close() if _, err = conn.WriteHelo(""); err != nil { t.Fatalf("Error writing handshake request: %#v", err) } defer conn.Purge() channelId, endpoint, err := conn.Subscribe() if err != nil { t.Fatalf("Error subscribing to channel: %#v", err) } if !isValidEndpoint(endpoint) { t.Fatalf("Invalid push endpoint for channel %#v: %#v", channelId, endpoint) } version := time.Now().UTC().Unix() var notifyWait sync.WaitGroup signal, errors := make(chan bool), make(chan error) notifyWait.Add(2) go func() { defer notifyWait.Done() timeout := time.After(1 * time.Minute) var ( isRemoved bool pendingTimer <-chan time.Time ) for ok := true; ok; { var packet client.Packet select { case ok = <-signal: case <-timeout: ok = false errors <- client.ErrTimedOut case <-pendingTimer: ok = false // Read the update, but don't call AcceptUpdate(). case packet, ok = <-conn.Packets: if !ok { err = client.ErrChanClosed break } var ( updates client.ServerUpdates hasUpdates bool ) if updates, hasUpdates = packet.(client.ServerUpdates); !hasUpdates { break } var ( update client.Update hasUpdate bool ) for _, update = range updates { if hasUpdate = update.ChannelId == channelId; hasUpdate { break } } if !hasUpdate { break } var err error if update.Version != version { err = fmt.Errorf("Expected update %#v, not %#v", version, update.Version) } else if isRemoved { err = fmt.Errorf("Update %#v resent on deregistered channel %#v", update.Version, update.ChannelId) } else { err = conn.Unregister(channelId) } if err != nil { ok = false errors <- err break } isRemoved = true timeout = nil // Queued updates should be sent immediately. pendingTimer = time.After(1 * time.Second) } } }() go func() { defer notifyWait.Done() select { case <-signal: case errors <- client.Notify(endpoint, version): } }() go func() { notifyWait.Wait() close(errors) }() for err = range errors { if err != nil { close(signal) t.Fatal(err) } } }
func TestBroadcastStaticLocator(t *testing.T) { if testing.Short() { t.Skip("Skipping router test in short mode") } cServer := &TestServer{Name: "c", LogLevel: 0} cApp, cConn, err := cServer.Dial() if err != nil { t.Fatalf("Error starting test application %q: %s", cServer.Name, err) } defer cServer.Stop() defer cConn.Close() defer cConn.Purge() bServer := &TestServer{ Name: "b", LogLevel: 0, Contacts: []string{cApp.Router().URL()}, } bApp, bConn, err := bServer.Dial() if err != nil { t.Fatalf("Error starting test application %q: %s", bServer.Name, err) } defer bServer.Stop() defer bConn.Close() defer bConn.Purge() aServer := &TestServer{ Name: "a", LogLevel: 0, Contacts: []string{ cApp.Router().URL(), bApp.Router().URL(), }, } aApp, aConn, err := aServer.Dial() if err != nil { t.Fatalf("Error starting test application %q: %s", aServer.Name, err) } defer aServer.Stop() defer aConn.Close() defer aConn.Purge() // Subscribe to a channel on c. cChan, cEndpoint, err := cConn.Subscribe() if err != nil { t.Fatalf("Error subscribing to channel: %s", err) } stopChan := make(chan bool) defer close(stopChan) errChan := make(chan error) notifyApp := func(app *Application, channelId, endpoint string, count int) { uri, err := url.Parse(endpoint) if err != nil { select { case <-stopChan: case errChan <- err: } return } uri.Host = app.EndpointHandler().Listener().Addr().String() for i := 1; i <= count; i++ { if err = client.Notify(uri.String(), int64(i)); err != nil { break } } select { case <-stopChan: case errChan <- err: } } // Wait for updates on c. go func() { var err error for i := 0; i < 10; i++ { var updates []client.Update if updates, err = cConn.ReadBatch(); err != nil { break } if err = cConn.AcceptBatch(updates); err != nil { break } } select { case <-stopChan: case errChan <- err: } }() // Send an update via a. go notifyApp(aApp, cChan, cEndpoint, 5) // Send an update via b. go notifyApp(bApp, cChan, cEndpoint, 5) for i := 0; i < 3; i++ { if err := <-errChan; err != nil { t.Fatal(err) } } }