Skip to content

Commit 508dcfc

Browse files
committed
chore: integration: perform tests against locally-running service
Testing against test-api.k6.io introduces reliability problems and may make the test flaky if the service is not responsive.
1 parent 1a0135c commit 508dcfc

File tree

2 files changed

+67
-27
lines changed

2 files changed

+67
-27
lines changed

integration/integration_test.go

+59-20
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
_ "embed"
77
"errors"
88
"io"
9+
"net/http"
10+
"net/http/httptest"
911
"os"
1012
"os/exec"
1113
"path/filepath"
@@ -35,18 +37,26 @@ func TestSMK6(t *testing.T) {
3537
t.Fatalf("sm-k6 binary does not seem to exist, must be compiled before running this test: %v", err)
3638
}
3739

38-
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
40+
httpEndpoint, httpsEndpoint := testHTTPServer(t)
41+
42+
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
3943
t.Cleanup(cancel)
4044

4145
outFile := filepath.Join(t.TempDir(), "metrics.txt")
4246

43-
cmd := exec.CommandContext(ctx, smk6, "run", "-", "-o=sm="+outFile)
47+
cmd := exec.CommandContext(ctx, smk6, "run", "-", "-o=sm="+outFile, "--insecure-skip-tls-verify")
4448
cmd.Stdin = bytes.NewReader(testScript)
45-
err = cmd.Run()
49+
cmd.Env = []string{
50+
"TEST_HTTP_HOST=" + httpEndpoint,
51+
"TEST_HTTPS_HOST=" + httpsEndpoint,
52+
}
53+
k6out, err := cmd.CombinedOutput()
4654
if err != nil {
47-
t.Fatalf("running sm-k6: %v", err)
55+
t.Fatalf("running sm-k6: %v\n%s", errors.Join(err, ctx.Err()), string(k6out))
4856
}
4957

