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
Michael Li 3 years ago committed by GitHub
parent 26a85ef61b
commit 8bd883a37d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -39,6 +39,11 @@ type DbInitInfo struct {
AuthMethod AuthMethodInfo `json:"auth_method"`
}
// CliError parses the Stderr from running a boundary command
type CliError struct {
Status int `json:"status"`
}
func loadConfig() (*config, error) {
var c config
err := envconfig.Process("", &c)

@ -18,11 +18,6 @@ type CommandResult struct {
Err error
}
// CliError parses the Stderr from running a boundary command
type CliError struct {
Status int `json:"status"`
}
// Option is a func that sets optional attributes for a call. This does not need
// to be used directly, but instead option arguments are built from the
// functions in this package. WithX options set a value to that given in the

@ -85,7 +85,7 @@ func TestCliStaticCredentialStore(t *testing.T) {
return fmt.Errorf("Deleted credential can still be read: '%s'", output.Stdout)
}
var response e2e.CliError
var response boundary.CliError
err := json.Unmarshal(output.Stderr, &response)
require.NoError(t, err)
statusCode := response.Status

@ -80,7 +80,7 @@ func TestCliSessionCancelGroup(t *testing.T) {
),
)
require.Error(t, output.Err, string(output.Stdout), string(output.Stderr))
var response e2e.CliError
var response boundary.CliError
err = json.Unmarshal(output.Stderr, &response)
require.NoError(t, err)
require.Equal(t, 403, int(response.Status))

@ -79,7 +79,7 @@ func TestCliSessionCancelUser(t *testing.T) {
),
)
require.Error(t, output.Err, string(output.Stdout), string(output.Stderr))
var response e2e.CliError
var response boundary.CliError
err = json.Unmarshal(output.Stderr, &response)
require.NoError(t, err)
require.Equal(t, 403, int(response.Status))

@ -97,9 +97,17 @@ func TestCliSessionEndWhenHostSetIsDeleted(t *testing.T) {
// 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 if session is active
// Check that session has been canceled or terminated
output = e2e.RunCommand(ctx, "boundary",
e2e.WithArgs("sessions", "read", "-id", session.Id, "-format", "json"),
)

@ -97,9 +97,17 @@ func TestCliSessionEndWhenHostIsDeleted(t *testing.T) {
// 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 if session is active
// Check that session has been canceled or terminated
output = e2e.RunCommand(ctx, "boundary",
e2e.WithArgs("sessions", "read", "-id", session.Id, "-format", "json"),
)

@ -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")
}

@ -90,9 +90,17 @@ func TestCliSessionEndWhenUserIsDeleted(t *testing.T) {
// 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 if session is active
// Check that session has been canceled or terminated
output = e2e.RunCommand(ctx, "boundary",
e2e.WithArgs("sessions", "read", "-id", session.Id, "-format", "json"),
)

Loading…
Cancel
Save