Database, SSH, Filesystem, Process, and Infrastructure Automation Patterns: Configuration, Design Patterns, and Trade-Offs
Choose deliberately among database versus API assertions, rollback versus cleanup, SSH versus local process execution, connection reuse, resource abstractions, and simulation versus local services.
Learning objectives
- Choose database versus API assertions based on the contract under test rather than convenience.
- Choose rollback, explicit cleanup, connection reuse, or per-test isolation based on observable state ownership.
- Compare SSH remote execution with local Process and simulation without hiding security or portability costs.
- Keep low-level library keywords behind a small domain infrastructure resource.
- Reason about parallel workers, CI workspaces, and container networking before sharing external state.
Current compatibility baseline — verified 2026-08-31.
Robot Framework 7.4.2 is the stable course
baseline. The mandatory database layer uses
robotframework-databaselibrary 2.4.1, which
requires Python 3.8.1+ and Robot Framework 5.0.1+; the lab uses
Python's built-in sqlite3 driver, so no database server
is required. SSHLibrary 3.8.0 is still the latest
stable PyPI release and 3.8.1rc1 remains prerelease. Its stable
Paramiko implementation accepts unknown host keys with
AutoAddPolicy; therefore real SSH is optional here and
never used as the mandatory production-security pattern. The
required path is local/free: SQLite, Robot standard
OperatingSystem/Process, synthetic files, and a loopback-equivalent
SSH simulation. No public host, production database, paid service,
Pabot, CI provider, or container runtime is required.
1. Design frame: minimize the number of mutable states a test owns
A test that opens a database connection, edits three files, starts a daemon, SSHes to a host, and then calls an API may be “end to end,” but it has five independent cleanup contracts. That increases diagnostic ambiguity. Prefer the smallest set of boundaries that can prove the intended behavior.
2. Direct database assertion versus API assertion
| Question | Direct DB assertion | API/service assertion |
|---|---|---|
| What is proven? | Persistence/storage state | Published service behavior |
| Coupling | Schema/driver/query coupling | HTTP/API contract coupling |
| Speed | Usually fast locally | Usually fast but includes service layer |
| Setup usefulness | Excellent for fixture verification | Excellent when API is supported fixture boundary |
| Risk | Bypasses business rules if used as mutation path | May hide DB-specific persistence defects |
| Production pattern | Use narrowly for integration/storage invariants | Prefer for business behavior when API is the product contract |
A useful rule: if the requirement says “the client receives X,” assert through the service. If the requirement says “migration/index/persistence contains X,” a direct database assertion can be appropriate. Do not use DB writes to bypass the exact business behavior you are testing unless the write is explicitly fixture setup outside the behavior under test.
3. Transaction rollback versus explicit cleanup
Rollback is ideal when all mutations stay inside one connection/transaction and the test can guarantee the transaction is never committed by the code under test. Explicit cleanup is needed when state crosses transaction boundaries or is visible to another process/service. The two strategies can coexist, but their ownership must be obvious.
| Strategy | Best fit | Failure mode |
|---|---|---|
| Rollback | single DB connection, test-only mutations | hidden commit makes rollback ineffective |
| Delete by owned ID | API/DB mutation committed by application | lost ID causes orphan state |
| Recreate disposable DB file | SQLite lab or isolated worker database | shared file path causes races |
| Snapshot/restore | complex controlled fixture with tooling support | expensive; easy to restore wrong target |
4. SSH remote command versus local Process
If the target is the same machine that runs Robot, use Process for a local program. Adding SSH to localhost adds authentication, host trust, port, daemon, and connection-state failure modes without changing the target. Use SSH only when remote execution is part of the integration boundary.
For a disposable remote fixture, expose a narrow domain keyword such
as Read Remote Service State, not arbitrary
Execute Command calls in every test. This is where an
allowlist can reject package managers, service stop/start, user
management, broad deletion, or shell metacharacters.
5. One domain resource versus library keywords everywhere
*** Keywords ***
Inventory Should Contain Ready Item
[Arguments] ${name}
${rows}= Get Inventory Row ${name}
Length Should Be ${rows} 1
Should Be Equal ${rows}[0][state] ready
The higher-level keyword owns the data-access pattern and diagnostic
message. A test now says what infrastructure condition matters
instead of repeating connection aliases, SQL placeholders, and
row-shape assumptions. Keep resources cohesive: one giant
Common.resource containing every infrastructure
operation creates dependency tangles and name collisions.
6. Persistent connection versus per-test isolation
| Choice | Advantage | Cost / risk | Use when |
|---|---|---|---|
| Suite-scoped DB connection | less setup overhead | transaction/session leakage between tests | read-heavy, well-reset local fixture |
| Per-test DB connection | stronger isolation | more connection cost | mutating tests, parallel workers, flaky shared state |
| Suite-scoped SSH connection | fewer handshakes | remote shell/session state can leak | read-only commands with strict reset |
| Per-test SSH connection | clear ownership | connection overhead | mutable remote state or stronger isolation |
Library scope and connection scope are different. DatabaseLibrary may be GLOBAL as a Robot library while it manages several independently aliased DB connections. SSHLibrary also maintains a global connection cache. Design the connection lifetime explicitly instead of inferring it from import placement.
7. Simulation versus real local service
Simulation is appropriate when the learning goal is Robot architecture, cleanup, and evidence—not protocol conformance. A real local service is appropriate when the behavior under test includes the protocol. The mandatory chapter uses real SQLite/filesystem/process boundaries and simulates SSH because safe SSH host-trust provisioning would otherwise dominate the lesson.
8. Absolute/owned paths versus working-directory folklore
Resolve run-owned paths once from ${OUTPUTDIR} or
${CURDIR} depending on ownership, normalize them, and
pass explicit paths to libraries. Do not assume the CI working
directory equals your laptop working directory. A child process can
also have its own cwd; that state is distinct from
Robot's ${EXECDIR}.
9. Parallelism and worker isolation
Pabot arrives later in Chapter 24, but infrastructure design must
already be concurrency-safe. A fixed SQLite path such as
/tmp/test.db, fixed SSH temp filename, or common
process port becomes a shared resource when workers run
concurrently. Use worker-specific/run-specific roots and never rely
on global mutable test variables to coordinate external state.
Do not solve a collision by adding sleeps. Collisions are ownership/design problems. A wait may help only when the underlying state transition is expected and uniquely owned.
10. “localhost” changes meaning across container boundaries
On a developer machine, 127.0.0.1 refers to that host.
Inside a container, it refers to the container itself. A database or
SSH service on the host is not automatically at the container's
localhost. Treat network namespace, published port, DNS name, and
trust material as explicit container/CI configuration. Do not
rewrite a failing target to a public hostname just to make the test
connect.
11. Worked decision table
| Scenario | Preferred boundary | Why |
|---|---|---|
| Verify local migration created one index | DatabaseLibrary + disposable DB | storage contract is the target |
| Verify customer status returned by service | API resource | business/API contract is the target |
| Run local compiler/helper | Process | no SSH/session/trust overhead |
| Check remote non-production host service version | domain SSH keyword on pre-trusted host | remote host is intentionally part of test |
| Teach remote-call orchestration without trusted SSH fixture | simulation | preserves architecture without fake security |
| Delete generated run directory | OperatingSystem behind exact ownership guard | filesystem ownership can be proven locally |
12. Configuration boundaries
- Robot core: variables, suites, selection, output directory, lifecycle.
- External libraries: DatabaseLibrary/SSHLibrary import args and connection APIs.
- Python environment: database drivers, Paramiko/SCP dependencies, interpreter.
- SUT/infrastructure: DB schema, SSH daemon, users, host keys, process executables.
- Editor/RobotCode: developer assistance only; not runtime target configuration.
- CI/container: workspace, network namespace, service containers, secret injection, artifact retention.
Knowledge check
When is a direct DB assertion better than an API assertion?
When the requirement itself concerns storage, schema, migration, persistence, or a DB integration invariant. Business behavior exposed by an API should usually be asserted through that API.
Why can a suite-scoped connection make tests order-dependent?
Connection-level transaction/session state can survive between tests unless every test resets it completely.
Why is SSH to localhost usually inferior to Process for a local helper?
It adds network daemon, authentication, host-key trust, and connection lifecycle without changing the execution host.
How should a Pabot worker change this chapter’s design even before Pabot is introduced?
External mutable resources must be namespaced per worker/run so workers do not share DB files, temp paths, ports, or remote records.
What does “localhost inside a container” mean?
The container’s own network namespace, not automatically the CI host or another service container.
13. Summary and next lesson
Good infrastructure tests choose one boundary for a reason, minimize owned state, and isolate connection/transaction/process/path lifecycles. Lesson 4 deliberately breaks those contracts and diagnoses the evidence without using destructive shortcuts.
References and version anchors
- Robot Framework 7.4.2 User Guide, Process 7.4.2, and OperatingSystem 7.4.2 — core execution, variables/lifecycle, structured child processes, filesystem operations, and current standard-library semantics.
- DatabaseLibrary 2.4.1 keyword documentation, PyPI release, and maintainer repository — connection, query, transaction wrapper, parameter, retry, alias, and SQLite guidance.
- SSHLibrary keyword documentation, SSHLibrary 3.8.0 on PyPI, and maintainer repository — connection/session behavior and current release status. The mandatory lab does not rely on a real SSH server.
- Python sqlite3 documentation — SQLite connection/transaction behavior used by the local database fixture.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.