mirror of https://github.com/coder/coder.git
1662 lines
57 KiB
Go
1662 lines
57 KiB
Go
package coderd_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"net/http"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/sync/errgroup"
|
|
|
|
"github.com/coder/coder/v2/coderd/audit"
|
|
"github.com/coder/coder/v2/coderd/coderdtest"
|
|
"github.com/coder/coder/v2/coderd/database"
|
|
"github.com/coder/coder/v2/coderd/externalauth"
|
|
"github.com/coder/coder/v2/coderd/rbac"
|
|
"github.com/coder/coder/v2/codersdk"
|
|
"github.com/coder/coder/v2/examples"
|
|
"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 TestTemplateVersion(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("Get", func(t *testing.T) {
|
|
t.Parallel()
|
|
client, _, api := coderdtest.NewWithAPI(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
authz := coderdtest.AssertRBAC(t, api, client).Reset()
|
|
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil, func(req *codersdk.CreateTemplateVersionRequest) {
|
|
req.Name = "bananas"
|
|
req.Message = "first try"
|
|
})
|
|
authz.AssertChecked(t, rbac.ActionCreate, rbac.ResourceTemplate.InOrg(user.OrganizationID))
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
authz.Reset()
|
|
tv, err := client.TemplateVersion(ctx, version.ID)
|
|
authz.AssertChecked(t, rbac.ActionRead, tv)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, "bananas", tv.Name)
|
|
assert.Equal(t, "first try", tv.Message)
|
|
})
|
|
|
|
t.Run("Message limit exceeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
client, _, _ := coderdtest.NewWithAPI(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
file, err := client.Upload(ctx, codersdk.ContentTypeTar, bytes.NewReader([]byte{}))
|
|
require.NoError(t, err)
|
|
_, err = client.CreateTemplateVersion(ctx, user.OrganizationID, codersdk.CreateTemplateVersionRequest{
|
|
Name: "bananas",
|
|
Message: strings.Repeat("a", 1048577),
|
|
StorageMethod: codersdk.ProvisionerStorageMethodFile,
|
|
FileID: file.ID,
|
|
Provisioner: codersdk.ProvisionerTypeEcho,
|
|
})
|
|
require.Error(t, err, "message too long, create should fail")
|
|
})
|
|
|
|
t.Run("MemberCanRead", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
|
|
ctx := testutil.Context(t, testutil.WaitLong)
|
|
|
|
client1, _ := coderdtest.CreateAnotherUser(t, client, user.OrganizationID)
|
|
|
|
_, err := client1.TemplateVersion(ctx, version.ID)
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestPostTemplateVersionsByOrganization(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("InvalidTemplate", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
templateID := uuid.New()
|
|
_, err := client.CreateTemplateVersion(ctx, user.OrganizationID, codersdk.CreateTemplateVersionRequest{
|
|
TemplateID: templateID,
|
|
StorageMethod: codersdk.ProvisionerStorageMethodFile,
|
|
FileID: uuid.New(),
|
|
Provisioner: codersdk.ProvisionerTypeEcho,
|
|
})
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
|
|
})
|
|
|
|
t.Run("FileNotFound", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
_, err := client.CreateTemplateVersion(ctx, user.OrganizationID, codersdk.CreateTemplateVersionRequest{
|
|
StorageMethod: codersdk.ProvisionerStorageMethodFile,
|
|
FileID: uuid.New(),
|
|
Provisioner: codersdk.ProvisionerTypeEcho,
|
|
})
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
|
|
})
|
|
|
|
t.Run("WithParameters", func(t *testing.T) {
|
|
t.Parallel()
|
|
auditor := audit.NewMock()
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, Auditor: auditor})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
data, err := echo.Tar(&echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionApply: echo.ApplyComplete,
|
|
ProvisionPlan: echo.PlanComplete,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
file, err := client.Upload(ctx, codersdk.ContentTypeTar, bytes.NewReader(data))
|
|
require.NoError(t, err)
|
|
version, err := client.CreateTemplateVersion(ctx, user.OrganizationID, codersdk.CreateTemplateVersionRequest{
|
|
Name: "bananas",
|
|
StorageMethod: codersdk.ProvisionerStorageMethodFile,
|
|
FileID: file.ID,
|
|
Provisioner: codersdk.ProvisionerTypeEcho,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, "bananas", version.Name)
|
|
require.Equal(t, provisionersdk.ScopeOrganization, version.Job.Tags[provisionersdk.TagScope])
|
|
|
|
require.Len(t, auditor.AuditLogs(), 2)
|
|
assert.Equal(t, database.AuditActionCreate, auditor.AuditLogs()[1].Action)
|
|
})
|
|
|
|
t.Run("Example", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
ls, err := examples.List()
|
|
require.NoError(t, err)
|
|
|
|
// try a bad example ID
|
|
_, err = client.CreateTemplateVersion(ctx, user.OrganizationID, codersdk.CreateTemplateVersionRequest{
|
|
Name: "my-example",
|
|
StorageMethod: codersdk.ProvisionerStorageMethodFile,
|
|
ExampleID: "not a real ID",
|
|
Provisioner: codersdk.ProvisionerTypeEcho,
|
|
})
|
|
require.Error(t, err)
|
|
require.ErrorContains(t, err, "not found")
|
|
|
|
// try file and example IDs
|
|
_, err = client.CreateTemplateVersion(ctx, user.OrganizationID, codersdk.CreateTemplateVersionRequest{
|
|
Name: "my-example",
|
|
StorageMethod: codersdk.ProvisionerStorageMethodFile,
|
|
ExampleID: ls[0].ID,
|
|
FileID: uuid.New(),
|
|
Provisioner: codersdk.ProvisionerTypeEcho,
|
|
})
|
|
require.Error(t, err)
|
|
require.ErrorContains(t, err, "example_id")
|
|
require.ErrorContains(t, err, "file_id")
|
|
|
|
// try a good example ID
|
|
tv, err := client.CreateTemplateVersion(ctx, user.OrganizationID, codersdk.CreateTemplateVersionRequest{
|
|
Name: "my-example",
|
|
StorageMethod: codersdk.ProvisionerStorageMethodFile,
|
|
ExampleID: ls[0].ID,
|
|
Provisioner: codersdk.ProvisionerTypeEcho,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, "my-example", tv.Name)
|
|
|
|
// ensure the template tar was uploaded correctly
|
|
fl, ct, err := client.Download(ctx, tv.Job.FileID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "application/x-tar", ct)
|
|
tar, err := examples.Archive(ls[0].ID)
|
|
require.NoError(t, err)
|
|
require.EqualValues(t, tar, fl)
|
|
|
|
// ensure we don't get file conflicts on multiple uses of the same example
|
|
tv, err = client.CreateTemplateVersion(ctx, user.OrganizationID, codersdk.CreateTemplateVersionRequest{
|
|
Name: "my-example",
|
|
StorageMethod: codersdk.ProvisionerStorageMethodFile,
|
|
ExampleID: ls[0].ID,
|
|
Provisioner: codersdk.ProvisionerTypeEcho,
|
|
})
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestPatchCancelTemplateVersion(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("AlreadyCompleted", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
err := client.CancelTemplateVersion(ctx, version.ID)
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
|
})
|
|
t.Run("AlreadyCanceled", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, &coderdtest.Options{
|
|
IncludeProvisionerDaemon: true,
|
|
})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionApply: []*proto.Response{{
|
|
Type: &proto.Response_Log{
|
|
Log: &proto.Log{},
|
|
},
|
|
}},
|
|
})
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
coderdtest.AwaitTemplateVersionJobRunning(t, client, version.ID)
|
|
err := client.CancelTemplateVersion(ctx, version.ID)
|
|
require.NoError(t, err)
|
|
err = client.CancelTemplateVersion(ctx, version.ID)
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
|
require.Eventually(t, func() bool {
|
|
var err error
|
|
version, err = client.TemplateVersion(ctx, version.ID)
|
|
return assert.NoError(t, err) && version.Job.Status == codersdk.ProvisionerJobFailed
|
|
}, testutil.WaitShort, testutil.IntervalFast)
|
|
})
|
|
// TODO(Cian): until we are able to test cancellation properly, validating
|
|
// Running -> Canceling is the best we can do for now.
|
|
t.Run("Canceling", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, &coderdtest.Options{
|
|
IncludeProvisionerDaemon: true,
|
|
})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionApply: []*proto.Response{{
|
|
Type: &proto.Response_Log{
|
|
Log: &proto.Log{},
|
|
},
|
|
}},
|
|
})
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
require.Eventually(t, func() bool {
|
|
var err error
|
|
version, err = client.TemplateVersion(ctx, version.ID)
|
|
if !assert.NoError(t, err) {
|
|
return false
|
|
}
|
|
t.Logf("Status: %s", version.Job.Status)
|
|
return version.Job.Status == codersdk.ProvisionerJobRunning
|
|
}, testutil.WaitShort, testutil.IntervalFast)
|
|
err := client.CancelTemplateVersion(ctx, version.ID)
|
|
require.NoError(t, err)
|
|
require.Eventually(t, func() bool {
|
|
var err error
|
|
version, err = client.TemplateVersion(ctx, version.ID)
|
|
// job gets marked Failed when there is an Error; in practice we never get to Status = Canceled
|
|
// because provisioners report an Error when canceled. We check the Error string to ensure we don't mask
|
|
// other errors in this test.
|
|
t.Logf("got version %s | %s", version.Job.Error, version.Job.Status)
|
|
return assert.NoError(t, err) &&
|
|
strings.HasSuffix(version.Job.Error, "canceled") &&
|
|
version.Job.Status == codersdk.ProvisionerJobFailed
|
|
}, testutil.WaitShort, testutil.IntervalFast)
|
|
})
|
|
}
|
|
|
|
func TestTemplateVersionsExternalAuth(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("Empty", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
_, err := client.TemplateVersionExternalAuth(ctx, version.ID)
|
|
require.NoError(t, err)
|
|
})
|
|
t.Run("Authenticated", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, &coderdtest.Options{
|
|
IncludeProvisionerDaemon: true,
|
|
ExternalAuthConfigs: []*externalauth.Config{{
|
|
InstrumentedOAuth2Config: &testutil.OAuth2Config{},
|
|
ID: "github",
|
|
Regex: regexp.MustCompile(`github\.com`),
|
|
Type: codersdk.EnhancedExternalAuthProviderGitHub.String(),
|
|
}},
|
|
})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionPlan: []*proto.Response{{
|
|
Type: &proto.Response_Plan{
|
|
Plan: &proto.PlanComplete{
|
|
ExternalAuthProviders: []*proto.ExternalAuthProviderResource{{Id: "github", Optional: true}},
|
|
},
|
|
},
|
|
}},
|
|
})
|
|
version = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
require.Empty(t, version.Job.Error)
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
// Not authenticated to start!
|
|
providers, err := client.TemplateVersionExternalAuth(ctx, version.ID)
|
|
require.NoError(t, err)
|
|
require.Len(t, providers, 1)
|
|
require.False(t, providers[0].Authenticated)
|
|
|
|
// Perform the Git auth callback to authenticate the user...
|
|
resp := coderdtest.RequestExternalAuthCallback(t, "github", client)
|
|
_ = resp.Body.Close()
|
|
require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
|
|
|
|
// Ensure that the returned Git auth for the template is authenticated!
|
|
providers, err = client.TemplateVersionExternalAuth(ctx, version.ID)
|
|
require.NoError(t, err)
|
|
require.Len(t, providers, 1)
|
|
require.True(t, providers[0].Authenticated)
|
|
require.True(t, providers[0].Optional)
|
|
})
|
|
}
|
|
|
|
func TestTemplateVersionResources(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("ListRunning", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
_, err := client.TemplateVersionResources(ctx, version.ID)
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
|
})
|
|
t.Run("List", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionApply: []*proto.Response{{
|
|
Type: &proto.Response_Apply{
|
|
Apply: &proto.ApplyComplete{
|
|
Resources: []*proto.Resource{{
|
|
Name: "some",
|
|
Type: "example",
|
|
Agents: []*proto.Agent{{
|
|
Id: "something",
|
|
Auth: &proto.Agent_Token{},
|
|
}},
|
|
}, {
|
|
Name: "another",
|
|
Type: "example",
|
|
}},
|
|
},
|
|
},
|
|
}},
|
|
})
|
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
resources, err := client.TemplateVersionResources(ctx, version.ID)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, resources)
|
|
require.Len(t, resources, 4)
|
|
require.Equal(t, "some", resources[2].Name)
|
|
require.Equal(t, "example", resources[2].Type)
|
|
require.Len(t, resources[2].Agents, 1)
|
|
})
|
|
}
|
|
|
|
func TestTemplateVersionLogs(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionPlan: echo.PlanComplete,
|
|
ProvisionApply: []*proto.Response{{
|
|
Type: &proto.Response_Log{
|
|
Log: &proto.Log{
|
|
Level: proto.LogLevel_INFO,
|
|
Output: "example",
|
|
},
|
|
},
|
|
}, {
|
|
Type: &proto.Response_Apply{
|
|
Apply: &proto.ApplyComplete{
|
|
Resources: []*proto.Resource{{
|
|
Name: "some",
|
|
Type: "example",
|
|
Agents: []*proto.Agent{{
|
|
Id: "something",
|
|
Auth: &proto.Agent_Token{
|
|
Token: uuid.NewString(),
|
|
},
|
|
}},
|
|
}, {
|
|
Name: "another",
|
|
Type: "example",
|
|
}},
|
|
},
|
|
},
|
|
}},
|
|
})
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
logs, closer, err := client.TemplateVersionLogsAfter(ctx, version.ID, 0)
|
|
require.NoError(t, err)
|
|
defer closer.Close()
|
|
for {
|
|
_, ok := <-logs
|
|
if !ok {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTemplateVersionsByTemplate(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("Get", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
versions, err := client.TemplateVersionsByTemplate(ctx, codersdk.TemplateVersionsByTemplateRequest{
|
|
TemplateID: template.ID,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, versions, 1)
|
|
})
|
|
}
|
|
|
|
func TestTemplateVersionByName(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("NotFound", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
_, err := client.TemplateVersionByName(ctx, template.ID, "nothing")
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
|
|
})
|
|
|
|
t.Run("Found", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
_, err := client.TemplateVersionByName(ctx, template.ID, version.Name)
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestPatchActiveTemplateVersion(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("NotFound", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
err := client.UpdateActiveTemplateVersion(ctx, template.ID, codersdk.UpdateActiveTemplateVersion{
|
|
ID: uuid.New(),
|
|
})
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
|
|
})
|
|
|
|
t.Run("CanceledBuild", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
version = coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, nil, template.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
err := client.CancelTemplateVersion(ctx, version.ID)
|
|
require.NoError(t, err)
|
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
err = client.UpdateActiveTemplateVersion(ctx, template.ID, codersdk.UpdateActiveTemplateVersion{
|
|
ID: version.ID,
|
|
})
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusForbidden, apiErr.StatusCode())
|
|
require.Contains(t, apiErr.Detail, "canceled")
|
|
})
|
|
|
|
t.Run("PendingBuild", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
version = coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, nil, template.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
err := client.UpdateActiveTemplateVersion(ctx, template.ID, codersdk.UpdateActiveTemplateVersion{
|
|
ID: version.ID,
|
|
})
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusForbidden, apiErr.StatusCode())
|
|
require.Contains(t, apiErr.Detail, "pending")
|
|
})
|
|
|
|
t.Run("DoesNotBelong", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, &coderdtest.Options{
|
|
IncludeProvisionerDaemon: true,
|
|
})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
err := client.UpdateActiveTemplateVersion(ctx, template.ID, codersdk.UpdateActiveTemplateVersion{
|
|
ID: version.ID,
|
|
})
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
|
})
|
|
|
|
t.Run("Archived", func(t *testing.T) {
|
|
t.Parallel()
|
|
auditor := audit.NewMock()
|
|
ownerClient := coderdtest.New(t, &coderdtest.Options{
|
|
IncludeProvisionerDaemon: true,
|
|
Auditor: auditor,
|
|
})
|
|
owner := coderdtest.CreateFirstUser(t, ownerClient)
|
|
client, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.RoleTemplateAdmin())
|
|
|
|
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
|
|
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
|
|
version = coderdtest.UpdateTemplateVersion(t, client, owner.OrganizationID, nil, template.ID)
|
|
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
err := client.SetArchiveTemplateVersion(ctx, version.ID, true)
|
|
require.NoError(t, err)
|
|
|
|
err = client.UpdateActiveTemplateVersion(ctx, template.ID, codersdk.UpdateActiveTemplateVersion{
|
|
ID: version.ID,
|
|
})
|
|
require.Error(t, err)
|
|
require.ErrorContains(t, err, "The provided template version is archived")
|
|
})
|
|
|
|
t.Run("SuccessfulBuild", func(t *testing.T) {
|
|
t.Parallel()
|
|
auditor := audit.NewMock()
|
|
client := coderdtest.New(t, &coderdtest.Options{
|
|
IncludeProvisionerDaemon: true,
|
|
Auditor: auditor,
|
|
})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
version = coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, nil, template.ID)
|
|
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
err := client.UpdateActiveTemplateVersion(ctx, template.ID, codersdk.UpdateActiveTemplateVersion{
|
|
ID: version.ID,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, auditor.AuditLogs(), 6)
|
|
assert.Equal(t, database.AuditActionWrite, auditor.AuditLogs()[5].Action)
|
|
})
|
|
}
|
|
|
|
func TestTemplateVersionDryRun(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("OK", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
resource := &proto.Resource{
|
|
Name: "cool-resource",
|
|
Type: "cool_resource_type",
|
|
}
|
|
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionApply: []*proto.Response{
|
|
{
|
|
Type: &proto.Response_Log{
|
|
Log: &proto.Log{},
|
|
},
|
|
},
|
|
{
|
|
Type: &proto.Response_Apply{
|
|
Apply: &proto.ApplyComplete{
|
|
Resources: []*proto.Resource{resource},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
// Create template version dry-run
|
|
job, err := client.CreateTemplateVersionDryRun(ctx, version.ID, codersdk.CreateTemplateVersionDryRunRequest{})
|
|
require.NoError(t, err)
|
|
|
|
// Fetch template version dry-run
|
|
newJob, err := client.TemplateVersionDryRun(ctx, version.ID, job.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, job.ID, newJob.ID)
|
|
|
|
// Stream logs
|
|
logs, closer, err := client.TemplateVersionDryRunLogsAfter(ctx, version.ID, job.ID, 0)
|
|
require.NoError(t, err)
|
|
defer closer.Close()
|
|
|
|
logsDone := make(chan struct{})
|
|
go func() {
|
|
defer close(logsDone)
|
|
|
|
logCount := 0
|
|
for range logs {
|
|
logCount++
|
|
}
|
|
assert.GreaterOrEqual(t, logCount, 1, "unexpected log count")
|
|
}()
|
|
|
|
// Wait for the job to complete
|
|
require.Eventually(t, func() bool {
|
|
job, err := client.TemplateVersionDryRun(ctx, version.ID, job.ID)
|
|
return assert.NoError(t, err) && job.Status == codersdk.ProvisionerJobSucceeded
|
|
}, testutil.WaitShort, testutil.IntervalFast)
|
|
|
|
<-logsDone
|
|
|
|
resources, err := client.TemplateVersionDryRunResources(ctx, version.ID, job.ID)
|
|
require.NoError(t, err)
|
|
require.Len(t, resources, 1)
|
|
require.Equal(t, resource.Name, resources[0].Name)
|
|
require.Equal(t, resource.Type, resources[0].Type)
|
|
})
|
|
|
|
t.Run("ImportNotFinished", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
// This import job will never finish
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionApply: []*proto.Response{{
|
|
Type: &proto.Response_Log{
|
|
Log: &proto.Log{},
|
|
},
|
|
}},
|
|
})
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
_, err := client.CreateTemplateVersionDryRun(ctx, version.ID, codersdk.CreateTemplateVersionDryRunRequest{})
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
|
})
|
|
|
|
t.Run("Cancel", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("OK", func(t *testing.T) {
|
|
t.Parallel()
|
|
client, closer := coderdtest.NewWithProvisionerCloser(t, nil)
|
|
defer closer.Close()
|
|
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionApply: []*proto.Response{
|
|
{
|
|
Type: &proto.Response_Log{
|
|
Log: &proto.Log{},
|
|
},
|
|
},
|
|
{
|
|
Type: &proto.Response_Apply{
|
|
Apply: &proto.ApplyComplete{},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
version = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
require.Equal(t, codersdk.ProvisionerJobSucceeded, version.Job.Status)
|
|
|
|
closer.Close()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
// Create the dry-run
|
|
job, err := client.CreateTemplateVersionDryRun(ctx, version.ID, codersdk.CreateTemplateVersionDryRunRequest{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, codersdk.ProvisionerJobPending, job.Status)
|
|
err = client.CancelTemplateVersionDryRun(ctx, version.ID, job.ID)
|
|
require.NoError(t, err)
|
|
job, err = client.TemplateVersionDryRun(ctx, version.ID, job.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, codersdk.ProvisionerJobCanceled, job.Status)
|
|
})
|
|
|
|
t.Run("AlreadyCompleted", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
// Create the dry-run
|
|
job, err := client.CreateTemplateVersionDryRun(ctx, version.ID, codersdk.CreateTemplateVersionDryRunRequest{})
|
|
require.NoError(t, err)
|
|
|
|
require.Eventually(t, func() bool {
|
|
job, err := client.TemplateVersionDryRun(ctx, version.ID, job.ID)
|
|
if !assert.NoError(t, err) {
|
|
return false
|
|
}
|
|
|
|
t.Logf("Status: %s", job.Status)
|
|
return job.Status == codersdk.ProvisionerJobSucceeded
|
|
}, testutil.WaitShort, testutil.IntervalFast)
|
|
|
|
err = client.CancelTemplateVersionDryRun(ctx, version.ID, job.ID)
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
|
})
|
|
|
|
t.Run("AlreadyCanceled", func(t *testing.T) {
|
|
t.Parallel()
|
|
client, closer := coderdtest.NewWithProvisionerCloser(t, nil)
|
|
defer closer.Close()
|
|
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionApply: []*proto.Response{
|
|
{
|
|
Type: &proto.Response_Log{
|
|
Log: &proto.Log{},
|
|
},
|
|
},
|
|
{
|
|
Type: &proto.Response_Apply{
|
|
Apply: &proto.ApplyComplete{},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
version = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
require.Equal(t, codersdk.ProvisionerJobSucceeded, version.Job.Status)
|
|
|
|
closer.Close()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
// Create the dry-run
|
|
job, err := client.CreateTemplateVersionDryRun(ctx, version.ID, codersdk.CreateTemplateVersionDryRunRequest{})
|
|
require.NoError(t, err)
|
|
|
|
err = client.CancelTemplateVersionDryRun(ctx, version.ID, job.ID)
|
|
require.NoError(t, err)
|
|
|
|
err = client.CancelTemplateVersionDryRun(ctx, version.ID, job.ID)
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
|
})
|
|
})
|
|
}
|
|
|
|
// TestPaginatedTemplateVersions creates a list of template versions and paginate.
|
|
func TestPaginatedTemplateVersions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
t.Cleanup(cancel)
|
|
// Populate database with template versions.
|
|
total := 9
|
|
eg, egCtx := errgroup.WithContext(ctx)
|
|
templateVersionIDs := make([]uuid.UUID, total)
|
|
data, err := echo.Tar(nil)
|
|
require.NoError(t, err)
|
|
file, err := client.Upload(egCtx, codersdk.ContentTypeTar, bytes.NewReader(data))
|
|
require.NoError(t, err)
|
|
for i := 0; i < total; i++ {
|
|
i := i
|
|
eg.Go(func() error {
|
|
templateVersion, err := client.CreateTemplateVersion(egCtx, user.OrganizationID, codersdk.CreateTemplateVersionRequest{
|
|
Name: uuid.NewString(),
|
|
TemplateID: template.ID,
|
|
FileID: file.ID,
|
|
StorageMethod: codersdk.ProvisionerStorageMethodFile,
|
|
Provisioner: codersdk.ProvisionerTypeEcho,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
templateVersionIDs[i] = templateVersion.ID
|
|
return nil
|
|
})
|
|
}
|
|
err = eg.Wait()
|
|
require.NoError(t, err, "create templates failed")
|
|
|
|
templateVersions, err := client.TemplateVersionsByTemplate(ctx,
|
|
codersdk.TemplateVersionsByTemplateRequest{
|
|
TemplateID: template.ID,
|
|
},
|
|
)
|
|
require.NoError(t, err)
|
|
require.Len(t, templateVersions, 10, "wrong number of template versions created")
|
|
|
|
type args struct {
|
|
pagination codersdk.Pagination
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want []codersdk.TemplateVersion
|
|
expectedError string
|
|
}{
|
|
{
|
|
name: "Single result",
|
|
args: args{pagination: codersdk.Pagination{Limit: 1}},
|
|
want: templateVersions[:1],
|
|
},
|
|
{
|
|
name: "Single result, second page",
|
|
args: args{pagination: codersdk.Pagination{Limit: 1, Offset: 1}},
|
|
want: templateVersions[1:2],
|
|
},
|
|
{
|
|
name: "Last two results",
|
|
args: args{pagination: codersdk.Pagination{Limit: 2, Offset: 8}},
|
|
want: templateVersions[8:10],
|
|
},
|
|
{
|
|
name: "AfterID returns next two results",
|
|
args: args{pagination: codersdk.Pagination{Limit: 2, AfterID: templateVersions[1].ID}},
|
|
want: templateVersions[2:4],
|
|
},
|
|
{
|
|
name: "No result after last AfterID",
|
|
args: args{pagination: codersdk.Pagination{Limit: 2, AfterID: templateVersions[9].ID}},
|
|
want: []codersdk.TemplateVersion{},
|
|
},
|
|
{
|
|
name: "No result after last Offset",
|
|
args: args{pagination: codersdk.Pagination{Limit: 2, Offset: 10}},
|
|
want: []codersdk.TemplateVersion{},
|
|
},
|
|
{
|
|
name: "After_id does not exist",
|
|
args: args{pagination: codersdk.Pagination{AfterID: uuid.New()}},
|
|
expectedError: "does not exist",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
|
|
defer cancel()
|
|
|
|
got, err := client.TemplateVersionsByTemplate(ctx, codersdk.TemplateVersionsByTemplateRequest{
|
|
TemplateID: template.ID,
|
|
Pagination: tt.args.pagination,
|
|
})
|
|
if tt.expectedError != "" {
|
|
require.Error(t, err)
|
|
require.ErrorContains(t, err, tt.expectedError)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tt.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTemplateVersionByOrganizationTemplateAndName(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("NotFound", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
_, err := client.TemplateVersionByOrganizationAndName(ctx, user.OrganizationID, template.Name, "nothing")
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
|
|
})
|
|
|
|
t.Run("Found", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
_, err := client.TemplateVersionByOrganizationAndName(ctx, user.OrganizationID, template.Name, version.Name)
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestPreviousTemplateVersion(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("Previous version not found", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
|
|
// Create two templates to be sure it is not returning a previous version
|
|
// from another template
|
|
templateAVersion1 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
coderdtest.CreateTemplate(t, client, user.OrganizationID, templateAVersion1.ID)
|
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, templateAVersion1.ID)
|
|
// Create two versions for the template B to be sure if we try to get the
|
|
// previous version of the first version it will returns a 404
|
|
templateBVersion1 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
templateB := coderdtest.CreateTemplate(t, client, user.OrganizationID, templateBVersion1.ID)
|
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, templateBVersion1.ID)
|
|
templateBVersion2 := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, nil, templateB.ID)
|
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, templateBVersion2.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
_, err := client.PreviousTemplateVersion(ctx, user.OrganizationID, templateB.Name, templateBVersion1.Name)
|
|
var apiErr *codersdk.Error
|
|
require.ErrorAs(t, err, &apiErr)
|
|
require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
|
|
})
|
|
|
|
t.Run("Previous version found", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
|
|
// Create two templates to be sure it is not returning a previous version
|
|
// from another template
|
|
templateAVersion1 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
coderdtest.CreateTemplate(t, client, user.OrganizationID, templateAVersion1.ID)
|
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, templateAVersion1.ID)
|
|
// Create two versions for the template B so we can try to get the previous
|
|
// version of version 2
|
|
templateBVersion1 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
templateB := coderdtest.CreateTemplate(t, client, user.OrganizationID, templateBVersion1.ID)
|
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, templateBVersion1.ID)
|
|
templateBVersion2 := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, nil, templateB.ID)
|
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, templateBVersion2.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
result, err := client.PreviousTemplateVersion(ctx, user.OrganizationID, templateB.Name, templateBVersion2.Name)
|
|
require.NoError(t, err)
|
|
require.Equal(t, templateBVersion1.ID, result.ID)
|
|
})
|
|
}
|
|
|
|
func TestTemplateExamples(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("OK", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
ex, err := client.TemplateExamples(ctx, user.OrganizationID)
|
|
require.NoError(t, err)
|
|
ls, err := examples.List()
|
|
require.NoError(t, err)
|
|
require.EqualValues(t, ls, ex)
|
|
})
|
|
}
|
|
|
|
func TestTemplateVersionVariables(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
createEchoResponses := func(templateVariables []*proto.TemplateVariable) *echo.Responses {
|
|
return &echo.Responses{
|
|
Parse: []*proto.Response{
|
|
{
|
|
Type: &proto.Response_Parse{
|
|
Parse: &proto.ParseComplete{
|
|
TemplateVariables: templateVariables,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ProvisionPlan: echo.PlanComplete,
|
|
ProvisionApply: echo.ApplyComplete,
|
|
}
|
|
}
|
|
|
|
t.Run("Pass value for required variable", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
templateVariables := []*proto.TemplateVariable{
|
|
{
|
|
Name: "first_variable",
|
|
Description: "This is the first variable",
|
|
Type: "string",
|
|
Required: true,
|
|
},
|
|
}
|
|
const firstVariableValue = "foobar"
|
|
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID,
|
|
createEchoResponses(templateVariables),
|
|
func(ctvr *codersdk.CreateTemplateVersionRequest) {
|
|
ctvr.UserVariableValues = []codersdk.VariableValue{
|
|
{
|
|
Name: templateVariables[0].Name,
|
|
Value: firstVariableValue,
|
|
},
|
|
}
|
|
},
|
|
)
|
|
templateVersion := coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
|
|
// As user passed the value for the first parameter, the job will succeed.
|
|
require.Empty(t, templateVersion.Job.Error)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
|
|
defer cancel()
|
|
|
|
actualVariables, err := client.TemplateVersionVariables(ctx, templateVersion.ID)
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, actualVariables, 1)
|
|
require.Equal(t, templateVariables[0].Name, actualVariables[0].Name)
|
|
require.Equal(t, templateVariables[0].Description, actualVariables[0].Description)
|
|
require.Equal(t, templateVariables[0].Type, actualVariables[0].Type)
|
|
require.Equal(t, templateVariables[0].DefaultValue, actualVariables[0].DefaultValue)
|
|
require.Equal(t, templateVariables[0].Required, actualVariables[0].Required)
|
|
require.Equal(t, templateVariables[0].Sensitive, actualVariables[0].Sensitive)
|
|
require.Equal(t, firstVariableValue, actualVariables[0].Value)
|
|
})
|
|
|
|
t.Run("Missing value for required variable", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
templateVariables := []*proto.TemplateVariable{
|
|
{
|
|
Name: "first_variable",
|
|
Description: "This is the first variable",
|
|
Type: "string",
|
|
Required: true,
|
|
},
|
|
{
|
|
Name: "second_variable",
|
|
Description: "This is the second variable",
|
|
DefaultValue: "123",
|
|
Type: "number",
|
|
},
|
|
}
|
|
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, createEchoResponses(templateVariables))
|
|
templateVersion := coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
|
|
// As the first variable is marked as required and misses the default value,
|
|
// the job will fail, but will populate the template_version_variables table with existing variables.
|
|
require.Contains(t, templateVersion.Job.Error, "required template variables need values")
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
|
|
defer cancel()
|
|
|
|
actualVariables, err := client.TemplateVersionVariables(ctx, templateVersion.ID)
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, actualVariables, 2)
|
|
for i := range templateVariables {
|
|
require.Equal(t, templateVariables[i].Name, actualVariables[i].Name)
|
|
require.Equal(t, templateVariables[i].Description, actualVariables[i].Description)
|
|
require.Equal(t, templateVariables[i].Type, actualVariables[i].Type)
|
|
require.Equal(t, templateVariables[i].DefaultValue, actualVariables[i].DefaultValue)
|
|
require.Equal(t, templateVariables[i].Required, actualVariables[i].Required)
|
|
require.Equal(t, templateVariables[i].Sensitive, actualVariables[i].Sensitive)
|
|
}
|
|
|
|
require.Equal(t, "", actualVariables[0].Value)
|
|
require.Equal(t, templateVariables[1].DefaultValue, actualVariables[1].Value)
|
|
})
|
|
|
|
t.Run("Redact sensitive variables", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
templateVariables := []*proto.TemplateVariable{
|
|
{
|
|
Name: "first_variable",
|
|
Description: "This is the first variable",
|
|
Type: "string",
|
|
Required: true,
|
|
Sensitive: true,
|
|
},
|
|
}
|
|
const firstVariableValue = "foobar"
|
|
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID,
|
|
createEchoResponses(templateVariables),
|
|
func(ctvr *codersdk.CreateTemplateVersionRequest) {
|
|
ctvr.UserVariableValues = []codersdk.VariableValue{
|
|
{
|
|
Name: templateVariables[0].Name,
|
|
Value: firstVariableValue,
|
|
},
|
|
}
|
|
},
|
|
)
|
|
templateVersion := coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
|
|
// As user passed the value for the first parameter, the job will succeed.
|
|
require.Empty(t, templateVersion.Job.Error)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
|
|
defer cancel()
|
|
|
|
actualVariables, err := client.TemplateVersionVariables(ctx, templateVersion.ID)
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, actualVariables, 1)
|
|
require.Equal(t, templateVariables[0].Name, actualVariables[0].Name)
|
|
require.Equal(t, templateVariables[0].Description, actualVariables[0].Description)
|
|
require.Equal(t, templateVariables[0].Type, actualVariables[0].Type)
|
|
require.Equal(t, templateVariables[0].Required, actualVariables[0].Required)
|
|
require.Equal(t, templateVariables[0].Sensitive, actualVariables[0].Sensitive)
|
|
require.Equal(t, "*redacted*", actualVariables[0].DefaultValue)
|
|
require.Equal(t, "*redacted*", actualVariables[0].Value)
|
|
})
|
|
}
|
|
|
|
func TestTemplateVersionPatch(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("Update the name", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
const newName = "new-name"
|
|
updatedVersion, err := client.UpdateTemplateVersion(ctx, version.ID, codersdk.PatchTemplateVersionRequest{
|
|
Name: newName,
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, newName, updatedVersion.Name)
|
|
assert.NotEqual(t, updatedVersion.Name, version.Name)
|
|
})
|
|
|
|
t.Run("Update the message", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil, func(req *codersdk.CreateTemplateVersionRequest) {
|
|
req.Message = "Example message"
|
|
})
|
|
coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
wantMessage := "Updated message"
|
|
updatedVersion, err := client.UpdateTemplateVersion(ctx, version.ID, codersdk.PatchTemplateVersionRequest{
|
|
Message: &wantMessage,
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, wantMessage, updatedVersion.Message)
|
|
})
|
|
|
|
t.Run("Remove the message", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil, func(req *codersdk.CreateTemplateVersionRequest) {
|
|
req.Message = "Example message"
|
|
})
|
|
coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
wantMessage := ""
|
|
updatedVersion, err := client.UpdateTemplateVersion(ctx, version.ID, codersdk.PatchTemplateVersionRequest{
|
|
Message: &wantMessage,
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, wantMessage, updatedVersion.Message)
|
|
})
|
|
|
|
t.Run("Keep the message", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
wantMessage := "Example message"
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil, func(req *codersdk.CreateTemplateVersionRequest) {
|
|
req.Message = wantMessage
|
|
})
|
|
coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
|
|
t.Log(version.Message)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
updatedVersion, err := client.UpdateTemplateVersion(ctx, version.ID, codersdk.PatchTemplateVersionRequest{
|
|
Message: nil,
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, wantMessage, updatedVersion.Message)
|
|
})
|
|
|
|
t.Run("Use the same name if a new name is not passed", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
updatedVersion, err := client.UpdateTemplateVersion(ctx, version.ID, codersdk.PatchTemplateVersionRequest{})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, version.Name, updatedVersion.Name)
|
|
})
|
|
|
|
t.Run("Use the same name for two different templates", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
|
|
version1 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
coderdtest.CreateTemplate(t, client, user.OrganizationID, version1.ID)
|
|
version2 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
coderdtest.CreateTemplate(t, client, user.OrganizationID, version2.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
const commonTemplateVersionName = "common-template-version-name"
|
|
updatedVersion1, err := client.UpdateTemplateVersion(ctx, version1.ID, codersdk.PatchTemplateVersionRequest{
|
|
Name: commonTemplateVersionName,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
updatedVersion2, err := client.UpdateTemplateVersion(ctx, version2.ID, codersdk.PatchTemplateVersionRequest{
|
|
Name: commonTemplateVersionName,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
assert.NotEqual(t, updatedVersion1.ID, updatedVersion2.ID)
|
|
assert.Equal(t, updatedVersion1.Name, updatedVersion2.Name)
|
|
})
|
|
|
|
t.Run("Use the same name for two versions for the same templates", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version1 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version1.ID)
|
|
|
|
version2 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil, func(ctvr *codersdk.CreateTemplateVersionRequest) {
|
|
ctvr.TemplateID = template.ID
|
|
})
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
_, err := client.UpdateTemplateVersion(ctx, version2.ID, codersdk.PatchTemplateVersionRequest{
|
|
Name: version1.Name,
|
|
})
|
|
require.Error(t, err)
|
|
})
|
|
|
|
t.Run("Rename the unassigned template", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version1 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
const commonTemplateVersionName = "common-template-version-name"
|
|
updatedVersion1, err := client.UpdateTemplateVersion(ctx, version1.ID, codersdk.PatchTemplateVersionRequest{
|
|
Name: commonTemplateVersionName,
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, commonTemplateVersionName, updatedVersion1.Name)
|
|
})
|
|
|
|
t.Run("Use incorrect template version name", func(t *testing.T) {
|
|
t.Parallel()
|
|
client := coderdtest.New(t, nil)
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version1 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
const incorrectTemplateVersionName = "incorrect/name"
|
|
_, err := client.UpdateTemplateVersion(ctx, version1.ID, codersdk.PatchTemplateVersionRequest{
|
|
Name: incorrectTemplateVersionName,
|
|
})
|
|
require.Error(t, err)
|
|
})
|
|
}
|
|
|
|
func TestTemplateVersionParameters_Order(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const (
|
|
firstParameterName = "first_parameter"
|
|
firstParameterType = "string"
|
|
firstParameterValue = "aaa"
|
|
// no order
|
|
|
|
secondParameterName = "Second_parameter"
|
|
secondParameterType = "number"
|
|
secondParameterValue = "2"
|
|
secondParameterOrder = 3
|
|
|
|
thirdParameterName = "third_parameter"
|
|
thirdParameterType = "number"
|
|
thirdParameterValue = "3"
|
|
thirdParameterOrder = 3
|
|
|
|
fourthParameterName = "Fourth_parameter"
|
|
fourthParameterType = "number"
|
|
fourthParameterValue = "3"
|
|
fourthParameterOrder = 2
|
|
|
|
fifthParameterName = "Fifth_parameter"
|
|
fifthParameterType = "string"
|
|
fifthParameterValue = "aaa"
|
|
// no order
|
|
)
|
|
|
|
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
user := coderdtest.CreateFirstUser(t, client)
|
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionPlan: []*proto.Response{
|
|
{
|
|
Type: &proto.Response_Plan{
|
|
Plan: &proto.PlanComplete{
|
|
Parameters: []*proto.RichParameter{
|
|
{
|
|
Name: firstParameterName,
|
|
Type: firstParameterType,
|
|
// No order
|
|
},
|
|
{
|
|
Name: secondParameterName,
|
|
Type: secondParameterType,
|
|
Order: secondParameterOrder,
|
|
},
|
|
{
|
|
Name: thirdParameterName,
|
|
Type: thirdParameterType,
|
|
Order: thirdParameterOrder,
|
|
},
|
|
{
|
|
Name: fourthParameterName,
|
|
Type: fourthParameterType,
|
|
Order: fourthParameterOrder,
|
|
},
|
|
{
|
|
Name: fifthParameterName,
|
|
Type: fifthParameterType,
|
|
// No order
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ProvisionApply: echo.ApplyComplete,
|
|
})
|
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
|
defer cancel()
|
|
|
|
templateRichParameters, err := client.TemplateVersionRichParameters(ctx, version.ID)
|
|
require.NoError(t, err)
|
|
require.Len(t, templateRichParameters, 5)
|
|
require.Equal(t, fifthParameterName, templateRichParameters[0].Name)
|
|
require.Equal(t, firstParameterName, templateRichParameters[1].Name)
|
|
require.Equal(t, fourthParameterName, templateRichParameters[2].Name)
|
|
require.Equal(t, secondParameterName, templateRichParameters[3].Name)
|
|
require.Equal(t, thirdParameterName, templateRichParameters[4].Name)
|
|
}
|
|
|
|
func TestTemplateArchiveVersions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ownerClient := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
|
owner := coderdtest.CreateFirstUser(t, ownerClient)
|
|
client, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.RoleTemplateAdmin())
|
|
|
|
var totalVersions int
|
|
// Create a template to archive
|
|
initialVersion := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
|
|
totalVersions++
|
|
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, initialVersion.ID)
|
|
|
|
allFailed := make([]uuid.UUID, 0)
|
|
expArchived := make([]uuid.UUID, 0)
|
|
// create some failed versions
|
|
for i := 0; i < 2; i++ {
|
|
failed := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, &echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionPlan: echo.PlanFailed,
|
|
ProvisionApply: echo.ApplyFailed,
|
|
}, func(req *codersdk.CreateTemplateVersionRequest) {
|
|
req.TemplateID = template.ID
|
|
})
|
|
allFailed = append(allFailed, failed.ID)
|
|
totalVersions++
|
|
}
|
|
|
|
// Create some unused versions
|
|
for i := 0; i < 2; i++ {
|
|
unused := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, &echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionPlan: echo.PlanComplete,
|
|
ProvisionApply: echo.ApplyComplete,
|
|
}, func(req *codersdk.CreateTemplateVersionRequest) {
|
|
req.TemplateID = template.ID
|
|
})
|
|
expArchived = append(expArchived, unused.ID)
|
|
totalVersions++
|
|
}
|
|
|
|
// Create some used template versions
|
|
for i := 0; i < 2; i++ {
|
|
used := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, &echo.Responses{
|
|
Parse: echo.ParseComplete,
|
|
ProvisionPlan: echo.PlanComplete,
|
|
ProvisionApply: echo.ApplyComplete,
|
|
}, func(req *codersdk.CreateTemplateVersionRequest) {
|
|
req.TemplateID = template.ID
|
|
})
|
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, used.ID)
|
|
workspace := coderdtest.CreateWorkspace(t, client, owner.OrganizationID, uuid.Nil, func(request *codersdk.CreateWorkspaceRequest) {
|
|
request.TemplateVersionID = used.ID
|
|
})
|
|
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
|
|
totalVersions++
|
|
}
|
|
|
|
ctx := testutil.Context(t, testutil.WaitMedium)
|
|
versions, err := client.TemplateVersionsByTemplate(ctx, codersdk.TemplateVersionsByTemplateRequest{
|
|
TemplateID: template.ID,
|
|
Pagination: codersdk.Pagination{
|
|
Limit: 100,
|
|
},
|
|
})
|
|
require.NoError(t, err, "fetch all versions")
|
|
require.Len(t, versions, totalVersions, "total versions")
|
|
|
|
// Archive failed versions
|
|
archiveFailed, err := client.ArchiveTemplateVersions(ctx, template.ID, false)
|
|
require.NoError(t, err, "archive failed versions")
|
|
require.ElementsMatch(t, archiveFailed.ArchivedIDs, allFailed, "all failed versions archived")
|
|
|
|
remaining, err := client.TemplateVersionsByTemplate(ctx, codersdk.TemplateVersionsByTemplateRequest{
|
|
TemplateID: template.ID,
|
|
Pagination: codersdk.Pagination{
|
|
Limit: 100,
|
|
},
|
|
})
|
|
require.NoError(t, err, "fetch all non-failed versions")
|
|
require.Len(t, remaining, totalVersions-len(allFailed), "remaining non-failed versions")
|
|
|
|
// Try archiving "All" unused templates
|
|
archived, err := client.ArchiveTemplateVersions(ctx, template.ID, true)
|
|
require.NoError(t, err, "archive versions")
|
|
require.ElementsMatch(t, archived.ArchivedIDs, expArchived, "all expected versions archived")
|
|
|
|
remaining, err = client.TemplateVersionsByTemplate(ctx, codersdk.TemplateVersionsByTemplateRequest{
|
|
TemplateID: template.ID,
|
|
Pagination: codersdk.Pagination{
|
|
Limit: 100,
|
|
},
|
|
})
|
|
require.NoError(t, err, "fetch all versions")
|
|
require.Len(t, remaining, totalVersions-len(expArchived)-len(allFailed), "remaining versions")
|
|
|
|
// Unarchive a version
|
|
err = client.SetArchiveTemplateVersion(ctx, expArchived[0], false)
|
|
require.NoError(t, err, "unarchive a version")
|
|
|
|
tv, err := client.TemplateVersion(ctx, expArchived[0])
|
|
require.NoError(t, err, "fetch version")
|
|
require.False(t, tv.Archived, "expect unarchived")
|
|
|
|
// Check the remaining again
|
|
remaining, err = client.TemplateVersionsByTemplate(ctx, codersdk.TemplateVersionsByTemplateRequest{
|
|
TemplateID: template.ID,
|
|
Pagination: codersdk.Pagination{
|
|
Limit: 100,
|
|
},
|
|
})
|
|
require.NoError(t, err, "fetch all versions")
|
|
require.Len(t, remaining, totalVersions-len(expArchived)-len(allFailed)+1, "remaining versions")
|
|
}
|