mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-08-03 23:28:47 +00:00
217 lines
6.2 KiB
Go
217 lines
6.2 KiB
Go
package handlers_test
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/runatlantis/atlantis/server/events/models"
|
|
"github.com/runatlantis/atlantis/server/handlers"
|
|
"github.com/runatlantis/atlantis/server/handlers/mocks"
|
|
"github.com/runatlantis/atlantis/server/handlers/mocks/matchers"
|
|
"github.com/runatlantis/atlantis/server/logging"
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
. "github.com/petergtz/pegomock"
|
|
. "github.com/runatlantis/atlantis/testing"
|
|
)
|
|
|
|
func createTestProjectCmdContext(t *testing.T) models.ProjectCommandContext {
|
|
logger := logging.NewNoopLogger(t)
|
|
return models.ProjectCommandContext{
|
|
BaseRepo: models.Repo{
|
|
Name: "test-repo",
|
|
Owner: "test-org",
|
|
},
|
|
HeadRepo: models.Repo{
|
|
Name: "test-repo",
|
|
Owner: "test-org",
|
|
},
|
|
Pull: models.PullRequest{
|
|
Num: 1,
|
|
HeadBranch: "master",
|
|
BaseBranch: "master",
|
|
Author: "test-user",
|
|
},
|
|
User: models.User{
|
|
Username: "test-user",
|
|
},
|
|
Log: logger,
|
|
Workspace: "myworkspace",
|
|
RepoRelDir: "test-dir",
|
|
ProjectName: "test-project",
|
|
}
|
|
}
|
|
|
|
func createProjectCommandOutputHandler(t *testing.T) handlers.ProjectCommandOutputHandler {
|
|
logger := logging.NewNoopLogger(t)
|
|
prjCmdOutputChan := make(chan *models.ProjectCmdOutputLine)
|
|
projectStatusUpdater := mocks.NewMockProjectStatusUpdater()
|
|
projectJobURLGenerator := mocks.NewMockProjectJobURLGenerator()
|
|
prjCmdOutputHandler := handlers.NewAsyncProjectCommandOutputHandler(
|
|
prjCmdOutputChan,
|
|
projectStatusUpdater,
|
|
projectJobURLGenerator,
|
|
logger,
|
|
)
|
|
|
|
go func() {
|
|
prjCmdOutputHandler.Handle()
|
|
}()
|
|
|
|
return prjCmdOutputHandler
|
|
}
|
|
|
|
func TestProjectCommandOutputHandler(t *testing.T) {
|
|
Msg := "Test Terraform Output"
|
|
ctx := createTestProjectCmdContext(t)
|
|
|
|
t.Run("receive message from main channel", func(t *testing.T) {
|
|
var wg sync.WaitGroup
|
|
var expectedMsg string
|
|
projectOutputHandler := createProjectCommandOutputHandler(t)
|
|
|
|
ch := make(chan string)
|
|
|
|
// register channel and backfill from buffer
|
|
// Note: We call this synchronously because otherwise
|
|
// there could be a race where we are unable to register the channel
|
|
// before sending messages due to the way we lock our buffer memory cache
|
|
projectOutputHandler.Register(ctx.PullInfo(), ch)
|
|
|
|
wg.Add(1)
|
|
|
|
// read from channel
|
|
go func() {
|
|
for msg := range ch {
|
|
expectedMsg = msg
|
|
wg.Done()
|
|
}
|
|
}()
|
|
|
|
projectOutputHandler.Send(ctx, Msg)
|
|
wg.Wait()
|
|
close(ch)
|
|
|
|
// Wait for the msg to be read.
|
|
wg.Wait()
|
|
Equals(t, expectedMsg, Msg)
|
|
})
|
|
|
|
t.Run("clear buffer", func(t *testing.T) {
|
|
var wg sync.WaitGroup
|
|
|
|
projectOutputHandler := createProjectCommandOutputHandler(t)
|
|
|
|
ch := make(chan string)
|
|
|
|
// register channel and backfill from buffer
|
|
// Note: We call this synchronously because otherwise
|
|
// there could be a race where we are unable to register the channel
|
|
// before sending messages due to the way we lock our buffer memory cache
|
|
projectOutputHandler.Register(ctx.PullInfo(), ch)
|
|
|
|
wg.Add(1)
|
|
// read from channel asynchronously
|
|
go func() {
|
|
for msg := range ch {
|
|
// we are done once we receive the clear message.
|
|
// prior message doesn't matter for this test.
|
|
if msg == models.LogStreamingClearMsg {
|
|
wg.Done()
|
|
}
|
|
}
|
|
}()
|
|
|
|
// send regular message followed by clear message
|
|
projectOutputHandler.Send(ctx, Msg)
|
|
projectOutputHandler.Clear(ctx)
|
|
wg.Wait()
|
|
close(ch)
|
|
|
|
dfProjectOutputHandler, ok := projectOutputHandler.(*handlers.AsyncProjectCommandOutputHandler)
|
|
assert.True(t, ok)
|
|
|
|
assert.Empty(t, dfProjectOutputHandler.GetProjectOutputBuffer(ctx.PullInfo()))
|
|
})
|
|
|
|
t.Run("copies buffer to new channels", func(t *testing.T) {
|
|
var wg sync.WaitGroup
|
|
|
|
projectOutputHandler := createProjectCommandOutputHandler(t)
|
|
|
|
// send first message to populated the buffer
|
|
projectOutputHandler.Send(ctx, Msg)
|
|
|
|
ch := make(chan string)
|
|
|
|
receivedMsgs := []string{}
|
|
|
|
wg.Add(1)
|
|
// read from channel asynchronously
|
|
go func() {
|
|
for msg := range ch {
|
|
receivedMsgs = append(receivedMsgs, msg)
|
|
|
|
// we're only expecting two messages here.
|
|
if len(receivedMsgs) >= 2 {
|
|
wg.Done()
|
|
}
|
|
}
|
|
}()
|
|
// register channel and backfill from buffer
|
|
// Note: We call this synchronously because otherwise
|
|
// there could be a race where we are unable to register the channel
|
|
// before sending messages due to the way we lock our buffer memory cache
|
|
projectOutputHandler.Register(ctx.PullInfo(), ch)
|
|
|
|
projectOutputHandler.Send(ctx, Msg)
|
|
wg.Wait()
|
|
close(ch)
|
|
|
|
expectedMsgs := []string{Msg, Msg}
|
|
assert.Equal(t, len(expectedMsgs), len(receivedMsgs))
|
|
for i := range expectedMsgs {
|
|
assert.Equal(t, expectedMsgs[i], receivedMsgs[i])
|
|
}
|
|
})
|
|
|
|
t.Run("update project status with project jobs url", func(t *testing.T) {
|
|
RegisterMockTestingT(t)
|
|
logger := logging.NewNoopLogger(t)
|
|
prjCmdOutputChan := make(chan *models.ProjectCmdOutputLine)
|
|
projectStatusUpdater := mocks.NewMockProjectStatusUpdater()
|
|
projectJobURLGenerator := mocks.NewMockProjectJobURLGenerator()
|
|
prjCmdOutputHandler := handlers.NewAsyncProjectCommandOutputHandler(
|
|
prjCmdOutputChan,
|
|
projectStatusUpdater,
|
|
projectJobURLGenerator,
|
|
logger,
|
|
)
|
|
|
|
When(projectJobURLGenerator.GenerateProjectJobURL(matchers.EqModelsProjectCommandContext(ctx))).ThenReturn("url-to-project-jobs", nil)
|
|
err := prjCmdOutputHandler.SetJobURLWithStatus(ctx, models.PlanCommand, models.PendingCommitStatus)
|
|
Ok(t, err)
|
|
|
|
projectStatusUpdater.VerifyWasCalledOnce().UpdateProject(ctx, models.PlanCommand, models.PendingCommitStatus, "url-to-project-jobs")
|
|
})
|
|
|
|
t.Run("update project status with project jobs url error", func(t *testing.T) {
|
|
RegisterMockTestingT(t)
|
|
logger := logging.NewNoopLogger(t)
|
|
prjCmdOutputChan := make(chan *models.ProjectCmdOutputLine)
|
|
projectStatusUpdater := mocks.NewMockProjectStatusUpdater()
|
|
projectJobURLGenerator := mocks.NewMockProjectJobURLGenerator()
|
|
prjCmdOutputHandler := handlers.NewAsyncProjectCommandOutputHandler(
|
|
prjCmdOutputChan,
|
|
projectStatusUpdater,
|
|
projectJobURLGenerator,
|
|
logger,
|
|
)
|
|
|
|
When(projectJobURLGenerator.GenerateProjectJobURL(matchers.EqModelsProjectCommandContext(ctx))).ThenReturn("url-to-project-jobs", errors.New("some error"))
|
|
err := prjCmdOutputHandler.SetJobURLWithStatus(ctx, models.PlanCommand, models.PendingCommitStatus)
|
|
assert.Error(t, err)
|
|
})
|
|
}
|