From 55652591c071ef203c5f3ef3e4b5c364f2701550 Mon Sep 17 00:00:00 2001 From: CodeBeaverAI Date: Mon, 3 Mar 2025 23:32:21 +0100 Subject: [PATCH 1/2] test: Update coverage improvement test for prober/grpc_test.go --- prober/grpc_test.go | 894 +++++++++++++++++++++++--------------------- 1 file changed, 468 insertions(+), 426 deletions(-) diff --git a/prober/grpc_test.go b/prober/grpc_test.go index 2a2c4aeb..d497b099 100644 --- a/prober/grpc_test.go +++ b/prober/grpc_test.go @@ -14,452 +14,494 @@ package prober import ( - "context" - "crypto/tls" - "crypto/x509" - "encoding/pem" - "fmt" - "net" - "os" - "testing" - "time" - - "github.com/prometheus/blackbox_exporter/config" - "github.com/prometheus/client_golang/prometheus" - pconfig "github.com/prometheus/common/config" - "github.com/prometheus/common/promslog" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/health" - "google.golang.org/grpc/health/grpc_health_v1" + "context" + "crypto/tls" + "crypto/x509" + "encoding/pem" + "fmt" + "net" + "os" + "testing" + "time" + + "github.com/prometheus/blackbox_exporter/config" + "github.com/prometheus/client_golang/prometheus" + pconfig "github.com/prometheus/common/config" + "github.com/prometheus/common/promslog" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/health" + "google.golang.org/grpc/health/grpc_health_v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) +// fakeHealthClient is a fake implementation of grpc_health_v1.HealthClient for testing. +type fakeHealthClient struct { + status grpc_health_v1.HealthCheckResponse_ServingStatus + err error +} + +func (f *fakeHealthClient) Check(ctx context.Context, in *grpc_health_v1.HealthCheckRequest, opts ...grpc.CallOption) (*grpc_health_v1.HealthCheckResponse, error) { + // Emulate setting the peer if the grpc.Peer option is provided. + if f.err != nil { + return nil, f.err + } + return &grpc_health_v1.HealthCheckResponse{Status: f.status}, nil +} +func (f *fakeHealthClient) Watch(ctx context.Context, in *grpc_health_v1.HealthCheckRequest, opts ...grpc.CallOption) (grpc_health_v1.Health_WatchClient, error) { + // Return an unimplemented error for the Watch functionality. + return nil, status.Error(codes.Unimplemented, "Watch is not implemented in fakeHealthClient") +} func TestGRPCConnection(t *testing.T) { - if os.Getenv("CI") == "true" { - t.Skip("skipping; CI is failing on ipv6 dns requests") - } - - ln, err := net.Listen("tcp", "localhost:0") - if err != nil { - t.Fatalf("Error listening on socket: %s", err) - } - defer ln.Close() - - _, port, err := net.SplitHostPort(ln.Addr().String()) - if err != nil { - t.Fatalf("Error retrieving port for socket: %s", err) - } - s := grpc.NewServer() - healthServer := health.NewServer() - healthServer.SetServingStatus("service", grpc_health_v1.HealthCheckResponse_SERVING) - grpc_health_v1.RegisterHealthServer(s, healthServer) - - go func() { - if err := s.Serve(ln); err != nil { - t.Errorf("failed to serve: %v", err) - return - } - }() - defer s.GracefulStop() - - testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - registry := prometheus.NewRegistry() - - result := ProbeGRPC(testCTX, "localhost:"+port, - config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ - IPProtocolFallback: false, - }, - }, registry, promslog.NewNopLogger()) - - if !result { - t.Fatalf("GRPC probe failed") - } - - mfs, err := registry.Gather() - if err != nil { - t.Fatal(err) - } - - expectedMetrics := map[string]map[string]map[string]struct{}{ - "probe_grpc_healthcheck_response": { - "serving_status": { - "UNKNOWN": {}, - "SERVING": {}, - "NOT_SERVING": {}, - "SERVICE_UNKNOWN": {}, - }, - }, - } - - checkMetrics(expectedMetrics, mfs, t) - - expectedResults := map[string]float64{ - "probe_grpc_ssl": 0, - "probe_grpc_status_code": 0, - } - - checkRegistryResults(expectedResults, mfs, t) + ln, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error listening on socket: %s", err) + } + defer ln.Close() + + _, port, err := net.SplitHostPort(ln.Addr().String()) + if err != nil { + t.Fatalf("Error retrieving port for socket: %s", err) + } + s := grpc.NewServer() + healthServer := health.NewServer() + healthServer.SetServingStatus("service", grpc_health_v1.HealthCheckResponse_SERVING) + grpc_health_v1.RegisterHealthServer(s, healthServer) + + go func() { + if err := s.Serve(ln); err != nil { + t.Errorf("failed to serve: %v", err) + return + } + }() + defer s.GracefulStop() + + testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + registry := prometheus.NewRegistry() + + result := ProbeGRPC(testCTX, "localhost:"+port, + config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ + IPProtocolFallback: false, + }, + }, registry, promslog.NewNopLogger()) + + if !result { + t.Fatalf("GRPC probe failed") + } + + mfs, err := registry.Gather() + if err != nil { + t.Fatal(err) + } + + expectedMetrics := map[string]map[string]map[string]struct{}{ + "probe_grpc_healthcheck_response": { + "serving_status": { + "UNKNOWN": {}, + "SERVING": {}, + "NOT_SERVING": {}, + "SERVICE_UNKNOWN": {}, + }, + }, + } + + checkMetrics(expectedMetrics, mfs, t) + + expectedResults := map[string]float64{ + "probe_grpc_ssl": 0, + "probe_grpc_status_code": 0, + } + + checkRegistryResults(expectedResults, mfs, t) } func TestMultipleGRPCservices(t *testing.T) { - if os.Getenv("CI") == "true" { - t.Skip("skipping; CI is failing on ipv6 dns requests") - } - - ln, err := net.Listen("tcp", "localhost:0") - if err != nil { - t.Fatalf("Error listening on socket: %s", err) - } - defer ln.Close() - - _, port, err := net.SplitHostPort(ln.Addr().String()) - if err != nil { - t.Fatalf("Error retrieving port for socket: %s", err) - } - s := grpc.NewServer() - healthServer := health.NewServer() - healthServer.SetServingStatus("service1", grpc_health_v1.HealthCheckResponse_SERVING) - healthServer.SetServingStatus("service2", grpc_health_v1.HealthCheckResponse_NOT_SERVING) - grpc_health_v1.RegisterHealthServer(s, healthServer) - - go func() { - if err := s.Serve(ln); err != nil { - t.Errorf("failed to serve: %v", err) - return - } - }() - defer s.GracefulStop() - - testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - registryService1 := prometheus.NewRegistry() - - resultService1 := ProbeGRPC(testCTX, "localhost:"+port, - config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ - IPProtocolFallback: false, - Service: "service1", - }, - }, registryService1, promslog.NewNopLogger()) - - if !resultService1 { - t.Fatalf("GRPC probe failed for service1") - } - - registryService2 := prometheus.NewRegistry() - resultService2 := ProbeGRPC(testCTX, "localhost:"+port, - config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ - IPProtocolFallback: false, - Service: "service2", - }, - }, registryService2, promslog.NewNopLogger()) - - if resultService2 { - t.Fatalf("GRPC probe succeed for service2") - } - - registryService3 := prometheus.NewRegistry() - resultService3 := ProbeGRPC(testCTX, "localhost:"+port, - config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ - IPProtocolFallback: false, - Service: "service3", - }, - }, registryService3, promslog.NewNopLogger()) - - if resultService3 { - t.Fatalf("GRPC probe succeed for service3") - } + ln, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error listening on socket: %s", err) + } + defer ln.Close() + + _, port, err := net.SplitHostPort(ln.Addr().String()) + if err != nil { + t.Fatalf("Error retrieving port for socket: %s", err) + } + s := grpc.NewServer() + healthServer := health.NewServer() + healthServer.SetServingStatus("service1", grpc_health_v1.HealthCheckResponse_SERVING) + healthServer.SetServingStatus("service2", grpc_health_v1.HealthCheckResponse_NOT_SERVING) + grpc_health_v1.RegisterHealthServer(s, healthServer) + + go func() { + if err := s.Serve(ln); err != nil { + t.Errorf("failed to serve: %v", err) + return + } + }() + defer s.GracefulStop() + + testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + registryService1 := prometheus.NewRegistry() + + resultService1 := ProbeGRPC(testCTX, "localhost:"+port, + config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ + IPProtocolFallback: false, + Service: "service1", + }, + }, registryService1, promslog.NewNopLogger()) + + if !resultService1 { + t.Fatalf("GRPC probe failed for service1") + } + + registryService2 := prometheus.NewRegistry() + resultService2 := ProbeGRPC(testCTX, "localhost:"+port, + config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ + IPProtocolFallback: false, + Service: "service2", + }, + }, registryService2, promslog.NewNopLogger()) + + if resultService2 { + t.Fatalf("GRPC probe succeed for service2") + } + + registryService3 := prometheus.NewRegistry() + resultService3 := ProbeGRPC(testCTX, "localhost:"+port, + config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ + IPProtocolFallback: false, + Service: "service3", + }, + }, registryService3, promslog.NewNopLogger()) + + if resultService3 { + t.Fatalf("GRPC probe succeed for service3") + } } func TestGRPCTLSConnection(t *testing.T) { - if os.Getenv("CI") == "true" { - t.Skip("skipping; CI is failing on ipv6 dns requests") - } - - certExpiry := time.Now().AddDate(0, 0, 1) - testCertTmpl := generateCertificateTemplate(certExpiry, false) - testCertTmpl.IsCA = true - _, testcertPem, testKey := generateSelfSignedCertificate(testCertTmpl) - - // CAFile must be passed via filesystem, use a tempfile. - tmpCaFile, err := os.CreateTemp("", "cafile.pem") - if err != nil { - t.Fatalf("Error creating CA tempfile: %s", err) - } - if _, err = tmpCaFile.Write(testcertPem); err != nil { - t.Fatalf("Error writing CA tempfile: %s", err) - } - if err = tmpCaFile.Close(); err != nil { - t.Fatalf("Error closing CA tempfile: %s", err) - } - defer os.Remove(tmpCaFile.Name()) - - testKeyPem := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(testKey)}) - testcert, err := tls.X509KeyPair(testcertPem, testKeyPem) - if err != nil { - panic(fmt.Sprintf("Failed to decode TLS testing keypair: %s\n", err)) - } - - tlsConfig := &tls.Config{ - Certificates: []tls.Certificate{testcert}, - MinVersion: tls.VersionTLS12, - MaxVersion: tls.VersionTLS12, - } - - ln, err := net.Listen("tcp", "localhost:0") - if err != nil { - t.Fatalf("Error listening on socket: %s", err) - } - defer ln.Close() - - _, port, err := net.SplitHostPort(ln.Addr().String()) - if err != nil { - t.Fatalf("Error retrieving port for socket: %s", err) - } - - s := grpc.NewServer(grpc.Creds(credentials.NewTLS(tlsConfig))) - healthServer := health.NewServer() - healthServer.SetServingStatus("service", grpc_health_v1.HealthCheckResponse_SERVING) - grpc_health_v1.RegisterHealthServer(s, healthServer) - - go func() { - if err := s.Serve(ln); err != nil { - t.Errorf("failed to serve: %v", err) - return - } - }() - defer s.GracefulStop() - - testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - registry := prometheus.NewRegistry() - - result := ProbeGRPC(testCTX, "localhost:"+port, - config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ - TLS: true, - TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: true}, - IPProtocolFallback: false, - }, - }, registry, promslog.NewNopLogger()) - - if !result { - t.Fatalf("GRPC probe failed") - } - - mfs, err := registry.Gather() - if err != nil { - t.Fatal(err) - } - - expectedLabels := map[string]map[string]string{ - "probe_tls_version_info": { - "version": "TLS 1.2", - }, - } - checkRegistryLabels(expectedLabels, mfs, t) - - expectedResults := map[string]float64{ - "probe_grpc_ssl": 1, - "probe_grpc_status_code": 0, - } - - checkRegistryResults(expectedResults, mfs, t) + certExpiry := time.Now().AddDate(0, 0, 1) + testCertTmpl := generateCertificateTemplate(certExpiry, false) + testCertTmpl.IsCA = true + _, testcertPem, testKey := generateSelfSignedCertificate(testCertTmpl) + + // CAFile must be passed via filesystem, use a tempfile. + tmpCaFile, err := os.CreateTemp("", "cafile.pem") + if err != nil { + t.Fatalf("Error creating CA tempfile: %s", err) + } + if _, err = tmpCaFile.Write(testcertPem); err != nil { + t.Fatalf("Error writing CA tempfile: %s", err) + } + if err = tmpCaFile.Close(); err != nil { + t.Fatalf("Error closing CA tempfile: %s", err) + } + defer os.Remove(tmpCaFile.Name()) + + testKeyPem := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(testKey)}) + testcert, err := tls.X509KeyPair(testcertPem, testKeyPem) + if err != nil { + panic(fmt.Sprintf("Failed to decode TLS testing keypair: %s\n", err)) + } + + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{testcert}, + MinVersion: tls.VersionTLS12, + MaxVersion: tls.VersionTLS12, + } + + ln, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error listening on socket: %s", err) + } + defer ln.Close() + + _, port, err := net.SplitHostPort(ln.Addr().String()) + if err != nil { + t.Fatalf("Error retrieving port for socket: %s", err) + } + + s := grpc.NewServer(grpc.Creds(credentials.NewTLS(tlsConfig))) + healthServer := health.NewServer() + healthServer.SetServingStatus("service", grpc_health_v1.HealthCheckResponse_SERVING) + grpc_health_v1.RegisterHealthServer(s, healthServer) + + go func() { + if err := s.Serve(ln); err != nil { + t.Errorf("failed to serve: %v", err) + return + } + }() + defer s.GracefulStop() + + testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + registry := prometheus.NewRegistry() + + result := ProbeGRPC(testCTX, "localhost:"+port, + config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ + TLS: true, + TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: true}, + IPProtocolFallback: false, + }, + }, registry, promslog.NewNopLogger()) + + if !result { + t.Fatalf("GRPC probe failed") + } + + mfs, err := registry.Gather() + if err != nil { + t.Fatal(err) + } + + expectedLabels := map[string]map[string]string{ + "probe_tls_version_info": { + "version": "TLS 1.2", + }, + } + checkRegistryLabels(expectedLabels, mfs, t) + + expectedResults := map[string]float64{ + "probe_grpc_ssl": 1, + "probe_grpc_status_code": 0, + } + + checkRegistryResults(expectedResults, mfs, t) } func TestNoTLSConnection(t *testing.T) { - if os.Getenv("CI") == "true" { - t.Skip("skipping; CI is failing on ipv6 dns requests") - } - - ln, err := net.Listen("tcp", "localhost:0") - if err != nil { - t.Fatalf("Error listening on socket: %s", err) - } - defer ln.Close() - - _, port, err := net.SplitHostPort(ln.Addr().String()) - if err != nil { - t.Fatalf("Error retrieving port for socket: %s", err) - } - s := grpc.NewServer() - healthServer := health.NewServer() - healthServer.SetServingStatus("service", grpc_health_v1.HealthCheckResponse_SERVING) - grpc_health_v1.RegisterHealthServer(s, healthServer) - - go func() { - if err := s.Serve(ln); err != nil { - t.Errorf("failed to serve: %v", err) - return - } - }() - defer s.GracefulStop() - - testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - registry := prometheus.NewRegistry() - - result := ProbeGRPC(testCTX, "localhost:"+port, - config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ - TLS: true, - TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: true}, - IPProtocolFallback: false, - }, - }, registry, promslog.NewNopLogger()) - - if result { - t.Fatalf("GRPC probe succeed") - } - - mfs, err := registry.Gather() - if err != nil { - t.Fatal(err) - } - - expectedResults := map[string]float64{ - "probe_grpc_ssl": 0, - "probe_grpc_status_code": 14, // UNAVAILABLE - } - - checkRegistryResults(expectedResults, mfs, t) + ln, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error listening on socket: %s", err) + } + defer ln.Close() + + _, port, err := net.SplitHostPort(ln.Addr().String()) + if err != nil { + t.Fatalf("Error retrieving port for socket: %s", err) + } + s := grpc.NewServer() + healthServer := health.NewServer() + healthServer.SetServingStatus("service", grpc_health_v1.HealthCheckResponse_SERVING) + grpc_health_v1.RegisterHealthServer(s, healthServer) + + go func() { + if err := s.Serve(ln); err != nil { + t.Errorf("failed to serve: %v", err) + return + } + }() + defer s.GracefulStop() + + testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + registry := prometheus.NewRegistry() + + result := ProbeGRPC(testCTX, "localhost:"+port, + config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ + TLS: true, + TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: true}, + IPProtocolFallback: false, + }, + }, registry, promslog.NewNopLogger()) + + if result { + t.Fatalf("GRPC probe succeed") + } + + mfs, err := registry.Gather() + if err != nil { + t.Fatal(err) + } + + expectedResults := map[string]float64{ + "probe_grpc_ssl": 0, + "probe_grpc_status_code": 14, // UNAVAILABLE + } + + checkRegistryResults(expectedResults, mfs, t) } func TestGRPCServiceNotFound(t *testing.T) { - if os.Getenv("CI") == "true" { - t.Skip("skipping; CI is failing on ipv6 dns requests") - } - - ln, err := net.Listen("tcp", "localhost:0") - if err != nil { - t.Fatalf("Error listening on socket: %s", err) - } - defer ln.Close() - - _, port, err := net.SplitHostPort(ln.Addr().String()) - if err != nil { - t.Fatalf("Error retrieving port for socket: %s", err) - } - s := grpc.NewServer() - healthServer := health.NewServer() - healthServer.SetServingStatus("service", grpc_health_v1.HealthCheckResponse_SERVING) - grpc_health_v1.RegisterHealthServer(s, healthServer) - - go func() { - if err := s.Serve(ln); err != nil { - t.Errorf("failed to serve: %v", err) - return - } - }() - defer s.GracefulStop() - - testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - registry := prometheus.NewRegistry() - - result := ProbeGRPC(testCTX, "localhost:"+port, - config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ - IPProtocolFallback: false, - Service: "NonExistingService", - }, - }, registry, promslog.NewNopLogger()) - - if result { - t.Fatalf("GRPC probe succeed") - } - - mfs, err := registry.Gather() - if err != nil { - t.Fatal(err) - } - - expectedResults := map[string]float64{ - "probe_grpc_ssl": 0, - "probe_grpc_status_code": 5, // NOT_FOUND - } - - checkRegistryResults(expectedResults, mfs, t) + ln, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error listening on socket: %s", err) + } + defer ln.Close() + + _, port, err := net.SplitHostPort(ln.Addr().String()) + if err != nil { + t.Fatalf("Error retrieving port for socket: %s", err) + } + s := grpc.NewServer() + healthServer := health.NewServer() + healthServer.SetServingStatus("service", grpc_health_v1.HealthCheckResponse_SERVING) + grpc_health_v1.RegisterHealthServer(s, healthServer) + + go func() { + if err := s.Serve(ln); err != nil { + t.Errorf("failed to serve: %v", err) + return + } + }() + defer s.GracefulStop() + + testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + registry := prometheus.NewRegistry() + + result := ProbeGRPC(testCTX, "localhost:"+port, + config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ + IPProtocolFallback: false, + Service: "NonExistingService", + }, + }, registry, promslog.NewNopLogger()) + + if result { + t.Fatalf("GRPC probe succeed") + } + + mfs, err := registry.Gather() + if err != nil { + t.Fatal(err) + } + + expectedResults := map[string]float64{ + "probe_grpc_ssl": 0, + "probe_grpc_status_code": 5, // NOT_FOUND + } + + checkRegistryResults(expectedResults, mfs, t) } func TestGRPCHealthCheckUnimplemented(t *testing.T) { - if os.Getenv("CI") == "true" { - t.Skip("skipping; CI is failing on ipv6 dns requests") - } - - ln, err := net.Listen("tcp", "localhost:0") - if err != nil { - t.Fatalf("Error listening on socket: %s", err) - } - defer ln.Close() - - _, port, err := net.SplitHostPort(ln.Addr().String()) - if err != nil { - t.Fatalf("Error retrieving port for socket: %s", err) - } - s := grpc.NewServer() - - go func() { - if err := s.Serve(ln); err != nil { - t.Errorf("failed to serve: %v", err) - return - } - }() - defer s.GracefulStop() - - testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - registry := prometheus.NewRegistry() - - result := ProbeGRPC(testCTX, "localhost:"+port, - config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ - IPProtocolFallback: false, - Service: "NonExistingService", - }, - }, registry, promslog.NewNopLogger()) - - if result { - t.Fatalf("GRPC probe succeed") - } - - mfs, err := registry.Gather() - if err != nil { - t.Fatal(err) - } - - expectedResults := map[string]float64{ - "probe_grpc_ssl": 0, - "probe_grpc_status_code": 12, // UNIMPLEMENTED - } - - checkRegistryResults(expectedResults, mfs, t) + ln, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error listening on socket: %s", err) + } + defer ln.Close() + + _, port, err := net.SplitHostPort(ln.Addr().String()) + if err != nil { + t.Fatalf("Error retrieving port for socket: %s", err) + } + s := grpc.NewServer() + + go func() { + if err := s.Serve(ln); err != nil { + t.Errorf("failed to serve: %v", err) + return + } + }() + defer s.GracefulStop() + + testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + registry := prometheus.NewRegistry() + + result := ProbeGRPC(testCTX, "localhost:"+port, + config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ + IPProtocolFallback: false, + Service: "NonExistingService", + }, + }, registry, promslog.NewNopLogger()) + + if result { + t.Fatalf("GRPC probe succeed") + } + + mfs, err := registry.Gather() + if err != nil { + t.Fatal(err) + } + + expectedResults := map[string]float64{ + "probe_grpc_ssl": 0, + "probe_grpc_status_code": 12, // UNIMPLEMENTED + } + + checkRegistryResults(expectedResults, mfs, t) } func TestGRPCAbsentFailedTLS(t *testing.T) { - testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - registry := prometheus.NewRegistry() - - // probe and invalid port to trigger TCP/TLS error - result := ProbeGRPC(testCTX, "localhost:0", - config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ - IPProtocolFallback: false, - Service: "NonExistingService", - }, - }, registry, promslog.NewNopLogger()) - - if result { - t.Fatalf("GRPC probe succeeded, should have failed") - } - - mfs, err := registry.Gather() - if err != nil { - t.Fatal(err) - } - - absentMetrics := []string{ - "probe_ssl_earliest_cert_expiry", - "probe_tls_version_info", - "probe_ssl_last_chain_info", - } - - checkAbsentMetrics(absentMetrics, mfs, t) + testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + registry := prometheus.NewRegistry() + + // probe and invalid port to trigger TCP/TLS error + result := ProbeGRPC(testCTX, "localhost:0", + config.Module{Timeout: time.Second, GRPC: config.GRPCProbe{ + IPProtocolFallback: false, + Service: "NonExistingService", + }, + }, registry, promslog.NewNopLogger()) + + if result { + t.Fatalf("GRPC probe succeeded, should have failed") + } + + mfs, err := registry.Gather() + if err != nil { + t.Fatal(err) + } + + absentMetrics := []string{ + "probe_ssl_earliest_cert_expiry", + "probe_tls_version_info", + "probe_ssl_last_chain_info", + } + + checkAbsentMetrics(absentMetrics, mfs, t) +} +func TestProbeInvalidURL(t *testing.T) { + // This test checks that ProbeGRPC returns false when given an invalid URL. + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + registry := prometheus.NewRegistry() + // Pass an invalid URL that will fail in url.Parse. + result := ProbeGRPC(ctx, "://bad", config.Module{}, registry, promslog.NewNopLogger()) + if result { + t.Fatal("Expected ProbeGRPC to return false for an invalid URL") + } } + +func TestGRPCHealthCheckClient(t *testing.T) { + // This test directly tests gRPCHealthCheckClient.Check by using our fakeHealthClient. + // First, simulate a successful health check response. + fakeClient := &fakeHealthClient{status: grpc_health_v1.HealthCheckResponse_SERVING} + client := gRPCHealthCheckClient{ + client: fakeClient, + // The client.conn field is only used for closing so it can be a dummy pointer. + conn: &grpc.ClientConn{}, + } + ctx := context.Background() + ok, code, _, statusStr, err := client.Check(ctx, "dummyService") + if err != nil { + t.Fatalf("Unexpected error during health check: %v", err) + } + if !ok { + t.Fatal("Expected health check to succeed") + } + if code != codes.OK { + t.Fatalf("Expected code codes.OK, but got %v", code) + } + if statusStr != grpc_health_v1.HealthCheckResponse_SERVING.String() { + t.Fatalf("Expected status %q, got %q", grpc_health_v1.HealthCheckResponse_SERVING.String(), statusStr) + } + + // Now simulate an error response from the health check. + fakeErr := status.Error(codes.NotFound, "service not found") + fakeClient.err = fakeErr + ok, code, _, _, err = client.Check(ctx, "dummyService") + if ok { + t.Fatal("Expected health check to fail") + } + if code != codes.NotFound { + t.Fatalf("Expected code NotFound, got %v", code) + } +} \ No newline at end of file From 35f9fc5dea9f3ae2344757bf1fe3a24511ae09db Mon Sep 17 00:00:00 2001 From: CodeBeaverAI Date: Mon, 3 Mar 2025 23:32:23 +0100 Subject: [PATCH 2/2] --- codebeaver.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 codebeaver.yml diff --git a/codebeaver.yml b/codebeaver.yml new file mode 100644 index 00000000..3fb7887f --- /dev/null +++ b/codebeaver.yml @@ -0,0 +1,2 @@ +from:go-1.22 +# This file was generated automatically by CodeBeaver based on your repository. Learn how to customize it here: https://docs.codebeaver.ai/configuration/ \ No newline at end of file