Add windows tests for query logger (#6653)

* Add windows tests
* Do not rely on time.Time in timer

Signed-off-by: Julien Pivotto <roidelapluie@inuits.eu>
This commit is contained in:
Julien Pivotto 2020-01-20 14:17:11 +01:00 committed by Brian Brazil
parent 46d18112a3
commit 2b2eb79e8b
9 changed files with 153 additions and 63 deletions

View file

@ -56,8 +56,14 @@ jobs:
working_directory: /go/src/github.com/prometheus/prometheus working_directory: /go/src/github.com/prometheus/prometheus
steps: steps:
- checkout - checkout
# TSDB is where the most risk is Windows wise, so only test there for now. - run:
- run: go test ./tsdb/... shell: bash
command: |
(cd web/ui && GOOS= GOARCH= go generate -mod=vendor)
go test -mod=vendor -test.v `go list ./...|grep -Exv "(github.com/prometheus/prometheus/discovery.*|github.com/prometheus/prometheus/config|github.com/prometheus/prometheus/web)"`
environment:
GOGC: "20"
GOOPTS: "-p 2 -mod=vendor"
fuzzit_regression: fuzzit_regression:
executor: fuzzit executor: fuzzit
working_directory: /go/src/github.com/prometheus/prometheus working_directory: /go/src/github.com/prometheus/prometheus

View file

@ -16,7 +16,7 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"net/http" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -51,54 +51,6 @@ func TestMain(m *testing.M) {
os.Exit(exitCode) os.Exit(exitCode)
} }
// As soon as prometheus starts responding to http request should be able to accept Interrupt signals for a graceful shutdown.
func TestStartupInterrupt(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
prom := exec.Command(promPath, "-test.main", "--config.file="+promConfig, "--storage.tsdb.path="+promData)
err := prom.Start()
if err != nil {
t.Errorf("execution error: %v", err)
return
}
done := make(chan error)
go func() {
done <- prom.Wait()
}()
var startedOk bool
var stoppedErr error
Loop:
for x := 0; x < 10; x++ {
// error=nil means prometheus has started so can send the interrupt signal and wait for the grace shutdown.
if _, err := http.Get("http://localhost:9090/graph"); err == nil {
startedOk = true
prom.Process.Signal(os.Interrupt)
select {
case stoppedErr = <-done:
break Loop
case <-time.After(10 * time.Second):
}
break Loop
}
time.Sleep(500 * time.Millisecond)
}
if !startedOk {
t.Errorf("prometheus didn't start in the specified timeout")
return
}
if err := prom.Process.Kill(); err == nil {
t.Errorf("prometheus didn't shutdown gracefully after sending the Interrupt signal")
} else if stoppedErr != nil && stoppedErr.Error() != "signal: interrupt" { // TODO - find a better way to detect when the process didn't exit as expected!
t.Errorf("prometheus exited with an unexpected error:%v", stoppedErr)
}
}
func TestComputeExternalURL(t *testing.T) { func TestComputeExternalURL(t *testing.T) {
tests := []struct { tests := []struct {
input string input string
@ -246,7 +198,16 @@ func TestWALSegmentSizeBounds(t *testing.T) {
for size, expectedExitStatus := range map[string]int{"9MB": 1, "257MB": 1, "10": 2, "1GB": 1, "12MB": 0} { for size, expectedExitStatus := range map[string]int{"9MB": 1, "257MB": 1, "10": 2, "1GB": 1, "12MB": 0} {
prom := exec.Command(promPath, "-test.main", "--storage.tsdb.wal-segment-size="+size, "--config.file="+promConfig) prom := exec.Command(promPath, "-test.main", "--storage.tsdb.wal-segment-size="+size, "--config.file="+promConfig)
err := prom.Start()
// Log stderr in case of failure.
stderr, err := prom.StderrPipe()
testutil.Ok(t, err)
go func() {
slurp, _ := ioutil.ReadAll(stderr)
t.Log(string(slurp))
}()
err = prom.Start()
testutil.Ok(t, err) testutil.Ok(t, err)
if expectedExitStatus == 0 { if expectedExitStatus == 0 {
@ -256,7 +217,7 @@ func TestWALSegmentSizeBounds(t *testing.T) {
case err := <-done: case err := <-done:
t.Errorf("prometheus should be still running: %v", err) t.Errorf("prometheus should be still running: %v", err)
case <-time.After(5 * time.Second): case <-time.After(5 * time.Second):
prom.Process.Signal(os.Interrupt) prom.Process.Kill()
} }
continue continue
} }

View file

@ -0,0 +1,74 @@
// Copyright 2020 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.
//
// +build !windows
package main
import (
"net/http"
"os"
"os/exec"
"testing"
"time"
)
// As soon as prometheus starts responding to http request it should be able to
// accept Interrupt signals for a graceful shutdown.
func TestStartupInterrupt(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
prom := exec.Command(promPath, "-test.main", "--config.file="+promConfig, "--storage.tsdb.path="+promData)
err := prom.Start()
if err != nil {
t.Errorf("execution error: %v", err)
return
}
done := make(chan error)
go func() {
done <- prom.Wait()
}()
var startedOk bool
var stoppedErr error
Loop:
for x := 0; x < 10; x++ {
// error=nil means prometheus has started so we can send the interrupt
// signal and wait for the graceful shutdown.
if _, err := http.Get("http://localhost:9090/graph"); err == nil {
startedOk = true
prom.Process.Signal(os.Interrupt)
select {
case stoppedErr = <-done:
break Loop
case <-time.After(10 * time.Second):
}
break Loop
}
time.Sleep(500 * time.Millisecond)
}
if !startedOk {
t.Errorf("prometheus didn't start in the specified timeout")
return
}
if err := prom.Process.Kill(); err == nil {
t.Errorf("prometheus didn't shutdown gracefully after sending the Interrupt signal")
} else if stoppedErr != nil && stoppedErr.Error() != "signal: interrupt" { // TODO - find a better way to detect when the process didn't exit as expected!
t.Errorf("prometheus exited with an unexpected error:%v", stoppedErr)
}
}

View file

@ -24,6 +24,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"runtime"
"strconv" "strconv"
"testing" "testing"
"time" "time"
@ -248,7 +249,7 @@ func (p *queryLogTest) run(t *testing.T) {
testutil.Ok(t, prom.Start()) testutil.Ok(t, prom.Start())
defer func() { defer func() {
prom.Process.Signal(os.Interrupt) prom.Process.Kill()
prom.Wait() prom.Wait()
}() }()
testutil.Ok(t, p.waitForPrometheus()) testutil.Ok(t, p.waitForPrometheus())
@ -298,9 +299,15 @@ func (p *queryLogTest) run(t *testing.T) {
p.validateLastQuery(t, ql) p.validateLastQuery(t, ql)
qc = len(ql) qc = len(ql)
// The last part of the test can not succeed on Windows because you can't
// rename files used by other processes.
if runtime.GOOS == "windows" {
return
}
// Move the file, Prometheus should still write to the old file. // Move the file, Prometheus should still write to the old file.
newFile, err := ioutil.TempFile("", "newLoc") newFile, err := ioutil.TempFile("", "newLoc")
testutil.Ok(t, err) testutil.Ok(t, err)
testutil.Ok(t, newFile.Close())
defer os.Remove(newFile.Name()) defer os.Remove(newFile.Name())
testutil.Ok(t, os.Rename(queryLogFile.Name(), newFile.Name())) testutil.Ok(t, os.Rename(queryLogFile.Name(), newFile.Name()))
ql = readQueryLog(t, newFile.Name()) ql = readQueryLog(t, newFile.Name())

View file

@ -80,6 +80,7 @@ func (t *testRunner) copyFileTo(src string, name string) string {
_, err = io.Copy(newf, f) _, err = io.Copy(newf, f)
testutil.Ok(t, err) testutil.Ok(t, err)
testutil.Ok(t, f.Close()) testutil.Ok(t, f.Close())
testutil.Ok(t, newf.Close())
dst := filepath.Join(t.dir, name) dst := filepath.Join(t.dir, name)
err = os.Rename(newf.Name(), dst) err = os.Rename(newf.Name(), dst)

View file

@ -14,10 +14,10 @@
package logging package logging
import ( import (
"errors"
"io/ioutil" "io/ioutil"
"os" "os"
"regexp" "regexp"
"strings"
"testing" "testing"
"github.com/prometheus/prometheus/util/testutil" "github.com/prometheus/prometheus/util/testutil"
@ -32,7 +32,8 @@ func TestJSONFileLogger_basic(t *testing.T) {
testutil.Ok(t, err) testutil.Ok(t, err)
testutil.Assert(t, l != nil, "logger can't be nil") testutil.Assert(t, l != nil, "logger can't be nil")
l.Log("test", "yes") err = l.Log("test", "yes")
testutil.Ok(t, err)
r := make([]byte, 1024) r := make([]byte, 1024)
_, err = f.Read(r) _, err = f.Read(r)
testutil.Ok(t, err) testutil.Ok(t, err)
@ -44,5 +45,40 @@ func TestJSONFileLogger_basic(t *testing.T) {
testutil.Ok(t, err) testutil.Ok(t, err)
err = l.file.Close() err = l.file.Close()
testutil.Assert(t, errors.Is(err, os.ErrClosed), "file was not closed") testutil.NotOk(t, err)
testutil.Assert(t, strings.HasSuffix(err.Error(), os.ErrClosed.Error()), "file not closed")
}
func TestJSONFileLogger_parallel(t *testing.T) {
f, err := ioutil.TempFile("", "")
testutil.Ok(t, err)
defer f.Close()
l, err := NewJSONFileLogger(f.Name())
testutil.Ok(t, err)
testutil.Assert(t, l != nil, "logger can't be nil")
err = l.Log("test", "yes")
testutil.Ok(t, err)
l2, err := NewJSONFileLogger(f.Name())
testutil.Ok(t, err)
testutil.Assert(t, l != nil, "logger can't be nil")
err = l2.Log("test", "yes")
testutil.Ok(t, err)
err = l.Close()
testutil.Ok(t, err)
err = l.file.Close()
testutil.NotOk(t, err)
testutil.Assert(t, strings.HasSuffix(err.Error(), os.ErrClosed.Error()), "file not closed")
err = l2.Close()
testutil.Ok(t, err)
err = l2.file.Close()
testutil.NotOk(t, err)
testutil.Assert(t, strings.HasSuffix(err.Error(), os.ErrClosed.Error()), "file not closed")
} }

View file

@ -16,6 +16,7 @@ package promql
import ( import (
"context" "context"
"errors" "errors"
"strings"
"testing" "testing"
"time" "time"
@ -106,7 +107,9 @@ func TestQueryTimeout(t *testing.T) {
testutil.NotOk(t, res.Err, "expected timeout error but got none") testutil.NotOk(t, res.Err, "expected timeout error but got none")
var e ErrQueryTimeout var e ErrQueryTimeout
testutil.Assert(t, errors.As(res.Err, &e), "expected timeout error but got: %s", res.Err) // TODO: when circleci-windows moves to go 1.13:
// testutil.Assert(t, errors.As(res.Err, &e), "expected timeout error but got: %s", res.Err)
testutil.Assert(t, strings.HasPrefix(res.Err.Error(), e.Error()), "expected timeout error but got: %s", res.Err)
} }
const errQueryCanceled = ErrQueryCanceled("test statement execution") const errQueryCanceled = ErrQueryCanceled("test statement execution")
@ -496,7 +499,9 @@ func TestEngineShutdown(t *testing.T) {
testutil.NotOk(t, res2.Err, "expected error on querying with canceled context but got none") testutil.NotOk(t, res2.Err, "expected error on querying with canceled context but got none")
var e ErrQueryCanceled var e ErrQueryCanceled
testutil.Assert(t, errors.As(res2.Err, &e), "expected cancellation error but got: %s", res2.Err) // TODO: when circleci-windows moves to go 1.13:
// testutil.Assert(t, errors.As(res2.Err, &e), "expected cancellation error but got: %s", res2.Err)
testutil.Assert(t, strings.HasPrefix(res2.Err.Error(), e.Error()), "expected cancellation error but got: %s", res2.Err)
} }
func TestEngineEvalStmtTimestamps(t *testing.T) { func TestEngineEvalStmtTimestamps(t *testing.T) {

View file

@ -24,7 +24,7 @@ import (
// was running (the time between Start() and Stop()). // was running (the time between Start() and Stop()).
type Timer struct { type Timer struct {
name fmt.Stringer name fmt.Stringer
created time.Time created int
start time.Time start time.Time
duration time.Duration duration time.Duration
} }
@ -72,7 +72,7 @@ func (t *TimerGroup) GetTimer(name fmt.Stringer) *Timer {
} }
timer := &Timer{ timer := &Timer{
name: name, name: name,
created: time.Now(), created: len(t.timers),
} }
t.timers[name] = timer t.timers[name] = timer
return timer return timer
@ -95,7 +95,7 @@ func (t Timers) Swap(i, j int) {
} }
func (s byCreationTimeSorter) Less(i, j int) bool { func (s byCreationTimeSorter) Less(i, j int) bool {
return s.Timers[i].created.Before(s.Timers[j].created) return s.Timers[i].created < s.Timers[j].created
} }
// Return a string representation of a TimerGroup. // Return a string representation of a TimerGroup.

View file

@ -57,7 +57,7 @@ func NotOk(tb TB, err error, a ...interface{}) {
if err == nil { if err == nil {
if len(a) != 0 { if len(a) != 0 {
format := a[0].(string) format := a[0].(string)
tb.Fatalf("\033[31m"+format+": expected error, got none\033[39m", a...) tb.Fatalf("\033[31m"+format+": expected error, got none\033[39m", a[1:]...)
} }
tb.Fatalf("\033[31mexpected error, got none\033[39m") tb.Fatalf("\033[31mexpected error, got none\033[39m")
} }