Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ jobs:
runs-on: ubuntu-22.04
env:
BATS_LIB_PATH: /usr/lib
TEST_TERMINAL_WIDTH: 200
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Check out platform
Expand Down Expand Up @@ -110,3 +111,4 @@ jobs:
- run: tests/kas-grants.bats
- run: tests/profile.bats
- run: tests/kas-registry.bats
- run: tests/namespaces.bats
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ build-test:

.PHONY: test-bats
test-bats: build-test
bats ./tests
./tests/resize_terminal.sh && bats ./tests

# Target for cleaning up the target directory
.PHONY: clean
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,14 @@ prerequisites are met:
- See the [platform README](https://github.com/opentdf/platform) for instructions

To run the tests you can either run `make test-bats` or execute specific test suites with `bats tests/<test>.bats`.

#### Terminal Size

Some tests for output rendered in the terminal will vary in behavior depending on terminal size.

Terminal size when testing:

1. set to standard defaults if running `make test-bats`
2. can be set manually by mouse in terminal where tests are triggered
3. can be set by argument `./tests/resize_terminal.sh < rows height > < columns width >`
4. can be set by environment variable, i.e. `export TEST_TERMINAL_WIDTH="200"` (200 is columns width)
10 changes: 9 additions & 1 deletion cmd/policy-attributeNamespaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ func policy_deactivateAttributeNamespace(cmd *cobra.Command, args []string) {
h := NewHandler(c)
defer h.Close()

force := c.Flags.GetOptionalBool("force")
id := c.Flags.GetRequiredString("id")

ns, err := h.GetNamespace(id)
Expand All @@ -112,7 +113,9 @@ func policy_deactivateAttributeNamespace(cmd *cobra.Command, args []string) {
cli.ExitWithError(errMsg, err)
}

cli.ConfirmAction(cli.ActionDeactivate, "namespace", ns.Name, false)
if !force {
cli.ConfirmAction(cli.ActionDeactivate, "namespace", ns.Name, false)
}

d, err := h.DeactivateNamespace(id)
if err != nil {
Expand Down Expand Up @@ -312,6 +315,11 @@ func init() {
deactivateCmd.GetDocFlag("id").Default,
deactivateCmd.GetDocFlag("id").Description,
)
deactivateCmd.Flags().Bool(
deactivateCmd.GetDocFlag("force").Name,
false,
deactivateCmd.GetDocFlag("force").Description,
)

// unsafe
unsafeCmd := man.Docs.GetCommand("policy/attributes/namespaces/unsafe")
Expand Down
4 changes: 3 additions & 1 deletion docs/man/policy/attributes/namespaces/deactivate.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ command:
shorthand: i
description: ID of the attribute namespace
required: true
- name: force
description: Force deletion without interactive confirmation (dangerous)
---

Deactivating an Attribute Namespace will make the namespace name inactive as well as any attribute definitions and values beneath.
Expand All @@ -16,4 +18,4 @@ Deactivation of a Namespace renders any existing TDFs of those attributes inacce
Deactivation will permanently reserve the Namespace name within a platform. Reactivation and deletion are both considered "unsafe"
behaviors.

For reactivation, see the `unsafe` command.
For reactivation, see the `unsafe` command.
10 changes: 5 additions & 5 deletions pkg/cli/flagValues.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func newFlagHelper(cmd *cobra.Command) *flagHelper {
func (f flagHelper) GetRequiredString(flag string) string {
v := f.cmd.Flag(flag).Value.String()
if v == "" {
fmt.Println(ErrorMessage("Flag "+flag+" is required", nil))
fmt.Println(ErrorMessage("Flag '--"+flag+"' is required", nil))
os.Exit(1)
}
return v
Expand All @@ -41,11 +41,11 @@ func (f flagHelper) GetOptionalString(flag string) string {

func (f flagHelper) GetStringSlice(flag string, v []string, opts FlagsStringSliceOptions) []string {
if len(v) < opts.Min {
fmt.Println(ErrorMessage(fmt.Sprintf("Flag %s must have at least %d non-empty values", flag, opts.Min), nil))
fmt.Println(ErrorMessage(fmt.Sprintf("Flag '--%s' must have at least %d non-empty values", flag, opts.Min), nil))
os.Exit(1)
}
if opts.Max > 0 && len(v) > opts.Max {
fmt.Println(ErrorMessage(fmt.Sprintf("Flag %s must have at most %d non-empty values", flag, opts.Max), nil))
fmt.Println(ErrorMessage(fmt.Sprintf("Flag '--%s' must have at most %d non-empty values", flag, opts.Max), nil))
os.Exit(1)
}
return v
Expand All @@ -54,7 +54,7 @@ func (f flagHelper) GetStringSlice(flag string, v []string, opts FlagsStringSlic
func (f flagHelper) GetRequiredInt32(flag string) int32 {
v, e := f.cmd.Flags().GetInt32(flag)
if e != nil {
fmt.Println(ErrorMessage("Flag "+flag+" is required", nil))
fmt.Println(ErrorMessage("Flag '--"+flag+"' is required", nil))
os.Exit(1)
}
// if v == 0 {
Expand All @@ -72,7 +72,7 @@ func (f flagHelper) GetOptionalBool(flag string) bool {
func (f flagHelper) GetRequiredBool(flag string) bool {
v, e := f.cmd.Flags().GetBool(flag)
if e != nil {
fmt.Println(ErrorMessage("Flag "+flag+" is required", nil))
fmt.Println(ErrorMessage("Flag '--"+flag+"' is required", nil))
os.Exit(1)
}
return v
Expand Down
19 changes: 17 additions & 2 deletions pkg/cli/utils.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
package cli

import (
"os"
"strconv"
"strings"

"github.com/opentdf/otdfctl/pkg/config"
"golang.org/x/term"
)

func CommaSeparated(values []string) string {
return "[" + strings.Join(values, ", ") + "]"
}

// Returns the terminal width (overridden by the TEST_TERMINAL_WIDTH env var for testing)
func TermWidth() int {
w, _, err := term.GetSize(0)
if err != nil {
var (
w int
err error
)
testSize := os.Getenv(config.TEST_TERMINAL_WIDTH)
if testSize == "" {
w, _, err = term.GetSize(0)
if err != nil {
return 80
}
return w
}
if w, err = strconv.Atoi(testSize); err != nil {
return 80
}
return w
Expand Down
3 changes: 3 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ var (
// Test mode is used to determine if the application is running in test mode
// "true" = running in test mode
TestMode = ""

// Test terminal size is a runtime env var to allow for testing of terminal output
TEST_TERMINAL_WIDTH = "TEST_TERMINAL_WIDTH"
)

type Output struct {
Expand Down
19 changes: 0 additions & 19 deletions tests/namespace.bats

This file was deleted.

172 changes: 172 additions & 0 deletions tests/namespaces.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#!/usr/bin/env bats

# Tests for namespaces

setup_file() {
echo -n '{"clientId":"opentdf","clientSecret":"secret"}' > creds.json
export WITH_CREDS='--with-client-creds-file ./creds.json'
export HOST='--host http://localhost:8080'

# Create the namespace to be used by other tests

export NS_NAME="creating-test-ns.net"
export NS_NAME_UPDATE="updated-test-ns.net"
export NS_ID=$(./otdfctl $HOST $WITH_CREDS policy attributes namespaces create -n "$NS_NAME" --json | jq -r '.id')
export NS_ID_FLAG="--id $NS_ID"
}

setup() {
load "${BATS_LIB_PATH}/bats-support/load.bash"
load "${BATS_LIB_PATH}/bats-assert/load.bash"

# invoke binary with credentials
run_otdfctl_ns () {
run sh -c "./otdfctl $HOST $WITH_CREDS policy attributes namespaces $*"
}
}

teardown_file() {
# clear out all test env vars
unset HOST WITH_CREDS NS_NAME NS_FQN NS_ID NS_ID_FLAG
}

@test "Create a namespace - Good" {
run_otdfctl_ns create --name throwaway.test
assert_output --partial "SUCCESS"
assert_output --regexp "Name.*throwaway.test"
assert_output --partial "Id"
assert_output --partial "Created At"
assert_output --regexp "Updated At"
}

@test "Create a namespace - Bad" {
# bad namespace names
run_otdfctl_ns create --name no_domain_extension
assert_failure
run_otdfctl_ns create --name -first-char-hyphen.co
assert_failure
run_otdfctl_ns create --name last-char-hyphen-.co
assert_failure

# missing flag
run_otdfctl_ns create
assert_failure
assert_output --partial "Flag '--name' is required"

# conflict
run_otdfctl_ns create -n "$NS_NAME"
assert_failure
assert_output --partial "AlreadyExists"
}

@test "Get a namespace - Good" {
run_otdfctl_ns get "$NS_ID_FLAG"
assert_success
assert_output --regexp "Id.*$NS_ID"
assert_output --regexp "Name.*$NS_NAME"

echo $NS_ID
run_otdfctl_ns get "$NS_ID_FLAG" --json
assert_success
[ "$(echo "$output" | jq -r '.id')" = "$NS_ID" ]
[ "$(echo "$output" | jq -r '.name')" = "$NS_NAME" ]
}

@test "List namespaces - when active" {
run_otdfctl_ns list --json
echo $output | jq --arg id "$NS_ID" '.[] | select(.[]? | type == "object" and .id == $id)'

run_otdfctl_ns list --state inactive --json
echo $output | refute_output --partial "$NS_ID"

run_otdfctl_ns list --state active
echo $output | assert_output --partial "$NS_ID"
}

@test "Update namespace - Safe" {
# extend labels
run_otdfctl_ns update "$NS_ID_FLAG" -l key=value --label test=true
assert_success
assert_output --regexp "Id.*$NS_ID"
assert_output --regexp "Name.*$NS_NAME"
assert_output --regexp "Labels.*key: value"
assert_output --regexp "Labels.*test: true"

# force replace labels
run_otdfctl_ns update "$NS_ID_FLAG" -l key=other --force-replace-labels
assert_success
assert_output --regexp "Id.*$NS_ID"
assert_output --regexp "Name.*$NS_NAME"
assert_output --regexp "Labels.*key: other"
refute_output --regexp "Labels.*key: value"
refute_output --regexp "Labels.*test: true"
}

@test "Update namespace - Unsafe" {
run_otdfctl_ns unsafe update "$NS_ID_FLAG" -n "$NS_NAME_UPDATE" --force
assert_success
assert_output --regexp "Id.*$NS_ID"
run_otdfctl_ns get "$NS_ID_FLAG"
assert_output --regexp "Name.*$NS_NAME_UPDATE"
refute_output --regexp "Name.*$NS_NAME"
}

@test "Deactivate namespace" {
run_otdfctl_ns deactivate "$NS_ID_FLAG" --force
assert_success
assert_output --regexp "Id.*$NS_ID"
assert_output --regexp "Id.*$NS_NAME_UPDATE"
}

@test "List namespaces - when inactive" {
run_otdfctl_ns list --json
echo $output | jq --arg id "$NS_ID" '.[] | select(.[]? | type == "object" and .id == $id)'

# json
run_otdfctl_ns list --state inactive --json
echo $output | assert_output --partial "$NS_ID"

run_otdfctl_ns list --state active --json
echo $output | refute_output --partial "$NS_ID"
# table
run_otdfctl_ns list --state inactive
echo $output | assert_output --partial "$NS_ID"

run_otdfctl_ns list --state active
echo $output | refute_output --partial "$NS_ID"
}

@test "Unsafe reactivate namespace" {
run_otdfctl_ns unsafe reactivate "$NS_ID_FLAG" --force
assert_success
assert_output --regexp "Id.*$NS_ID"
}

@test "List namespaces - when reactivated" {
run_otdfctl_ns list --json
echo $output | jq --arg id "$NS_ID" '.[] | select(.[]? | type == "object" and .id == $id)'

run_otdfctl_ns list --state inactive --json
echo $output | refute_output --partial "$NS_ID"

run_otdfctl_ns list --state active
echo $output | assert_output --partial "$NS_ID"
}

@test "Unsafe delete namespace" {
run_otdfctl_ns unsafe delete "$NS_ID_FLAG" --force
assert_success
assert_output --regexp "Id.*$NS_ID"
assert_output --regexp "Id.*$NS_NAME_UPDATE"
}

@test "List namespaces - when deleted" {
run_otdfctl_ns list --json
echo $output | refute_output --partial "$NS_ID"

run_otdfctl_ns list --state inactive --json
echo $output | refute_output --partial "$NS_ID"

run_otdfctl_ns list --state active
echo $output | refute_output --partial "$NS_ID"
}
21 changes: 1 addition & 20 deletions tests/profile.bats
Original file line number Diff line number Diff line change
@@ -1,27 +1,8 @@
#!/usr/bin/env bats

setup() {
bats_require_minimum_version 1.5.0

setup() {
OTDFCTL_BIN=./otdfctl_testbuild

if [[ $(which bats) == *"homebrew"* ]]; then
BATS_LIB_PATH=$(brew --prefix)/lib
fi

# Check if BATS_LIB_PATH environment variable exists
if [ -z "${BATS_LIB_PATH}" ]; then
# Check if bats bin has homebrew in path name
if [[ $(which bats) == *"homebrew"* ]]; then
BATS_LIB_PATH=$(dirname $(which bats))/../lib
elif [ -d "/usr/lib/bats-support" ]; then
BATS_LIB_PATH="/usr/lib"
elif [ -d "/usr/local/lib/bats-support" ]; then
# Check if bats-support exists in /usr/local/lib
BATS_LIB_PATH="/usr/local/lib"
fi
fi
echo "BATS_LIB_PATH: $BATS_LIB_PATH"
load "${BATS_LIB_PATH}/bats-support/load.bash"
load "${BATS_LIB_PATH}/bats-assert/load.bash"

Expand Down
Loading