mirror of https://github.com/hashicorp/boundary
test(e2e): Add tests to validate that session ends after target is deleted (#2709)
* test(e2e): Add more "session end" tests These tests validate that the session ends when the respective project or target is deleted. It also ensures that the session can still be read after the deletion of the corresponding item. * Removing test from PR due to bug This test found a bug that will be resolved in the future. Taking this test out of the PR and will add it once the bug is fixed.pull/2313/head
parent
26a85ef61b
commit
8bd883a37d
@ -0,0 +1,140 @@
|
||||
package static_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/hashicorp/boundary/api/sessions"
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e"
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e/boundary"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestCliSessionEndWhenTargetIsDeleted tests that an active session is canceled when the respective
|
||||
// target for the session is deleted.
|
||||
func TestCliSessionEndWhenTargetIsDeleted(t *testing.T) {
|
||||
e2e.MaybeSkipTest(t)
|
||||
c, err := loadConfig()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
boundary.AuthenticateAdminCli(t, ctx)
|
||||
newOrgId := boundary.CreateNewOrgCli(t, ctx)
|
||||
t.Cleanup(func() {
|
||||
ctx := context.Background()
|
||||
boundary.AuthenticateAdminCli(t, ctx)
|
||||
output := e2e.RunCommand(ctx, "boundary", e2e.WithArgs("scopes", "delete", "-id", newOrgId))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
newProjectId := boundary.CreateNewProjectCli(t, ctx, newOrgId)
|
||||
newHostCatalogId := boundary.CreateNewHostCatalogCli(t, ctx, newProjectId)
|
||||
newHostSetId := boundary.CreateNewHostSetCli(t, ctx, newHostCatalogId)
|
||||
newHostId := boundary.CreateNewHostCli(t, ctx, newHostCatalogId, c.TargetIp)
|
||||
boundary.AddHostToHostSetCli(t, ctx, newHostSetId, newHostId)
|
||||
newTargetId := boundary.CreateNewTargetCli(t, ctx, newProjectId, c.TargetPort)
|
||||
boundary.AddHostSourceToTargetCli(t, ctx, newTargetId, newHostSetId)
|
||||
acctName := "e2e-account"
|
||||
newAccountId, acctPassword := boundary.CreateNewAccountCli(t, ctx, acctName)
|
||||
t.Cleanup(func() {
|
||||
boundary.AuthenticateAdminCli(t, context.Background())
|
||||
output := e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs("accounts", "delete", "-id", newAccountId),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
newUserId := boundary.CreateNewUserCli(t, ctx, "global")
|
||||
t.Cleanup(func() {
|
||||
boundary.AuthenticateAdminCli(t, context.Background())
|
||||
output := e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs("users", "delete", "-id", newUserId),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
boundary.SetAccountToUserCli(t, ctx, newUserId, newAccountId)
|
||||
newRoleId := boundary.CreateNewRoleCli(t, ctx, newProjectId)
|
||||
boundary.AddGrantToRoleCli(t, ctx, newRoleId, "id=*;type=target;actions=authorize-session")
|
||||
boundary.AddPrincipalToRoleCli(t, ctx, newRoleId, newUserId)
|
||||
|
||||
// Connect to target to create a session
|
||||
ctxCancel, cancel := context.WithCancel(context.Background())
|
||||
errChan := make(chan *e2e.CommandResult)
|
||||
go func() {
|
||||
token := boundary.GetAuthenticationTokenCli(t, ctx, acctName, acctPassword)
|
||||
t.Log("Starting session as user...")
|
||||
errChan <- e2e.RunCommand(ctxCancel, "boundary",
|
||||
e2e.WithArgs(
|
||||
"connect",
|
||||
"-token", "env://E2E_AUTH_TOKEN",
|
||||
"-target-id", newTargetId,
|
||||
"-exec", "/usr/bin/ssh", "--",
|
||||
"-l", c.TargetSshUser,
|
||||
"-i", c.TargetSshKeyPath,
|
||||
"-o", "UserKnownHostsFile=/dev/null",
|
||||
"-o", "StrictHostKeyChecking=no",
|
||||
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
|
||||
"-p", "{{boundary.port}}", // this is provided by boundary
|
||||
"{{boundary.ip}}",
|
||||
"hostname -i; sleep 60",
|
||||
),
|
||||
e2e.WithEnv("E2E_AUTH_TOKEN", token),
|
||||
)
|
||||
}()
|
||||
t.Cleanup(cancel)
|
||||
session := boundary.WaitForSessionToBeActiveCli(t, ctx, newProjectId)
|
||||
assert.Equal(t, newTargetId, session.TargetId)
|
||||
assert.Equal(t, newHostId, session.HostId)
|
||||
|
||||
// Delete Target
|
||||
t.Log("Deleting target...")
|
||||
output := e2e.RunCommand(ctx, "boundary", e2e.WithArgs("targets", "delete", "-id", newTargetId))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
// Check if session has terminated
|
||||
t.Log("Waiting for session to be canceling/terminated...")
|
||||
select {
|
||||
case output := <-errChan:
|
||||
// `boundary connect` returns a 255 when cancelled
|
||||
require.Equal(t, output.ExitCode, 255, string(output.Stdout), string(output.Stderr))
|
||||
case <-time.After(time.Second * 5):
|
||||
t.Fatal("Timed out waiting for session command to exit")
|
||||
}
|
||||
|
||||
err = backoff.RetryNotify(
|
||||
func() error {
|
||||
// Check that session has been canceled or terminated
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs("sessions", "read", "-id", session.Id, "-format", "json"),
|
||||
)
|
||||
if output.Err != nil {
|
||||
return backoff.Permanent(errors.New(string(output.Stderr)))
|
||||
}
|
||||
|
||||
var sessionReadResult sessions.SessionReadResult
|
||||
err = json.Unmarshal(output.Stdout, &sessionReadResult)
|
||||
if err != nil {
|
||||
return backoff.Permanent(err)
|
||||
}
|
||||
|
||||
if sessionReadResult.Item.Status != "canceling" && sessionReadResult.Item.Status != "terminated" {
|
||||
return errors.New(fmt.Sprintf("Session has unexpected status. Expected: %s, Actual: %s",
|
||||
"`canceling` or `terminated`",
|
||||
sessionReadResult.Item.Status,
|
||||
))
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
backoff.WithMaxRetries(backoff.NewConstantBackOff(3*time.Second), 5),
|
||||
func(err error, td time.Duration) {
|
||||
t.Logf("%s. Retrying...", err.Error())
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
t.Log("Session successfully ended after target was deleted")
|
||||
}
|
||||
Loading…
Reference in new issue