Skip to content

Commit 3738605

Browse files
temblekingdangaiden
authored andcommitted
ci: improve sysdig client test coverage (#81)
4 functions in client.go had 0% coverage (GetTokenFromContext, GetHostFromContext, WithFallbackAuthentication, WithVersion). New tests exercise auth strategies through the actual client against httptest servers, not as isolated RequestEditorFn unit tests. Refactors duplicated handler into shared permissionsHandler across TLS and auth tests.
1 parent 7548f2a commit 3738605

1 file changed

Lines changed: 140 additions & 17 deletions

File tree

internal/infra/sysdig/client_test.go

Lines changed: 140 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,26 @@ import (
1212
"github.com/sysdiglabs/sysdig-mcp-server/internal/infra/sysdig"
1313
)
1414

15+
func permissionsHandler(captureHeaders func(http.Header)) http.Handler {
16+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
17+
if captureHeaders != nil {
18+
captureHeaders(r.Header)
19+
}
20+
if r.URL.Path == "/api/users/me/permissions" {
21+
w.Header().Set("Content-Type", "application/json")
22+
w.WriteHeader(http.StatusOK)
23+
_, _ = w.Write([]byte(`{"permissions":[]}`))
24+
return
25+
}
26+
w.WriteHeader(http.StatusNotFound)
27+
})
28+
}
29+
1530
var _ = Describe("Client TLS", func() {
1631
var ts *httptest.Server
1732

1833
BeforeEach(func() {
19-
// Start a TLS server with a self-signed certificate
20-
ts = httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
21-
if r.URL.Path == "/api/users/me/permissions" {
22-
w.Header().Set("Content-Type", "application/json")
23-
w.WriteHeader(http.StatusOK)
24-
_, _ = w.Write([]byte(`{"permissions":[]}`))
25-
return
26-
}
27-
w.WriteHeader(http.StatusNotFound)
28-
}))
29-
// Redirect server logs to GinkgoWriter to avoid noise in test output
34+
ts = httptest.NewTLSServer(permissionsHandler(nil))
3035
ts.Config.ErrorLog = log.New(GinkgoWriter, "", 0)
3136
})
3237

@@ -35,35 +40,153 @@ var _ = Describe("Client TLS", func() {
3540
})
3641

3742
It("should fail request with self-signed cert by default", func() {
38-
// Create client pointing to the TLS server without custom transport
3943
client, err := sysdig.NewSysdigClient(
4044
sysdig.WithFixedHostAndToken(ts.URL, "dummy-token"),
4145
)
4246
Expect(err).NotTo(HaveOccurred())
4347

44-
// Attempt request
4548
_, err = client.GetMyPermissionsWithResponse(context.Background())
4649
Expect(err).To(HaveOccurred())
47-
// Verification that it failed due to certificate issues
4850
Expect(err.Error()).To(Or(ContainSubstring("certificate"), ContainSubstring("unknown authority")))
4951
})
5052

