Example #1
0
func TestMultipleClientsBecomeHealthy(t *testing.T) {

	health := newHealthChecker()
	health.disconnectedThreshold = testDisconnectedThreshold

	id1 := cluster.MemberID("member-id-1")
	id2 := cluster.MemberID("member-id-2")
	id3 := cluster.MemberID("member-id-3")

	cl1 := &mockClient{connected: true}
	cl2 := &mockClient{connected: true}
	cl3 := &mockClient{connected: false}

	health.AddClient(id1, cl1)
	health.AddClient(id2, cl2)
	health.AddClient(id3, cl3)

	status := health.Check()
	assert.True(t, status.Healthy, "Expected healthy but got %v", status)

	time.Sleep(testDisconnectedThreshold)

	status = health.Check()
	assert.False(t, status.Healthy, "Expected unhealthy but got %v", status)

	_, err := cl3.connect()
	if err != nil {
		// errcheck bypass
	}

	status = health.Check()
	assert.True(t, status.Healthy, "Expected healthy but got %v", status)

}
Example #2
0
func (s *server) validateConnection(rw http.ResponseWriter, req *http.Request) cluster.MemberID {
	// Make sure that the writer supports flushing.
	_, ok := rw.(http.Flusher)

	if !ok {
		s.logger.Errorf("Streaming unsupported. Member %s", req.RemoteAddr)
		http.Error(rw, "Streaming unsupported!", http.StatusInternalServerError)
		return ""
	}

	rw.Header().Set("Content-Type", "text/event-stream")
	rw.Header().Set("Cache-Control", "no-cache")
	rw.Header().Set("Connection", "keep-alive")

	memberID := req.Header.Get(headerMemberID)
	if memberID == "" {
		s.logger.Errorf("Missing header Memeber-ID from connection address %s", req.RemoteAddr)
		http.Error(rw, "Missing header Member-ID", http.StatusBadRequest)
		return ""
	}

	if cluster.MemberID(memberID) == s.registrator.Self().ID() {
		s.logger.Errorf("Header Member-ID %s conflicts with self on connection %s", memberID, req.RemoteAddr)
		http.Error(rw, "Wrong Member-ID", http.StatusBadRequest)
		return ""
	}
	return cluster.MemberID(memberID)
}
func TestIncomingReplication(t *testing.T) {
	if testing.Short() {
		t.Skip()
	}

	rep := createMockupReplication()
	close(rep.(*mockupReplication).syncChan) //Make sure no deadlock occur

	ns := auth.NamespaceFrom("ns1")

	r := newInMemoryRegistry(nil, rep)
	assert.NotContains(t, r.(*inMemoryRegistry).namespaces, ns)

	inst := newServiceInstance("Calc1", "192.168.0.1", 9080)
	payload, _ := json.Marshal(inst)
	data, _ := json.Marshal(&replicatedMsg{RepType: REGISTER, Payload: payload})
	rep.(*mockupReplication).NotifyChannel <- &replication.InMessage{cluster.MemberID("192.1.1.3:6100"), ns, data}

	catalog, err := r.GetCatalog(auth.NamespaceFrom("ns1"))

	// NOTICE, it may fail, since a race between the registry and the test...
	time.Sleep(time.Duration(5) * time.Second)

	assert.NoError(t, err)

	instances1, err1 := catalog.List("Calc1", protocolPredicate)
	assert.NoError(t, err1)
	assert.Len(t, instances1, 1)
}
Example #4
0
func TestHealthySingleClient(t *testing.T) {

	health := newHealthChecker()
	health.disconnectedThreshold = testDisconnectedThreshold

	id := cluster.MemberID("member-id")

	health.AddClient(id, &mockClient{connected: true})

	status := health.Check()
	assert.True(t, status.Healthy, "Expected healthy but got %v", status)

}
Example #5
0
func (s *server) serveRep(rw http.ResponseWriter, req *http.Request) {
	memberID := s.validateConnection(rw, req)
	if memberID == "" {
		return
	}
	s.logger.Infof("Peer Member %s connected from address %s", memberID, req.RemoteAddr)

	peer := &peer{memberID: cluster.MemberID(memberID), msgChannel: make(chan *sse)}

	// Signal that we have a new connection
	s.newPeers <- peer

	// Remove this client from the map of connected clients
	// when this handler exits.
	defer func() {
		s.closingPeers <- peer
	}()

	// Listen to connection close and un-register messageChan
	notify := rw.(http.CloseNotifier).CloseNotify()
	go func() {
		<-notify
		s.closingPeers <- peer
		s.logger.Infof("Peer member %s has been disconnected", memberID)
	}()

	// Send the response header to client side
	flusher := rw.(http.Flusher)

	gzipped := strings.Contains(req.Header.Get("Accept-Encoding"), "gzip")

	var gzipWriter *gzip.Writer
	var err error

	if gzipped {
		// override the response writer to be a gzipped writer
		if gzipWriter, err = gzip.NewWriterLevel(rw, gzip.BestSpeed); err == nil {
			rw = gzipResponseWrapper{Writer: gzipWriter, ResponseWriter: rw}
			rw.Header().Set("Content-Encoding", "gzip")
			flusher = rw.(http.Flusher)
			defer func() {
				gzipWriter.Close()
			}()
		} else {
			s.logger.Warnf("Gzip wrapper creation for %s from %s failed: %v. Falling back to uncompressed HTTP", memberID, req.RemoteAddr, err)
		}
	}

	encoder := newEncoder(rw)
	ticker := time.NewTicker(time.Millisecond * 100).C
	for {
		select {
		case ev, ok := <-peer.msgChannel:
			if !ok {
				return
			}
			// Write to the ResponseWriter
			// Server Sent Events compatible
			if err := encoder.Encode(ev); err != nil {
				s.logger.WithFields(log.Fields{
					"error": err,
				}).Errorf("Failed to encode replication message to member %s", memberID)
				break
			}
		case <-ticker:
			flusher.Flush()
		}
	}
}