Files
kopia/internal/clock/now_testing.go
Jarek Kowalski 1a8fcb086c Added endurance test which tests kopia over long time scale (#558)
Globally replaced all use of time with internal 'clock' package
which provides indirection to time.Now()

Added support for faking clock in Kopia via KOPIA_FAKE_CLOCK_ENDPOINT

logfile: squelch annoying log message

testenv: added faketimeserver which serves time over HTTP

testing: added endurance test which tests kopia over long time scale

This creates kopia repository and simulates usage of Kopia over multiple
months (using accelerated fake time) to trigger effects that are only
visible after long time passage (maintenance, compactions, expirations).

The test is not used part of any test suite yet but will run in
post-submit mode only, preferably 24/7.

testing: refactored internal/clock to only support injection when
'testing' build tag is present
2020-08-26 23:03:46 -07:00

75 lines
1.8 KiB
Go

// +build testing
package clock
import (
"encoding/json"
"log"
"net/http"
"os"
"sync"
"time"
)
const refreshServerTimeEvery = 3 * time.Second
// Now is overridable function that returns current wall clock time.
var Now = time.Now // allow:no-inject-time
func init() {
fakeTimeServer := os.Getenv("KOPIA_FAKE_CLOCK_ENDPOINT")
if fakeTimeServer == "" {
return
}
Now = getTimeFromServer(fakeTimeServer)
}
// getTimeFromServer returns a function that will return timestamp as returned by the server
// increasing it client-side by certain inteval until maximum is reached, at which point
// it will ask the server again for new timestamp.
//
// The server endpoint must be HTTP and be set using KOPIA_FAKE_CLOCK_ENDPOINT environment
// variable.
func getTimeFromServer(endpoint string) func() time.Time {
var mu sync.Mutex
var timeInfo struct {
Next int64 `json:"next"`
Step int64 `json:"step"`
Until int64 `json:"until"`
}
nextRefreshRealTime := time.Now() // allow:no-inject-time
return func() time.Time {
mu.Lock()
defer mu.Unlock()
if timeInfo.Next >= timeInfo.Until || time.Now().After(nextRefreshRealTime) { // allow:no-inject-time
resp, err := http.Get(endpoint) //nolint:gosec,noctx
if err != nil {
log.Fatalf("unable to get fake time from server: %v", err)
}
defer resp.Body.Close() //nolint:errcheck
if resp.StatusCode != http.StatusOK {
log.Fatalf("unable to get fake time from server: %v", resp.Status)
}
if err := json.NewDecoder(resp.Body).Decode(&timeInfo); err != nil {
log.Fatalf("invalid time received from fake time server: %v", err)
}
nextRefreshRealTime = time.Now().Add(refreshServerTimeEvery) // allow:no-inject-time
}
v := timeInfo.Next
timeInfo.Next += timeInfo.Step
n := time.Unix(0, v)
return n
}
}