5153
It("should succeed request when using custom HTTP client with InsecureSkipVerify", func() {
52-
// Create custom HTTP client that skips verification
5354
transport := http.DefaultTransport.(*http.Transport).Clone()
5455
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
5556
httpClient := &http.Client{Transport: transport}
5657

57-
// Create client using the custom HTTP client
5858
client, err := sysdig.NewSysdigClient(
5959
sysdig.WithFixedHostAndToken(ts.URL, "dummy-token"),
6060
sysdig.WithHTTPClient(httpClient),
6161
)
6262
Expect(err).NotTo(HaveOccurred())
6363

64-
// Attempt request
6564
resp, err := client.GetMyPermissionsWithResponse(context.Background())
6665
Expect(err).NotTo(HaveOccurred())
6766
Expect(resp.HTTPResponse.StatusCode).To(Equal(http.StatusOK))
6867
})
6968
})
69+
70+
var _ = Describe("Context helpers", func() {
71+
It("roundtrips token through context", func() {
72+
ctx := sysdig.WrapContextWithToken(context.Background(), "my-token")
73+
Expect(sysdig.GetTokenFromContext(ctx)).To(Equal("my-token"))
74+
})
75+
76+
It("roundtrips host through context", func() {
77+
ctx := sysdig.WrapContextWithHost(context.Background(), "https://example.com")
78+
Expect(sysdig.GetHostFromContext(ctx)).To(Equal("https://example.com"))
79+
})
80+
81+
It("panics when token is missing from context", func() {
82+
Expect(func() {
83+
sysdig.GetTokenFromContext(context.Background())
84+
}).To(Panic())
85+
})
86+
87+
It("panics when host is missing from context", func() {
88+
Expect(func() {
89+
sysdig.GetHostFromContext(context.Background())
90+
}).To(Panic())
91+
})
92+
})
93+
94+
var _ = Describe("Client authentication", func() {
95+
var ts *httptest.Server
96+
var lastHeaders http.Header
97+
98+
BeforeEach(func() {
99+
ts = httptest.NewServer(permissionsHandler(func(h http.Header) {
100+
lastHeaders = h.Clone()
101+
}))
102+
})
103+
104+
AfterEach(func() {
105+
ts.Close()
106+
})
107+
108+
Describe("WithHostAndTokenFromContext", func() {
109+
It("authenticates using context values", func() {
110+
client, err := sysdig.NewSysdigClient(sysdig.WithHostAndTokenFromContext())
111+
Expect(err).NotTo(HaveOccurred())
112+
113+
ctx := sysdig.WrapContextWithHost(context.Background(), ts.URL)
114+
ctx = sysdig.WrapContextWithToken(ctx, "ctx-token")
115+
116+
resp, err := client.GetMyPermissionsWithResponse(ctx)
117+
Expect(err).NotTo(HaveOccurred())
118+
Expect(resp.HTTPResponse.StatusCode).To(Equal(http.StatusOK))
119+
Expect(lastHeaders.Get("Authorization")).To(Equal("Bearer ctx-token"))
120+
})
121+
122+
It("fails when token is missing from context", func() {
123+
client, err := sysdig.NewSysdigClient(sysdig.WithHostAndTokenFromContext())
124+
Expect(err).NotTo(HaveOccurred())
125+
126+
ctx := sysdig.WrapContextWithHost(context.Background(), ts.URL)
127+
128+
_, err = client.GetMyPermissionsWithResponse(ctx)
129+
Expect(err).To(MatchError(ContainSubstring("authorization token not present")))
130+
})
131+
})
132+
133+
Describe("WithFallbackAuthentication", func() {
134+
It("uses first auth when it succeeds", func() {
135+
client, err := sysdig.NewSysdigClient(
136+
sysdig.WithFallbackAuthentication(
137+
sysdig.WithFixedHostAndToken(ts.URL, "primary-token"),
138+
sysdig.WithFixedHostAndToken(ts.URL, "fallback-token"),
139+
),
140+
)
141+
Expect(err).NotTo(HaveOccurred())
142+
143+
resp, err := client.GetMyPermissionsWithResponse(context.Background())
144+
Expect(err).NotTo(HaveOccurred())
145+
Expect(resp.HTTPResponse.StatusCode).To(Equal(http.StatusOK))
146+
Expect(lastHeaders.Get("Authorization")).To(Equal("Bearer primary-token"))
147+
})
148+
149+
It("falls back to second auth when first fails", func() {
150+
client, err := sysdig.NewSysdigClient(
151+
sysdig.WithFallbackAuthentication(
152+
sysdig.WithHostAndTokenFromContext(),
153+
sysdig.WithFixedHostAndToken(ts.URL, "fallback-token"),
154+
),
155+
)
156+
Expect(err).NotTo(HaveOccurred())
157+
158+
resp, err := client.GetMyPermissionsWithResponse(context.Background())
159+
Expect(err).NotTo(HaveOccurred())
160+
Expect(resp.HTTPResponse.StatusCode).To(Equal(http.StatusOK))
161+
Expect(lastHeaders.Get("Authorization")).To(Equal("Bearer fallback-token"))
162+
})
163+
164+
It("fails when all auth methods fail", func() {
165+
client, err := sysdig.NewSysdigClient(
166+
sysdig.WithFallbackAuthentication(
167+
sysdig.WithHostAndTokenFromContext(),
168+
sysdig.WithHostAndTokenFromContext(),
169+
),
170+
)
171+
Expect(err).NotTo(HaveOccurred())
172+
173+
_, err = client.GetMyPermissionsWithResponse(context.Background())
174+
Expect(err).To(MatchError(ContainSubstring("unable to authenticate")))
175+
})
176+
})
177+
178+
Describe("WithVersion", func() {
179+
It("sends User-Agent header with version", func() {
180+
client, err := sysdig.NewSysdigClient(
181+
sysdig.WithFixedHostAndToken(ts.URL, "tok"),
182+
sysdig.WithVersion("2.0.0"),
183+
)
184+
Expect(err).NotTo(HaveOccurred())
185+
186+
resp, err := client.GetMyPermissionsWithResponse(context.Background())
187+
Expect(err).NotTo(HaveOccurred())
188+
Expect(resp.HTTPResponse.StatusCode).To(Equal(http.StatusOK))
189+
Expect(lastHeaders.Get("User-Agent")).To(Equal("sysdig-mcp-server/2.0.0"))
190+
})
191+
})
192+
})

0 commit comments

Comments
 (0)