270 lines
7.2 KiB
Go
270 lines
7.2 KiB
Go
// Copyright 2013 The Prometheus Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package retrieval
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
clientmodel "github.com/prometheus/client_golang/model"
|
|
|
|
"github.com/prometheus/prometheus/utility"
|
|
)
|
|
|
|
func TestBaseLabels(t *testing.T) {
|
|
target := NewTarget("http://example.com/metrics", 0, clientmodel.LabelSet{"job": "some_job", "foo": "bar"})
|
|
want := clientmodel.LabelSet{"job": "some_job", "foo": "bar", "instance": "example.com:80"}
|
|
got := target.BaseLabels()
|
|
if !reflect.DeepEqual(want, got) {
|
|
t.Errorf("want base labels %v, got %v", want, got)
|
|
}
|
|
delete(want, "job")
|
|
delete(want, "instance")
|
|
got = target.BaseLabelsWithoutJobAndInstance()
|
|
if !reflect.DeepEqual(want, got) {
|
|
t.Errorf("want base labels %v, got %v", want, got)
|
|
}
|
|
}
|
|
|
|
func TestTargetHidesURLAuth(t *testing.T) {
|
|
testVectors := []string{"http://secret:data@host.com/query?args#fragment", "https://example.net/foo", "http://foo.com:31337/bar"}
|
|
testResults := []string{"host.com:80", "example.net:443", "foo.com:31337"}
|
|
if len(testVectors) != len(testResults) {
|
|
t.Errorf("Test vector length does not match test result length.")
|
|
}
|
|
|
|
for i := 0; i < len(testVectors); i++ {
|
|
testTarget := target{
|
|
state: Unknown,
|
|
url: testVectors[i],
|
|
httpClient: utility.NewDeadlineClient(0),
|
|
}
|
|
u := testTarget.InstanceIdentifier()
|
|
if u != testResults[i] {
|
|
t.Errorf("Expected InstanceIdentifier to be %v, actual %v", testResults[i], u)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTargetScrapeUpdatesState(t *testing.T) {
|
|
testTarget := target{
|
|
state: Unknown,
|
|
url: "bad schema",
|
|
httpClient: utility.NewDeadlineClient(0),
|
|
}
|
|
testTarget.scrape(nopAppender{})
|
|
if testTarget.state != Unhealthy {
|
|
t.Errorf("Expected target state %v, actual: %v", Unhealthy, testTarget.state)
|
|
}
|
|
}
|
|
|
|
func TestTargetScrapeWithFullChannel(t *testing.T) {
|
|
server := httptest.NewServer(
|
|
http.HandlerFunc(
|
|
func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", `text/plain; version=0.0.4`)
|
|
for i := 0; i < 2*ingestedSamplesCap; i++ {
|
|
w.Write([]byte(
|
|
fmt.Sprintf("test_metric_%d{foo=\"bar\"} 123.456\n", i),
|
|
))
|
|
}
|
|
},
|
|
),
|
|
)
|
|
defer server.Close()
|
|
|
|
testTarget := NewTarget(
|
|
server.URL,
|
|
10*time.Millisecond,
|
|
clientmodel.LabelSet{"dings": "bums"},
|
|
).(*target)
|
|
|
|
testTarget.scrape(slowAppender{})
|
|
if testTarget.state != Unhealthy {
|
|
t.Errorf("Expected target state %v, actual: %v", Unhealthy, testTarget.state)
|
|
}
|
|
if testTarget.lastError != errIngestChannelFull {
|
|
t.Errorf("Expected target error %q, actual: %q", errIngestChannelFull, testTarget.lastError)
|
|
}
|
|
}
|
|
|
|
func TestTargetRecordScrapeHealth(t *testing.T) {
|
|
testTarget := NewTarget(
|
|
"http://example.url", 0, clientmodel.LabelSet{clientmodel.JobLabel: "testjob"},
|
|
).(*target)
|
|
|
|
now := clientmodel.Now()
|
|
appender := &collectResultAppender{}
|
|
testTarget.recordScrapeHealth(appender, now, true, 2*time.Second)
|
|
|
|
result := appender.result
|
|
|
|
if len(result) != 2 {
|
|
t.Fatalf("Expected two samples, got %d", len(result))
|
|
}
|
|
|
|
actual := result[0]
|
|
expected := &clientmodel.Sample{
|
|
Metric: clientmodel.Metric{
|
|
clientmodel.MetricNameLabel: scrapeHealthMetricName,
|
|
InstanceLabel: "example.url:80",
|
|
clientmodel.JobLabel: "testjob",
|
|
},
|
|
Timestamp: now,
|
|
Value: 1,
|
|
}
|
|
|
|
if !actual.Equal(expected) {
|
|
t.Fatalf("Expected and actual samples not equal. Expected: %v, actual: %v", expected, actual)
|
|
}
|
|
|
|
actual = result[1]
|
|
expected = &clientmodel.Sample{
|
|
Metric: clientmodel.Metric{
|
|
clientmodel.MetricNameLabel: scrapeDurationMetricName,
|
|
InstanceLabel: "example.url:80",
|
|
clientmodel.JobLabel: "testjob",
|
|
},
|
|
Timestamp: now,
|
|
Value: 2.0,
|
|
}
|
|
|
|
if !actual.Equal(expected) {
|
|
t.Fatalf("Expected and actual samples not equal. Expected: %v, actual: %v", expected, actual)
|
|
}
|
|
}
|
|
|
|
func TestTargetScrapeTimeout(t *testing.T) {
|
|
signal := make(chan bool, 1)
|
|
server := httptest.NewServer(
|
|
http.HandlerFunc(
|
|
func(w http.ResponseWriter, r *http.Request) {
|
|
<-signal
|
|
w.Header().Set("Content-Type", `text/plain; version=0.0.4`)
|
|
w.Write([]byte{})
|
|
},
|
|
),
|
|
)
|
|
defer server.Close()
|
|
|
|
testTarget := NewTarget(server.URL, 10*time.Millisecond, clientmodel.LabelSet{})
|
|
appender := nopAppender{}
|
|
|
|
// scrape once without timeout
|
|
signal <- true
|
|
if err := testTarget.(*target).scrape(appender); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// let the deadline lapse
|
|
time.Sleep(15 * time.Millisecond)
|
|
|
|
// now scrape again
|
|
signal <- true
|
|
if err := testTarget.(*target).scrape(appender); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// now timeout
|
|
if err := testTarget.(*target).scrape(appender); err == nil {
|
|
t.Fatal("expected scrape to timeout")
|
|
} else {
|
|
signal <- true // let handler continue
|
|
}
|
|
|
|
// now scrape again without timeout
|
|
signal <- true
|
|
if err := testTarget.(*target).scrape(appender); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestTargetScrape404(t *testing.T) {
|
|
server := httptest.NewServer(
|
|
http.HandlerFunc(
|
|
func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
},
|
|
),
|
|
)
|
|
defer server.Close()
|
|
|
|
testTarget := NewTarget(server.URL, 10*time.Millisecond, clientmodel.LabelSet{})
|
|
appender := nopAppender{}
|
|
|
|
want := errors.New("server returned HTTP status 404 Not Found")
|
|
got := testTarget.(*target).scrape(appender)
|
|
if got == nil || want.Error() != got.Error() {
|
|
t.Fatalf("want err %q, got %q", want, got)
|
|
}
|
|
}
|
|
|
|
func TestTargetRunScraperScrapes(t *testing.T) {
|
|
testTarget := target{
|
|
state: Unknown,
|
|
url: "bad schema",
|
|
httpClient: utility.NewDeadlineClient(0),
|
|
scraperStopping: make(chan struct{}),
|
|
scraperStopped: make(chan struct{}),
|
|
}
|
|
go testTarget.RunScraper(nopAppender{}, time.Duration(time.Millisecond))
|
|
|
|
// Enough time for a scrape to happen.
|
|
time.Sleep(2 * time.Millisecond)
|
|
if testTarget.lastScrape.IsZero() {
|
|
t.Errorf("Scrape hasn't occured.")
|
|
}
|
|
|
|
testTarget.StopScraper()
|
|
// Wait for it to take effect.
|
|
time.Sleep(2 * time.Millisecond)
|
|
last := testTarget.lastScrape
|
|
// Enough time for a scrape to happen.
|
|
time.Sleep(2 * time.Millisecond)
|
|
if testTarget.lastScrape != last {
|
|
t.Errorf("Scrape occured after it was stopped.")
|
|
}
|
|
}
|
|
|
|
func BenchmarkScrape(b *testing.B) {
|
|
server := httptest.NewServer(
|
|
http.HandlerFunc(
|
|
func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", `text/plain; version=0.0.4`)
|
|
w.Write([]byte("test_metric{foo=\"bar\"} 123.456\n"))
|
|
},
|
|
),
|
|
)
|
|
defer server.Close()
|
|
|
|
testTarget := NewTarget(
|
|
server.URL,
|
|
100*time.Millisecond,
|
|
clientmodel.LabelSet{"dings": "bums"},
|
|
)
|
|
appender := nopAppender{}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
if err := testTarget.(*target).scrape(appender); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
}
|