mirror of
https://github.com/kopia/kopia.git
synced 2026-02-01 18:23:36 -05:00
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
75 lines
1.8 KiB
Go
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
|
|
}
|
|
}
|