164 lines
5.2 KiB
Go
164 lines
5.2 KiB
Go
package controller
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/hashicorp/boundary/internal/db"
|
|
"github.com/hashicorp/boundary/internal/errors"
|
|
"github.com/hashicorp/boundary/internal/iam"
|
|
"github.com/hashicorp/boundary/internal/kms"
|
|
"github.com/hashicorp/boundary/internal/scheduler"
|
|
"github.com/hashicorp/boundary/internal/servers"
|
|
"github.com/hashicorp/boundary/internal/session"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// assert the interface
|
|
var _ = scheduler.Job(new(sessionCleanupJob))
|
|
|
|
// This test has been largely adapted from
|
|
// TestRepository_CloseDeadConnectionsOnWorker in
|
|
// internal/session/repository_connection_test.go.
|
|
func TestSessionCleanupJob(t *testing.T) {
|
|
t.Parallel()
|
|
require, assert := require.New(t), assert.New(t)
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
iamRepo := iam.TestRepo(t, conn, wrapper)
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
serversRepo, err := servers.NewRepository(rw, rw, kms)
|
|
require.NoError(err)
|
|
sessionRepo, err := session.NewRepository(rw, rw, kms)
|
|
require.NoError(err)
|
|
ctx := context.Background()
|
|
numConns := 12
|
|
|
|
// Create two "workers". One will remain untouched while the other "goes
|
|
// away and comes back" (worker 2).
|
|
worker1 := session.TestWorker(t, conn, wrapper, session.WithServerId("worker1"))
|
|
worker2 := session.TestWorker(t, conn, wrapper, session.WithServerId("worker2"))
|
|
|
|
// Create a few sessions on each, activate, and authorize a connection
|
|
var connIds []string
|
|
connIdsByWorker := make(map[string][]string)
|
|
for i := 0; i < numConns; i++ {
|
|
serverId := worker1.PrivateId
|
|
if i%2 == 0 {
|
|
serverId = worker2.PrivateId
|
|
}
|
|
sess := session.TestDefaultSession(t, conn, wrapper, iamRepo, session.WithServerId(serverId), session.WithDbOpts(db.WithSkipVetForWrite(true)))
|
|
sess, _, err = sessionRepo.ActivateSession(ctx, sess.GetPublicId(), sess.Version, serverId, "worker", []byte("foo"))
|
|
require.NoError(err)
|
|
c, cs, _, err := sessionRepo.AuthorizeConnection(ctx, sess.GetPublicId(), serverId)
|
|
require.NoError(err)
|
|
require.Len(cs, 1)
|
|
require.Equal(session.StatusAuthorized, cs[0].Status)
|
|
connIds = append(connIds, c.GetPublicId())
|
|
if i%2 == 0 {
|
|
connIdsByWorker[worker2.PrivateId] = append(connIdsByWorker[worker2.PrivateId], c.GetPublicId())
|
|
} else {
|
|
connIdsByWorker[worker1.PrivateId] = append(connIdsByWorker[worker1.PrivateId], c.GetPublicId())
|
|
}
|
|
}
|
|
|
|
// Mark half of the connections connected and leave the others authorized.
|
|
// This is just to ensure we have a spread when we test it out.
|
|
for i, connId := range connIds {
|
|
if i%2 == 0 {
|
|
_, cs, err := sessionRepo.ConnectConnection(ctx, session.ConnectWith{
|
|
ConnectionId: connId,
|
|
ClientTcpAddress: "127.0.0.1",
|
|
ClientTcpPort: 22,
|
|
EndpointTcpAddress: "127.0.0.1",
|
|
EndpointTcpPort: 22,
|
|
})
|
|
require.NoError(err)
|
|
require.Len(cs, 2)
|
|
var foundAuthorized, foundConnected bool
|
|
for _, status := range cs {
|
|
if status.Status == session.StatusAuthorized {
|
|
foundAuthorized = true
|
|
}
|
|
if status.Status == session.StatusConnected {
|
|
foundConnected = true
|
|
}
|
|
}
|
|
require.True(foundAuthorized)
|
|
require.True(foundConnected)
|
|
}
|
|
}
|
|
|
|
// Create the job.
|
|
job, err := newSessionCleanupJob(
|
|
func() (*session.Repository, error) { return sessionRepo, nil },
|
|
session.DeadWorkerConnCloseMinGrace,
|
|
)
|
|
require.NoError(err)
|
|
|
|
// sleep the status grace period.
|
|
time.Sleep(time.Second * time.Duration(session.DeadWorkerConnCloseMinGrace))
|
|
|
|
// Push an upsert to the first worker so that its status has been
|
|
// updated.
|
|
_, rowsUpdated, err := serversRepo.UpsertServer(ctx, worker1, []servers.Option{}...)
|
|
require.NoError(err)
|
|
require.Equal(1, rowsUpdated)
|
|
|
|
// Run the job.
|
|
require.NoError(job.Run(ctx))
|
|
|
|
// Assert connection state on both workers.
|
|
assertConnections := func(workerId string, closed bool) {
|
|
connIds, ok := connIdsByWorker[workerId]
|
|
require.True(ok)
|
|
require.Len(connIds, 6)
|
|
for _, connId := range connIds {
|
|
_, states, err := sessionRepo.LookupConnection(ctx, connId, nil)
|
|
require.NoError(err)
|
|
var foundClosed bool
|
|
for _, state := range states {
|
|
if state.Status == session.StatusClosed {
|
|
foundClosed = true
|
|
break
|
|
}
|
|
}
|
|
assert.Equal(closed, foundClosed)
|
|
}
|
|
}
|
|
|
|
// Assert that all connections on the second worker are closed
|
|
assertConnections(worker2.PrivateId, true)
|
|
// Assert that all connections on the first worker are still open
|
|
assertConnections(worker1.PrivateId, false)
|
|
}
|
|
|
|
func TestSessionCleanupJobNewJobErr(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
const op = "controller.newNewSessionCleanupJob"
|
|
require := require.New(t)
|
|
|
|
job, err := newSessionCleanupJob(nil, 0)
|
|
require.Equal(err, errors.E(
|
|
ctx,
|
|
errors.WithCode(errors.InvalidParameter),
|
|
errors.WithOp(op),
|
|
errors.WithMsg("missing sessionRepoFn"),
|
|
))
|
|
require.Nil(job)
|
|
|
|
job, err = newSessionCleanupJob(func() (*session.Repository, error) { return nil, nil }, 0)
|
|
require.Equal(err, errors.E(
|
|
ctx,
|
|
errors.WithCode(errors.InvalidParameter),
|
|
errors.WithOp(op),
|
|
errors.WithMsg(fmt.Sprintf("invalid gracePeriod, must be greater than %d", session.DeadWorkerConnCloseMinGrace)),
|
|
))
|
|
require.Nil(job)
|
|
}
|