mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: unexpose coderdtest.NewWithAPI (#2613)
* feat: unexpose coderdtest.NewWithAPI
This commit is contained in:
+5
-1
@@ -287,7 +287,11 @@ func New(options *Options) *API {
|
||||
|
||||
r.Post("/authorization", api.checkPermissions)
|
||||
|
||||
r.Post("/keys", api.postAPIKey)
|
||||
r.Route("/keys", func(r chi.Router) {
|
||||
r.Post("/", api.postAPIKey)
|
||||
r.Get("/{keyid}", api.apiKey)
|
||||
})
|
||||
|
||||
r.Route("/organizations", func(r chi.Router) {
|
||||
r.Get("/", api.organizationsByUser)
|
||||
r.Get("/{organizationname}", api.organizationByUserAndName)
|
||||
|
||||
+108
-6
@@ -2,8 +2,14 @@ package coderd_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"database/sql"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -14,10 +20,23 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/goleak"
|
||||
"golang.org/x/xerrors"
|
||||
"google.golang.org/api/idtoken"
|
||||
"google.golang.org/api/option"
|
||||
|
||||
"cdr.dev/slog"
|
||||
"cdr.dev/slog/sloggers/slogtest"
|
||||
|
||||
"github.com/coder/coder/buildinfo"
|
||||
"github.com/coder/coder/coderd"
|
||||
"github.com/coder/coder/coderd/autobuild/executor"
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/coderd/database"
|
||||
"github.com/coder/coder/coderd/database/databasefake"
|
||||
"github.com/coder/coder/coderd/database/postgres"
|
||||
"github.com/coder/coder/coderd/gitsshkey"
|
||||
"github.com/coder/coder/coderd/rbac"
|
||||
"github.com/coder/coder/coderd/telemetry"
|
||||
"github.com/coder/coder/coderd/turnconn"
|
||||
"github.com/coder/coder/codersdk"
|
||||
"github.com/coder/coder/provisioner/echo"
|
||||
"github.com/coder/coder/provisionersdk/proto"
|
||||
@@ -39,13 +58,96 @@ func TestBuildInfo(t *testing.T) {
|
||||
// TestAuthorizeAllEndpoints will check `authorize` is called on every endpoint registered.
|
||||
func TestAuthorizeAllEndpoints(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
var (
|
||||
ctx = context.Background()
|
||||
authorizer = &fakeAuthorizer{}
|
||||
)
|
||||
|
||||
authorizer := &fakeAuthorizer{}
|
||||
client, api := coderdtest.NewWithAPI(t, &coderdtest.Options{
|
||||
Authorizer: authorizer,
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
// This function was taken from coderdtest.newWithAPI. It is intentionally
|
||||
// copied to avoid exposing the API to other tests in coderd. Tests should
|
||||
// not need a reference to coderd.API...this test is an exception.
|
||||
newClient := func(authorizer rbac.Authorizer) (*codersdk.Client, *coderd.API) {
|
||||
// This can be hotswapped for a live database instance.
|
||||
db := databasefake.New()
|
||||
pubsub := database.NewPubsubInMemory()
|
||||
if os.Getenv("DB") != "" {
|
||||
connectionURL, closePg, err := postgres.Open()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(closePg)
|
||||
sqlDB, err := sql.Open("postgres", connectionURL)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_ = sqlDB.Close()
|
||||
})
|
||||
err = database.MigrateUp(sqlDB)
|
||||
require.NoError(t, err)
|
||||
db = database.New(sqlDB)
|
||||
|
||||
pubsub, err = database.NewPubsub(context.Background(), sqlDB, connectionURL)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_ = pubsub.Close()
|
||||
})
|
||||
}
|
||||
|
||||
tickerCh := make(chan time.Time)
|
||||
t.Cleanup(func() { close(tickerCh) })
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
lifecycleExecutor := executor.New(
|
||||
ctx,
|
||||
db,
|
||||
slogtest.Make(t, nil).Named("autobuild.executor").Leveled(slog.LevelDebug),
|
||||
tickerCh,
|
||||
).WithStatsChannel(nil)
|
||||
lifecycleExecutor.Run()
|
||||
|
||||
srv := httptest.NewUnstartedServer(nil)
|
||||
srv.Config.BaseContext = func(_ net.Listener) context.Context {
|
||||
return ctx
|
||||
}
|
||||
srv.Start()
|
||||
serverURL, err := url.Parse(srv.URL)
|
||||
require.NoError(t, err)
|
||||
|
||||
turnServer, err := turnconn.New(nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
validator, err := idtoken.NewValidator(ctx, option.WithoutAuthentication())
|
||||
require.NoError(t, err)
|
||||
|
||||
// We set the handler after server creation for the access URL.
|
||||
coderAPI := coderd.New(&coderd.Options{
|
||||
AgentConnectionUpdateFrequency: 150 * time.Millisecond,
|
||||
AccessURL: serverURL,
|
||||
Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
|
||||
Database: db,
|
||||
Pubsub: pubsub,
|
||||
|
||||
AWSCertificates: nil,
|
||||
AzureCertificates: x509.VerifyOptions{},
|
||||
GithubOAuth2Config: nil,
|
||||
GoogleTokenValidator: validator,
|
||||
SSHKeygenAlgorithm: gitsshkey.AlgorithmEd25519,
|
||||
TURNServer: turnServer,
|
||||
APIRateLimit: 0,
|
||||
Authorizer: authorizer,
|
||||
Telemetry: telemetry.NewNoop(),
|
||||
})
|
||||
srv.Config.Handler = coderAPI.Handler
|
||||
|
||||
_ = coderdtest.NewProvisionerDaemon(t, coderAPI)
|
||||
t.Cleanup(func() {
|
||||
cancelFunc()
|
||||
_ = turnServer.Close()
|
||||
srv.Close()
|
||||
_ = coderAPI.Close()
|
||||
})
|
||||
|
||||
return codersdk.New(serverURL), coderAPI
|
||||
}
|
||||
|
||||
client, api := newClient(authorizer)
|
||||
admin := coderdtest.CreateFirstUser(t, client)
|
||||
// The provisioner will call to coderd and register itself. This is async,
|
||||
// so we wait for it to occur.
|
||||
|
||||
@@ -74,12 +74,31 @@ type Options struct {
|
||||
|
||||
// New constructs a codersdk client connected to an in-memory API instance.
|
||||
func New(t *testing.T, options *Options) *codersdk.Client {
|
||||
client, _ := NewWithAPI(t, options)
|
||||
client, _ := newWithCloser(t, options)
|
||||
return client
|
||||
}
|
||||
|
||||
// NewWithAPI constructs a codersdk client connected to the returned in-memory API instance.
|
||||
func NewWithAPI(t *testing.T, options *Options) (*codersdk.Client, *coderd.API) {
|
||||
// NewWithProvisionerCloser returns a client as well as a handle to close
|
||||
// the provisioner. This is a temporary function while work is done to
|
||||
// standardize how provisioners are registered with coderd. The option
|
||||
// to include a provisioner is set to true for convenience.
|
||||
func NewWithProvisionerCloser(t *testing.T, options *Options) (*codersdk.Client, io.Closer) {
|
||||
if options == nil {
|
||||
options = &Options{}
|
||||
}
|
||||
options.IncludeProvisionerD = true
|
||||
client, closer := newWithCloser(t, options)
|
||||
return client, closer
|
||||
}
|
||||
|
||||
// newWithCloser constructs a codersdk client connected to an in-memory API instance.
|
||||
// The returned closer closes a provisioner if it was provided
|
||||
// The API is intentionally not returned here because coderd tests should not
|
||||
// require a handle to the API. Do not expose the API or wrath shall descend
|
||||
// upon thee. Even the io.Closer that is exposed here shouldn't be exposed
|
||||
// and is a temporary measure while the API to register provisioners is ironed
|
||||
// out.
|
||||
func newWithCloser(t *testing.T, options *Options) (*codersdk.Client, io.Closer) {
|
||||
if options == nil {
|
||||
options = &Options{}
|
||||
}
|
||||
@@ -169,17 +188,21 @@ func NewWithAPI(t *testing.T, options *Options) (*codersdk.Client, *coderd.API)
|
||||
Telemetry: telemetry.NewNoop(),
|
||||
})
|
||||
srv.Config.Handler = coderAPI.Handler
|
||||
|
||||
var provisionerCloser io.Closer = nopcloser{}
|
||||
if options.IncludeProvisionerD {
|
||||
_ = NewProvisionerDaemon(t, coderAPI)
|
||||
provisionerCloser = NewProvisionerDaemon(t, coderAPI)
|
||||
}
|
||||
|
||||
t.Cleanup(func() {
|
||||
cancelFunc()
|
||||
_ = turnServer.Close()
|
||||
srv.Close()
|
||||
_ = coderAPI.Close()
|
||||
_ = provisionerCloser.Close()
|
||||
})
|
||||
|
||||
return codersdk.New(serverURL), coderAPI
|
||||
return codersdk.New(serverURL), provisionerCloser
|
||||
}
|
||||
|
||||
// NewProvisionerDaemon launches a provisionerd instance configured to work
|
||||
@@ -648,3 +671,7 @@ type roundTripper func(req *http.Request) (*http.Response, error)
|
||||
func (r roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return r(req)
|
||||
}
|
||||
|
||||
type nopcloser struct{}
|
||||
|
||||
func (nopcloser) Close() error { return nil }
|
||||
|
||||
@@ -14,9 +14,10 @@ func TestMain(m *testing.M) {
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
t.Parallel()
|
||||
client, coderAPI := coderdtest.NewWithAPI(t, nil)
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
closer := coderdtest.NewProvisionerDaemon(t, coderAPI)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
@@ -25,5 +26,4 @@ func TestNew(t *testing.T) {
|
||||
coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID)
|
||||
_, _ = coderdtest.NewGoogleInstanceIdentity(t, "example", false)
|
||||
_, _ = coderdtest.NewAWSInstanceIdentity(t, "an-instance")
|
||||
closer.Close()
|
||||
}
|
||||
|
||||
@@ -79,9 +79,10 @@ func TestGitSSHKey(t *testing.T) {
|
||||
func TestAgentGitSSHKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client, coderAPI := coderdtest.NewWithAPI(t, nil)
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
daemonCloser := coderdtest.NewProvisionerDaemon(t, coderAPI)
|
||||
authToken := uuid.NewString()
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
@@ -107,7 +108,6 @@ func TestAgentGitSSHKey(t *testing.T) {
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID)
|
||||
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
|
||||
daemonCloser.Close()
|
||||
|
||||
agentClient := codersdk.New(client.URL)
|
||||
agentClient.SessionToken = authToken
|
||||
|
||||
@@ -2,7 +2,6 @@ package coderd_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -12,7 +11,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/coderd/database"
|
||||
"github.com/coder/coder/codersdk"
|
||||
"github.com/coder/coder/provisioner/echo"
|
||||
"github.com/coder/coder/provisionersdk/proto"
|
||||
@@ -555,18 +553,30 @@ func TestTemplateVersionDryRun(t *testing.T) {
|
||||
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client, api := coderdtest.NewWithAPI(t, &coderdtest.Options{IncludeProvisionerD: true})
|
||||
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,
|
||||
Provision: []*proto.Provision_Response{{
|
||||
Type: &proto.Provision_Response_Log{
|
||||
Log: &proto.Log{},
|
||||
Provision: []*proto.Provision_Response{
|
||||
{
|
||||
Type: &proto.Provision_Response_Log{
|
||||
Log: &proto.Log{},
|
||||
}},
|
||||
{
|
||||
Type: &proto.Provision_Response_Complete{
|
||||
Complete: &proto.Provision_Complete{},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
})
|
||||
forceCompleteTemplateVersionJob(t, api.Database, client, version)
|
||||
|
||||
version = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
require.Equal(t, codersdk.ProvisionerJobSucceeded, version.Job.Status)
|
||||
|
||||
closer.Close()
|
||||
// Create the dry-run
|
||||
job, err := client.CreateTemplateVersionDryRun(context.Background(), version.ID, codersdk.CreateTemplateVersionDryRunRequest{
|
||||
ParameterValues: []codersdk.CreateParameterRequest{},
|
||||
@@ -578,7 +588,7 @@ func TestTemplateVersionDryRun(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Logf("Status: %s", job.Status)
|
||||
return job.Status == codersdk.ProvisionerJobRunning
|
||||
return job.Status == codersdk.ProvisionerJobPending
|
||||
}, 5*time.Second, 25*time.Millisecond)
|
||||
|
||||
err = client.CancelTemplateVersionDryRun(context.Background(), version.ID, job.ID)
|
||||
@@ -589,7 +599,7 @@ func TestTemplateVersionDryRun(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Logf("Status: %s", job.Status)
|
||||
return job.Status == codersdk.ProvisionerJobCanceled
|
||||
return job.Status == codersdk.ProvisionerJobCanceling
|
||||
}, 5*time.Second, 25*time.Millisecond)
|
||||
})
|
||||
|
||||
@@ -622,17 +632,29 @@ func TestTemplateVersionDryRun(t *testing.T) {
|
||||
|
||||
t.Run("AlreadyCanceled", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client, api := coderdtest.NewWithAPI(t, &coderdtest.Options{IncludeProvisionerD: true})
|
||||
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,
|
||||
Provision: []*proto.Provision_Response{{
|
||||
Type: &proto.Provision_Response_Log{
|
||||
Log: &proto.Log{},
|
||||
Provision: []*proto.Provision_Response{
|
||||
{
|
||||
Type: &proto.Provision_Response_Log{
|
||||
Log: &proto.Log{},
|
||||
}},
|
||||
{
|
||||
Type: &proto.Provision_Response_Complete{
|
||||
Complete: &proto.Provision_Complete{},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
})
|
||||
forceCompleteTemplateVersionJob(t, api.Database, client, version)
|
||||
|
||||
version = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
require.Equal(t, codersdk.ProvisionerJobSucceeded, version.Job.Status)
|
||||
|
||||
closer.Close()
|
||||
|
||||
// Create the dry-run
|
||||
job, err := client.CreateTemplateVersionDryRun(context.Background(), version.ID, codersdk.CreateTemplateVersionDryRunRequest{
|
||||
@@ -753,23 +775,3 @@ func TestPaginatedTemplateVersions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func forceCompleteTemplateVersionJob(t *testing.T, db database.Store, client *codersdk.Client, version codersdk.TemplateVersion) {
|
||||
t.Helper()
|
||||
|
||||
// HACK: we need the template version job to be finished so the dry-run job
|
||||
// can be created. We do this by canceling the job and then marking it as
|
||||
// successful.
|
||||
err := client.CancelTemplateVersion(context.Background(), version.ID)
|
||||
require.NoError(t, err)
|
||||
err = db.UpdateProvisionerJobWithCompleteByID(context.Background(), database.UpdateProvisionerJobWithCompleteByIDParams{
|
||||
ID: version.Job.ID,
|
||||
UpdatedAt: time.Now(),
|
||||
CompletedAt: sql.NullTime{
|
||||
Time: time.Now(),
|
||||
Valid: true,
|
||||
},
|
||||
Error: sql.NullString{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -719,6 +719,34 @@ func (api *API) postAPIKey(rw http.ResponseWriter, r *http.Request) {
|
||||
httpapi.Write(rw, http.StatusCreated, codersdk.GenerateAPIKeyResponse{Key: sessionToken})
|
||||
}
|
||||
|
||||
func (api *API) apiKey(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
user = httpmw.UserParam(r)
|
||||
)
|
||||
|
||||
if !api.Authorize(r, rbac.ActionRead, rbac.ResourceAPIKey.WithOwner(user.ID.String())) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
|
||||
keyID := chi.URLParam(r, "keyid")
|
||||
key, err := api.Database.GetAPIKeyByID(ctx, keyID)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
|
||||
Message: "Internal error fetching API key.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(rw, http.StatusOK, convertAPIKey(key))
|
||||
}
|
||||
|
||||
// Clear the user's session cookie.
|
||||
func (api *API) postLogout(rw http.ResponseWriter, r *http.Request) {
|
||||
// Get a blank token cookie.
|
||||
@@ -1008,3 +1036,16 @@ func parseUserStatus(v string) ([]database.UserStatus, error) {
|
||||
}
|
||||
return statuses, nil
|
||||
}
|
||||
|
||||
func convertAPIKey(k database.APIKey) codersdk.APIKey {
|
||||
return codersdk.APIKey{
|
||||
ID: k.ID,
|
||||
UserID: k.UserID,
|
||||
LastUsed: k.LastUsed,
|
||||
ExpiresAt: k.ExpiresAt,
|
||||
CreatedAt: k.CreatedAt,
|
||||
UpdatedAt: k.UpdatedAt,
|
||||
LoginType: codersdk.LoginType(k.LoginType),
|
||||
LifetimeSeconds: k.LifetimeSeconds,
|
||||
}
|
||||
}
|
||||
|
||||
+13
-120
@@ -2,7 +2,6 @@ package coderd_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
@@ -14,8 +13,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/coderd/database"
|
||||
"github.com/coder/coder/coderd/database/databasefake"
|
||||
"github.com/coder/coder/coderd/httpmw"
|
||||
"github.com/coder/coder/coderd/rbac"
|
||||
"github.com/coder/coder/codersdk"
|
||||
@@ -138,94 +135,24 @@ func TestPostLogin(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
)
|
||||
client, api := coderdtest.NewWithAPI(t, nil)
|
||||
client := coderdtest.New(t, nil)
|
||||
admin := coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
split := strings.Split(client.SessionToken, "-")
|
||||
loginKey, err := api.Database.GetAPIKeyByID(ctx, split[0])
|
||||
key, err := client.GetAPIKey(ctx, admin.UserID.String(), split[0])
|
||||
require.NoError(t, err, "fetch login key")
|
||||
require.Equal(t, int64(86400), loginKey.LifetimeSeconds, "default should be 86400")
|
||||
require.Equal(t, int64(86400), key.LifetimeSeconds, "default should be 86400")
|
||||
|
||||
// Generated tokens have a longer life
|
||||
token, err := client.CreateAPIKey(ctx, admin.UserID.String())
|
||||
require.NoError(t, err, "make new api key")
|
||||
split = strings.Split(token.Key, "-")
|
||||
apiKey, err := api.Database.GetAPIKeyByID(ctx, split[0])
|
||||
apiKey, err := client.GetAPIKey(ctx, admin.UserID.String(), split[0])
|
||||
require.NoError(t, err, "fetch api key")
|
||||
|
||||
require.True(t, apiKey.ExpiresAt.After(time.Now().Add(time.Hour*24*6)), "api key lasts more than 6 days")
|
||||
require.True(t, apiKey.ExpiresAt.After(loginKey.ExpiresAt.Add(time.Hour)), "api key should be longer expires")
|
||||
require.Greater(t, apiKey.LifetimeSeconds, loginKey.LifetimeSeconds, "api key should have longer lifetime")
|
||||
})
|
||||
|
||||
t.Run("APIKeyExtend", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var (
|
||||
ctx = context.Background()
|
||||
)
|
||||
client, api := coderdtest.NewWithAPI(t, nil)
|
||||
admin := coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
token, err := client.CreateAPIKey(ctx, admin.UserID.String())
|
||||
require.NoError(t, err, "make new api key")
|
||||
client.SessionToken = token.Key
|
||||
split := strings.Split(token.Key, "-")
|
||||
|
||||
apiKey, err := api.Database.GetAPIKeyByID(ctx, split[0])
|
||||
require.NoError(t, err, "fetch api key")
|
||||
|
||||
err = api.Database.UpdateAPIKeyByID(ctx, database.UpdateAPIKeyByIDParams{
|
||||
ID: apiKey.ID,
|
||||
LastUsed: apiKey.LastUsed,
|
||||
IPAddress: apiKey.IPAddress,
|
||||
// This should cause a refresh
|
||||
ExpiresAt: apiKey.ExpiresAt.Add(time.Hour * -2),
|
||||
OAuthAccessToken: apiKey.OAuthAccessToken,
|
||||
OAuthRefreshToken: apiKey.OAuthRefreshToken,
|
||||
OAuthExpiry: apiKey.OAuthExpiry,
|
||||
})
|
||||
require.NoError(t, err, "update api key")
|
||||
|
||||
_, err = client.User(ctx, codersdk.Me)
|
||||
require.NoError(t, err, "fetch user")
|
||||
|
||||
apiKey, err = api.Database.GetAPIKeyByID(ctx, split[0])
|
||||
require.NoError(t, err, "fetch refreshed api key")
|
||||
// 1 minute tolerance
|
||||
require.True(t, apiKey.ExpiresAt.After(time.Now().Add(time.Hour*24*7).Add(time.Minute*-1)), "api key lasts 7 days")
|
||||
})
|
||||
|
||||
t.Run("LoginKeyExtend", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var (
|
||||
ctx = context.Background()
|
||||
)
|
||||
client, api := coderdtest.NewWithAPI(t, nil)
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
split := strings.Split(client.SessionToken, "-")
|
||||
|
||||
apiKey, err := api.Database.GetAPIKeyByID(ctx, split[0])
|
||||
require.NoError(t, err, "fetch login key")
|
||||
|
||||
err = api.Database.UpdateAPIKeyByID(ctx, database.UpdateAPIKeyByIDParams{
|
||||
ID: apiKey.ID,
|
||||
LastUsed: apiKey.LastUsed,
|
||||
IPAddress: apiKey.IPAddress,
|
||||
// This should cause a refresh
|
||||
ExpiresAt: apiKey.ExpiresAt.Add(time.Hour * -2),
|
||||
OAuthAccessToken: apiKey.OAuthAccessToken,
|
||||
OAuthRefreshToken: apiKey.OAuthRefreshToken,
|
||||
OAuthExpiry: apiKey.OAuthExpiry,
|
||||
})
|
||||
require.NoError(t, err, "update login key")
|
||||
|
||||
_, err = client.User(ctx, codersdk.Me)
|
||||
require.NoError(t, err, "fetch user")
|
||||
|
||||
apiKey, err = api.Database.GetAPIKeyByID(ctx, split[0])
|
||||
require.NoError(t, err, "fetch refreshed login key")
|
||||
// 1 minute tolerance
|
||||
require.True(t, apiKey.ExpiresAt.After(time.Now().Add(time.Hour*24).Add(time.Minute*-1)), "login key lasts 24 hrs")
|
||||
require.True(t, apiKey.ExpiresAt.After(key.ExpiresAt.Add(time.Hour)), "api key should be longer expires")
|
||||
require.Greater(t, apiKey.LifetimeSeconds, key.LifetimeSeconds, "api key should have longer lifetime")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -237,11 +164,11 @@ func TestPostLogout(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
client, api := coderdtest.NewWithAPI(t, nil)
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
client := coderdtest.New(t, nil)
|
||||
admin := coderdtest.CreateFirstUser(t, client)
|
||||
keyID := strings.Split(client.SessionToken, "-")[0]
|
||||
|
||||
apiKey, err := api.Database.GetAPIKeyByID(ctx, keyID)
|
||||
apiKey, err := client.GetAPIKey(ctx, admin.UserID.String(), keyID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, keyID, apiKey.ID, "API key should exist in the database")
|
||||
|
||||
@@ -259,44 +186,10 @@ func TestPostLogout(t *testing.T) {
|
||||
require.Equal(t, httpmw.SessionTokenKey, cookies[0].Name, "Cookie should be the auth cookie")
|
||||
require.Equal(t, -1, cookies[0].MaxAge, "Cookie should be set to delete")
|
||||
|
||||
apiKey, err = api.Database.GetAPIKeyByID(ctx, keyID)
|
||||
require.ErrorIs(t, err, sql.ErrNoRows, "API key should not exist in the database")
|
||||
})
|
||||
|
||||
t.Run("LogoutWithoutKey", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
client, api := coderdtest.NewWithAPI(t, nil)
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
keyID := strings.Split(client.SessionToken, "-")[0]
|
||||
|
||||
apiKey, err := api.Database.GetAPIKeyByID(ctx, keyID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, keyID, apiKey.ID, "API key should exist in the database")
|
||||
|
||||
// Setting a fake database without the API Key to be used by the API.
|
||||
// The middleware that extracts the API key is already set to read
|
||||
// from the original database.
|
||||
dbWithoutKey := databasefake.New()
|
||||
api.Database = dbWithoutKey
|
||||
|
||||
fullURL, err := client.URL.Parse("/api/v2/users/logout")
|
||||
require.NoError(t, err, "Server URL should parse successfully")
|
||||
|
||||
res, err := client.Request(ctx, http.MethodPost, fullURL.String(), nil)
|
||||
require.NoError(t, err, "/logout request should succeed")
|
||||
res.Body.Close()
|
||||
require.Equal(t, http.StatusInternalServerError, res.StatusCode)
|
||||
|
||||
cookies := res.Cookies()
|
||||
require.Len(t, cookies, 1, "Exactly one cookie should be returned")
|
||||
|
||||
require.Equal(t, httpmw.SessionTokenKey, cookies[0].Name, "Cookie should be the auth cookie")
|
||||
require.Equal(t, -1, cookies[0].MaxAge, "Cookie should be set to delete")
|
||||
|
||||
apiKey, err = api.Database.GetAPIKeyByID(ctx, keyID)
|
||||
require.ErrorIs(t, err, sql.ErrNoRows, "API key should not exist in the database")
|
||||
_, err = client.GetAPIKey(ctx, admin.UserID.String(), keyID)
|
||||
var sdkErr = &codersdk.Error{}
|
||||
require.ErrorAs(t, err, &sdkErr)
|
||||
require.Equal(t, http.StatusUnauthorized, sdkErr.StatusCode(), "Expecting 401")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -27,9 +27,10 @@ func TestWorkspaceAgent(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("Connect", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client, coderAPI := coderdtest.NewWithAPI(t, nil)
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
daemonCloser := coderdtest.NewProvisionerDaemon(t, coderAPI)
|
||||
authToken := uuid.NewString()
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
@@ -56,7 +57,6 @@ func TestWorkspaceAgent(t *testing.T) {
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
|
||||
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
|
||||
daemonCloser.Close()
|
||||
|
||||
resources, err := client.WorkspaceResourcesByBuild(context.Background(), workspace.LatestBuild.ID)
|
||||
require.NoError(t, err)
|
||||
@@ -72,9 +72,10 @@ func TestWorkspaceAgentListen(t *testing.T) {
|
||||
t.Run("Connect", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client, coderAPI := coderdtest.NewWithAPI(t, nil)
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
daemonCloser := coderdtest.NewProvisionerDaemon(t, coderAPI)
|
||||
authToken := uuid.NewString()
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
@@ -100,7 +101,6 @@ func TestWorkspaceAgentListen(t *testing.T) {
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
|
||||
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
|
||||
daemonCloser.Close()
|
||||
|
||||
agentClient := codersdk.New(client.URL)
|
||||
agentClient.SessionToken = authToken
|
||||
@@ -124,11 +124,11 @@ func TestWorkspaceAgentListen(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
client, coderAPI := coderdtest.NewWithAPI(t, nil)
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
daemonCloser := coderdtest.NewProvisionerDaemon(t, coderAPI)
|
||||
defer daemonCloser.Close()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
authToken := uuid.NewString()
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
@@ -196,9 +196,11 @@ func TestWorkspaceAgentListen(t *testing.T) {
|
||||
|
||||
func TestWorkspaceAgentTURN(t *testing.T) {
|
||||
t.Parallel()
|
||||
client, coderAPI := coderdtest.NewWithAPI(t, nil)
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
daemonCloser := coderdtest.NewProvisionerDaemon(t, coderAPI)
|
||||
authToken := uuid.NewString()
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
@@ -224,7 +226,6 @@ func TestWorkspaceAgentTURN(t *testing.T) {
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
|
||||
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
|
||||
daemonCloser.Close()
|
||||
|
||||
agentClient := codersdk.New(client.URL)
|
||||
agentClient.SessionToken = authToken
|
||||
@@ -257,9 +258,10 @@ func TestWorkspaceAgentPTY(t *testing.T) {
|
||||
// it seems like it could be either.
|
||||
t.Skip("ConPTY appears to be inconsistent on Windows.")
|
||||
}
|
||||
client, coderAPI := coderdtest.NewWithAPI(t, nil)
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
daemonCloser := coderdtest.NewProvisionerDaemon(t, coderAPI)
|
||||
authToken := uuid.NewString()
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
@@ -285,7 +287,6 @@ func TestWorkspaceAgentPTY(t *testing.T) {
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
|
||||
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
|
||||
daemonCloser.Close()
|
||||
|
||||
agentClient := codersdk.New(client.URL)
|
||||
agentClient.SessionToken = authToken
|
||||
|
||||
@@ -36,9 +36,10 @@ func TestWorkspaceAppsProxyPath(t *testing.T) {
|
||||
go server.Serve(ln)
|
||||
tcpAddr, _ := ln.Addr().(*net.TCPAddr)
|
||||
|
||||
client, coderAPI := coderdtest.NewWithAPI(t, nil)
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
coderdtest.NewProvisionerDaemon(t, coderAPI)
|
||||
authToken := uuid.NewString()
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
|
||||
@@ -237,12 +237,12 @@ func TestWorkspaceBuildResources(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("ListRunning", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client, coderAPI := coderdtest.NewWithAPI(t, nil)
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
closeDaemon := coderdtest.NewProvisionerDaemon(t, coderAPI)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
closeDaemon.Close()
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
|
||||
_, err := client.WorkspaceResourcesByBuild(context.Background(), workspace.LatestBuild.ID)
|
||||
|
||||
@@ -46,9 +46,10 @@ func TestWorkspaceResource(t *testing.T) {
|
||||
|
||||
t.Run("Apps", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client, coderd := coderdtest.NewWithAPI(t, nil)
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
coderdtest.NewProvisionerDaemon(t, coderd)
|
||||
app := &proto.App{
|
||||
Name: "code-server",
|
||||
Command: "some-command",
|
||||
|
||||
@@ -656,14 +656,15 @@ func TestPostWorkspaceBuild(t *testing.T) {
|
||||
|
||||
t.Run("AlreadyActive", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client, coderAPI := coderdtest.NewWithAPI(t, nil)
|
||||
client, closer := coderdtest.NewWithProvisionerCloser(t, nil)
|
||||
defer closer.Close()
|
||||
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
closeDaemon := coderdtest.NewProvisionerDaemon(t, coderAPI)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
closer.Close()
|
||||
// Close here so workspace build doesn't process!
|
||||
closeDaemon.Close()
|
||||
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
|
||||
_, err := client.CreateWorkspaceBuild(context.Background(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{
|
||||
TemplateVersionID: template.ActiveVersionID,
|
||||
@@ -694,15 +695,15 @@ func TestPostWorkspaceBuild(t *testing.T) {
|
||||
|
||||
t.Run("WithState", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client, coderAPI := coderdtest.NewWithAPI(t, nil)
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
closeDaemon := coderdtest.NewProvisionerDaemon(t, coderAPI)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
|
||||
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
|
||||
_ = closeDaemon.Close()
|
||||
wantState := []byte("something")
|
||||
build, err := client.CreateWorkspaceBuild(context.Background(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{
|
||||
TemplateVersionID: template.ActiveVersionID,
|
||||
|
||||
Reference in New Issue
Block a user