mirror of https://github.com/coder/coder.git
316 lines
7.7 KiB
Go
316 lines
7.7 KiB
Go
package echo_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/coder/coder/v2/provisioner/echo"
|
|
"github.com/coder/coder/v2/provisionersdk"
|
|
"github.com/coder/coder/v2/provisionersdk/proto"
|
|
"github.com/coder/coder/v2/testutil"
|
|
)
|
|
|
|
func TestEcho(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
workdir := t.TempDir()
|
|
|
|
// Create an in-memory provisioner to communicate with.
|
|
client, server := provisionersdk.MemTransportPipe()
|
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
|
t.Cleanup(func() {
|
|
_ = client.Close()
|
|
_ = server.Close()
|
|
cancelFunc()
|
|
})
|
|
go func() {
|
|
err := echo.Serve(ctx, &provisionersdk.ServeOptions{
|
|
Listener: server,
|
|
WorkDirectory: workdir,
|
|
})
|
|
assert.NoError(t, err)
|
|
}()
|
|
api := proto.NewDRPCProvisionerClient(client)
|
|
|
|
t.Run("Parse", func(t *testing.T) {
|
|
t.Parallel()
|
|
ctx, cancel := context.WithTimeout(ctx, testutil.WaitShort)
|
|
defer cancel()
|
|
|
|
responses := []*proto.Response{
|
|
{
|
|
Type: &proto.Response_Log{
|
|
Log: &proto.Log{
|
|
Output: "log-output",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Type: &proto.Response_Parse{
|
|
Parse: &proto.ParseComplete{},
|
|
},
|
|
},
|
|
}
|
|
data, err := echo.Tar(&echo.Responses{
|
|
Parse: responses,
|
|
})
|
|
require.NoError(t, err)
|
|
client, err := api.Session(ctx)
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
err := client.Close()
|
|
require.NoError(t, err)
|
|
}()
|
|
err = client.Send(&proto.Request{Type: &proto.Request_Config{Config: &proto.Config{
|
|
TemplateSourceArchive: data,
|
|
}}})
|
|
require.NoError(t, err)
|
|
|
|
err = client.Send(&proto.Request{Type: &proto.Request_Parse{Parse: &proto.ParseRequest{}}})
|
|
require.NoError(t, err)
|
|
log, err := client.Recv()
|
|
require.NoError(t, err)
|
|
require.Equal(t, responses[0].GetLog().Output, log.GetLog().Output)
|
|
complete, err := client.Recv()
|
|
require.NoError(t, err)
|
|
require.NotNil(t, complete)
|
|
})
|
|
|
|
t.Run("Provision", func(t *testing.T) {
|
|
t.Parallel()
|
|
ctx, cancel := context.WithTimeout(ctx, testutil.WaitShort)
|
|
defer cancel()
|
|
|
|
planResponses := []*proto.Response{
|
|
{
|
|
Type: &proto.Response_Log{
|
|
Log: &proto.Log{
|
|
Level: proto.LogLevel_INFO,
|
|
Output: "log-output",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Type: &proto.Response_Plan{
|
|
Plan: &proto.PlanComplete{
|
|
Resources: []*proto.Resource{{
|
|
Name: "resource",
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
applyResponses := []*proto.Response{
|
|
{
|
|
Type: &proto.Response_Log{
|
|
Log: &proto.Log{
|
|
Level: proto.LogLevel_INFO,
|
|
Output: "log-output",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Type: &proto.Response_Apply{
|
|
Apply: &proto.ApplyComplete{
|
|
Resources: []*proto.Resource{{
|
|
Name: "resource",
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
data, err := echo.Tar(&echo.Responses{
|
|
ProvisionPlan: planResponses,
|
|
ProvisionApply: applyResponses,
|
|
})
|
|
require.NoError(t, err)
|
|
client, err := api.Session(ctx)
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
err := client.Close()
|
|
require.NoError(t, err)
|
|
}()
|
|
err = client.Send(&proto.Request{Type: &proto.Request_Config{Config: &proto.Config{
|
|
TemplateSourceArchive: data,
|
|
}}})
|
|
require.NoError(t, err)
|
|
|
|
err = client.Send(&proto.Request{Type: &proto.Request_Plan{Plan: &proto.PlanRequest{}}})
|
|
require.NoError(t, err)
|
|
log, err := client.Recv()
|
|
require.NoError(t, err)
|
|
require.Equal(t, planResponses[0].GetLog().Output, log.GetLog().Output)
|
|
complete, err := client.Recv()
|
|
require.NoError(t, err)
|
|
require.Equal(t, planResponses[1].GetPlan().Resources[0].Name,
|
|
complete.GetPlan().Resources[0].Name)
|
|
|
|
err = client.Send(&proto.Request{Type: &proto.Request_Apply{Apply: &proto.ApplyRequest{}}})
|
|
require.NoError(t, err)
|
|
log, err = client.Recv()
|
|
require.NoError(t, err)
|
|
require.Equal(t, applyResponses[0].GetLog().Output, log.GetLog().Output)
|
|
complete, err = client.Recv()
|
|
require.NoError(t, err)
|
|
require.Equal(t, applyResponses[1].GetApply().Resources[0].Name,
|
|
complete.GetApply().Resources[0].Name)
|
|
})
|
|
|
|
t.Run("ProvisionStop", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Stop responses should be returned when the workspace is being stopped.
|
|
data, err := echo.Tar(&echo.Responses{
|
|
ProvisionApply: applyCompleteResource("DEFAULT"),
|
|
ProvisionPlan: planCompleteResource("DEFAULT"),
|
|
ProvisionPlanMap: map[proto.WorkspaceTransition][]*proto.Response{
|
|
proto.WorkspaceTransition_STOP: planCompleteResource("STOP"),
|
|
},
|
|
ProvisionApplyMap: map[proto.WorkspaceTransition][]*proto.Response{
|
|
proto.WorkspaceTransition_STOP: applyCompleteResource("STOP"),
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
client, err := api.Session(ctx)
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
err := client.Close()
|
|
require.NoError(t, err)
|
|
}()
|
|
err = client.Send(&proto.Request{Type: &proto.Request_Config{Config: &proto.Config{
|
|
TemplateSourceArchive: data,
|
|
}}})
|
|
require.NoError(t, err)
|
|
|
|
// Do stop.
|
|
err = client.Send(&proto.Request{
|
|
Type: &proto.Request_Plan{
|
|
Plan: &proto.PlanRequest{
|
|
Metadata: &proto.Metadata{
|
|
WorkspaceTransition: proto.WorkspaceTransition_STOP,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
complete, err := client.Recv()
|
|
require.NoError(t, err)
|
|
require.Equal(t,
|
|
"STOP",
|
|
complete.GetPlan().Resources[0].Name,
|
|
)
|
|
|
|
// Do start.
|
|
err = client.Send(&proto.Request{
|
|
Type: &proto.Request_Plan{
|
|
Plan: &proto.PlanRequest{
|
|
Metadata: &proto.Metadata{
|
|
WorkspaceTransition: proto.WorkspaceTransition_START,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
complete, err = client.Recv()
|
|
require.NoError(t, err)
|
|
require.Equal(t,
|
|
"DEFAULT",
|
|
complete.GetPlan().Resources[0].Name,
|
|
)
|
|
})
|
|
|
|
t.Run("ProvisionWithLogLevel", func(t *testing.T) {
|
|
t.Parallel()
|
|
ctx, cancel := context.WithTimeout(ctx, testutil.WaitShort)
|
|
defer cancel()
|
|
|
|
responses := []*proto.Response{{
|
|
Type: &proto.Response_Log{
|
|
Log: &proto.Log{
|
|
Level: proto.LogLevel_TRACE,
|
|
Output: "log-output-trace",
|
|
},
|
|
},
|
|
}, {
|
|
Type: &proto.Response_Log{
|
|
Log: &proto.Log{
|
|
Level: proto.LogLevel_INFO,
|
|
Output: "log-output-info",
|
|
},
|
|
},
|
|
}, {
|
|
Type: &proto.Response_Apply{
|
|
Apply: &proto.ApplyComplete{
|
|
Resources: []*proto.Resource{{
|
|
Name: "resource",
|
|
}},
|
|
},
|
|
},
|
|
}}
|
|
data, err := echo.Tar(&echo.Responses{
|
|
ProvisionPlan: echo.PlanComplete,
|
|
ProvisionApply: responses,
|
|
})
|
|
require.NoError(t, err)
|
|
client, err := api.Session(ctx)
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
err := client.Close()
|
|
require.NoError(t, err)
|
|
}()
|
|
err = client.Send(&proto.Request{Type: &proto.Request_Config{Config: &proto.Config{
|
|
TemplateSourceArchive: data,
|
|
ProvisionerLogLevel: "debug",
|
|
}}})
|
|
require.NoError(t, err)
|
|
|
|
// Plan is required before apply
|
|
err = client.Send(&proto.Request{Type: &proto.Request_Plan{Plan: &proto.PlanRequest{}}})
|
|
require.NoError(t, err)
|
|
complete, err := client.Recv()
|
|
require.NoError(t, err)
|
|
require.NotNil(t, complete.GetPlan())
|
|
|
|
err = client.Send(&proto.Request{Type: &proto.Request_Apply{Apply: &proto.ApplyRequest{}}})
|
|
require.NoError(t, err)
|
|
log, err := client.Recv()
|
|
require.NoError(t, err)
|
|
// Skip responses[0] as it's trace level
|
|
require.Equal(t, responses[1].GetLog().Output, log.GetLog().Output)
|
|
complete, err = client.Recv()
|
|
require.NoError(t, err)
|
|
require.Equal(t, responses[2].GetApply().Resources[0].Name,
|
|
complete.GetApply().Resources[0].Name)
|
|
})
|
|
}
|
|
|
|
func planCompleteResource(name string) []*proto.Response {
|
|
return []*proto.Response{{
|
|
Type: &proto.Response_Plan{
|
|
Plan: &proto.PlanComplete{
|
|
Resources: []*proto.Resource{{
|
|
Name: name,
|
|
}},
|
|
},
|
|
},
|
|
}}
|
|
}
|
|
|
|
func applyCompleteResource(name string) []*proto.Response {
|
|
return []*proto.Response{{
|
|
Type: &proto.Response_Apply{
|
|
Apply: &proto.ApplyComplete{
|
|
Resources: []*proto.Resource{{
|
|
Name: name,
|
|
}},
|
|
},
|
|
},
|
|
}}
|
|
}
|