github.com/google/cloudprober@v0.11.3/surfacers/pubsub/pubsub_test.go (about) 1 // Copyright 2020 The Cloudprober Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package pubsub 16 17 import ( 18 "context" 19 "fmt" 20 "net" 21 "reflect" 22 "strings" 23 "sync" 24 "testing" 25 "time" 26 27 "cloud.google.com/go/pubsub" 28 "github.com/google/cloudprober/logger" 29 "github.com/google/cloudprober/metrics" 30 "github.com/google/cloudprober/surfacers/common/compress" 31 "github.com/google/cloudprober/surfacers/common/options" 32 configpb "github.com/google/cloudprober/surfacers/pubsub/proto" 33 "google.golang.org/api/option" 34 pb "google.golang.org/genproto/googleapis/pubsub/v1" 35 pb_grpc "google.golang.org/genproto/googleapis/pubsub/v1" 36 "google.golang.org/grpc" 37 "google.golang.org/grpc/codes" 38 "google.golang.org/grpc/status" 39 "google.golang.org/protobuf/proto" 40 ) 41 42 // testServer is the underlying service implementor. It is not intended to be used 43 // directly. 44 type testServer struct { 45 pb_grpc.PublisherServer 46 pb_grpc.SubscriberServer 47 48 topics map[string]*pb.Topic 49 msgs []*Message // all messages ever published 50 wg sync.WaitGroup 51 nextID int 52 } 53 54 // A Message is a message that was published to the server. 55 type Message struct { 56 Data []byte 57 Attributes map[string]string 58 } 59 60 func (s *testServer) CreateTopic(_ context.Context, t *pb.Topic) (*pb.Topic, error) { 61 if s.topics[t.Name] != nil { 62 return nil, status.Errorf(codes.AlreadyExists, "topic %q", t.Name) 63 } 64 s.topics[t.Name] = t 65 return t, nil 66 } 67 68 func (s *testServer) GetTopic(_ context.Context, req *pb.GetTopicRequest) (*pb.Topic, error) { 69 if t := s.topics[req.Topic]; t != nil { 70 return t, nil 71 } 72 return nil, status.Errorf(codes.NotFound, "topic %q", req.Topic) 73 } 74 75 func (s *testServer) Publish(_ context.Context, req *pb.PublishRequest) (*pb.PublishResponse, error) { 76 var ids []string 77 for _, pm := range req.Messages { 78 m := &Message{ 79 Data: pm.Data, 80 Attributes: pm.Attributes, 81 } 82 ids = append(ids, fmt.Sprintf("m%d", s.nextID)) 83 s.nextID++ 84 s.msgs = append(s.msgs, m) 85 } 86 return &pb.PublishResponse{MessageIds: ids}, nil 87 } 88 89 func TestSurfacer(t *testing.T) { 90 for _, compression := range []bool{false, true} { 91 t.Run(fmt.Sprintf("with_compression=%v", compression), func(t *testing.T) { 92 l, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", 0)) 93 if err != nil { 94 t.Fatalf("Error creating listener: %v", err) 95 } 96 defer l.Close() 97 98 gSrv := grpc.NewServer() 99 srv := &testServer{ 100 topics: map[string]*pb.Topic{}, 101 } 102 103 pb_grpc.RegisterPublisherServer(gSrv, srv) 104 pb_grpc.RegisterSubscriberServer(gSrv, srv) 105 106 go func() { 107 if err := gSrv.Serve(l); err != nil { 108 t.Errorf("gRPC server start: %v", err) 109 } 110 }() 111 defer gSrv.Stop() 112 113 // Connect to the server without using TLS. 114 conn, err := grpc.Dial(l.Addr().String(), grpc.WithInsecure()) 115 if err != nil { 116 t.Fatalf("Error establishing connection to the test pubsub server (%s): %v", l.Addr().String(), err) 117 } 118 defer conn.Close() 119 120 newPubsubClient = func(ctx context.Context, project string) (*pubsub.Client, error) { 121 return pubsub.NewClient(ctx, project, option.WithGRPCConn(conn)) 122 } 123 124 createSurfacerAndVerify(t, srv, compression) 125 }) 126 } 127 } 128 129 func createSurfacerAndVerify(t *testing.T, srv *testServer, compression bool) { 130 t.Helper() 131 132 //ctx, cancel := context.WithCancel(context.Background()) 133 //defer cancel() 134 135 s, err := New(context.Background(), &configpb.SurfacerConf{ 136 TopicName: proto.String("test-topic"), 137 CompressionEnabled: proto.Bool(compression), 138 }, &options.Options{MetricsBufferSize: 1000}, &logger.Logger{}) 139 if err != nil { 140 t.Fatalf("Error while creating new surfacer: %v", err) 141 } 142 143 testEM := []*metrics.EventMetrics{ 144 metrics.NewEventMetrics(time.Now()).AddMetric("float-test", metrics.NewInt(123456)), 145 metrics.NewEventMetrics(time.Now()).AddMetric("float-test", metrics.NewInt(123457)), 146 } 147 148 var expectedMsgs []string 149 for _, em := range testEM { 150 s.Write(context.Background(), em) 151 expectedMsgs = append(expectedMsgs, em.String()) 152 } 153 154 // Closing the surfacer waits for inputs to be processed. 155 s.close() 156 157 srv.wg.Wait() 158 159 if compression { 160 b, err := compress.Compress([]byte(strings.Join(expectedMsgs, "\n") + "\n")) 161 if err != nil { 162 t.Fatalf("Error while compressing data (%s): %v", string(b), err) 163 } 164 expectedMsgs = []string{string(b)} 165 } 166 167 if len(srv.msgs) != len(expectedMsgs) { 168 t.Fatalf("Got %d message, expected: %d", len(srv.msgs), len(expectedMsgs)) 169 } 170 171 expectedAttributes := map[string]string{ 172 "starttime": s.starttime, 173 "compressed": map[bool]string{false: "false", true: "true"}[compression], 174 } 175 176 for i, msg := range srv.msgs { 177 if !reflect.DeepEqual(msg.Attributes, expectedAttributes) { 178 t.Errorf("Message attributes: %v, expected: %v", msg.Attributes, expectedAttributes) 179 } 180 if string(msg.Data) != expectedMsgs[i] { 181 t.Errorf("Message data=%s, expected=%s", string(msg.Data), expectedMsgs[i]) 182 } 183 } 184 }