58+
t.Log(string(k6out))
59+
5060
out, err := os.Open(outFile)
5161
if err != nil {
5262
t.Fatalf("reading output metrics: %v", err)
@@ -218,44 +228,44 @@ func TestSMK6(t *testing.T) {
218228
{
219229
name: "HTTP duration second has a duration-ish value",
220230
metricName: "probe_http_duration_seconds",
221-
metricLabels: map[string]string{"phase": "processing", "url": "https://test-api.k6.io/public/crocodiles/"},
231+
metricLabels: map[string]string{"phase": "processing", "url": httpsEndpoint + "/public/crocodiles/"},
222232
assertValue: nonZero,
223233
},
224234
// Custom http phases. Check for each one individually as we use slightly different names than k6 uses.
225235
{
226236
name: "HTTP duration seconds has phase=resolve",
227237
metricName: "probe_http_duration_seconds",
228-
metricLabels: map[string]string{"phase": "resolve", "url": "https://test-api.k6.io/public/crocodiles/"},
238+
metricLabels: map[string]string{"phase": "resolve", "url": httpsEndpoint + "/public/crocodiles/"},
229239
assertValue: any, // Just fail if not present.
230240
},
231241
{
232242
name: "HTTP duration seconds has phase=connect",
233243
metricName: "probe_http_duration_seconds",
234-
metricLabels: map[string]string{"phase": "connect", "url": "https://test-api.k6.io/public/crocodiles/"},
244+
metricLabels: map[string]string{"phase": "connect", "url": httpsEndpoint + "/public/crocodiles/"},
235245
assertValue: any, // Just fail if not present.
236246
},
237247
{
238248
name: "HTTP duration seconds has phase=tls",
239249
metricName: "probe_http_duration_seconds",
240-
metricLabels: map[string]string{"phase": "tls", "url": "https://test-api.k6.io/public/crocodiles/"},
250+
metricLabels: map[string]string{"phase": "tls", "url": httpsEndpoint + "/public/crocodiles/"},
241251
assertValue: any, // Just fail if not present.
242252
},
243253
{
244254
name: "HTTP duration seconds has phase=processing",
245255
metricName: "probe_http_duration_seconds",
246-
metricLabels: map[string]string{"phase": "processing", "url": "https://test-api.k6.io/public/crocodiles/"},
256+
metricLabels: map[string]string{"phase": "processing", "url": httpsEndpoint + "/public/crocodiles/"},
247257
assertValue: any, // Just fail if not present.
248258
},
249259
{
250260
name: "HTTP duration seconds has phase=transfer",
251261
metricName: "probe_http_duration_seconds",
252-
metricLabels: map[string]string{"phase": "transfer", "url": "https://test-api.k6.io/public/crocodiles/"},
262+
metricLabels: map[string]string{"phase": "transfer", "url": httpsEndpoint + "/public/crocodiles/"},
253263
assertValue: any, // Just fail if not present.
254264
},
255265
{
256266
name: "Error code for request that should succeed",
257267
metricName: "probe_http_error_code",
258-
metricLabels: map[string]string{"url": "https://test-api.k6.io/public/crocodiles/"},
268+
metricLabels: map[string]string{"url": httpsEndpoint + "/public/crocodiles/"},
259269
assertValue: equals(0),
260270
},
261271
{
@@ -267,56 +277,56 @@ func TestSMK6(t *testing.T) {
267277
{
268278
name: "HTTP status code for a request that should succeed",
269279
metricName: "probe_http_status_code",
270-
metricLabels: map[string]string{"url": "https://test-api.k6.io/public/crocodiles/"},
280+
metricLabels: map[string]string{"url": httpsEndpoint + "/public/crocodiles/"},
271281
assertValue: equals(200),
272282
},
273283
{
274284
name: "Expected response for a request that should succeed",
275285
metricName: "probe_http_got_expected_response",
276-
metricLabels: map[string]string{"url": "https://test-api.k6.io/public/crocodiles/"},
286+
metricLabels: map[string]string{"url": httpsEndpoint + "/public/crocodiles/"},
277287
assertValue: equals(1),
278288
},
279289
{
280290
name: "Expected response for a request that should fail",
281291
metricName: "probe_http_got_expected_response",
282-
metricLabels: map[string]string{"url": "https://test-api.k6.io/public/crocodiles2/"},
292+
metricLabels: map[string]string{"url": httpsEndpoint + "/public/crocodiles2/"},
283293
assertValue: equals(0),
284294
},
285295
{
286296
name: "Total requests for a URL accessed once",
287297
metricName: "probe_http_requests_total",
288-
metricLabels: map[string]string{"url": "https://test-api.k6.io/public/crocodiles/"},
298+
metricLabels: map[string]string{"url": httpsEndpoint + "/public/crocodiles/"},
289299
assertValue: equals(1),
290300
},
291301
{
292302
name: "Total requests for a URL accessed twice",
293303
metricName: "probe_http_requests_total",
294-
metricLabels: map[string]string{"url": "https://test-api.k6.io/public/crocodiles4/"},
304+
metricLabels: map[string]string{"url": httpsEndpoint + "/public/crocodiles4/"},
295305
assertValue: equals(2),
296306
},
297307
{
298308
name: "HTTP requests failed rate",
299309
metricName: "probe_http_requests_failed",
300-
metricLabels: map[string]string{"url": "https://test-api.k6.io/public/crocodiles4/"},
310+
metricLabels: map[string]string{"url": httpsEndpoint + "/public/crocodiles4/"},
301311
assertValue: equals(1),
302312
},
303313
{
304314
name: "HTTP requests failed ttoal",
305315
metricName: "probe_http_requests_failed_total",
306-
metricLabels: map[string]string{"url": "https://test-api.k6.io/public/crocodiles4/"},
316+
metricLabels: map[string]string{"url": httpsEndpoint + "/public/crocodiles4/"},
307317
assertValue: equals(2),
308318
},
309319
{
310320
name: "HTTP version",
311321
metricName: "probe_http_version",
312-
metricLabels: map[string]string{"url": "https://test-api.k6.io/public/crocodiles/"},
322+
metricLabels: map[string]string{"url": httpsEndpoint + "/public/crocodiles/"},
313323
assertValue: func(f float64) bool { return f >= 1.1 },
314324
},
315325
{
316326
name: "TLS version label value",
317327
metricName: "probe_http_info",
318328
// Test for a paticular URL to avoid matching a failed request, which has no TLS version.
319-
metricLabels: map[string]string{"tls_version": "1.3", "url": "https://test-api.k6.io/public/crocodiles/"},
329+
metricLabels: map[string]string{"tls_version": "1.3", "url": httpsEndpoint + "/public/crocodiles/"},
320330
assertValue: any, // Just fail if not present.
321331
},
322332
} {
@@ -383,3 +393,32 @@ func nonZero(v float64) bool {
383393
func any(float64) bool {
384394
return true
385395
}
396+
397+
// testHTTPServer starts an HTTP and HTTPS servers that can be used to perform requests to.
398+
// The HTTP server redirects all requests to the HTTPS one.
399+
func testHTTPServer(t *testing.T) (string, string) {
400+
t.Helper()
401+
402+
mux := http.NewServeMux()
403+
mux.HandleFunc("/{$}", func(rw http.ResponseWriter, _ *http.Request) {
404+
// `/{$}` matches exactly `/`, and not `/foo`.
405+
_, _ = rw.Write([]byte("Hello world!"))
406+
})
407+
mux.HandleFunc("/public/crocodiles/", func(rw http.ResponseWriter, _ *http.Request) {
408+
_, _ = rw.Write([]byte("One, two, three, croc!"))
409+
})
410+
tlsServer := httptest.NewTLSServer(mux)
411+
t.Cleanup(func() {
412+
tlsServer.Close()
413+
})
414+
415+
plainServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
416+
rw.Header().Add("Location", tlsServer.URL+"/"+strings.TrimPrefix(r.URL.Path, "/"))
417+
rw.WriteHeader(http.StatusPermanentRedirect)
418+
}))
419+
t.Cleanup(func() {
420+
plainServer.Close()
421+
})
422+
423+
return plainServer.URL, tlsServer.URL
424+
}

integration/test-script.js

+8-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { check } from 'k6';
22
import http from 'k6/http';
33
import { Trend, Counter, Gauge } from 'k6/metrics';
44

5-
const testHost = __ENV.TEST_HOST ? __ENV.TEST_HOST : "test-api.k6.io";
5+
const httpHost = __ENV.TEST_HTTP_HOST ? __ENV.TEST_HTTP_HOST : "test-api.k6.io";
6+
const httpsHost = __ENV.TEST_HTTPS_HOST ? __ENV.TEST_HTTPS_HOST : "test-api.k6.io";
67

78
const myTrend = new Trend('waiting_time');
89
const myCounter = new Counter('my_counter');
@@ -36,11 +37,11 @@ export default function () {
3637
}
3738
);
3839

39-
http.get(`http://${testHost}`); // non-https.
40-
http.get(`https://${testHost}/public/crocodiles/`);
41-
http.get(`https://${testHost}/public/crocodiles2/`); // 404
42-
http.get(`https://${testHost}/public/crocodiles3/`); // 404
43-
http.get(`https://${testHost}/public/crocodiles4/`); // 404
44-
http.get(`https://${testHost}/public/crocodiles4/`); // Second 404, to assert differences between failure rate and counter.
40+
http.get(`${httpHost}`); // non-https.
41+
http.get(`${httpsHost}/public/crocodiles/`);
42+
http.get(`${httpsHost}/public/crocodiles2/`); // 404
43+
http.get(`${httpsHost}/public/crocodiles3/`); // 404
44+
http.get(`${httpsHost}/public/crocodiles4/`); // 404
45+
http.get(`${httpsHost}/public/crocodiles4/`); // Second 404, to assert differences between failure rate and counter.
4546
http.get(`http://fail.internal/public/crocodiles4/`); // failed
4647
}

0 commit comments

Comments
 (0)