cloudflared-mirror/k8s/watcher_test.go

155 lines
3.8 KiB
Go

package k8s
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// fakeK8sServer returns an httptest.Server that responds to /api/v1/services
// with the given service list.
func fakeK8sServer(t *testing.T, services serviceList) *httptest.Server {
t.Helper()
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(services); err != nil {
t.Fatalf("failed to encode services: %v", err)
}
}))
}
func TestDiscoverServicesWithMockServer(t *testing.T) {
log := zerolog.Nop()
svcList := serviceList{
Items: []serviceItem{
{
Metadata: objectMeta{
Name: "web",
Namespace: "default",
Annotations: map[string]string{
AnnotationEnabled: "true",
},
},
Spec: serviceSpec{
ClusterIP: "10.96.0.1",
Ports: []servicePort{{Name: "http", Port: 80, Protocol: "TCP"}},
},
},
{
Metadata: objectMeta{
Name: "skipped",
Namespace: "default",
Annotations: map[string]string{
// No tunnel annotation
},
},
Spec: serviceSpec{
ClusterIP: "10.96.0.2",
Ports: []servicePort{{Port: 80}},
},
},
{
Metadata: objectMeta{
Name: "api",
Namespace: "prod",
Annotations: map[string]string{
AnnotationEnabled: "true",
AnnotationHostname: "api.mycompany.com",
AnnotationScheme: "https",
AnnotationPort: "443",
},
},
Spec: serviceSpec{
ClusterIP: "10.96.1.5",
Ports: []servicePort{
{Name: "http", Port: 80},
{Name: "https", Port: 443},
},
},
},
},
}
server := fakeK8sServer(t, svcList)
defer server.Close()
cfg := &Config{
Enabled: true,
BaseDomain: "example.com",
}
// Override the client builder for testing.
client := &kubeClient{
baseURL: server.URL,
httpClient: server.Client(),
log: &log,
}
ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)
defer cancel()
body, err := client.do(ctx, http.MethodGet, "/api/v1/services")
require.NoError(t, err)
var list serviceList
require.NoError(t, json.Unmarshal(body, &list))
require.Len(t, list.Items, 3)
// Now test the full discovery pipeline by filtering.
services := make([]ServiceInfo, 0, len(list.Items))
for _, item := range list.Items {
ann := item.Metadata.Annotations
if ann == nil {
continue
}
enabled, ok := ann[AnnotationEnabled]
if !ok || !isTrue(enabled) {
continue
}
si, err := serviceInfoFromItem(item, cfg)
if err != nil {
continue
}
services = append(services, *si)
}
require.Len(t, services, 2)
// web service
assert.Equal(t, "web", services[0].Name)
assert.Equal(t, "web-default.example.com", services[0].Hostname)
assert.Equal(t, "http", services[0].Scheme)
assert.Equal(t, int32(80), services[0].Port)
// api service
assert.Equal(t, "api", services[1].Name)
assert.Equal(t, "api.mycompany.com", services[1].Hostname)
assert.Equal(t, "https", services[1].Scheme)
assert.Equal(t, int32(443), services[1].Port)
}
func TestWatcherServicesEqual(t *testing.T) {
a := []ServiceInfo{
{Name: "web", Namespace: "default", ClusterIP: "10.0.0.1", Port: 80, Scheme: "http", Hostname: "web.example.com"},
}
b := []ServiceInfo{
{Name: "web", Namespace: "default", ClusterIP: "10.0.0.1", Port: 80, Scheme: "http", Hostname: "web.example.com"},
}
assert.True(t, servicesEqual(a, b))
assert.True(t, servicesEqual(nil, nil))
assert.False(t, servicesEqual(a, nil))
assert.False(t, servicesEqual(nil, b))
c := append(b, ServiceInfo{Name: "api", Namespace: "default", ClusterIP: "10.0.0.2", Port: 443, Scheme: "https", Hostname: "api.example.com"})
assert.False(t, servicesEqual(a, c))
}