Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions .github/workflows/compliance-tests.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
name: Compliance Tests

---
name: Compliance
on:
pull_request:
push:
branches: [main]

permissions:
contents: read

jobs:
remotewrite-compliance:
remotewrite-sender:
name: Remote Write Sender
runs-on: ubuntu-latest

container:
image: quay.io/prometheus/golang-builder:1.25-base
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.22'

- name: Run Remote Write Prometheus Compliance Tests
run: |
cd remotewrite/sender
go test --tags=compliance -run "TestRemoteWrite/prometheus/.+" -v ./
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- run: cd remotewrite && make sender
4 changes: 4 additions & 0 deletions remotewrite/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
results.json
config.yml
index.preloaded.html
bin/
57 changes: 57 additions & 0 deletions remotewrite/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Set the default target to 'help' so it runs when you just type 'make'
.DEFAULT_GOAL := help

mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
ROOT_DIR := $(dir $(mkfile_path))

SED=$(shell which gsed 2>/dev/null || which sed)

# Shared variables
DEBUG=""
TIMEOUT="10m"
PROMETHEUS_RW_COMPLIANCE_TEST_RE=""
PROMETHEUS_RW_COMPLIANCE_SKIP_TEST_RE=""
RESULT_FILE="$(ROOT_DIR)/results.json"

# Go test arguments and the base execution command.
BASE_TEST_ARGS = -run $(PROMETHEUS_RW_COMPLIANCE_TEST_RE) -skip $(PROMETHEUS_RW_COMPLIANCE_SKIP_TEST_RE)
RUN_TEST = cd ./$(COMPONENT) && DEBUG=$(DEBUG) $(COMPONENT_ENV) go test $(BASE_TEST_ARGS)

# Use target-specific variables to dynamically inject directories and environment variables.
sender sender-%: PROMETHEUS_COMPLIANCE_RW_SENDERS="prometheus"
sender sender-%: COMPONENT = sender
sender sender-%: COMPONENT_ENV = PROMETHEUS_COMPLIANCE_RW_SENDERS=$(PROMETHEUS_COMPLIANCE_RW_SENDERS)

receiver receiver-%: COMPONENT = receiver
receiver receiver-%: COMPONENT_ENV = PROMETHEUS_RW2_COMPLIANCE_RECEIVERS=$(PROMETHEUS_RW2_COMPLIANCE_RECEIVERS)

.PHONY: help
help: ## Show this help message
@echo "Usage: make [target]"
@echo ""
@echo "Available commands:"
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

.PHONY: sender
sender: ## Run sender compliance tests for a given senders suitable for humans and CI.
$(RUN_TEST) -v -timeout=$(TIMEOUT)

.PHONY: sender-web
sender-web: ## Run sender compliance tests for a given senders with a HTML results view.
@$(RUN_TEST) -json | tee $(RESULT_FILE)
@$(MAKE) results-web

.PHONY: receiver
receiver: ## Run receiver compliance tests for a given receivers suitable for humans and CI.
$(RUN_TEST) -v -timeout=$(TIMEOUT)

.PHONY: receiver-web
receiver-web: ## Run receiver compliance tests for a given receivers with a HTML results view.
@$(RUN_TEST) -json | tee $(RESULT_FILE)
@$(MAKE) results-web

.PHONY: results-web
results-web: ## Generate HTML view with ./results.json from the index.html file and open in your browser. We re-generate HTML file to avoid CORS issue on secure browsers.
@cat index.html | perl -pe 'BEGIN{local $$/; open(F,"<results.json"); $$c=<F>; close F} s/const PRELOADED_RESULT_DATA = ``;/const PRELOADED_RESULT_DATA = `$$c`;/' > index.preloaded.html
@open index.preloaded.html
165 changes: 90 additions & 75 deletions remotewrite/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,90 @@

