-
Notifications
You must be signed in to change notification settings - Fork 1
chore: upodate make test #1815
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
chore: upodate make test #1815
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -111,6 +111,7 @@ require ( | |
| ) | ||
|
|
||
| require ( | ||
| github.com/clipperhouse/stringish v0.1.1 // indirect | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's check the current state of go.mod and see line 114 in context
head -n 120 go.mod | tail -n 20Repository: flanksource/duty Length of output: 667 🏁 Script executed: # Also check the full size of go.mod to understand the file better
wc -l go.modRepository: flanksource/duty Length of output: 70 🏁 Script executed: # Let's search for the stringish dependency to understand the context
rg "stringish" go.mod go.sumRepository: flanksource/duty Length of output: 319 🏁 Script executed: # Show larger context around line 114 - the indirect require block
sed -n '110,130p' go.modRepository: flanksource/duty Length of output: 879 🏁 Script executed: # Check the entire indirect require block to see ordering
sed -n '/^require (/,/^)/p' go.mod | grep "indirect"Repository: flanksource/duty Length of output: 16297 🏁 Script executed: # Look for CI configuration files that might show the lint failure
find . -maxdepth 2 -name ".github" -o -name "*.yml" -o -name "*.yaml" | head -20Repository: flanksource/duty Length of output: 132 🏁 Script executed: # Check if there's a Makefile or script that runs go mod tidy
find . -maxdepth 2 -name "Makefile" -o -name "*.sh" | xargs grep -l "go mod tidy" 2>/dev/null || echo "No tidy scripts found"Repository: flanksource/duty Length of output: 70 🏁 Script executed: # Check the Makefile for tidy/lint targets
grep -A 3 "tidy\|lint\|mod" Makefile | head -20Repository: flanksource/duty Length of output: 518 🏁 Script executed: # Look for GitHub Actions workflows
ls -la .github/workflows/ 2>/dev/null || echo "No workflows directory"Repository: flanksource/duty Length of output: 535 🏁 Script executed: # Check golangci.yaml for relevant lint rules
cat .golangci.yamlRepository: flanksource/duty Length of output: 671 🏁 Script executed: # Check the lint.yml workflow for go mod tidy check
cat .github/workflows/lint.ymlRepository: flanksource/duty Length of output: 961 Commit the tidied module files. The 🤖 Prompt for AI Agents |
||
| github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect | ||
| github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect | ||
| github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,241 @@ | ||
| package setup | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "os" | ||
| "strconv" | ||
| "strings" | ||
|
|
||
| embeddedPG "github.com/fergusstrange/embedded-postgres" | ||
| "github.com/flanksource/commons/logger" | ||
| "github.com/flanksource/commons/properties" | ||
| "github.com/flanksource/duty" | ||
| "github.com/flanksource/duty/context" | ||
| dutyKubernetes "github.com/flanksource/duty/kubernetes" | ||
| "github.com/flanksource/duty/shutdown" | ||
| "github.com/flanksource/duty/telemetry" | ||
| "github.com/flanksource/duty/tests/fixtures/dummy" | ||
| "github.com/onsi/ginkgo/v2" | ||
| v1 "k8s.io/api/core/v1" | ||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| "k8s.io/client-go/kubernetes/fake" | ||
| ) | ||
|
|
||
| type SetupOpts struct { | ||
| DummyData bool | ||
| } | ||
|
|
||
| type templateInfo struct { | ||
| AdminURL string `json:"admin_url"` | ||
| TemplateDB string `json:"template_db"` | ||
| Port int `json:"port"` | ||
| } | ||
|
|
||
| func (t templateInfo) Marshal() []byte { | ||
| data, err := json.Marshal(t) | ||
| if err != nil { | ||
| panic(fmt.Sprintf("failed to marshal templateInfo: %v", err)) | ||
| } | ||
| return data | ||
| } | ||
|
|
||
| func unmarshalTemplateInfo(data []byte) templateInfo { | ||
| var info templateInfo | ||
| if err := json.Unmarshal(data, &info); err != nil { | ||
| panic(fmt.Sprintf("failed to unmarshal templateInfo: %v", err)) | ||
| } | ||
| return info | ||
| } | ||
|
|
||
| var ( | ||
| adminURL string | ||
| nodeDBName string | ||
| ) | ||
|
|
||
| func SetupTemplate(opts SetupOpts) []byte { | ||
| if err := properties.LoadFile(findFileInPath("test.properties", 2)); err != nil { | ||
| logger.Errorf("Failed to load test properties: %v", err) | ||
| } | ||
|
|
||
| defer telemetry.InitTracer() | ||
|
|
||
| var port int | ||
| if val, ok := os.LookupEnv(TEST_DB_PORT); ok { | ||
| parsed, err := strconv.ParseInt(val, 10, 32) | ||
| if err != nil { | ||
| panic(fmt.Sprintf("failed to parse TEST_DB_PORT: %v", err)) | ||
| } | ||
| port = int(parsed) | ||
| } else { | ||
| port = duty.FreePort() | ||
| } | ||
|
|
||
| templateDB := "duty_test_template" | ||
|
|
||
| url := os.Getenv(DUTY_DB_URL) | ||
| if url != "" && !recreateDatabase { | ||
| // DUTY_DB_CREATE=false: use direct connection, no template | ||
| PgUrl = url | ||
| return templateInfo{AdminURL: url, TemplateDB: "", Port: port}.Marshal() | ||
| } | ||
|
|
||
| adminConn, err := ensurePostgres(port) | ||
| if err != nil { | ||
| panic(fmt.Sprintf("failed to start postgres: %v", err)) | ||
| } | ||
| adminURL = adminConn | ||
|
|
||
| // Always recreate — dummy data uses uuid.New() so a cached template has stale UUIDs | ||
| _ = execPostgres(adminConn, fmt.Sprintf("ALTER DATABASE %s WITH is_template = false", templateDB)) | ||
| _ = execPostgres(adminConn, fmt.Sprintf( | ||
| "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '%s' AND pid <> pg_backend_pid()", templateDB)) | ||
| _ = execPostgres(adminConn, fmt.Sprintf("DROP DATABASE IF EXISTS %s (FORCE)", templateDB)) | ||
|
|
||
| if err := execPostgres(adminConn, fmt.Sprintf("CREATE DATABASE %s", templateDB)); err != nil { | ||
| panic(fmt.Sprintf("failed to create template db: %v", err)) | ||
| } | ||
|
|
||
| templateURL := strings.Replace(adminConn, "/postgres", "/"+templateDB, 1) | ||
| if !strings.Contains(adminConn, "/postgres") { | ||
| templateURL = fmt.Sprintf("postgres://postgres:postgres@localhost:%d/%s?sslmode=disable", port, templateDB) | ||
| } | ||
|
|
||
| dbOptions := []duty.StartOption{duty.DisablePostgrest, duty.RunMigrations, duty.WithUrl(templateURL)} | ||
| if !disableRLS { | ||
| dbOptions = append(dbOptions, duty.EnableRLS) | ||
| } | ||
|
|
||
| ctx, stop, err := duty.Start(templateDB, dbOptions...) | ||
| if err != nil { | ||
| panic(fmt.Sprintf("failed to start duty for template: %v", err)) | ||
| } | ||
|
|
||
| if err := ctx.DB().Exec("SET TIME ZONE 'UTC'").Error; err != nil { | ||
| panic(fmt.Sprintf("failed to set timezone: %v", err)) | ||
| } | ||
|
|
||
| if opts.DummyData { | ||
| dummyData = dummy.GetStaticDummyData(ctx.DB()) | ||
| if err := dummyData.Delete(ctx.DB()); err != nil { | ||
| logger.Errorf(err.Error()) | ||
| } | ||
| if err := dummyData.Populate(ctx); err != nil { | ||
| panic(fmt.Sprintf("failed to populate dummy data: %v", err)) | ||
| } | ||
| logger.Infof("Created dummy data in template (%d checks)", len(dummyData.Checks)) | ||
| } | ||
|
|
||
| // Close all connections so the DB can be used as a template | ||
| stop() | ||
| _ = execPostgres(adminConn, fmt.Sprintf( | ||
| "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '%s' AND pid <> pg_backend_pid()", templateDB)) | ||
|
|
||
| if err := execPostgres(adminConn, fmt.Sprintf("ALTER DATABASE %s WITH is_template = true", templateDB)); err != nil { | ||
| panic(fmt.Sprintf("failed to mark template db: %v", err)) | ||
| } | ||
|
|
||
| return templateInfo{AdminURL: adminConn, TemplateDB: templateDB, Port: port}.Marshal() | ||
| } | ||
|
|
||
| func SetupNode(data []byte, opts SetupOpts) context.Context { | ||
| info := unmarshalTemplateInfo(data) | ||
|
|
||
| if info.TemplateDB == "" { | ||
| // Direct connection mode (DUTY_DB_CREATE=false) | ||
| PgUrl = info.AdminURL | ||
| ctx, _, err := duty.Start("direct", duty.ClientOnly, duty.WithUrl(PgUrl)) | ||
| if err != nil { | ||
| panic(fmt.Sprintf("failed to connect to db: %v", err)) | ||
| } | ||
| return setupNodeContext(ctx, "direct") | ||
|
Comment on lines
+144
to
+151
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Direct mode regresses the old setup contract. Unlike 🧰 Tools🪛 GitHub Actions: Test[error] 149-149: PANICKED! BeforeSuite failed: failed to connect to db: ERROR: relation "migration_logs" does not exist (SQLSTATE 42P01); earlier errors include relation "properties" does not exist. This caused the OpenAPI/Duty test suite to abort with a failing BeforeSuite. 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| adminURL = info.AdminURL | ||
| nodeDBName = fmt.Sprintf("duty_test_node%d", ginkgo.GinkgoParallelProcess()) | ||
|
|
||
| // Drop and clone from template | ||
| _ = execPostgres(adminURL, fmt.Sprintf("DROP DATABASE IF EXISTS %s (FORCE)", nodeDBName)) | ||
|
|
||
| // Terminate any lingering connections to the template before cloning | ||
| _ = execPostgres(adminURL, fmt.Sprintf( | ||
| "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '%s' AND pid <> pg_backend_pid()", info.TemplateDB)) | ||
|
|
||
| // Unmark template temporarily for cloning (some pg versions need this) | ||
| _ = execPostgres(adminURL, fmt.Sprintf("ALTER DATABASE %s WITH is_template = false", info.TemplateDB)) | ||
| if err := execPostgres(adminURL, fmt.Sprintf("CREATE DATABASE %s TEMPLATE %s", nodeDBName, info.TemplateDB)); err != nil { | ||
| panic(fmt.Sprintf("failed to clone template: %v", err)) | ||
| } | ||
| _ = execPostgres(adminURL, fmt.Sprintf("ALTER DATABASE %s WITH is_template = true", info.TemplateDB)) | ||
|
|
||
| // Build node connection URL | ||
| if strings.Contains(adminURL, "/postgres") { | ||
| PgUrl = strings.Replace(adminURL, "/postgres", "/"+nodeDBName, 1) | ||
| } else { | ||
| PgUrl = fmt.Sprintf("postgres://postgres:postgres@localhost:%d/%s?sslmode=disable", info.Port, nodeDBName) | ||
| } | ||
|
|
||
| // Skip migrations — the clone is byte-for-byte identical to the template | ||
| ctx, _, err := duty.Start(nodeDBName, duty.ClientOnly, duty.WithUrl(PgUrl)) | ||
| if err != nil { | ||
| panic(fmt.Sprintf("failed to connect to node db: %v", err)) | ||
| } | ||
|
|
||
| return setupNodeContext(ctx, nodeDBName) | ||
| } | ||
|
|
||
| func setupNodeContext(ctx context.Context, dbName string) context.Context { | ||
| if err := ctx.DB().Exec("SET TIME ZONE 'UTC'").Error; err != nil { | ||
| panic(fmt.Sprintf("failed to set timezone: %v", err)) | ||
| } | ||
|
|
||
| ctx = ctx.WithValue("db_name", dbName).WithValue("db_url", PgUrl) | ||
|
|
||
| clientset := fake.NewClientset(&v1.ConfigMap{ | ||
| ObjectMeta: metav1.ObjectMeta{Name: "test-cm", Namespace: "default"}, | ||
| Data: map[string]string{"foo": "bar"}, | ||
| }, &v1.Secret{ | ||
| ObjectMeta: metav1.ObjectMeta{Name: "test-secret", Namespace: "default"}, | ||
| Data: map[string][]byte{"foo": []byte("secret")}, | ||
| }) | ||
|
|
||
| return ctx.WithLocalKubernetes(dutyKubernetes.NewKubeClient(logger.GetLogger("k8s"), clientset, nil)) | ||
| } | ||
|
|
||
| func SynchronizedAfterSuiteAllNodes() { | ||
| if nodeDBName != "" && adminURL != "" { | ||
| if err := execPostgres(adminURL, fmt.Sprintf("DROP DATABASE IF EXISTS %s (FORCE)", nodeDBName)); err != nil { | ||
| logger.Errorf("failed to drop node db: %v", err) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| func SynchronizedAfterSuiteNode1() { | ||
| shutdown.Shutdown() | ||
| } | ||
|
|
||
|
|
||
| func ensurePostgres(port int) (string, error) { | ||
| url := os.Getenv(DUTY_DB_URL) | ||
| if url != "" { | ||
| postgresDBUrl = url | ||
| return url, nil | ||
| } | ||
|
|
||
| if postgresServer == nil { | ||
| config, _ := GetEmbeddedPGConfig("postgres", port) | ||
|
|
||
| if v, ok := os.LookupEnv(DUTY_DB_DATA_DIR); ok { | ||
| config = config.DataPath(v) | ||
| } | ||
|
|
||
| postgresServer = embeddedPG.NewDatabase(config) | ||
| logger.Infof("starting embedded postgres on port %d", port) | ||
| if err := postgresServer.Start(); err != nil { | ||
| return "", err | ||
| } | ||
| logger.Infof("Started postgres on port %d", port) | ||
| } | ||
|
|
||
| return fmt.Sprintf("postgres://postgres:postgres@localhost:%d/postgres?sslmode=disable", port), nil | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: flanksource/duty
Length of output: 42
Add
!ignore_localfilter to match repository standards.The repository standard (per learnings) is to use
--label-filter='!ignore_local'when running tests with ginkgo. Update both targets to include this filter, e.g.--label-filter "!e2e && !ignore_local".🤖 Prompt for AI Agents