Skip to content

Commit

Permalink
add windows integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
wildum committed Nov 8, 2024
1 parent 9198a3a commit 44d2d92
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 18 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/integration-tests-win.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Integration Tests Windows
on:
# Run tests on main just so the module and build cache can be saved and used
# in PRs. This speeds up the time it takes to test PRs dramatically.
# (More information on https://docs.github.com/en/[email protected]/actions/using-workflows/caching-dependencies-to-speed-up-workflows)
push:
branches:
- main
pull_request:
jobs:
run_tests:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Run tests
run: make integration-test
1 change: 0 additions & 1 deletion internal/cmd/integration-tests/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
version: "3"
services:

mimir:
Expand Down
26 changes: 19 additions & 7 deletions internal/cmd/integration-tests/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -32,24 +33,35 @@ func runIntegrationTests(cmd *cobra.Command, args []string) {
defer reportResults()
defer cleanUpEnvironment()

testFolder := "./tests/"
alloyBinaryPath := "../../../../../build/alloy"
alloyBinary := "build/alloy"

if runtime.GOOS == "windows" {
testFolder = "./tests-windows/"
alloyBinaryPath = "..\\..\\..\\..\\..\\build\\alloy.exe"
alloyBinary = "build/alloy.exe"
} else {
setupEnvironment()
}

if !skipBuild {
buildAlloy()
buildAlloy(alloyBinary)
}
setupEnvironment()

if specificTest != "" {
fmt.Println("Running", specificTest)
if !filepath.IsAbs(specificTest) && !strings.HasPrefix(specificTest, "./tests/") {
specificTest = "./tests/" + specificTest
if !filepath.IsAbs(specificTest) && !strings.HasPrefix(specificTest, testFolder) {
specificTest = testFolder + specificTest
}
logChan = make(chan TestLog, 1)
runSingleTest(specificTest, 12345)
runSingleTest(alloyBinaryPath, specificTest, 12345)
} else {
testDirs, err := filepath.Glob("./tests/*")
testDirs, err := filepath.Glob(testFolder + "*")
if err != nil {
panic(err)
}
logChan = make(chan TestLog, len(testDirs))
runAllTests()
runAllTests(alloyBinaryPath, testFolder)
}
}
23 changes: 23 additions & 0 deletions internal/cmd/integration-tests/tests-windows/windows/config.alloy
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
prometheus.exporter.windows "default" { }

prometheus.scrape "default" {
targets = prometheus.exporter.windows.default.targets
forward_to = [prometheus.remote_write.default.receiver]
scrape_interval = "1s"
scrape_timeout = "500ms"
}

prometheus.remote_write "default" {
endpoint {
url = "http://localhost:9090/receive"
metadata_config {
send_interval = "1s"
}
queue_config {
max_samples_per_send = 100
}
}
external_labels = {
test_name = "win_metrics",
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//go:build windows

package main

import (
"context"
"fmt"
"io"
"net/http"
"testing"
"time"

"github.com/golang/snappy"
"github.com/prometheus/prometheus/prompb"
"github.com/stretchr/testify/require"
)

// List of expected Windows metrics
var winMetrics = []string{
"windows_cpu_time_total", // cpu
"windows_cs_logical_processors", // cs
"windows_logical_disk_info", // logical_disk
"windows_net_bytes_received_total", // net
"windows_os_info", // os
"windows_service_info", // service
"windows_system_system_up_time", // system
}

// TestWindowsMetrics sets up a server to receive remote write requests
// and checks if required metrics appear within a one minute timeout
func TestWindowsMetrics(t *testing.T) {
foundMetrics := make(map[string]bool)
for _, metric := range winMetrics {
foundMetrics[metric] = false
}

done := make(chan bool)
srv := &http.Server{Addr: ":9090"}
http.HandleFunc("/receive", func(w http.ResponseWriter, r *http.Request) {
ts, _ := handlePost(t, w, r)

for _, timeseries := range ts {
var metricName string
for _, label := range timeseries.Labels {
if label.Name == "__name__" {
metricName = label.Value
break
}
}
for _, requiredMetric := range winMetrics {
if requiredMetric == metricName && !foundMetrics[requiredMetric] {
foundMetrics[requiredMetric] = true
}
}
}

allFound := true
for _, found := range foundMetrics {
if !found {
allFound = false
break
}
}

if allFound {
done <- true
}
})

go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
panic(fmt.Errorf("could not start server: %v", err))
}
}()
defer srv.Shutdown(context.Background())

ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()

select {
case <-ctx.Done():
missingMetrics := []string{}
for metric, found := range foundMetrics {
if !found {
missingMetrics = append(missingMetrics, metric)
}
}
if len(missingMetrics) > 0 {
t.Errorf("Timeout reached. Missing metrics: %v", missingMetrics)
} else {
t.Log("All required metrics received.")
}
case <-done:
t.Log("All required metrics received within the timeout.")
}
}

func handlePost(t *testing.T, _ http.ResponseWriter, r *http.Request) ([]prompb.TimeSeries, []prompb.MetricMetadata) {
defer r.Body.Close()
data, err := io.ReadAll(r.Body)
require.NoError(t, err)

data, err = snappy.Decode(nil, data)
require.NoError(t, err)

var req prompb.WriteRequest
err = req.Unmarshal(data)
require.NoError(t, err)
return req.GetTimeseries(), req.Metadata
}
19 changes: 9 additions & 10 deletions internal/cmd/integration-tests/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ import (
"time"
)

const (
alloyBinaryPath = "../../../../../build/alloy"
)

type TestLog struct {
TestDir string
AlloyLog string
Expand All @@ -34,8 +30,8 @@ func executeCommand(command string, args []string, taskDescription string) {
}
}

func buildAlloy() {
executeCommand("make", []string{"-C", "../../..", "alloy"}, "Building Alloy")
func buildAlloy(alloyBinary string) {
executeCommand("make", []string{"-C", "../../..", "alloy", fmt.Sprintf("ALLOY_BINARY=%s", alloyBinary)}, "Building Alloy")
}

func setupEnvironment() {
Expand All @@ -44,7 +40,7 @@ func setupEnvironment() {
time.Sleep(45 * time.Second)
}

func runSingleTest(testDir string, port int) {
func runSingleTest(alloyBinaryPath string, testDir string, port int) {
info, err := os.Stat(testDir)
if err != nil {
panic(err)
Expand Down Expand Up @@ -88,14 +84,17 @@ func runSingleTest(testDir string, port int) {
}
}

// sleep for a few seconds before deleting the files to make sure that they are not use anymore
time.Sleep(5 * time.Second)

err = os.RemoveAll(filepath.Join(testDir, "data-alloy"))
if err != nil {
panic(err)
}
}

func runAllTests() {
testDirs, err := filepath.Glob("./tests/*")
func runAllTests(alloyBinaryPath string, testFolder string) {
testDirs, err := filepath.Glob(testFolder + "*")
if err != nil {
panic(err)
}
Expand All @@ -106,7 +105,7 @@ func runAllTests() {
wg.Add(1)
go func(td string, offset int) {
defer wg.Done()
runSingleTest(td, port+offset)
runSingleTest(alloyBinaryPath, td, port+offset)
}(testDir, i)
}
wg.Wait()
Expand Down

0 comments on commit 44d2d92

Please sign in to comment.