This repository contains compliance test suites for both **senders** and **receivers** of the Prometheus Remote-Write Protocol 2.0. It validates implementation of the Remote-Write v2 specification according to the [official protocol requirements](https://prometheus.io/docs/specs/prw/remote_write_spec_2_0/) as well as some more strict Prometheus implementation aspects.

## Overview
Both [sender](#sender-compliance-sender) and [receiver](#receiver-compliance-receiver) test suites uses a shared [`./index.html`](./index.html) file that enables viewing compliance test results after they complete.

The test suites validate protocol compliance for both sides of Remote-Write communication:
To generate and view results, add `-json` flag to `go test` command and `tee` the results to a file called `results.json`.

### Sender Compliance (`/sender`)
Tests that Remote-Write senders properly implement the protocol by forking sender instances (e.g., Prometheus), examining generated requests, and validating them against the specification.
Tests are marked with compliance levels according to RFC specifications:
- **MUST**: Required by Remote Write specification
- **SHOULD**: Recommended by Remote Write specification
- **MAY**: Could have by Remote Write specification
- **RECOMMENDED**: Not in Remote Write specification, but recommended for performance or Prometheus compatibility reasons

## Sender Compliance (`/sender`)

Tests that Remote-Write senders implement the RW2 protocol by running tests cases with:

1. Scraper exposing OpenMetrics 1.0
2. Target sender to test (e.g., Prometheus),
3. Special receiver that tests various elements of the request(s).

Tests cover:
- Series encoding
- Float samples encoding
- Native Histograms encoding
- Exemplars encoding
- Protocol headers and content negotiation
- Error handling and retry logic
- Backoff and batching behavior
- Metadata and symbol table management
- Metadata encoding
- Protocol headers
- Error handling, basic batching and retry logic
- Request formatting and compression
- Various Prometheus / OpenMetrics 1.0 semantics as "RECOMMENDED" (staleness, upness). Because this test depends on scraping behaviour we
are testing some elements of the exposition format support too.

### Prerequisites

- Go 1.23 or later
- The sender binary you want to test (e.g., Prometheus)
- Requires OpenMetrics 1.0 scrape capability.
- Required Remote Write sending capability.

The test suite automatically downloads and runs Prometheus as the reference sender implementation.

### Configuration

The test suite uses environment variables:

**Sender Selection:**

```bash
PROMETHEUS_COMPLIANCE_RW_SENDERS="prometheus"
```

Currently supported senders:
- `prometheus` - The reference Prometheus implementation (automatically downloaded).
- `process` - For custom sender that is a local binary.

For testing custom senders:

* Add target running code and register it the `sender/main_test.go`.

TODO: Implement that.
* Use custom process target via `PROMETHEUS_COMPLIANCE_RW_SENDERS="process"` and `PROMETHEUS_COMPLIANCE_RW_PROCESS_BINARY=<path>` envvars.

**Debug output:**

Debug variable controls if the tested process suppresses output (empty DEBUG) or not.

```bash
DEBUG="1"
```

### Running Tests

```bash
make sender
```

To use visualization HTML page:

```bash
make sender-web
```

See Makefile for detailed invocation.

## Receiver Compliance (`/receiver`)

### Receiver Compliance (`/receiver`)
Tests that Remote-Write endpoints properly handle incoming requests by sending various Remote-Write v2 requests and validating responses.

Tests cover:
Expand All @@ -31,51 +97,24 @@ Tests cover:
- Content-Type validation
- Response headers (`X-Prometheus-Remote-Write-*-Written`)

## Limitations

### Sender Tests
The test suite validates the format and structure of requests sent by the sender but does not verify end-to-end data flow or persistence. Because senders may have different configuration options and capabilities, passing all tests does not guarantee a sender supports every Remote-Write feature (such as Native Histograms). Some senders may not expose certain features or may require specific configuration.
### Limitations

### Receiver Tests
This test suite does not verify data ingestion by reading data back from the receiver. Some requests that are valid for one backend might be rejected by another. The suite tolerates both 200 and 400 series HTTP responses since actual data validation is up to the receiver. Therefore, passing all tests does not guarantee that a receiver supports every Remote-Write feature.

**Important**: You should review the detailed test output to judge compliance for your implementation. A successful `go test` run alone is not sufficient.

## Prerequisites

### For Sender Tests
- Go 1.23 or later
- The sender binary to test (e.g., Prometheus)

The test suite automatically downloads and runs Prometheus as the reference sender implementation. For testing custom senders, place the binary in the `bin/` directory.

### For Receiver Tests
A Prometheus server with Remote-Write Receiver enabled, as baseline:
```bash
prometheus --web.enable-remote-write-receiver --enable-feature=native-histograms
```

Or any other Remote-Write Receiver endpoint.
### Prerequisites

## Configuration
You need a receiving endpoint you want to test.

### Sender Configuration
The test suite uses environment variables:
For example, a Prometheus server with Remote-Write Receiver enabled could be used as a baseline:

**Sender Selection:**
```bash
export PROMETHEUS_RW2_COMPLIANCE_SENDERS="prometheus"
prometheus --web.enable-remote-write-receiver --enable-feature=native-histograms # Add config file.
```

Currently supported senders:
- `prometheus` - The reference Prometheus implementation (automatically downloaded)
### Configuration

**Test Timeout:**
```bash
export PROMETHEUS_RW2_COMPLIANCE_TEST_TIMEOUT="10m"
```

### Receiver Configuration
The main configuration file `config.yml` in the `/remotewrite/receiver/` directory controls which receiver endpoints to test. It follows the Prometheus [`remote_write`](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write) structure:

```yaml
Expand All @@ -94,48 +133,24 @@ If no `config.yml` exists, the test suite will fall back to `config_example.yml`
Alternatively, use the `PROMETHEUS_RW2_COMPLIANCE_CONFIG_FILE` environment variable.

**Receiver Filtering:**
```bash
export PROMETHEUS_RW2_COMPLIANCE_RECEIVERS="local-prometheus,mimir"
```

## Running Tests
You can configure which remote write endpoints to test from the provided `PROMETHEUS_RW2_COMPLIANCE_CONFIG_FILE` file
via the `PROMETHEUS_RW2_COMPLIANCE_RECEIVERS` environment variable:

### Sender Tests
```bash
PROMETHEUS_RW2_COMPLIANCE_SENDERS="prometheus" go test -v
# Or other sender if you want
```

### Receiver Tests
```bash
PROMETHEUS_RW2_COMPLIANCE_RECEIVERS="local-prometheus" go test -v
# Or other receiver if you want
export PROMETHEUS_RW2_COMPLIANCE_RECEIVERS="local-prometheus,mimir"
```

## HTML Visualization

Both sender and receiver test suites include an `index.html` file that enables viewing compliance test results.

To generate and view results:
### Running Tests

**For Sender Tests:**
```bash
cd sender
go test -json | tee results.json
# Open index.html in your browser
make receiver
```

**For Receiver Tests:**
To use visualization HTML page:

```bash
cd receiver
go test -json | tee results.json
# Open index.html in your browser
make receiver-web
```

## Protocol Compliance Levels

Tests are marked with compliance levels according to RFC specifications:
- **MUST**: Required by specification
- **SHOULD**: Recommended by specification
- **MAY**: Could have by specification
- **RECOMMENDED**: Not in specification but recommended for performance
See Makefile for detailed invocation.
Loading