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())
	}
}
Exemple #2
0
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
}
Exemple #3
0
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)
		}
	}
}