mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-29 12:08:24 +00:00
305 lines
10 KiB
Go
305 lines
10 KiB
Go
package server_test
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/google/go-github/github"
|
|
. "github.com/petergtz/pegomock"
|
|
"github.com/runatlantis/atlantis/server"
|
|
"github.com/runatlantis/atlantis/server/events"
|
|
"github.com/runatlantis/atlantis/server/events/locking"
|
|
"github.com/runatlantis/atlantis/server/events/locking/boltdb"
|
|
"github.com/runatlantis/atlantis/server/events/mocks"
|
|
"github.com/runatlantis/atlantis/server/events/mocks/matchers"
|
|
"github.com/runatlantis/atlantis/server/events/models"
|
|
"github.com/runatlantis/atlantis/server/events/runtime"
|
|
"github.com/runatlantis/atlantis/server/events/terraform"
|
|
vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks"
|
|
"github.com/runatlantis/atlantis/server/events/webhooks"
|
|
"github.com/runatlantis/atlantis/server/events/yaml"
|
|
"github.com/runatlantis/atlantis/server/logging"
|
|
. "github.com/runatlantis/atlantis/testing"
|
|
)
|
|
|
|
/*
|
|
flows:
|
|
- pull request opened autoplan
|
|
- comment to apply
|
|
|
|
github/gitlab
|
|
|
|
locking
|
|
|
|
merging pull requests
|
|
|
|
different repo organizations
|
|
|
|
atlantis.yaml
|
|
|
|
*/
|
|
func TestGitHubWorkflow(t *testing.T) {
|
|
RegisterMockTestingT(t)
|
|
|
|
cases := []struct {
|
|
Description string
|
|
// RepoDir is relative to testfixtures/test-repos.
|
|
RepoDir string
|
|
ModifiedFiles []string
|
|
ExpAutoplanCommentFile string
|
|
ExpMergeCommentFile string
|
|
CommentAndReplies []string
|
|
}{
|
|
{
|
|
Description: "simple",
|
|
RepoDir: "simple",
|
|
ModifiedFiles: []string{"main.tf"},
|
|
ExpAutoplanCommentFile: "exp-output-autoplan.txt",
|
|
CommentAndReplies: []string{
|
|
"atlantis apply", "exp-output-apply.txt",
|
|
},
|
|
ExpMergeCommentFile: "exp-output-merge.txt",
|
|
},
|
|
}
|
|
for _, c := range cases {
|
|
ctrl, vcsClient, githubGetter, atlantisWorkspace := setupE2E(t)
|
|
t.Run(c.Description, func(t *testing.T) {
|
|
// Set the repo to be cloned through the testing backdoor.
|
|
repoDir, err := filepath.Abs(filepath.Join("testfixtures", "test-repos", c.RepoDir))
|
|
Ok(t, err)
|
|
atlantisWorkspace.TestingOverrideCloneURL = fmt.Sprintf("file://%s", repoDir)
|
|
|
|
// Setup test dependencies.
|
|
w := httptest.NewRecorder()
|
|
When(githubGetter.GetPullRequest(AnyRepo(), AnyInt())).ThenReturn(GitHubPullRequestParsed(), nil)
|
|
When(vcsClient.GetModifiedFiles(AnyRepo(), matchers.AnyModelsPullRequest())).ThenReturn(c.ModifiedFiles, nil)
|
|
|
|
// First, send the open pull request event and trigger an autoplan.
|
|
pullOpenedReq := GitHubPullRequestOpenedEvent(t)
|
|
ctrl.Post(w, pullOpenedReq)
|
|
responseContains(t, w, 200, "Processing...")
|
|
_, _, autoplanComment := vcsClient.VerifyWasCalledOnce().CreateComment(AnyRepo(), AnyInt(), AnyString()).GetCapturedArguments()
|
|
exp, err := ioutil.ReadFile(filepath.Join(repoDir, c.ExpAutoplanCommentFile))
|
|
Ok(t, err)
|
|
Equals(t, string(exp), autoplanComment)
|
|
|
|
// Now send any other comments.
|
|
for i := 0; i < len(c.CommentAndReplies); i += 2 {
|
|
comment := c.CommentAndReplies[i]
|
|
expOutputFile := c.CommentAndReplies[i+1]
|
|
|
|
commentReq := GitHubCommentEvent(t, comment)
|
|
w = httptest.NewRecorder()
|
|
ctrl.Post(w, commentReq)
|
|
responseContains(t, w, 200, "Processing...")
|
|
_, _, autoplanComment = vcsClient.VerifyWasCalled(Twice()).CreateComment(AnyRepo(), AnyInt(), AnyString()).GetCapturedArguments()
|
|
|
|
exp, err = ioutil.ReadFile(filepath.Join(repoDir, expOutputFile))
|
|
Ok(t, err)
|
|
// Replace all 'ID: 1111818181' strings with * so we can do a comparison.
|
|
idRegex := regexp.MustCompile(`\(ID: [0-9]+\)`)
|
|
autoplanComment = idRegex.ReplaceAllString(autoplanComment, "(ID: ******************)")
|
|
Equals(t, string(exp), autoplanComment)
|
|
}
|
|
|
|
// Finally, send the pull request merged event.
|
|
pullClosedReq := GitHubPullRequestClosedEvent(t)
|
|
w = httptest.NewRecorder()
|
|
ctrl.Post(w, pullClosedReq)
|
|
responseContains(t, w, 200, "Pull request cleaned successfully")
|
|
_, _, pullClosedComment := vcsClient.VerifyWasCalled(Times(3)).CreateComment(AnyRepo(), AnyInt(), AnyString()).GetCapturedArguments()
|
|
exp, err = ioutil.ReadFile(filepath.Join(repoDir, c.ExpMergeCommentFile))
|
|
Ok(t, err)
|
|
Equals(t, string(exp), pullClosedComment)
|
|
})
|
|
}
|
|
}
|
|
|
|
func setupE2E(t *testing.T) (server.EventsController, *vcsmocks.MockClientProxy, *mocks.MockGithubPullGetter, *events.FileWorkspace) {
|
|
allowForkPRs := false
|
|
dataDir, cleanup := TempDir(t)
|
|
defer cleanup()
|
|
testRepoDir, err := filepath.Abs("testfixtures/test-repos/simple")
|
|
Ok(t, err)
|
|
|
|
// Mocks.
|
|
e2eVCSClient := vcsmocks.NewMockClientProxy()
|
|
e2eStatusUpdater := mocks.NewMockCommitStatusUpdater()
|
|
e2eGithubGetter := mocks.NewMockGithubPullGetter()
|
|
e2eGitlabGetter := mocks.NewMockGitlabMergeRequestGetter()
|
|
|
|
// Real dependencies.
|
|
logger := logging.NewSimpleLogger("server", nil, true, logging.Debug)
|
|
eventParser := &events.EventParser{
|
|
GithubUser: "github-user",
|
|
GithubToken: "github-token",
|
|
GitlabUser: "gitlab-user",
|
|
GitlabToken: "gitlab-token",
|
|
}
|
|
commentParser := &events.CommentParser{
|
|
GithubUser: "github-user",
|
|
GithubToken: "github-token",
|
|
GitlabUser: "gitlab-user",
|
|
GitlabToken: "gitlab-token",
|
|
}
|
|
terraformClient, err := terraform.NewClient(dataDir)
|
|
Ok(t, err)
|
|
boltdb, err := boltdb.New(dataDir)
|
|
Ok(t, err)
|
|
lockingClient := locking.NewClient(boltdb)
|
|
projectLocker := &events.DefaultProjectLocker{
|
|
Locker: lockingClient,
|
|
}
|
|
atlantisWorkspace := &events.FileWorkspace{
|
|
DataDir: dataDir,
|
|
TestingOverrideCloneURL: testRepoDir,
|
|
}
|
|
|
|
defaultTFVersion := terraformClient.Version()
|
|
commandHandler := &events.CommandHandler{
|
|
EventParser: eventParser,
|
|
VCSClient: e2eVCSClient,
|
|
GithubPullGetter: e2eGithubGetter,
|
|
GitlabMergeRequestGetter: e2eGitlabGetter,
|
|
CommitStatusUpdater: e2eStatusUpdater,
|
|
AtlantisWorkspaceLocker: events.NewDefaultAtlantisWorkspaceLocker(),
|
|
MarkdownRenderer: &events.MarkdownRenderer{},
|
|
Logger: logger,
|
|
AllowForkPRs: allowForkPRs,
|
|
AllowForkPRsFlag: "allow-fork-prs",
|
|
PullRequestOperator: &events.DefaultPullRequestOperator{
|
|
TerraformExecutor: terraformClient,
|
|
DefaultTFVersion: defaultTFVersion,
|
|
ParserValidator: &yaml.ParserValidator{},
|
|
ProjectFinder: &events.DefaultProjectFinder{},
|
|
VCSClient: e2eVCSClient,
|
|
Workspace: atlantisWorkspace,
|
|
ProjectOperator: events.ProjectOperator{
|
|
Locker: projectLocker,
|
|
LockURLGenerator: &mockLockURLGenerator{},
|
|
InitStepOperator: runtime.InitStepOperator{
|
|
TerraformExecutor: terraformClient,
|
|
DefaultTFVersion: defaultTFVersion,
|
|
},
|
|
PlanStepOperator: runtime.PlanStepOperator{
|
|
TerraformExecutor: terraformClient,
|
|
DefaultTFVersion: defaultTFVersion,
|
|
},
|
|
ApplyStepOperator: runtime.ApplyStepOperator{
|
|
TerraformExecutor: terraformClient,
|
|
},
|
|
RunStepOperator: runtime.RunStepOperator{},
|
|
ApprovalOperator: runtime.ApprovalOperator{
|
|
VCSClient: e2eVCSClient,
|
|
},
|
|
Workspace: atlantisWorkspace,
|
|
Webhooks: &mockWebhookSender{},
|
|
},
|
|
},
|
|
}
|
|
|
|
ctrl := server.EventsController{
|
|
TestingMode: true,
|
|
CommandRunner: commandHandler,
|
|
PullCleaner: &events.PullClosedExecutor{
|
|
Locker: lockingClient,
|
|
VCSClient: e2eVCSClient,
|
|
Workspace: atlantisWorkspace,
|
|
},
|
|
Logger: logger,
|
|
Parser: eventParser,
|
|
CommentParser: commentParser,
|
|
GithubWebHookSecret: nil,
|
|
GithubRequestValidator: &server.DefaultGithubRequestValidator{},
|
|
GitlabRequestParser: &server.DefaultGitlabRequestParser{},
|
|
GitlabWebHookSecret: nil,
|
|
RepoWhitelist: &events.RepoWhitelist{
|
|
Whitelist: "*",
|
|
},
|
|
SupportedVCSHosts: []models.VCSHostType{models.Gitlab, models.Github},
|
|
VCSClient: e2eVCSClient,
|
|
AtlantisGithubUser: models.User{
|
|
Username: "atlantisbot",
|
|
},
|
|
AtlantisGitlabUser: models.User{
|
|
Username: "atlantisbot",
|
|
},
|
|
}
|
|
return ctrl, e2eVCSClient, e2eGithubGetter, atlantisWorkspace
|
|
}
|
|
|
|
type mockLockURLGenerator struct{}
|
|
|
|
func (m *mockLockURLGenerator) GenerateLockURL(lockID string) string {
|
|
return "lock-url"
|
|
}
|
|
|
|
type mockWebhookSender struct{}
|
|
|
|
func (w *mockWebhookSender) Send(log *logging.SimpleLogger, result webhooks.ApplyResult) error {
|
|
return nil
|
|
}
|
|
|
|
func GitHubCommentEvent(t *testing.T, comment string) *http.Request {
|
|
requestJSON, err := ioutil.ReadFile(filepath.Join("testfixtures", "githubIssueCommentEvent.json"))
|
|
Ok(t, err)
|
|
requestJSON = []byte(strings.Replace(string(requestJSON), "###comment body###", comment, 1))
|
|
req, err := http.NewRequest("POST", "/events", bytes.NewBuffer(requestJSON))
|
|
Ok(t, err)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set(githubHeader, "issue_comment")
|
|
return req
|
|
}
|
|
|
|
func GitHubPullRequestOpenedEvent(t *testing.T) *http.Request {
|
|
requestJSON, err := ioutil.ReadFile(filepath.Join("testfixtures", "githubPullRequestOpenedEvent.json"))
|
|
Ok(t, err)
|
|
req, err := http.NewRequest("POST", "/events", bytes.NewBuffer(requestJSON))
|
|
Ok(t, err)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set(githubHeader, "pull_request")
|
|
return req
|
|
}
|
|
|
|
func GitHubPullRequestClosedEvent(t *testing.T) *http.Request {
|
|
requestJSON, err := ioutil.ReadFile(filepath.Join("testfixtures", "githubPullRequestClosedEvent.json"))
|
|
Ok(t, err)
|
|
req, err := http.NewRequest("POST", "/events", bytes.NewBuffer(requestJSON))
|
|
Ok(t, err)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set(githubHeader, "pull_request")
|
|
return req
|
|
}
|
|
|
|
func GitHubPullRequestParsed() *github.PullRequest {
|
|
return &github.PullRequest{
|
|
Number: github.Int(1),
|
|
State: github.String("open"),
|
|
HTMLURL: github.String("htmlurl"),
|
|
Head: &github.PullRequestBranch{
|
|
Repo: &github.Repository{
|
|
FullName: github.String("runatlantis/atlantis-tests"),
|
|
CloneURL: github.String("/runatlantis/atlantis-tests.git"),
|
|
},
|
|
SHA: github.String("sha"),
|
|
Ref: github.String("branch"),
|
|
},
|
|
Base: &github.PullRequestBranch{
|
|
Repo: &github.Repository{
|
|
FullName: github.String("runatlantis/atlantis-tests"),
|
|
CloneURL: github.String("/runatlantis/atlantis-tests.git"),
|
|
},
|
|
},
|
|
User: &github.User{
|
|
Login: github.String("atlantisbot"),
|
|
},
|
|
}
|
|
}
|