Ctrl K
ComunidadGuías…

tests/member_test.go

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

Archivo original ↗Preguntar a KiBot
package main

import (
	"net/http"
	"testing"
	"time"

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

const (
	departingUsername = "departing"
	departingEmail    = "departing@ossystems.com.br"
	departingPassword = "password"
)

// TestRemoveMemberThroughTheAdminCLI removes a member with the admin CLI, a process apart from the
// server that caches the member's token and holds the tunnels of the devices they paired.
func TestRemoveMemberThroughTheAdminCLI(t *testing.T) {
	t.Parallel()

	t.Run("refuses their token at once and keeps the API keys they created", func(t *testing.T) {
		compose := newSSHEnvironment(t, t.Context(), newNamespace)
		member := signInDepartingMember(t, compose)

		key := new(responses.CreateAPIKey)
		resp, err := asBearer(t, compose, member.Token).
			SetBody(&requests.CreateAPIKey{Name: "departing", ExpiresAt: -1}).
			SetResult(key).
			Post("/api/namespaces/api-key")
		require.NoError(t, err)
		require.Equal(t, http.StatusOK, resp.StatusCode(), resp.String())

		withToken := func() *resty.Request { return asBearer(t, compose, member.Token) }
		withKey := func() *resty.Request { return compose.Anonymous(t.Context()).SetHeader("X-API-Key", key.Key) }

		for _, request := range []func() *resty.Request{withToken, withKey} {
			resp, err := request().Get("/api/devices")
			require.NoError(t, err)
			require.Equal(t, http.StatusOK, resp.StatusCode(), resp.String())
		}

		compose.RemoveMember(t, departingUsername, ShellHubNamespaceName)

		resp, err = withToken().Get("/api/devices")
		require.NoError(t, err)
		assert.Equal(t, http.StatusUnauthorized, resp.StatusCode(), resp.String())

		resp, err = withKey().Get("/api/devices")
		require.NoError(t, err)
		assert.Equal(t, http.StatusOK, resp.StatusCode(), resp.String())
	})

	t.Run("closes their paired devices' tunnels within a heartbeat", func(t *testing.T) {
		compose := newFastTunnelPingEnvironment(t, t.Context(), newNamespace)
		member := signInDepartingMember(t, compose)

		agent := startAgent(t, t.Context(), compose, NewAgentContainerUnpaired())
		uid := pairAgent(t, compose, agent, member.Token)
		awaitAgentConnected(t, agent)
		compose.AwaitDeviceOnline(t, uid)

		compose.RemoveMember(t, departingUsername, ShellHubNamespaceName)

		require.EventuallyWithT(t, func(tt *assert.CollectT) {
			current, resp, err := compose.GetDevice(t.Context(), uid)
			if !assert.NoError(tt, err) {
				return
			}

			if !assert.Equal(tt, http.StatusOK, resp.StatusCode(), resp.String()) {
				return
			}

			assert.Equal(tt, models.DeviceStatusRemoved, current.Status)
			assert.False(tt, current.Online, "the removed device still holds its tunnel")
		}, tunnelBeatTimeout, time.Second)
	})
}

func signInDepartingMember(t *testing.T, compose *environment.DockerCompose) *models.UserAuthResponse {
	t.Helper()

	compose.NewUser(t, departingUsername, departingEmail, departingPassword)
	compose.NewMember(t, departingUsername, ShellHubNamespaceName, string(authorizer.RoleAdministrator))

	return signInto(t, compose, departingUsername, departingPassword)
}

func asBearer(t *testing.T, compose *environment.DockerCompose, token string) *resty.Request {
	t.Helper()

	return compose.Anonymous(t.Context()).SetAuthToken(token)
}

func pairAgent(t *testing.T, compose *environment.DockerCompose, agent testcontainers.Container, token string) string {
	t.Helper()

	return acceptPairing(t, asBearer(t, compose, token), awaitAgentPairingCode(t, agent)).UID
}