mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-28 23:28:21 +00:00
Test EventsController Post()
This commit is contained in:
@@ -8,6 +8,11 @@ import (
|
||||
"github.com/hootsuite/atlantis/server/recovery"
|
||||
)
|
||||
|
||||
//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_command_runner.go CommandRunner
|
||||
type CommandRunner interface {
|
||||
ExecuteCommand(ctx *CommandContext)
|
||||
}
|
||||
|
||||
// CommandHandler is the first step when processing a comment command.
|
||||
type CommandHandler struct {
|
||||
PlanExecutor Executor
|
||||
|
||||
68
server/events/mocks/mock_command_runner.go
Normal file
68
server/events/mocks/mock_command_runner.go
Normal file
@@ -0,0 +1,68 @@
|
||||
// Automatically generated by pegomock. DO NOT EDIT!
|
||||
// Source: github.com/hootsuite/atlantis/server/events (interfaces: CommandRunner)
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
events "github.com/hootsuite/atlantis/server/events"
|
||||
pegomock "github.com/petergtz/pegomock"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type MockCommandRunner struct {
|
||||
fail func(message string, callerSkip ...int)
|
||||
}
|
||||
|
||||
func NewMockCommandRunner() *MockCommandRunner {
|
||||
return &MockCommandRunner{fail: pegomock.GlobalFailHandler}
|
||||
}
|
||||
|
||||
func (mock *MockCommandRunner) ExecuteCommand(ctx *events.CommandContext) {
|
||||
params := []pegomock.Param{ctx}
|
||||
pegomock.GetGenericMockFrom(mock).Invoke("ExecuteCommand", params, []reflect.Type{})
|
||||
}
|
||||
|
||||
func (mock *MockCommandRunner) VerifyWasCalledOnce() *VerifierCommandRunner {
|
||||
return &VerifierCommandRunner{mock, pegomock.Times(1), nil}
|
||||
}
|
||||
|
||||
func (mock *MockCommandRunner) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierCommandRunner {
|
||||
return &VerifierCommandRunner{mock, invocationCountMatcher, nil}
|
||||
}
|
||||
|
||||
func (mock *MockCommandRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierCommandRunner {
|
||||
return &VerifierCommandRunner{mock, invocationCountMatcher, inOrderContext}
|
||||
}
|
||||
|
||||
type VerifierCommandRunner struct {
|
||||
mock *MockCommandRunner
|
||||
invocationCountMatcher pegomock.Matcher
|
||||
inOrderContext *pegomock.InOrderContext
|
||||
}
|
||||
|
||||
func (verifier *VerifierCommandRunner) ExecuteCommand(ctx *events.CommandContext) *CommandRunner_ExecuteCommand_OngoingVerification {
|
||||
params := []pegomock.Param{ctx}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ExecuteCommand", params)
|
||||
return &CommandRunner_ExecuteCommand_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
|
||||
type CommandRunner_ExecuteCommand_OngoingVerification struct {
|
||||
mock *MockCommandRunner
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *CommandRunner_ExecuteCommand_OngoingVerification) GetCapturedArguments() *events.CommandContext {
|
||||
ctx := c.GetAllCapturedArguments()
|
||||
return ctx[len(ctx)-1]
|
||||
}
|
||||
|
||||
func (c *CommandRunner_ExecuteCommand_OngoingVerification) GetAllCapturedArguments() (_param0 []*events.CommandContext) {
|
||||
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(params) > 0 {
|
||||
_param0 = make([]*events.CommandContext, len(params[0]))
|
||||
for u, param := range params[0] {
|
||||
_param0[u] = param.(*events.CommandContext)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -10,10 +10,13 @@ import (
|
||||
)
|
||||
|
||||
type EventsController struct {
|
||||
CommandHandler *events.CommandHandler
|
||||
PullClosedExecutor *events.PullClosedExecutor
|
||||
Logger *logging.SimpleLogger
|
||||
Parser events.EventParsing
|
||||
CommandRunner events.CommandRunner
|
||||
PullClosedExecutor *events.PullClosedExecutor
|
||||
Logger *logging.SimpleLogger
|
||||
Parser events.EventParsing
|
||||
// GithubWebHookSecret is the secret added to this webhook via the GitHub
|
||||
// UI that identifies this call as coming from GitHub. If empty, no
|
||||
// request validation is done.
|
||||
GithubWebHookSecret []byte
|
||||
Validator GHRequestValidator
|
||||
}
|
||||
@@ -65,7 +68,7 @@ func (e *EventsController) HandleCommentEvent(w http.ResponseWriter, event *gith
|
||||
// We use a goroutine so that this function returns and the connection is
|
||||
// closed.
|
||||
fmt.Fprintln(w, "Processing...")
|
||||
go e.CommandHandler.ExecuteCommand(ctx)
|
||||
go e.CommandRunner.ExecuteCommand(ctx)
|
||||
}
|
||||
|
||||
// HandlePullRequestEvent will delete any locks associated with the pull request
|
||||
|
||||
@@ -9,8 +9,16 @@ import (
|
||||
"net/http"
|
||||
"bytes"
|
||||
"github.com/hootsuite/atlantis/server/mocks"
|
||||
emocks "github.com/hootsuite/atlantis/server/events/mocks"
|
||||
"net/http/httptest"
|
||||
"errors"
|
||||
"strings"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"github.com/google/go-github/github"
|
||||
"github.com/hootsuite/atlantis/server/events/models"
|
||||
"github.com/hootsuite/atlantis/server/events"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestPost_InvalidSecret(t *testing.T) {
|
||||
@@ -35,26 +43,134 @@ func TestPost_InvalidSecret(t *testing.T) {
|
||||
func TestPost_UnsupportedEvent(t *testing.T) {
|
||||
t.Log("when the event type is unsupported we ignore it")
|
||||
RegisterMockTestingT(t)
|
||||
v := mocks.NewMockGHRequestValidator()
|
||||
e := server.EventsController{
|
||||
Logger: logging.NewNoopLogger(),
|
||||
Validator: v,
|
||||
}
|
||||
req, err := http.NewRequest("GET", "http://localhost/event", bytes.NewBuffer(nil))
|
||||
Ok(t, err)
|
||||
w := httptest.NewRecorder()
|
||||
When(v.Validate(req, nil)).ThenReturn([]byte(`{"not an event": ""}`), nil)
|
||||
e.Post(w, req)
|
||||
|
||||
Equals(t, http.StatusOK, w.Result().StatusCode)
|
||||
body, _ := ioutil.ReadAll(w.Result().Body)
|
||||
Assert(t, strings.Contains(string(body), "Ignoring unsupported event"), "Response body was: %s", string(body))
|
||||
}
|
||||
|
||||
func TestPost_CommentNotCreated(t *testing.T) {
|
||||
t.Log("when the event is a comment but it's not a created event we ignore it")
|
||||
RegisterMockTestingT(t)
|
||||
v := mocks.NewMockGHRequestValidator()
|
||||
e := server.EventsController{
|
||||
Logger: logging.NewNoopLogger(),
|
||||
Validator: v,
|
||||
}
|
||||
req, err := http.NewRequest("GET", "http://localhost/event", bytes.NewBuffer(nil))
|
||||
req.Header.Set("X-Github-Event", "issue_comment")
|
||||
Ok(t, err)
|
||||
|
||||
// comment action is deleted, not created
|
||||
event := `{"action": "deleted"}`
|
||||
When(v.Validate(req, nil)).ThenReturn([]byte(event), nil)
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, req)
|
||||
|
||||
Equals(t, http.StatusOK, w.Result().StatusCode)
|
||||
body, _ := ioutil.ReadAll(w.Result().Body)
|
||||
Assert(t, strings.Contains(string(body), "Ignoring comment event since action was not created"), "Response body was: %s", string(body))
|
||||
}
|
||||
|
||||
func TestPost_CommentInvalidComment(t *testing.T) {
|
||||
t.Log("when the event is a comment without all expected data we return a 400")
|
||||
RegisterMockTestingT(t)
|
||||
v := mocks.NewMockGHRequestValidator()
|
||||
p := emocks.NewMockEventParsing()
|
||||
e := server.EventsController{
|
||||
Logger: logging.NewNoopLogger(),
|
||||
Validator: v,
|
||||
Parser: p,
|
||||
}
|
||||
req, err := http.NewRequest("GET", "http://localhost/event", bytes.NewBuffer(nil))
|
||||
req.Header.Set("X-Github-Event", "issue_comment")
|
||||
Ok(t, err)
|
||||
|
||||
event := `{"action": "created"}`
|
||||
When(v.Validate(req, nil)).ThenReturn([]byte(event), nil)
|
||||
When(p.ExtractCommentData(AnyComment())).ThenReturn(models.Repo{}, models.User{}, models.PullRequest{}, errors.New("err"))
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, req)
|
||||
|
||||
Equals(t, http.StatusBadRequest, w.Result().StatusCode)
|
||||
body, _ := ioutil.ReadAll(w.Result().Body)
|
||||
Assert(t, strings.Contains(string(body), "Failed parsing event"), "Response body was: %s", string(body))
|
||||
}
|
||||
|
||||
func TestPost_CommentInvalidCommand(t *testing.T) {
|
||||
t.Log("when the event is a comment with an invalid command we ignore it")
|
||||
RegisterMockTestingT(t)
|
||||
v := mocks.NewMockGHRequestValidator()
|
||||
p := emocks.NewMockEventParsing()
|
||||
e := server.EventsController{
|
||||
Logger: logging.NewNoopLogger(),
|
||||
Validator: v,
|
||||
Parser: p,
|
||||
}
|
||||
req, err := http.NewRequest("GET", "http://localhost/event", bytes.NewBuffer(nil))
|
||||
req.Header.Set("X-Github-Event", "issue_comment")
|
||||
Ok(t, err)
|
||||
|
||||
event := `{"action": "created"}`
|
||||
When(v.Validate(req, nil)).ThenReturn([]byte(event), nil)
|
||||
When(p.ExtractCommentData(AnyComment())).ThenReturn(models.Repo{}, models.User{}, models.PullRequest{}, nil)
|
||||
When(p.DetermineCommand(AnyComment())).ThenReturn(nil, errors.New("err"))
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, req)
|
||||
|
||||
Equals(t, http.StatusOK, w.Result().StatusCode)
|
||||
body, _ := ioutil.ReadAll(w.Result().Body)
|
||||
Assert(t, strings.Contains(string(body), "Ignoring: err"), "Response body was: %s", string(body))
|
||||
}
|
||||
|
||||
func TestPost_CommentSuccess(t *testing.T) {
|
||||
t.Log("when the event is comment with a valid command we call the command handler")
|
||||
RegisterMockTestingT(t)
|
||||
v := mocks.NewMockGHRequestValidator()
|
||||
p := emocks.NewMockEventParsing()
|
||||
cr := emocks.NewMockCommandRunner()
|
||||
e := server.EventsController{
|
||||
Logger: logging.NewNoopLogger(),
|
||||
Validator: v,
|
||||
Parser: p,
|
||||
CommandRunner: cr,
|
||||
}
|
||||
req, err := http.NewRequest("GET", "http://localhost/event", bytes.NewBuffer(nil))
|
||||
req.Header.Set("X-Github-Event", "issue_comment")
|
||||
Ok(t, err)
|
||||
|
||||
event := `{"action": "created"}`
|
||||
When(v.Validate(req, nil)).ThenReturn([]byte(event), nil)
|
||||
baseRepo := models.Repo{}
|
||||
user := models.User{}
|
||||
pull := models.PullRequest{}
|
||||
cmd := events.Command{}
|
||||
When(p.ExtractCommentData(AnyComment())).ThenReturn(baseRepo, user, pull, nil)
|
||||
When(p.DetermineCommand(AnyComment())).ThenReturn(&cmd, nil)
|
||||
w := httptest.NewRecorder()
|
||||
e.Post(w, req)
|
||||
|
||||
Equals(t, http.StatusOK, w.Result().StatusCode)
|
||||
body, _ := ioutil.ReadAll(w.Result().Body)
|
||||
Equals(t, "Processing...\n", string(body))
|
||||
|
||||
// wait for 200ms so goroutine is called
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
ctx := cr.VerifyWasCalledOnce().ExecuteCommand(AnyCommandContext()).GetCapturedArguments()
|
||||
Equals(t, baseRepo, ctx.BaseRepo)
|
||||
Equals(t, user, ctx.User)
|
||||
Equals(t, pull, ctx.Pull)
|
||||
Equals(t, cmd, *ctx.Command)
|
||||
}
|
||||
|
||||
func TestPost_PullRequestNotClosed(t *testing.T) {
|
||||
@@ -81,3 +197,13 @@ func TestPost_PullRequestSuccess(t *testing.T) {
|
||||
t.Log("when the event is a pull request and everything works we return a 200")
|
||||
RegisterMockTestingT(t)
|
||||
}
|
||||
|
||||
func AnyComment() *github.IssueCommentEvent {
|
||||
RegisterMatcher(NewAnyMatcher(reflect.TypeOf(&github.IssueCommentEvent{})))
|
||||
return &github.IssueCommentEvent{}
|
||||
}
|
||||
|
||||
func AnyCommandContext() *events.CommandContext {
|
||||
RegisterMatcher(NewAnyMatcher(reflect.TypeOf(&events.CommandContext{})))
|
||||
return &events.CommandContext{}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ func NewServer(config ServerConfig) (*Server, error) {
|
||||
Logger: logger,
|
||||
}
|
||||
eventsController := &EventsController{
|
||||
CommandHandler: commandHandler,
|
||||
CommandRunner: commandHandler,
|
||||
PullClosedExecutor: pullClosedExecutor,
|
||||
Parser: eventParser,
|
||||
Logger: logger,
|
||||
|
||||
Reference in New Issue
Block a user