tests/member_test.go
Rama master · réplica de lectura del repositorio original.
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
}