Exemple #1
0
func (t caseTest) TestHelo() error {
	deviceId, err := id.Generate()
	if err != nil {
		return fmt.Errorf("On test %v, error generating device ID: %#v", t.CaseTestType, err)
	}
	addExistsHook(deviceId, true)
	defer removeExistsHook(deviceId)
	channelId, err := id.Generate()
	if err != nil {
		return fmt.Errorf("On test %v, error generating channel ID: %#v", t.CaseTestType, err)
	}
	origin, err := testServer.Origin()
	if err != nil {
		return fmt.Errorf("On test %v, error initializing test server: %#v", t.CaseTestType, err)
	}
	conn, err := client.DialOrigin(origin)
	if err != nil {
		return fmt.Errorf("On test %v, error dialing origin: %#v", t.CaseTestType, err)
	}
	defer conn.Close()
	defer conn.Purge()
	request := CaseHelo{t.CaseTestType, client.NewHelo(deviceId, []string{channelId}).(client.ClientHelo)}
	reply, err := conn.WriteRequest(request)
	if t.statusCode >= 200 && t.statusCode < 300 {
		if err != nil {
			return fmt.Errorf("On test %v, error writing handshake request: %#v", t.CaseTestType, err)
		}
		helo, ok := reply.(client.ServerHelo)
		if !ok {
			return fmt.Errorf("On test %v, type assertion failed for handshake reply: %#v", t.CaseTestType, reply)
		}
		if helo.StatusCode != t.statusCode {
			return fmt.Errorf("On test %v, unexpected reply status: got %#v; want %#v", t.CaseTestType, helo.StatusCode, t.statusCode)
		}
		if t.shouldReset {
			if helo.DeviceId == deviceId {
				return fmt.Errorf("On test %v, want new device ID; got %#v", t.CaseTestType, deviceId)
			}
			return nil
		}
		if helo.DeviceId != deviceId {
			return fmt.Errorf("On test %v, mismatched device ID: got %#v; want %#v", t.CaseTestType, helo.DeviceId, deviceId)
		}
		return nil
	}
	if err != io.EOF {
		return fmt.Errorf("On test %v, error writing handshake: got %#v; want io.EOF", t.CaseTestType, err)
	}
	err = conn.Close()
	clientErr, ok := err.(client.Error)
	if !ok {
		return fmt.Errorf("On test %v, type assertion failed for close error: %#v", t.CaseTestType, err)
	}
	if clientErr.Status() != t.statusCode {
		return fmt.Errorf("On test %v, unexpected close error status: got %#v; want %#v", t.CaseTestType, clientErr.Status(), t.statusCode)
	}
	return nil
}
Exemple #2
0
func reconnect(origin, deviceId, channelId, endpoint string) (err error) {
	socket, err := ws.Dial(origin, "", origin)
	if err != nil {
		return fmt.Errorf("Error dialing origin: %s", err)
	}
	connId, err := id.Generate()
	if err != nil {
		return fmt.Errorf("Error generating connection ID: %#v", err)
	}
	conn := client.NewConn(socket, connId, true)
	defer conn.Close()
	defer conn.Purge()
	actualId, err := conn.WriteHelo(deviceId, channelId)
	if err != nil {
		return fmt.Errorf("Error writing handshake request: %s", err)
	}
	if actualId != deviceId {
		return fmt.Errorf("Mismatched device IDs: got %q; want %q",
			actualId, deviceId)
	}
	if err = roundTrip(conn, deviceId, channelId, endpoint, 2); err != nil {
		return fmt.Errorf("Error sending notification after reconnect: %s", err)
	}
	return nil
}
Exemple #3
0
func TestPrematureUnregister(t *testing.T) {
	channelId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating channel ID: %#v", err)
	}
	origin, err := testServer.Origin()
	if err != nil {
		t.Fatalf("Error initializing test server: %#v", err)
	}
	conn, err := client.DialOrigin(origin)
	if err != nil {
		t.Fatalf("Error dialing origin: %#v", err)
	}
	defer conn.Close()
	defer conn.Purge()
	conn.RegisterDecoder("unregister", client.DecoderFunc(decodeUnregisterReply))
	request := client.NewUnregister(channelId, true)
	_, err = conn.WriteRequest(request)
	if err != io.EOF {
		t.Fatalf("Error writing deregistration request: got %#v; want io.EOF", err)
	}
	err = conn.Close()
	clientErr, ok := err.(client.Error)
	if !ok {
		t.Fatalf("Type assertion failed for close error: %#v", err)
	}
	if clientErr.Status() != 401 {
		t.Errorf("Unexpected close error status: got %#v; want 401", clientErr.Status())
	}
}
Exemple #4
0
func TestMultipleRegister(t *testing.T) {
	channelId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating channel ID: %#v", err)
	}
	origin, err := testServer.Origin()
	if err != nil {
		t.Fatalf("Error initializing test server: %#v", err)
	}
	conn, _, err := client.Dial(origin)
	if err != nil {
		t.Fatalf("Error dialing origin: %#v", err)
	}
	defer conn.Close()
	defer conn.Purge()
	request := MultipleRegister{client.NewRegister(channelId).(client.ClientRegister)}
	_, err = conn.WriteRequest(request)
	if err != io.EOF {
		t.Fatalf("Error writing registration request: got %#v; want io.EOF", err)
	}
	err = conn.Close()
	clientErr, ok := err.(client.Error)
	if !ok {
		t.Fatalf("Type assertion failed for close error: %#v", err)
	}
	if clientErr.Status() != 401 {
		t.Errorf("Unexpected close error status: got %#v; want 401", clientErr.Status())
	}
}
Exemple #5
0
// Status determines whether etcd can respond to requests. Implements
// Locator.Status().
func (l *EtcdLocator) Status() (ok bool, err error) {
	fakeID, err := id.Generate()
	if err != nil {
		return false, err
	}
	key, expected := "status_"+fakeID, "test"
	if _, err = l.client.Set(key, expected, uint64(6*time.Second)); err != nil {
		if l.logger.ShouldLog(ERROR) {
			l.logger.Error("etcd", "Error storing health check key",
				LogFields{"error": err.Error(), "key": key})
		}
		return false, err
	}
	resp, err := l.client.Get(key, false, false)
	if err != nil {
		if l.logger.ShouldLog(ERROR) {
			l.logger.Error("etcd", "Error fetching health check key",
				LogFields{"error": err.Error(), "key": key})
		}
		return false, err
	}
	if resp.Node.Value != expected {
		if l.logger.ShouldLog(ERROR) {
			l.logger.Error("etcd", "Unexpected health check result", LogFields{
				"key": key, "expected": expected, "actual": resp.Node.Value})
		}
		return false, ErrEtcdStatus
	}
	l.client.Delete(key, false)
	return true, nil
}
Exemple #6
0
func TestMultiRegister(t *testing.T) {
	channelId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating channel ID: %#v", err)
	}
	origin, err := testServer.Origin()
	if err != nil {
		t.Fatalf("Error initializing test server: %#v", err)
	}
	conn, _, err := client.Dial(origin)
	if err != nil {
		t.Fatalf("Error dialing origin: %#v", err)
	}
	defer conn.Close()
	defer conn.Purge()
	endpoint, err := conn.Register(channelId)
	if err != nil {
		t.Fatalf("Error writing registration request: %#v", err)
	}
	if !isValidEndpoint(endpoint) {
		t.Errorf("Invalid push endpoint: %#v", endpoint)
	}
	_, err = conn.Register("")
	if err != io.EOF {
		t.Fatalf("Error writing malformed registration request: got %#v; want io.EOF", err)
	}
	err = conn.Close()
	if clientErr, ok := err.(client.Error); ok && clientErr.Status() != 401 {
		t.Errorf("Unexpected close error status: got %#v; want 401", clientErr.Status())
	} else if !ok {
		t.Fatalf("Type assertion failed for close error: %#v", err)
	}
}
Exemple #7
0
func Dial(origin string) (conn *Conn, deviceId string, err error) {
	if deviceId, err = id.Generate(); err != nil {
		return nil, "", err
	}
	if conn, err = DialId(origin, &deviceId); err != nil {
		return nil, "", err
	}
	return conn, deviceId, nil
}
Exemple #8
0
func (t idTest) TestHelo() error {
	deviceId, err := id.Generate()
	if err != nil {
		return fmt.Errorf("On handshake test %v, error generating device ID: %#v", t.name, err)
	}
	addExistsHook(deviceId, true)
	defer removeExistsHook(deviceId)
	origin, err := testServer.Origin()
	if err != nil {
		return fmt.Errorf("On handshake test %v, error initializing test server: %#v", t.name, err)
	}
	conn, err := client.DialOrigin(origin)
	if err != nil {
		return fmt.Errorf("On handshake test %v, error dialing origin: %#v", t.name, err)
	}
	defer conn.Close()
	defer conn.Purge()
	request := CustomHelo{
		MessageType: "hello",
		DeviceId:    deviceId,
		ChannelIds:  []interface{}{t.channelId},
		replies:     make(chan client.Reply),
		errors:      make(chan error),
	}
	reply, err := conn.WriteRequest(request)
	if t.statusCode >= 200 && t.statusCode < 300 {
		if err != nil {
			return fmt.Errorf("On handshake test %v, error writing request: %#v", t.name, err)
		}
		helo, ok := reply.(client.ServerHelo)
		if !ok {
			return fmt.Errorf("On handshake test %v, type assertion failed for reply: %#v", t.name, reply)
		}
		if helo.StatusCode != 200 {
			return fmt.Errorf("On handshake test %v, unexpected status code: got %#v; want 200", t.name, helo.StatusCode)
		}
		// The Simple Push server requires the channelIDs field to be present in
		// the handshake, but does not validate its contents, since any queued
		// messages will be immediately flushed to the client.
		if helo.DeviceId != deviceId {
			return fmt.Errorf("On handshake test %v, mismatched device ID: got %#v; want %#v", t.name, helo.DeviceId, deviceId)
		}
		return nil
	}
	if err != io.EOF {
		return fmt.Errorf("On handshake test %v, error writing request: got %#v; want io.EOF", t.name, err)
	}
	err = conn.Close()
	clientErr, ok := err.(client.Error)
	if !ok {
		return fmt.Errorf("On handshake test %v, type assertion failed for close error: %#v", t.name, err)
	}
	if clientErr.Status() != t.statusCode {
		return fmt.Errorf("On handshake test %v, unexpected close error status: got %#v; want %#v", t.name, clientErr.Status(), t.statusCode)
	}
	return nil
}
Exemple #9
0
// Subscribe subscribes a client to a new channel.
func (c *Conn) Subscribe() (channelId, endpoint string, err error) {
	if channelId, err = id.Generate(); err != nil {
		return "", "", err
	}
	if endpoint, err = c.Register(channelId); err != nil {
		return "", "", err
	}
	return
}
Exemple #10
0
func DialOrigin(origin string) (*Conn, error) {
	socket, err := ws.Dial(origin, "", origin)
	if err != nil {
		return nil, err
	}
	id, err := id.Generate()
	if err != nil {
		return nil, err
	}
	return NewConn(socket, id, false), nil
}
Exemple #11
0
func TestMessageTypes(t *testing.T) {
	longId, err := generateIdSize(64000)
	if err != nil {
		t.Fatalf("Error generating longId: %#v", err)
	}

	existingId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating existingId: %#v", err)
	}
	addExistsHook(existingId, true)
	defer removeExistsHook(existingId)

	missingId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating missingId: %#v", err)
	}
	addExistsHook(missingId, false)
	defer removeExistsHook(missingId)

	specialTypes := []typeTest{
		{name: "long device ID", messageType: "hello", deviceId: longId, statusCode: 200, shouldReset: true},
		{name: "long message type", messageType: longId, deviceId: validId, statusCode: 401},

		{name: "existing device ID with channels", messageType: "hello", deviceId: existingId, statusCode: 200, shouldReset: false},
		// Sending channel IDs with an unknown device ID should return a new device ID.
		{name: "unknown device ID with channels", messageType: "hello", deviceId: missingId, statusCode: 200, shouldReset: true},
	}
	for _, test := range specialTypes {
		if err := test.Run(); err != nil {
			t.Error(err)
		}
	}

	for _, test := range typeTests {
		if err := test.Run(); err != nil {
			t.Error(err)
		}
	}
}
Exemple #12
0
func TestMessageTypes(t *testing.T) {
	longId, err := generateIdSize(64000)
	if err != nil {
		t.Fatalf("Error generating longId: %#v", err)
	}

	existingId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating existingId: %#v", err)
	}
	addExistsHook(existingId, true)
	defer removeExistsHook(existingId)

	missingId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating missingId: %#v", err)
	}
	addExistsHook(missingId, false)
	defer removeExistsHook(missingId)

	specialTypes := []typeTest{
		{"long device ID", "hello", longId, 503, true},
		{"long message type", longId, validId, 401, true},

		{"existing device ID with channels", "hello", existingId, 200, false},
		// Sending channel IDs with an unknown device ID should return a new device ID.
		{"unknown device ID with channels", "hello", missingId, 200, true},
	}
	for _, test := range specialTypes {
		if err := test.Run(); err != nil {
			t.Error(err)
		}
	}

	for _, test := range typeTests {
		if err := test.Run(); err != nil {
			t.Error(err)
		}
	}
}
Exemple #13
0
func TestDuplicateRegisterHandshake(t *testing.T) {
	deviceId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating device ID: %#v", err)
	}
	addExistsHook(deviceId, true)
	defer removeExistsHook(deviceId)
	channelId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating channel ID: %#v", err)
	}
	origin, err := testServer.Origin()
	if err != nil {
		t.Fatalf("Error initializing test server: %#v", err)
	}
	conn, err := client.DialOrigin(origin)
	if err != nil {
		t.Fatalf("Error dialing origin: %#v", err)
	}
	defer conn.Close()
	defer conn.Purge()
	actualId, err := conn.WriteHelo(deviceId, channelId)
	if err != nil {
		t.Fatalf("Error writing handshake request: %#v", err)
	}
	if actualId != deviceId {
		t.Errorf("Mismatched device ID: got %#v; want %#v", actualId, deviceId)
	}
	if !AllowDupes {
		return
	}
	endpoint, err := conn.Register(channelId)
	if err != nil {
		t.Fatalf("Error writing duplicate registration request: %#v", err)
	}
	if !isValidEndpoint(endpoint) {
		t.Errorf("Invalid push endpoint for channel %#v: %#v", channelId, endpoint)
	}
}
Exemple #14
0
func TestPrematureACK(t *testing.T) {
	channelId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating channel ID: %#v", err)
	}
	origin, err := testServer.Origin()
	if err != nil {
		t.Fatalf("Error initializing test server: %#v", err)
	}
	conn, err := client.DialOrigin(origin)
	if err != nil {
		t.Fatalf("Error dialing origin: %#v", err)
	}
	defer conn.Close()
	defer conn.Purge()
	conn.RegisterDecoder("ack", client.DecoderFunc(decodeServerInvalidACK))
	updates := []client.Update{
		client.Update{
			ChannelId: channelId,
			Version:   time.Now().UTC().Unix(),
		},
	}
	request := ClientInvalidACK{client.NewACK(updates, true)}
	reply, err := conn.WriteRequest(request)
	if err != nil {
		t.Fatalf("Error writing acknowledgement: %#v", err)
	}
	if reply.Status() != 401 {
		t.Errorf("Incorrect status code: got %#v, wanted 401", reply.Status())
	}
	if r, ok := reply.(ServerInvalidACK); ok {
		if len(r.Updates) != len(updates) {
			t.Errorf("Incorrect update count: got %#v; want %#v", len(r.Updates), len(updates))
		} else {
			for index, update := range r.Updates {
				if update != updates[index] {
					t.Errorf("On update %#v, got %#v; want %#v", index, update, updates[index])
				}
			}
		}
	} else {
		t.Errorf("Type assertion failed for reply: %#v", reply)
	}
	// The connection should be closed by the push server after sending
	// the error response.
	if err = conn.Close(); err != io.EOF {
		t.Fatalf("Unexpected close error: got %#v; want io.EOF", err)
	}
}
Exemple #15
0
// ServeHTTP implements http.Handler.ServeHTTP.
func (h *LogHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
	receivedAt := time.Now()

	// The `X-Request-Id` header is used by Heroku, restify, etc. to correlate
	// logs for the same request.
	requestID := req.Header.Get(HeaderID)
	if !id.Valid(requestID) {
		requestID, _ = id.Generate()
		req.Header.Set(HeaderID, requestID)
	}

	writer := &logResponseWriter{ResponseWriter: res, StatusCode: http.StatusOK}
	defer h.logResponse(writer, req, requestID, receivedAt)

	h.Handler.ServeHTTP(writer, req)
}
Exemple #16
0
func TestDupeDisconnect(t *testing.T) {
	channelId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating channel ID: %#v", err)
	}
	origin, err := testServer.Origin()
	if err != nil {
		t.Fatalf("Error initializing test server: %s", err)
	}
	conn, deviceId, err := client.Dial(origin, channelId)
	if err != nil {
		t.Fatalf("Error dialing origin: %s", err)
	}
	defer conn.Close()
	stopChan := make(chan bool)
	defer close(stopChan)
	errChan := make(chan error)
	go func() {
		var err error
		select {
		case <-conn.CloseNotify():
		case <-time.After(5 * time.Second):
			err = fmt.Errorf("Initial connection for %q not closed", deviceId)
		}
		select {
		case <-stopChan:
		case errChan <- err:
		}
	}()
	go func(dupeId string) {
		dupeConn, err := client.DialId(origin, &dupeId, channelId)
		if err != nil {
			err = fmt.Errorf("Error reconnecting to origin: %s", err)
		}
		defer dupeConn.Close()
		select {
		case <-stopChan:
		case errChan <- err:
		}
	}(deviceId)
	for i := 0; i < 2; i++ {
		if err := <-errChan; err != nil {
			t.Fatal(err)
		}
	}
}
Exemple #17
0
// IsEtcdHealthy indicates whether etcd can respond to requests.
func IsEtcdHealthy(client *etcd.Client) (ok bool, err error) {
	fakeID, err := id.Generate()
	if err != nil {
		return false, fmt.Errorf("Error generating health check key: %s", err)
	}
	key, expected := "status_"+fakeID, "test"
	if _, err = client.Set(key, expected, uint64(3*time.Second)); err != nil {
		return false, fmt.Errorf("Error storing health check key %#v: %s",
			key, err)
	}
	resp, err := client.Get(key, false, false)
	if err != nil {
		return false, fmt.Errorf("Error fetching health check key %#v: %s",
			key, err)
	}
	if resp.Node.Value != expected {
		return false, fmt.Errorf(
			"Unexpected value for health check key %#v: got %s; want %s",
			key, resp.Node.Value, expected)
	}
	return true, nil
}
Exemple #18
0
func TestTooManyChannels(t *testing.T) {
	deviceId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating device ID: %#v", err)
	}
	origin, err := testServer.Origin()
	if err != nil {
		t.Fatalf("Error initializing test server: %#v", err)
	}
	conn, err := client.DialOrigin(origin)
	if err != nil {
		t.Fatalf("Error dialing origin: %#v", err)
	}
	defer conn.Close()
	defer conn.Purge()
	actualId, err := conn.WriteHelo(deviceId, channelIds...)
	if err != nil {
		t.Fatalf("Error writing large handshake request: %#v", err)
	}
	if actualId == deviceId {
		t.Errorf("Want new device ID; got %#v", actualId)
	}
}
Exemple #19
0
func connect(origin string) (deviceId, channelId, endpoint string, err error) {
	if channelId, err = id.Generate(); err != nil {
		err = fmt.Errorf("Error generating channel ID: %s", err)
		return
	}
	conn, deviceId, err := client.Dial(origin)
	if err != nil {
		err = fmt.Errorf("Error dialing origin: %s", err)
		return
	}
	defer conn.Close()
	defer conn.Purge()
	if endpoint, err = conn.Register(channelId); err != nil {
		err = fmt.Errorf("Error subscribing to channel %q: %s",
			channelId, err)
		return
	}
	if err = roundTrip(conn, deviceId, channelId, endpoint, 1); err != nil {
		err = fmt.Errorf("Error sending initial notification: %s", err)
		return
	}
	return
}
Exemple #20
0
func TestHandshakeWithId(t *testing.T) {
	origin, err := testServer.Origin()
	if err != nil {
		t.Fatalf("Error initializing test server: %#v", err)
	}
	deviceId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating device ID: %#v", err)
	}
	conn, err := client.DialOrigin(origin)
	if err != nil {
		t.Fatalf("Error dialing origin: %#v", err)
	}
	defer conn.Close()
	defer conn.Purge()
	actualId, err := conn.WriteHelo(deviceId)
	if err != nil {
		t.Fatalf("Error writing handshake request: %#v", err)
	}
	if actualId != deviceId {
		t.Errorf("Mismatched device IDs: got %#v; want %#v", actualId, deviceId)
	}
}
Exemple #21
0
// Status queries whether memcached is available for reading and writing.
// Implements Store.Status().
func (s *GomemcStore) Status() (success bool, err error) {
	fakeID, err := id.Generate()
	if err != nil {
		return false, err
	}
	key, expected := "status_"+fakeID, []byte("test")
	err = s.client.Set(
		&mc.Item{
			Key:        key,
			Value:      expected,
			Expiration: 6,
		})
	if err != nil {
		if s.logger.ShouldLog(ERROR) {
			s.logger.Error("gomemc", "Error storing health check key",
				LogFields{"error": err.Error(), "key": key})
		}
		return false, err
	}
	raw, err := s.client.Get(key)
	if err != nil {
		if s.logger.ShouldLog(ERROR) {
			s.logger.Error("gomemc", "Error fetching health check key",
				LogFields{"error": err.Error(), "key": key})
		}
		return false, err
	}
	if !bytes.Equal(raw.Value, expected) {
		if s.logger.ShouldLog(ERROR) {
			s.logger.Error("gomemc", "Unexpected health check result",
				LogFields{"expected": string(expected), "actual": string(raw.Value)})
		}
		return false, ErrMemcacheStatus
	}
	s.client.Delete(key)
	return true, nil
}
Exemple #22
0
func TestDuplicateHandshake(t *testing.T) {
	deviceId, err := id.Generate()
	if err != nil {
		t.Fatalf("Error generating device ID: %#v", err)
	}
	origin, err := testServer.Origin()
	if err != nil {
		t.Fatalf("Error initializing test server: %#v", err)
	}
	conn, err := client.DialOrigin(origin)
	if err != nil {
		t.Fatalf("Error dialing origin: %#v", err)
	}
	defer conn.Close()
	defer conn.Purge()
	firstId, err := conn.WriteHelo(deviceId)
	if err != nil {
		t.Fatalf("Error writing initial handshake request: %#v", err)
	}
	if firstId != deviceId {
		t.Errorf("Mismatched device ID for initial handshake: got %#v; want %#v", firstId, deviceId)
	}
	secondId, err := conn.WriteHelo(firstId)
	if err != nil {
		t.Fatalf("Error writing duplicate handshake request: %#v", err)
	}
	if secondId != firstId {
		t.Errorf("Mismatched device ID for duplicate handshake: got %#v; want %#v", secondId, firstId)
	}
	thirdId, err := conn.WriteHelo("")
	if err != nil {
		t.Fatalf("Error writing implicit handshake request: %#v", err)
	}
	if thirdId != secondId {
		t.Errorf("Mismatched device ID for implicit handshake: got %#v; want %#v", thirdId, secondId)
	}
}
Exemple #23
0
// Status queries whether memcached is available for reading and writing.
// Implements Store.Status().
func (s *EmceeStore) Status() (success bool, err error) {
	fakeID, err := id.Generate()
	if err != nil {
		return false, err
	}
	key, expected := "status_"+fakeID, "test"
	client, err := s.getClient()
	defer s.releaseWithout(client, &err)
	if err != nil {
		return false, err
	}
	if err = client.Set(key, expected, 6*time.Second); err != nil {
		if s.logger.ShouldLog(ERROR) {
			s.logger.Error("emcee", "Error storing health check key",
				LogFields{"error": err.Error(), "key": key})
		}
		return false, err
	}
	var actual string
	if err = client.Get(key, &actual); err != nil {
		if s.logger.ShouldLog(ERROR) {
			s.logger.Error("emcee", "Error fetching health check key",
				LogFields{"error": err.Error(), "key": key})
		}
		return false, err
	}
	if expected != actual {
		if s.logger.ShouldLog(ERROR) {
			s.logger.Error("emcee", "Unexpected health check result", LogFields{
				"key": key, "expected": expected, "actual": actual})
		}
		return false, ErrMemcacheStatus
	}
	client.Delete(key, 0)
	return true, nil
}
Exemple #24
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)
		}
	}
}
Exemple #25
0
// A client connects!
func (self *Serv) Hello(worker *Worker, cmd PushCommand, sock *PushWS) (result int, arguments JsMap) {
	var uaid string

	args := cmd.Arguments
	if self.logger.ShouldLog(INFO) {
		chidss := ""
		if chids, ok := args["channelIDs"]; ok {
			chidss = "[" + strings.Join(chids.([]string), ", ") + "]"
		}
		self.logger.Info("server", "handling 'hello'",
			LogFields{"uaid": args["uaid"].(string),
				"channelIDs": chidss})
	}

	// TODO: If the client needs to connect to a different server,
	// Look up the appropriate server (based on UAID)
	// return a response that looks like:
	// { uaid: UAIDValue, status: 302, redirect: NewWS_URL }

	// New connects overwrite previous connections.
	// Raw client
	if args["uaid"] == "" {
		uaid, _ = id.Generate()
		if self.logger.ShouldLog(DEBUG) {
			self.logger.Debug("server",
				"Generating new UAID",
				LogFields{"uaid": uaid})
		}
	} else {
		uaid = args["uaid"].(string)
		if self.logger.ShouldLog(DEBUG) {
			self.logger.Debug("server",
				"Using existing UAID",
				LogFields{"uaid": uaid})
		}
		delete(args, "uaid")
	}

	if connect, _ := args["connect"].([]byte); len(connect) > 0 && self.prop != nil {
		if err := self.prop.Register(uaid, connect); err != nil {
			if self.logger.ShouldLog(WARNING) {
				self.logger.Warn("server", "Could not set proprietary info",
					LogFields{"error": err.Error(),
						"connect": string(connect)})
			}
		}
	}

	// Create a new, live client entry for this record.
	// See Bye for discussion of potential longer term storage of this info
	sock.Uaid = uaid
	client := &Client{
		Worker: worker,
		PushWS: *sock,
		UAID:   uaid,
	}
	self.app.AddClient(uaid, client)
	self.logger.Info("dash", "Client registered", nil)

	// We don't register the list of known ChannelIDs since we echo
	// back any ChannelIDs sent on behalf of this UAID.
	args["uaid"] = uaid
	arguments = args
	result = 200
	return result, arguments
}