Skip to content

Commit

Permalink
fix: implement tests for gitlab client 409 Conflict handling
Browse files Browse the repository at this point in the history
  • Loading branch information
jippi committed May 14, 2024
1 parent d1c3913 commit 0b8be9d
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 4 deletions.
9 changes: 6 additions & 3 deletions server/events/vcs/gitlab_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,10 +441,13 @@ func (g *GitlabClient) UpdateStatus(logger logging.SimpleLogging, repo models.Re
var (
resp *gitlab.Response
maxAttempts = 10
b = &backoff.Backoff{Jitter: true}
retryer = &backoff.Backoff{
Jitter: true,
Max: g.PollingInterval,
}
)

for i := 0; i <= maxAttempts; i++ {
for i := 0; i < maxAttempts; i++ {
logger := logger.With(
"attempt", i+1,
"max_attempts", maxAttempts,
Expand Down Expand Up @@ -475,7 +478,7 @@ func (g *GitlabClient) UpdateStatus(logger logging.SimpleLogging, repo models.Re
// GitLab does not allow merge requests to be merged when the pipeline status is "running."

if resp.StatusCode == http.StatusConflict {
sleep := b.ForAttempt(float64(i))
sleep := retryer.ForAttempt(float64(i))

logger.With("retry_in", sleep).Warn("GitLab returned HTTP [409 Conflict] when updating commit status")
time.Sleep(sleep)
Expand Down
108 changes: 107 additions & 1 deletion server/events/vcs/gitlab_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ func TestGitlabClient_GetModifiedFiles(t *testing.T) {
Equals(t, []string{"somefile.yaml"}, filenames)
})
}

}

func TestGitlabClient_MergePull(t *testing.T) {
Expand Down Expand Up @@ -346,6 +345,113 @@ func TestGitlabClient_UpdateStatus(t *testing.T) {
}
}

func TestGitlabClient_UpdateStatusRetryable(t *testing.T) {
logger := logging.NewNoopLogger(t)
pipelineSuccess, err := os.ReadFile("testdata/gitlab-pipeline-success.json")
Ok(t, err)

cases := []struct {
status models.CommitStatus
numberOfConflicts int
expNumberOfRequests int
expState string
expError bool
}{
// Ensure that 0 x 409 Conflict succeeds
{
status: models.PendingCommitStatus,
numberOfConflicts: 0,
expNumberOfRequests: 1,
expState: "running",
},
// Ensure that 5 x 409 Conflict still succeeds
{
status: models.PendingCommitStatus,
numberOfConflicts: 5,
expNumberOfRequests: 6,
expState: "running",
},
// Ensure that 10 x 409 Conflict still fail due to running out of retries
{
status: models.FailedCommitStatus,
numberOfConflicts: 100, // anything larger than 10 is fine
expNumberOfRequests: 10,
expState: "failed",
expError: true,
},
}
for _, c := range cases {
t.Run(c.expState, func(t *testing.T) {
handledNumberOfRequests := 0

testServer := httptest.NewServer(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.RequestURI {
case "/api/v4/projects/runatlantis%2Fatlantis/statuses/sha":
handledNumberOfRequests++
shouldSendConflict := handledNumberOfRequests <= c.numberOfConflicts

body, err := io.ReadAll(r.Body)
Ok(t, err)
exp := fmt.Sprintf(`{"state":"%s","ref":"patch-1-merger","context":"src","target_url":"https://google.com","description":"description"}`, c.expState)
Equals(t, exp, string(body))
defer r.Body.Close() // nolint: errcheck

if shouldSendConflict {
w.WriteHeader(http.StatusConflict)
}

w.Write([]byte("{}")) // nolint: errcheck

case "/api/v4/projects/runatlantis%2Fatlantis/merge_requests/1":
w.WriteHeader(http.StatusOK)
w.Write(pipelineSuccess) // nolint: errcheck

case "/api/v4/":
// Rate limiter requests.
w.WriteHeader(http.StatusOK)

default:
t.Errorf("got unexpected request at %q", r.RequestURI)
http.Error(w, "not found", http.StatusNotFound)
}
}))

internalClient, err := gitlab.NewClient("token", gitlab.WithBaseURL(testServer.URL))
Ok(t, err)
client := &GitlabClient{
Client: internalClient,
Version: nil,
PollingInterval: 10 * time.Millisecond,
}

repo := models.Repo{
FullName: "runatlantis/atlantis",
Owner: "runatlantis",
Name: "atlantis",
}
err = client.UpdateStatus(
logger,
repo,
models.PullRequest{
Num: 1,
BaseRepo: repo,
HeadCommit: "sha",
HeadBranch: "test",
}, c.status, "src", "description", "https://google.com")

if c.expError {
ErrContains(t, "failed to update commit status for 'runatlantis/atlantis' @ 'sha' to 'src' after 10 attempts", err)
ErrContains(t, "409", err)
} else {
Ok(t, err)
}

Assert(t, c.expNumberOfRequests == handledNumberOfRequests, fmt.Sprintf("expected %d number of requests, but processed %d", c.expNumberOfRequests, handledNumberOfRequests))
})
}
}

func TestGitlabClient_PullIsMergeable(t *testing.T) {
logger := logging.NewNoopLogger(t)
gitlabClientUnderTest = true
Expand Down

0 comments on commit 0b8be9d

Please sign in to comment.