all repos — dot @ master

Shell, editor and terminal configuration, and the tools that go with them

secrets/test/README.md (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
# szecret Test Suite

Unit tests for the szecret secret management system.

## Running Tests

```bash
# Run all tests
./test/run.sh

# Run specific test files
./test/run.sh list get

# Run a single test file directly
./test/list.sh
```

## Test Structure

```
test/
├── common.sh        # Shared utilities, setup/teardown, assertions
├── run.sh           # Test runner entrypoint
├── create-local.sh  # Tests for create-local command
├── edge-cases.sh    # Edge case tests (special chars, unicode, etc.)
├── ensure.sh        # Tests for ensure command
├── get.sh           # Tests for get command
├── list.sh          # Tests for list command
├── local.sh         # Tests for put-local/get-local commands
├── main.sh          # Tests for main entrypoint
├── paths.sh         # Tests for where the store and public key are found
├── put.sh           # Tests for put command
└── ready.sh         # Tests for ready command
```

## Writing New Tests

### Basic test file template

```bash
#!/bin/bash
# Tests for <command> command

this_dir="$(cd "$(dirname "$0")" && pwd)"
source "${this_dir}/common.sh"

test_something() {
    # Test code here
    pass "description of what passed"
}

test_something_else() {
    # Test code here
    pass "another test"
}

run_tests() {
    test_something
    test_something_else
}

[[ "${BASH_SOURCE[0]}" == "${0}" ]] && run_tests
```

### Available helpers

From `common.sh`:

| Function | Description |
|----------|-------------|
| `szecret <cmd> [args]` | Run a szecret command via main.sh |
| `szecret_script <name> [args]` | Run a specific script directly (e.g., `szecret_script get secret-name`) |
| `pass <msg>` | Print green PASS message |
| `fail <msg>` | Print red FAIL message and exit |
| `skip <msg>` | Print yellow SKIP message |
| `assert_success <cmd>` | Assert command exits 0 |
| `assert_failure <cmd>` | Assert command exits non-zero |
| `assert_equals <expected> <actual> [msg]` | Assert string equality |
| `assert_contains <haystack> <needle> [msg]` | Assert string contains substring |
| `assert_file_exists <path> [msg]` | Assert file exists |

### Environment variables

Tests run in an isolated environment with these variables set:

| Variable | Description |
|----------|-------------|
| `TEST_DIR` | Temporary directory for test artifacts |
| `SZECRET_STORE` | Points to `$TEST_DIR/store` |
| `SZECRET_PUBLIC_KEY` | Points to test public key |
| `SZECRET_PRIVATE_KEY` | Points to test private key |

The test environment is created automatically when `common.sh` is sourced and cleaned up on exit.

## Design Notes

### Isolation

Each test file runs in its own subprocess with a fresh environment. This ensures tests don't interfere with each other. The `run.sh` runner executes each test file as a separate process.

### Auto-setup

The `common.sh` file automatically runs `setup` and registers the `teardown` trap when first sourced. A guard variable (`_SZECRET_TEST_INITIALIZED`) prevents duplicate initialization if common.sh is sourced multiple times.

### Configurable paths

The szecret scripts support these environment variables for testing:

- `SZECRET_STORE` - Override the store directory
- `SZECRET_PUBLIC_KEY` - Override the public key path
- `SZECRET_PRIVATE_KEY` - Override the private key path

This allows tests to use a temporary directory without affecting the real secret store.

## Known Limitations

### Trailing newlines

Bash command substitution `$()` strips trailing newlines. This means:

```bash
# This will lose the trailing newline
retrieved="$(szecret get my-secret)"
```

This is bash behavior, not a szecret bug. The encrypted data preserves trailing newlines correctly.

### Interactive commands

The `ensure` command prompts for private key input when run interactively. This flow isn't fully tested since it requires TTY input. The tests verify it fails gracefully in non-interactive mode.

### Binary data

The tests don't currently cover binary data. Secrets are expected to be text (the encryption handles binary, but shell pipelines may have issues with null bytes).

## Adding Tests for New Commands

1. Create `test/<command>.sh` following the template above
2. Make it executable: `chmod +x test/<command>.sh`
3. The runner will automatically discover and run it

## CI Integration

The test suite exits with code 0 on success, non-zero on failure. Example CI usage:

```bash
./secrets/test/run.sh || exit 1
```