tests/device_accept_mac_connected_test.go
Rama master · réplica de lectura del repositorio original.
package main
import (
"net/http"
"testing"
"time"
"github.com/shellhub-io/shellhub/pkg/api/requests"
"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"
)
// TestDeviceAcceptMACTwinConnected covers accepting a device whose MAC address an accepted device
// holds while its agent is still connected. The accept would merge the connected device away, so it
// is refused and both devices stay as they were. A newcomer an automatic key would accept stays
// pending instead, and is accepted on a later authentication, past the interval that throttles
// re-evaluation, once the twin's agent is gone. The cases share one stack, so each twin agent
// carries a hostname no other case uses.
func TestDeviceAcceptMACTwinConnected(t *testing.T) {
t.Parallel()
compose := newSSHEnvironment(t, t.Context(), newNamespace)
t.Run("an accept is refused on identity.mac and leaves both devices intact", func(t *testing.T) {
_, twin := startNamedAcceptedAgent(t, compose, "connected-twin")
newcomer := enrollDevice(t, compose, "connected-newcomer", twin.Identity.MAC)
refusal := requireAcceptConflict(t, compose, newcomer)
assert.Contains(t, refusal.Fields, "identity.mac")
kept := requireDevice(t, compose, twin.UID)
assert.Equal(t, models.DeviceStatusAccepted, kept.Status)
assert.True(t, kept.Online, "the connected twin was merged away")
assert.Equal(t, twin.Name, kept.Name)
})
t.Run("an automatic-key newcomer stays pending until the twin goes offline", func(t *testing.T) {
key := compose.CreateProvisioningKey(t, &requests.CreateProvisioningKey{
Name: "twin-automatic",
Mode: string(models.ProvisioningKeyModeAutomatic),
}).Key
agent, twin := startNamedAcceptedAgent(t, compose, "automatic-twin")
req := newKeyedDeviceAuthRequest(t, key, "automatic-newcomer", twin.Identity.MAC)
newcomer := enroll(t, compose, req)
require.Equal(t, models.DeviceStatusPending, newcomer.Status, "the automatic key merged the connected twin away")
compose.AgeLastEnrollmentAttempt(t, newcomer.UID, models.EnrollmentReconcileInterval+time.Second)
requireStatusOnReauth(t, compose, req, newcomer.UID, models.DeviceStatusPending)
assert.True(t, requireDevice(t, compose, twin.UID).Online, "the connected twin was merged away")
require.NoError(t, agent.Stop(t.Context(), nil))
compose.AwaitDeviceOffline(t, twin.UID)
compose.AgeLastEnrollmentAttempt(t, newcomer.UID, models.EnrollmentReconcileInterval+time.Second)
requireStatusOnReauth(t, compose, req, newcomer.UID, models.DeviceStatusAccepted)
_, resp, err := compose.GetDevice(t.Context(), twin.UID)
require.NoError(t, err)
assert.Equal(t, http.StatusNotFound, resp.StatusCode(), "the accept left the offline twin behind: %s", resp.String())
})
}
func startNamedAcceptedAgent(t *testing.T, compose *environment.DockerCompose, hostname string) (testcontainers.Container, models.Device) {
t.Helper()
agent := startAgent(t, t.Context(), compose, NewAgentContainerWithHostname(hostname))
pending := compose.AwaitDeviceNamed(t, hostname)
compose.UpdateDeviceStatus(t, pending.UID, environment.DeviceActionAccept)
return agent, compose.AwaitDeviceOnline(t, pending.UID)
}