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) }
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) }
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) }
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() } } }