feat(tfstated): allow configuration of version history limit via environment variable

This commit is contained in:
Julien Dessaux 2024-10-18 00:01:50 +02:00
parent 4c2032e1f0
commit 1ebf0341dd
Signed by: adyxax
GPG key ID: F92E51B86E07177E
5 changed files with 43 additions and 9 deletions

View file

@ -10,6 +10,7 @@ import (
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
"strconv"
"sync" "sync"
"time" "time"
@ -42,6 +43,14 @@ func run(
if err := db.SetDataEncryptionKey(dataEncryptionKey); err != nil { if err := db.SetDataEncryptionKey(dataEncryptionKey); err != nil {
return err return err
} }
versionsHistoryLimit := getenv("VERSIONS_HISTORY_LIMIT")
if versionsHistoryLimit != "" {
n, err := strconv.Atoi(versionsHistoryLimit)
if err != nil {
return fmt.Errorf("failed to parse the VERSIONS_HISTORY_LIMIT environment variable: %w", err)
}
db.SetVersionsHistoryLimit(n)
}
mux := http.NewServeMux() mux := http.NewServeMux()
addRoutes( addRoutes(

View file

@ -18,6 +18,7 @@ var baseURI = url.URL{
Path: "/", Path: "/",
Scheme: "http", Scheme: "http",
} }
var db *database.DB
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
ctx := context.Background() ctx := context.Background()
@ -27,7 +28,8 @@ func TestMain(m *testing.M) {
Port: "8081", Port: "8081",
} }
_ = os.Remove("./test.db") _ = os.Remove("./test.db")
db, err := database.NewDB(ctx, "./test.db") var err error
db, err = database.NewDB(ctx, "./test.db")
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "%+v\n", err) fmt.Fprintf(os.Stderr, "%+v\n", err)
os.Exit(1) os.Exit(1)
@ -36,6 +38,8 @@ func TestMain(m *testing.M) {
switch key { switch key {
case "DATA_ENCRYPTION_KEY": case "DATA_ENCRYPTION_KEY":
return "hP3ZSCnY3LMgfTQjwTaGrhKwdA0yXMXIfv67OJnntqM=" return "hP3ZSCnY3LMgfTQjwTaGrhKwdA0yXMXIfv67OJnntqM="
case "VERSIONS_HISTORY_LIMIT":
return "3"
default: default:
return "" return ""
} }

View file

@ -30,6 +30,9 @@ func TestPost(t *testing.T) {
{"GET", url.URL{Path: "/test_post"}, nil, "the_test_post4", http.StatusOK, "/test_post"}, {"GET", url.URL{Path: "/test_post"}, nil, "the_test_post4", http.StatusOK, "/test_post"},
{"POST", url.URL{Path: "/test_post"}, strings.NewReader("the_test_post5"), "", http.StatusOK, "without lock ID in query string on a locked state"}, {"POST", url.URL{Path: "/test_post"}, strings.NewReader("the_test_post5"), "", http.StatusOK, "without lock ID in query string on a locked state"},
{"GET", url.URL{Path: "/test_post"}, nil, "the_test_post5", http.StatusOK, "/test_post"}, {"GET", url.URL{Path: "/test_post"}, nil, "the_test_post5", http.StatusOK, "/test_post"},
{"POST", url.URL{Path: "/test_post"}, strings.NewReader("the_test_post6"), "", http.StatusOK, "another post just to make sure the history limit works"},
{"POST", url.URL{Path: "/test_post"}, strings.NewReader("the_test_post7"), "", http.StatusOK, "another post just to make sure the history limit works"},
{"POST", url.URL{Path: "/test_post"}, strings.NewReader("the_test_post8"), "", http.StatusOK, "another post just to make sure the history limit works"},
} }
for _, tt := range tests { for _, tt := range tests {
runHTTPRequest(tt.method, &tt.uri, tt.body, func(r *http.Response, err error) { runHTTPRequest(tt.method, &tt.uri, tt.body, func(r *http.Response, err error) {
@ -46,4 +49,15 @@ func TestPost(t *testing.T) {
} }
}) })
} }
var n int
err := db.QueryRow(`SELECT COUNT(versions.id)
FROM versions
JOIN states ON states.id = versions.state_id
WHERE states.name = "/test_post"`).Scan(&n)
if err != nil {
t.Fatalf("failed to count versions for the /test_post state: %s", err)
}
if n != 3 {
t.Fatalf("there should only be 3 versions of the /test_post state, got %d", n)
}
} }

View file

@ -29,6 +29,7 @@ type DB struct {
ctx context.Context ctx context.Context
dataEncryptionKey scrypto.AES256Key dataEncryptionKey scrypto.AES256Key
readDB *sql.DB readDB *sql.DB
versionsHistoryLimit int
writeDB *sql.DB writeDB *sql.DB
} }
@ -58,6 +59,7 @@ func NewDB(ctx context.Context, url string) (*DB, error) {
db := DB{ db := DB{
ctx: ctx, ctx: ctx,
readDB: readDB, readDB: readDB,
versionsHistoryLimit: 64,
writeDB: writeDB, writeDB: writeDB,
} }
if _, err = db.Exec("PRAGMA foreign_keys = ON"); err != nil { if _, err = db.Exec("PRAGMA foreign_keys = ON"); err != nil {
@ -101,3 +103,7 @@ func (db *DB) QueryRow(query string, args ...any) *sql.Row {
func (db *DB) SetDataEncryptionKey(s string) error { func (db *DB) SetDataEncryptionKey(s string) error {
return db.dataEncryptionKey.FromBase64(s) return db.dataEncryptionKey.FromBase64(s)
} }
func (db *DB) SetVersionsHistoryLimit(n int) {
db.versionsHistoryLimit = n
}

View file

@ -102,7 +102,8 @@ func (db *DB) SetState(name string, data []byte, lockID string) (bool, error) {
JOIN states ON states.id = versions.state_id JOIN states ON states.id = versions.state_id
WHERE states.name = :name WHERE states.name = :name
ORDER BY versions.id DESC ORDER BY versions.id DESC
LIMIT 64));`, LIMIT :limit));`,
sql.Named("limit", db.versionsHistoryLimit),
sql.Named("name", name), sql.Named("name", name),
) )
if err != nil { if err != nil {