Ctrl K
ComunidadGuías…

tests/cloud_account_confirmation_test.go

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package main

import (
	"context"
	"net/http"
	"testing"

	"github.com/go-resty/resty/v2"
	"github.com/shellhub-io/shellhub/pkg/models"
	"github.com/shellhub-io/shellhub/tests/environment"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// TestCloudAccountConfirmation runs a cloud instance, the only edition with open sign-up, for the
// code a new account confirms its email with.
func TestCloudAccountConfirmation(t *testing.T) {
	t.Parallel()

	ctx := context.Background()

	compose := environment.New(t, run).WithEdition(environment.EditionCloud).Up(ctx)
	t.Cleanup(compose.Down)

	t.Run("the emailed code confirms the account and signs it in", func(t *testing.T) {
		email := signUp(t, compose, "confirm-code")
		code := confirmationCode(t, compose.AwaitEmail(t, email, "/confirm-account"))

		auth := requireConfirmed(t, compose, "confirm-code", code)

		resp, err := asBearer(t, compose, auth.Token).Get("/api/auth/user")
		require.NoError(t, err)
		assert.Equal(t, http.StatusOK, resp.StatusCode(), resp.String())
	})

	t.Run("the email confirms an account signed in with its email", func(t *testing.T) {
		email := signUp(t, compose, "confirm-by-email")
		code := confirmationCode(t, compose.AwaitEmail(t, email, "/confirm-account"))

		requireConfirmed(t, compose, email, code)
	})

	t.Run("wrong codes lock a pending and an unknown identifier out alike, on the third", func(t *testing.T) {
		email := signUp(t, compose, "confirm-wrong")
		code := confirmationCode(t, compose.AwaitEmail(t, email, "/confirm-account"))

		wrong := "000000"
		if code == wrong {
			wrong = "111111"
		}

		for _, identifier := range []string{"confirm-wrong", "confirm-unknown"} {
			for _, status := range []int{http.StatusUnauthorized, http.StatusUnauthorized, http.StatusTooManyRequests} {
				resp := confirmAccount(t, compose, identifier, wrong, nil)
				require.Equal(t, status, resp.StatusCode(), "%s: %s", identifier, resp.String())
			}
		}
	})

	t.Run("a resend delivers the same code, once a minute", func(t *testing.T) {
		email := signUp(t, compose, "confirm-resend")
		first := confirmationCode(t, compose.AwaitEmail(t, email, "/confirm-account"))

		resp := resend(t, compose, "confirm-resend")
		require.Equal(t, http.StatusOK, resp.StatusCode(), resp.String())

		emails := compose.AwaitEmails(t, email, "/confirm-account", 2)
		assert.Equal(t, first, confirmationCode(t, emails[0]))

		resp = resend(t, compose, "confirm-resend")
		assert.Equal(t, http.StatusTooManyRequests, resp.StatusCode(), resp.String())
	})

	t.Run("a resend answers alike for an unknown and a confirmed account, and sends nothing", func(t *testing.T) {
		done := "confirm-done" + stripeTestEmailDomain
		compose.NewUser(t, "confirm-done", done, ShellHubPassword)

		for _, identifier := range []string{"confirm-nobody", "confirm-done"} {
			resp := resend(t, compose, identifier)
			assert.Equal(t, http.StatusOK, resp.StatusCode(), "%s: %s", identifier, resp.String())
		}

		pending := signUp(t, compose, "confirm-flushed")
		compose.AwaitEmail(t, pending, "/confirm-account")
		assert.Empty(t, compose.Emails(t, done, "/confirm-account"))
	})

	t.Run("a code never confirms a confirmed account", func(t *testing.T) {
		compose.NewUser(t, "confirm-already", "confirm-already"+stripeTestEmailDomain, ShellHubPassword)

		resp := confirmAccount(t, compose, "confirm-already", "123456", nil)
		assert.Equal(t, http.StatusUnauthorized, resp.StatusCode(), resp.String())
	})

	t.Run("signing in to a pending account checks the password first", func(t *testing.T) {
		signUp(t, compose, "confirm-login")

		for password, status := range map[string]int{"wrong-password": http.StatusUnauthorized, ShellHubPassword: http.StatusForbidden} {
			resp, err := compose.Anonymous(t.Context()).
				SetBody(map[string]string{"username": "confirm-login", "password": password}).
				Post("/api/login")
			require.NoError(t, err)
			assert.Equal(t, status, resp.StatusCode(), "%s: %s", password, resp.String())
		}
	})
}

func signUp(t *testing.T, compose *environment.DockerCompose, username string) string {
	t.Helper()

	email := username + stripeTestEmailDomain

	resp := signUpWithEmail(t, compose, username, email)
	require.Equal(t, http.StatusNoContent, resp.StatusCode(), resp.String())

	return email
}

func confirmationCode(t *testing.T, email environment.Email) string {
	t.Helper()

	code, ok := email.Labelled("Confirmation code")
	require.True(t, ok, "the email carries no confirmation code: %s", email.Text())
	require.Len(t, code, 6)

	return code
}

func confirmAccount(t *testing.T, compose *environment.DockerCompose, identifier, code string, result any) *resty.Response {
	t.Helper()

	req := compose.Anonymous(t.Context()).
		SetBody(map[string]string{"identifier": identifier, "code": code})
	if result != nil {
		req.SetResult(result)
	}

	resp, err := req.Post("/api/user/confirm_account")
	require.NoError(t, err)

	return resp
}

func requireConfirmed(t *testing.T, compose *environment.DockerCompose, identifier, code string) *models.UserAuthResponse {
	t.Helper()

	auth := new(models.UserAuthResponse)
	resp := confirmAccount(t, compose, identifier, code, auth)
	require.Equal(t, http.StatusOK, resp.StatusCode(), resp.String())
	require.NotEmpty(t, auth.Token)

	return auth
}

func resend(t *testing.T, compose *environment.DockerCompose, identifier string) *resty.Response {
	t.Helper()

	resp, err := compose.Anonymous(t.Context()).
		SetBody(map[string]string{"identifier": identifier}).
		Post("/api/user/resend_email")
	require.NoError(t, err)

	return resp
}