-
Notifications
You must be signed in to change notification settings - Fork 63
test: retry operations in e2e tests #1071
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-alerts-management-api
Are you sure you want to change the base?
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 |
|---|---|---|
|
|
@@ -10,11 +10,47 @@ import ( | |
| "io" | ||
| "net/http" | ||
| "net/url" | ||
| "time" | ||
|
|
||
| "k8s.io/apimachinery/pkg/util/wait" | ||
|
|
||
| "github.com/openshift/monitoring-plugin/internal/managementrouter" | ||
| "github.com/openshift/monitoring-plugin/test/e2e/framework" | ||
| ) | ||
|
|
||
| // poll calls the given function f() every given interval | ||
| // until it returns no error or the given timeout occurs. | ||
| // When a timeout occurs, the last observed error is returned | ||
| // wrapped in a wait.ErrWaitTimeout. | ||
| func poll(interval, timeout time.Duration, f func() error) error { | ||
| var lastErr error | ||
| err := wait.PollUntilContextTimeout(context.Background(), interval, timeout, true, func(context.Context) (bool, error) { | ||
| if lastErr = f(); lastErr != nil { | ||
| return false, nil | ||
| } | ||
|
|
||
| return true, nil | ||
| }) | ||
| if err != nil && lastErr != nil { | ||
| return fmt.Errorf("%w: %w", err, lastErr) | ||
| } | ||
|
|
||
| return err | ||
| } | ||
|
|
||
| func createRuleViaAPIWithRetry(ctx context.Context, f *framework.Framework, createAlertRuleRequest managementrouter.CreateAlertRuleRequest) (string, error) { | ||
| var id string | ||
| err := poll(time.Second, 20*time.Second, func() error { | ||
| var err error | ||
| id, err = createRuleViaAPI(ctx, f, createAlertRuleRequest) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to create alert rule: %w", err) | ||
| } | ||
| return nil | ||
| }) | ||
| return id, err | ||
| } | ||
|
Comment on lines
+41
to
+52
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. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift Retry-wrapping non-idempotent create/delete calls without idempotency safeguards. Both sites use
Consider making retries idempotency-aware, e.g., treat "already deleted"/"not found" as success on delete, or query current state before retrying on create. 📍 Affects 2 files
🤖 Prompt for AI Agents
Contributor
Author
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. This is indeed a good remark but it also deserves a discussion with @sradco @PeterYurkovich and @jgbernalp about the semantics of the bulk delete API:
Right now the API returns HTTP 200 OK on partial success which is a bit misleading IMHO
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. There isn't an HTTP code for partial success/failures, which is why the request returns a per-item response result in the body. I'd assume the response if the id doesn't exist should just be 200 OK on the request and then on the individual item in the body a "no ID found" 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.
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. There is a "new" http code for multi status. Which internally assigns status to individual operations.
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. I saw that yesterday, but if you look at the description it states it is used exclusively for a specific usecase
Contributor
Author
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. Returning "200 OK" when an ID doesn't exist is ok-ish but not a good option when the request partially fails for other reasons. In addition, you can't simply forward the downstream response codes because it could a mix of "200 OK", "400 Bad Request" and "500 Server Unavailable".
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. I think it just reflects that HTTP codes were created with single resource operations in mind, different from what we have today or in this context. A "200" could indicate that the bulk action itself was successful, but the results of individual updates can be included inside the payload. |
||
|
|
||
| func createRuleViaAPI(ctx context.Context, f *framework.Framework, payload managementrouter.CreateAlertRuleRequest) (string, error) { | ||
| reqBody, err := json.Marshal(payload) | ||
| if err != 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.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Unchecked
resp.Body.Close()error return.Flagged by errcheck; per path instructions, Go code should never ignore error returns.
🔧 Suggested fix
🧰 Tools
🪛 golangci-lint (2.12.2)
[error] 95-95: Error return value of
resp.Body.Closeis not checked(errcheck)
🤖 Prompt for AI Agents
Sources: Path instructions, Linters/SAST tools