Skip to content

Commit b98cced

Browse files
authored
chore: property and test improvements (#911)
* chore: Add DUTY_DB_CREATE * chore: add playbooks description to playbook_names * chore: build supported property list * chore: lint fixes * chore: linting details
1 parent fa887ae commit b98cced

File tree

7 files changed

+153
-93
lines changed

7 files changed

+153
-93
lines changed

.github/workflows/lint.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ permissions:
88
jobs:
99
golangci:
1010
permissions:
11-
contents: read # for actions/checkout to fetch code
12-
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
11+
contents: read # for actions/checkout to fetch code
12+
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
1313
name: lint
1414
runs-on: ubuntu-latest
1515
steps:
@@ -30,4 +30,4 @@ jobs:
3030
cd hack/migrate
3131
go mod tidy
3232
changed_files=$(git status -s)
33-
[[ -z "$changed_files" ]] || (printf "Change is detected in: \n$changed_files\n Did you run 'go mod tidy' before sending the PR?" && exit 1)
33+
[[ -z "$changed_files" ]] || ( git diff && printf "Change is detected in: \n$changed_files\n Did you run 'go mod tidy' before sending the PR?" && exit 1)

context/properties.go

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,56 +9,108 @@ import (
99
"strings"
1010
"time"
1111

12+
"github.com/flanksource/commons/console"
1213
"github.com/flanksource/commons/logger"
1314
"github.com/flanksource/duty/models"
15+
cmap "github.com/orcaman/concurrent-map/v2"
1416
"github.com/patrickmn/go-cache"
1517
)
1618

1719
var Local map[string]string
20+
var supportedProperties = cmap.New[string]()
1821

1922
var propertyCache = cache.New(time.Minute*15, time.Minute*15)
2023

2124
func (k Context) ClearCache() {
2225
propertyCache = cache.New(time.Minute*15, time.Minute*15)
2326
}
2427

28+
func nilSafe(v interface{}) string {
29+
if v == nil {
30+
return ""
31+
}
32+
return fmt.Sprintf("%v", v)
33+
}
34+
func newProp(key, def string, val interface{}) {
35+
if loaded := supportedProperties.SetIfAbsent(key, fmt.Sprintf("%s", val)); loaded {
36+
if val == nil {
37+
logger.Tracef("property: %s=%v", key, console.Grayf(nilSafe(def)))
38+
} else {
39+
logger.Debugf("property: %s=%v (default %v)", key, console.Greenf("%s", val), nilSafe(def))
40+
}
41+
}
42+
}
43+
44+
func (p Properties) SupportedProperties() map[string]string {
45+
m := make(map[string]string)
46+
for t := range supportedProperties.IterBuffered() {
47+
m[t.Key] = nilSafe(t.Val)
48+
}
49+
return m
50+
}
51+
2552
type Properties map[string]string
2653

27-
func (p Properties) On(key string) bool {
28-
return p[key] == "true" || p[key] == "off"
54+
// Returns true if the property is true|enabled|on, if there is no property it defaults to true
55+
func (p Properties) On(def bool, keys ...string) bool {
56+
for _, key := range keys {
57+
k, ok := p[key]
58+
if ok {
59+
v := k == "true" || k == "enabled" || k == "on"
60+
newProp(key, fmt.Sprintf("%v", def), v)
61+
return v
62+
}
63+
newProp(key, fmt.Sprintf("%v", def), nil)
64+
}
65+
return def
2966
}
3067

3168
func (p Properties) Duration(key string, def time.Duration) time.Duration {
3269
if d, ok := p[key]; !ok {
70+
newProp(key, fmt.Sprintf("%v", def), nil)
3371
return def
3472
} else if dur, err := time.ParseDuration(d); err != nil {
3573
logger.Warnf("property[%s] invalid duration %s", key, d)
3674
return def
3775
} else {
76+
newProp(key, fmt.Sprintf("%v", def), dur)
3877
return dur
3978
}
4079
}
4180

4281
func (p Properties) Int(key string, def int) int {
4382
if d, ok := p[key]; !ok {
83+
newProp(key, fmt.Sprintf("%v", def), nil)
4484
return def
4585
} else if i, err := strconv.Atoi(d); err != nil {
4686
logger.Warnf("property[%s] invalid int %s", key, d)
4787
return def
4888
} else {
89+
newProp(key, fmt.Sprintf("%v", def), i)
4990
return i
5091
}
5192
}
5293

5394
func (p Properties) String(key string, def string) string {
5495
if d, ok := p[key]; ok {
96+
newProp(key, fmt.Sprintf("%v", def), d)
5597
return d
5698
}
99+
newProp(key, fmt.Sprintf("%v", def), nil)
57100
return def
101+
58102
}
59103

60-
func (p Properties) Off(key string) bool {
61-
return p[key] == "false" || p[key] == "disabled"
104+
// Returns true if the property is false|disabled|off, if there is no property it defaults to true
105+
func (p Properties) Off(key string, def bool) bool {
106+
k, ok := p[key]
107+
if !ok {
108+
newProp(key, fmt.Sprintf("%v", def), nil)
109+
return def
110+
}
111+
v := k == "false" || k == "disabled" || k == "off"
112+
newProp(key, fmt.Sprintf("%v", def), v)
113+
return v
62114
}
63115

64116
// Properties returns a cached map of properties

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ require (
3232
github.com/ohler55/ojg v1.20.3
3333
github.com/onsi/ginkgo/v2 v2.17.2
3434
github.com/onsi/gomega v1.33.0
35+
github.com/orcaman/concurrent-map/v2 v2.0.1
3536
github.com/patrickmn/go-cache v2.1.0+incompatible
3637
github.com/prometheus/client_golang v1.14.0
3738
github.com/robfig/cron/v3 v3.0.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,8 @@ github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxj
12661266
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
12671267
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
12681268
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
1269+
github.com/orcaman/concurrent-map/v2 v2.0.1 h1:jOJ5Pg2w1oeB6PeDurIYf6k9PQ+aTITr/6lP/L/zp6c=
1270+
github.com/orcaman/concurrent-map/v2 v2.0.1/go.mod h1:9Eq3TG2oBe5FirmYWQfYO5iH1q0Jv47PLaNK++uCdOM=
12691271
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
12701272
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
12711273
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=

job/job.go

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -324,12 +324,24 @@ func (j *Job) Run() {
324324
}
325325
}
326326

327-
func getProperty(j *Job, properties map[string]string, property string) (string, bool) {
328-
if val, ok := properties[j.Name+"."+property]; ok {
329-
return val, ok
327+
func (j *Job) getPropertyNames(key string) []string {
328+
if j.ID == "" {
329+
return []string{
330+
fmt.Sprintf("jobs.%s.%s", j.Name, key),
331+
fmt.Sprintf("jobs.%s", key)}
330332
}
331-
if val, ok := properties[fmt.Sprintf("%s[%s].%s", j.Name, j.ID, property)]; ok {
332-
return val, ok
333+
return []string{
334+
fmt.Sprintf("jobs.%s.%s.%s", j.Name, j.ID, key),
335+
fmt.Sprintf("jobs.%s.%s", j.Name, key),
336+
fmt.Sprintf("jobs.%s", key)}
337+
}
338+
339+
func (j *Job) GetProperty(property string) (string, bool) {
340+
if val := j.Context.Properties().String(j.Name+"."+property, ""); val != "" {
341+
return val, true
342+
}
343+
if val := j.Context.Properties().String(fmt.Sprintf("%s[%s].%s", j.Name, j.ID, property), ""); val != "" {
344+
return val, true
333345
}
334346
return "", false
335347
}
@@ -346,34 +358,21 @@ func (j *Job) init() error {
346358

347359
j.lastHistoryCleanup = time.Now()
348360

349-
properties := j.Context.Properties()
350-
if schedule, ok := getProperty(j, properties, "schedule"); ok {
361+
if schedule, ok := j.GetProperty("schedule"); ok {
351362
j.Schedule = schedule
352363
}
353364

354-
if timeout, ok := getProperty(j, properties, "timeout"); ok {
365+
if timeout, ok := j.GetProperty("timeout"); ok {
355366
duration, err := time.ParseDuration(timeout)
356367
if err != nil {
357368
j.Context.Warnf("invalid timeout %s", timeout)
358369
}
359370
j.Timeout = duration
360371
}
361372

362-
if history, ok := getProperty(j, properties, "history"); ok {
363-
j.JobHistory = !(history != "false")
364-
}
365-
366-
if trace := properties["jobs.trace"]; trace == "true" {
367-
j.Trace = true
368-
} else if trace, ok := getProperty(j, properties, "trace"); ok {
369-
j.Trace = trace == "true"
370-
}
371-
372-
if debug := properties["jobs.debug"]; debug == "true" {
373-
j.Debug = true
374-
} else if debug, ok := getProperty(j, properties, "debug"); ok {
375-
j.Debug = debug == "true"
376-
}
373+
j.JobHistory = j.Properties().On(true, j.getPropertyNames("history")...)
374+
j.Trace = j.Properties().On(false, j.getPropertyNames("trace")...)
375+
j.Debug = j.Properties().On(false, j.getPropertyNames("debug")...)
377376

378377
// Set default retention if it is unset
379378
if j.Retention.Empty() {
@@ -408,7 +407,7 @@ func (j *Job) init() error {
408407

409408
j.Context = j.Context.WithObject(obj)
410409

411-
if dbLevel, ok := getProperty(j, properties, "db-log-level"); ok {
410+
if dbLevel, ok := j.GetProperty("db-log-level"); ok {
412411
j.Context = j.Context.WithDBLogLevel(dbLevel)
413412
}
414413

@@ -452,7 +451,7 @@ func (j *Job) GetResourcedName() string {
452451
func (j *Job) AddToScheduler(cronRunner *cron.Cron) error {
453452
cronRunner.Start()
454453
schedule := j.Schedule
455-
if override, ok := getProperty(j, j.Context.Properties(), "schedule"); ok {
454+
if override, ok := j.GetProperty("schedule"); ok {
456455
schedule = override
457456
}
458457

tests/setup/common.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ func MustDB() *sql.DB {
6262
}
6363

6464
var WithoutDummyData = "without_dummy_data"
65+
var WithExistingDatabase = "with_existing_database"
66+
var recreateDatabase = os.Getenv("DUTY_DB_CREATE") != "false"
6567

6668
func BeforeSuiteFn(args ...interface{}) context.Context {
6769
logger.UseZap()
@@ -72,6 +74,9 @@ func BeforeSuiteFn(args ...interface{}) context.Context {
7274
if arg == WithoutDummyData {
7375
importDummyData = false
7476
}
77+
if arg == WithExistingDatabase {
78+
recreateDatabase = false
79+
}
7580
}
7681

7782
logger.Infof("Initializing test db debug=%v db.trace=%v", trace, dbTrace)
@@ -93,15 +98,17 @@ func BeforeSuiteFn(args ...interface{}) context.Context {
9398

9499
PgUrl = fmt.Sprintf("postgres://postgres:postgres@localhost:%d/%s?sslmode=disable", port, dbName)
95100
url := os.Getenv("DUTY_DB_URL")
96-
if url != "" {
101+
if url != "" && !recreateDatabase {
102+
PgUrl = url
103+
} else if url != "" && recreateDatabase {
97104
postgresDBUrl = url
98105
dbName = fmt.Sprintf("duty_gingko%d", port)
99106
PgUrl = strings.Replace(url, "/postgres", "/"+dbName, 1)
100107
_ = execPostgres(postgresDBUrl, "DROP DATABASE "+dbName)
101108
if err := execPostgres(postgresDBUrl, "CREATE DATABASE "+dbName); err != nil {
102109
panic(fmt.Sprintf("Cannot create %s: %v", dbName, err))
103110
}
104-
} else {
111+
} else if url == "" {
105112
config, _ := GetEmbeddedPGConfig(dbName, port)
106113
postgresServer = embeddedPG.NewDatabase(config)
107114
if err = postgresServer.Start(); err != nil {
@@ -165,7 +172,7 @@ func AfterSuiteFn() {
165172
if err := postgresServer.Stop(); err != nil {
166173
ginkgo.Fail(err.Error())
167174
}
168-
} else {
175+
} else if recreateDatabase {
169176
if err := execPostgres(postgresDBUrl, fmt.Sprintf("DROP DATABASE %s (FORCE)", dbName)); err != nil {
170177
ginkgo.Fail(fmt.Sprintf("Cannot drop %s: %v", dbName, err))
171178
}

0 commit comments

Comments
 (0)