Skip to content

Commit 8fed84c

Browse files
committed
add windows integration test
1 parent 9198a3a commit 8fed84c

File tree

6 files changed

+196
-19
lines changed

6 files changed

+196
-19
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Integration Tests Windows
2+
on:
3+
# Run tests on main just so the module and build cache can be saved and used
4+
# in PRs. This speeds up the time it takes to test PRs dramatically.
5+
# (More information on https://docs.github.com/en/[email protected]/actions/using-workflows/caching-dependencies-to-speed-up-workflows)
6+
push:
7+
branches:
8+
- main
9+
pull_request:
10+
jobs:
11+
run_tests:
12+
runs-on: windows-latest
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v4
16+
- name: Setup Go
17+
uses: actions/setup-go@v5
18+
with:
19+
go-version: "1.22"
20+
- name: Run tests
21+
run: make integration-test

internal/cmd/integration-tests/docker-compose.yaml

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
version: "3"
21
services:
32

43
mimir:

internal/cmd/integration-tests/main.go

+20-8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"os"
66
"path/filepath"
7+
"runtime"
78
"strings"
89

910
"github.com/spf13/cobra"
@@ -30,26 +31,37 @@ func main() {
3031

3132
func runIntegrationTests(cmd *cobra.Command, args []string) {
3233
defer reportResults()
33-
defer cleanUpEnvironment()
34+
35+
testFolder := "./tests/"
36+
alloyBinaryPath := "../../../../../build/alloy"
37+
alloyBinary := "build/alloy"
38+
39+
if runtime.GOOS == "windows" {
40+
testFolder = "./tests-windows/"
41+
alloyBinaryPath = "..\\..\\..\\..\\..\\build\\alloy.exe"
42+
alloyBinary = "build/alloy.exe"
43+
} else {
44+
setupEnvironment()
45+
defer cleanUpEnvironment()
46+
}
3447

3548
if !skipBuild {
36-
buildAlloy()
49+
buildAlloy(alloyBinary)
3750
}
38-
setupEnvironment()
3951

4052
if specificTest != "" {
4153
fmt.Println("Running", specificTest)
42-
if !filepath.IsAbs(specificTest) && !strings.HasPrefix(specificTest, "./tests/") {
43-
specificTest = "./tests/" + specificTest
54+
if !filepath.IsAbs(specificTest) && !strings.HasPrefix(specificTest, testFolder) {
55+
specificTest = testFolder + specificTest
4456
}
4557
logChan = make(chan TestLog, 1)
46-
runSingleTest(specificTest, 12345)
58+
runSingleTest(alloyBinaryPath, specificTest, 12345)
4759
} else {
48-
testDirs, err := filepath.Glob("./tests/*")
60+
testDirs, err := filepath.Glob(testFolder + "*")
4961
if err != nil {
5062
panic(err)
5163
}
5264
logChan = make(chan TestLog, len(testDirs))
53-
runAllTests()
65+
runAllTests(alloyBinaryPath, testFolder)
5466
}
5567
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
prometheus.exporter.windows "default" { }
2+
3+
prometheus.scrape "default" {
4+
targets = prometheus.exporter.windows.default.targets
5+
forward_to = [prometheus.remote_write.default.receiver]
6+
scrape_interval = "1s"
7+
scrape_timeout = "500ms"
8+
}
9+
10+
prometheus.remote_write "default" {
11+
endpoint {
12+
url = "http://localhost:9090/receive"
13+
metadata_config {
14+
send_interval = "1s"
15+
}
16+
queue_config {
17+
max_samples_per_send = 100
18+
}
19+
}
20+
external_labels = {
21+
test_name = "win_metrics",
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
//go:build windows
2+
3+
package main
4+
5+
import (
6+
"context"
7+
"fmt"
8+
"io"
9+
"net"
10+
"net/http"
11+
"strings"
12+
"testing"
13+
"time"
14+
15+
"github.com/golang/snappy"
16+
"github.com/prometheus/prometheus/prompb"
17+
"github.com/stretchr/testify/require"
18+
)
19+
20+
// List of expected Windows metrics
21+
var winMetrics = []string{
22+
"windows_cpu_time_total", // cpu
23+
"windows_cs_logical_processors", // cs
24+
"windows_logical_disk_info", // logical_disk
25+
"windows_net_bytes_received_total", // net
26+
"windows_os_info", // os
27+
"windows_service_info", // service
28+
"windows_system_system_up_time", // system
29+
}
30+
31+
// TestWindowsMetrics sets up a server to receive remote write requests
32+
// and checks if required metrics appear within a one minute timeout
33+
func TestWindowsMetrics(t *testing.T) {
34+
foundMetrics := make(map[string]bool)
35+
for _, metric := range winMetrics {
36+
foundMetrics[metric] = false
37+
}
38+
39+
done := make(chan bool)
40+
srv := &http.Server{Addr: ":9090"}
41+
http.HandleFunc("/receive", func(w http.ResponseWriter, r *http.Request) {
42+
ts, _, err := handlePost(t, w, r)
43+
44+
if err != nil {
45+
t.Log("Cancel processing request.")
46+
return
47+
}
48+
49+
for _, timeseries := range ts {
50+
var metricName string
51+
for _, label := range timeseries.Labels {
52+
if label.Name == "__name__" {
53+
metricName = label.Value
54+
break
55+
}
56+
}
57+
for _, requiredMetric := range winMetrics {
58+
if requiredMetric == metricName && !foundMetrics[requiredMetric] {
59+
foundMetrics[requiredMetric] = true
60+
}
61+
}
62+
}
63+
64+
allFound := true
65+
for _, found := range foundMetrics {
66+
if !found {
67+
allFound = false
68+
break
69+
}
70+
}
71+
72+
if allFound {
73+
done <- true
74+
}
75+
})
76+
77+
go func() {
78+
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
79+
panic(fmt.Errorf("could not start server: %v", err))
80+
}
81+
}()
82+
defer srv.Shutdown(context.Background())
83+
84+
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
85+
defer cancel()
86+
87+
select {
88+
case <-ctx.Done():
89+
missingMetrics := []string{}
90+
for metric, found := range foundMetrics {
91+
if !found {
92+
missingMetrics = append(missingMetrics, metric)
93+
}
94+
}
95+
if len(missingMetrics) > 0 {
96+
t.Errorf("Timeout reached. Missing metrics: %v", missingMetrics)
97+
} else {
98+
t.Log("All required metrics received.")
99+
}
100+
case <-done:
101+
t.Log("All required metrics received within the timeout.")
102+
}
103+
}
104+
105+
func handlePost(t *testing.T, _ http.ResponseWriter, r *http.Request) ([]prompb.TimeSeries, []prompb.MetricMetadata, error) {
106+
defer r.Body.Close()
107+
data, err := io.ReadAll(r.Body)
108+
109+
// ignore this error because the server might shutdown while a request is being processed
110+
if opErr, ok := err.(*net.OpError); ok && strings.Contains(opErr.Err.Error(), "use of closed network connection") {
111+
return nil, nil, err
112+
}
113+
114+
require.NoError(t, err)
115+
116+
data, err = snappy.Decode(nil, data)
117+
require.NoError(t, err)
118+
119+
var req prompb.WriteRequest
120+
err = req.Unmarshal(data)
121+
require.NoError(t, err)
122+
return req.GetTimeseries(), req.Metadata, nil
123+
}

internal/cmd/integration-tests/utils.go

+9-10
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ import (
1212
"time"
1313
)
1414

15-
const (
16-
alloyBinaryPath = "../../../../../build/alloy"
17-
)
18-
1915
type TestLog struct {
2016
TestDir string
2117
AlloyLog string
@@ -34,8 +30,8 @@ func executeCommand(command string, args []string, taskDescription string) {
3430
}
3531
}
3632

37-
func buildAlloy() {
38-
executeCommand("make", []string{"-C", "../../..", "alloy"}, "Building Alloy")
33+
func buildAlloy(alloyBinary string) {
34+
executeCommand("make", []string{"-C", "../../..", "alloy", fmt.Sprintf("ALLOY_BINARY=%s", alloyBinary)}, "Building Alloy")
3935
}
4036

4137
func setupEnvironment() {
@@ -44,7 +40,7 @@ func setupEnvironment() {
4440
time.Sleep(45 * time.Second)
4541
}
4642

47-
func runSingleTest(testDir string, port int) {
43+
func runSingleTest(alloyBinaryPath string, testDir string, port int) {
4844
info, err := os.Stat(testDir)
4945
if err != nil {
5046
panic(err)
@@ -88,14 +84,17 @@ func runSingleTest(testDir string, port int) {
8884
}
8985
}
9086

87+
// sleep for a few seconds before deleting the files to make sure that they are not use anymore
88+
time.Sleep(5 * time.Second)
89+
9190
err = os.RemoveAll(filepath.Join(testDir, "data-alloy"))
9291
if err != nil {
9392
panic(err)
9493
}
9594
}
9695

97-
func runAllTests() {
98-
testDirs, err := filepath.Glob("./tests/*")
96+
func runAllTests(alloyBinaryPath string, testFolder string) {
97+
testDirs, err := filepath.Glob(testFolder + "*")
9998
if err != nil {
10099
panic(err)
101100
}
@@ -106,7 +105,7 @@ func runAllTests() {
106105
wg.Add(1)
107106
go func(td string, offset int) {
108107
defer wg.Done()
109-
runSingleTest(td, port+offset)
108+
runSingleTest(alloyBinaryPath, td, port+offset)
110109
}(testDir, i)
111110
}
112111
wg.Wait()

0 commit comments

Comments
 (0)