Files
coder/cli/resetpassword_test.go
Hugo Dutka 1bfa7d42e8 chore: add postgres template caching for tests (#15336)
This PR is the first in a series aimed at closing
[#15109](https://github.com/coder/coder/issues/15109).

### Changes

- **Template Database Creation:**  
`dbtestutil.Open` now has the ability to create a template database if
none is provided via `DB_FROM`. The template database’s name is derived
from a hash of the migration files, ensuring that it can be reused
across tests and is automatically updated whenever migrations change.

- **Optimized Database Handling:**  
Previously, `dbtestutil.Open` would spin up a new container for each
test when `DB_FROM` was unset. Now, it first checks for an active
PostgreSQL instance on `localhost:5432`. If none is found, it creates a
single container that remains available for subsequent tests,
eliminating repeated container startups.

These changes address the long individual test times (10+ seconds)
reported by some users, likely due to the time Docker took to start and
complete migrations.
2024-11-04 17:23:31 +01:00

111 lines
2.6 KiB
Go

package cli_test
import (
"context"
"net/url"
"runtime"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/cli/clitest"
"github.com/coder/coder/v2/coderd/database/dbtestutil"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/pty/ptytest"
"github.com/coder/coder/v2/testutil"
)
// nolint:paralleltest
func TestResetPassword(t *testing.T) {
// dbtestutil.Open() seems to be creating race conditions when run in parallel.
// t.Parallel()
if runtime.GOOS != "linux" || testing.Short() {
// Skip on non-Linux because it spawns a PostgreSQL instance.
t.SkipNow()
}
const email = "some@one.com"
const username = "example"
const oldPassword = "MyOldPassword!"
const newPassword = "MyNewPassword!"
// start postgres and coder server processes
connectionURL, err := dbtestutil.Open(t)
require.NoError(t, err)
ctx, cancelFunc := context.WithCancel(context.Background())
serverDone := make(chan struct{})
serverinv, cfg := clitest.New(t,
"server",
"--http-address", ":0",
"--access-url", "http://example.com",
"--postgres-url", connectionURL,
"--cache-dir", t.TempDir(),
)
go func() {
defer close(serverDone)
err = serverinv.WithContext(ctx).Run()
assert.NoError(t, err)
}()
var rawURL string
require.Eventually(t, func() bool {
rawURL, err = cfg.URL().Read()
return err == nil && rawURL != ""
}, testutil.WaitLong, testutil.IntervalFast)
accessURL, err := url.Parse(rawURL)
require.NoError(t, err)
client := codersdk.New(accessURL)
_, err = client.CreateFirstUser(ctx, codersdk.CreateFirstUserRequest{
Email: email,
Username: username,
Password: oldPassword,
})
require.NoError(t, err)
// reset the password
resetinv, cmdCfg := clitest.New(t, "reset-password", "--postgres-url", connectionURL, username)
clitest.SetupConfig(t, client, cmdCfg)
cmdDone := make(chan struct{})
pty := ptytest.New(t)
resetinv.Stdin = pty.Input()
resetinv.Stdout = pty.Output()
go func() {
defer close(cmdDone)
err = resetinv.Run()
assert.NoError(t, err)
}()
matches := []struct {
output string
input string
}{
{"Enter new", newPassword},
{"Confirm", newPassword},
}
for _, match := range matches {
pty.ExpectMatch(match.output)
pty.WriteLine(match.input)
}
<-cmdDone
// now try logging in
_, err = client.LoginWithPassword(ctx, codersdk.LoginWithPasswordRequest{
Email: email,
Password: oldPassword,
})
require.Error(t, err)
_, err = client.LoginWithPassword(ctx, codersdk.LoginWithPasswordRequest{
Email: email,
Password: newPassword,
})
require.NoError(t, err)
cancelFunc()
<-serverDone
}