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
21 changes: 21 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# make library-net-smoke on-target mqtt.library end-to-end API test (real broker)
# make volamos-library-net-smoke same check via volamos - faster local loop, not a CI substitute
# make library-reconnect-smoke on-target mco_AutoReconnect test (broker restart mid-run)
# make fetch-amissl-sdk fetch the AmiSSL v5 SDK (needed for Amiga-side TLS support)
# make library-tls-smoke on-target mco_TLS test - local-only, needs an amibake image
# make clean
#
# The core is portable C99, so `test` and `cli` build with any host compiler.
Expand Down Expand Up @@ -386,6 +388,25 @@ libreconn-m68k: library-headers | $(BUILD)/.dir
library-reconnect-smoke: library libreconn-m68k cli
sh tests/library/reconn-run.sh

# --- m68k: on-target mco_TLS end-to-end smoke test (issue #3 Phase 3) ---
# Same shape as libnet-m68k (a normal CLI program against the generated
# caller-side headers only - no AmiSSL headers needed by the caller) - see
# tests/library/libtls.c.
libtls-m68k: library-headers | $(BUILD)/.dir
$(M68K_CC) $(M68K_CFLAGS) -I$(LIB_INCDIR) tests/library/libtls.c -o $(BUILD)/libtls

# Local-only, NOT a CI/release gate (unlike library-net-smoke): needs a
# real AmigaOS 3.2.2 + AmiSSL boot image built by amibake
# (github.com/sidick/amibake), since AmiSSL needs real Devs:/Libs: install
# layout that the plain bundled-AROS/HostSocket boot the other
# library-*-smoke targets use doesn't have - see
# tests/library/README.md's "TLS smoke test" section for setup. Also
# needs `library` built with AmiSSL support (`make fetch-amissl-sdk`
# first - see M68K_HAS_AMISSL above), and $MIDGE_TLS_AMIGA_IMAGE pointing
# at the amibake output directory.
library-tls-smoke: library libtls-m68k cli
sh tests/library/tls-run.sh

# --- m68k: on-target check that examples/pubexample.c actually works ---
# Real Copperline boot (CI/release gate): stages build/pubexample and
# build/mqtt.library into a throwaway boot volume with Copperline's
Expand Down
71 changes: 71 additions & 0 deletions tests/library/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# tests/library/ — on-target mqtt.library smoke tests

`run.sh`, `net-run.sh`, and `reconn-run.sh` (and their `volamos-*`
counterparts) all boot Copperline's bundled AROS Kickstart replacement with
the HostSocket board fitted (see `../net/README.md`'s "Why this needs no
machine-specific assets") - no Kickstart ROM, no Workbench image, nothing
beyond `copperline`/`mosquitto` on `PATH`. They're CI/release gates
(`.github/workflows/ci.yml`).

## TLS smoke test

`tls-run.sh` (`make library-tls-smoke`) is different: it's **local-only**,
not a CI/release gate, because AmiSSL needs things the bundled-AROS boot
doesn't have:

- A real `AmigaOS` `Devs:`/`Libs:` install layout - the `amissl` package's
own install step assigns `AmiSSL:` to `SYS:Devs/AmiSSL` (where its cert
store lives), which only exists on a real OS boot.
- A real Kickstart ROM - AmiSSL requires actual AmigaOS 3.0+, not the
bundled-AROS Kickstart replacement the other tests use.

Neither is something CI can be handed (a Kickstart ROM is Cloanto/Hyperion
licensed media; a full OS install image is large and itself
proprietary-derived) - same reasoning `../copperline/`'s optional ROM and
`../net/`'s original (superseded) Roadshow-image design ran into.

### Building the image

Use [amibake](https://github.com/sidick/amibake) (a separate,
manifest-driven Amiga image builder) to build a real AmigaOS 3.2.2 +
AmiSSL 5.27 image:

```sh
# in a checkout of amibake, with your own licensed AmigaOS 3.2 install
# media + Kickstart ROM under assets/ (see amibake's own docs/limits.md)
cat > manifests/midge-library-tls.toml <<'EOF'
base = "os3.2.2"
machine = { cpu = "68020", ram = "chip:1M,fast:8M" }
packages = ["amissl = 5.27"]
output = ["dir"]
emit = ["copperline"]
EOF
.venv/bin/amibake resolve manifests/midge-library-tls.toml
.venv/bin/amibake build manifests/midge-library-tls.toml --assets assets
```

This writes `manifests/midge-library-tls/` (the boot image) and
`manifests/midge-library-tls.copperline.toml` (which names the Kickstart
ROM amibake resolved against - `tls-run.sh` re-derives its own machine
config, but that file tells you which ROM path to point
`MIDGE_TLS_KICKSTART` at if it isn't amibake's own default location).

### Running it

```sh
export MIDGE_TLS_AMIGA_IMAGE=/path/to/amibake/manifests/midge-library-tls
export MIDGE_TLS_KICKSTART=/path/to/amibake/assets/roms/kickstart-47.7.rom
make fetch-amissl-sdk # once, populates AMISSL_SDK_DIR for `make library`
make library-tls-smoke
```

`tls-run.sh` stages `build/libtls` + `build/mqtt.library` into the image
and overwrites its `S/User-Startup` on every run (see the script's own
banner for exactly what it does and why) - point `MIDGE_TLS_AMIGA_IMAGE` at
an image you don't mind that happening to, not a real Workbench install you
use for anything else.

See [tests/copperline/amissl-spike/](../copperline/amissl-spike/) for the
earlier de-risking investigation this test's approach (amibake image,
`AmiSSL:` assign trap, real-hardware CPU-speed caveat) is drawn from -
issue #3 has the full writeup.
136 changes: 136 additions & 0 deletions tests/library/libtls.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/* libtls.c — on-target (m68k/AmigaOS) end-to-end TLS smoke test for
* mqtt.library's mco_TLS/mco_TLSInsecure (issue #3 Phase 3): OpenLibrary,
* CreateClient with mco_TLS set, Connect, Subscribe, GetMessage, Publish,
* Disconnect, DeleteClient, CloseLibrary, all against a real TLS Mosquitto
* reachable over Copperline's HostSocket board - mqtt.library's TLS
* counterpart to libnet.c (see that file's banner for the shared shape;
* this one differs only in needing AmiSSL and a real AmigaOS boot instead
* of the bundled-AROS/HostSocket-only boot libnet.c uses - see
* tests/library/README.md's "TLS smoke test" section for why).
*
* Same PASS/FAIL/RESULT/END serial contract as libnet.c/libsmoke.c/
* codec_selftest.c, via exec/RawPutChar rather than stdio.
*/

#include <exec/types.h>
#include <exec/libraries.h>
#include <proto/exec.h>
#include <proto/dos.h>

#include <libraries/mqtt.h>
#include <proto/mqtt.h>

#include <string.h>

/* See libnet.c's banner: a normal CLI program must define + fill this in
* itself, unlike a library's own base. */
struct Library *MqttBase;

static void raw_put(char c)
{
void *SysBase = *(void **)4UL;
register long d0 __asm__("d0") = (unsigned char)c;
register void *a6 __asm__("a6") = SysBase;
__asm__ volatile("jsr -516(%%a6)" : : "r"(d0), "r"(a6)
: "d1", "a0", "a1", "cc", "memory");
}

static void raw_str(const char *s)
{
while (*s)
raw_put(*s++);
}

static int g_fails;

static void check(int cond, const char *name)
{
if (cond) {
raw_str("PASS ");
} else {
raw_str("FAIL ");
g_fails++;
}
raw_str(name);
raw_str("\r\n");
}

/* Must match tls-run.sh's own PORT/topic/payload constants exactly. */
#define TEST_HOST "127.0.0.1"
#define TEST_PORT 18884
#define TOPIC_IN "midge/lib/tls/in"
#define TOPIC_OUT "midge/lib/tls/out"
#define RETAINED_PAYLOAD "hello-from-host-retained-tls"
#define OUT_PAYLOAD "hello-from-mqtt-library-tls"

/* Poll budget for the retained message - see libnet.c's own comment. A
* real TLS handshake costs more than a plaintext connect, so this budget
* is a little more generous than libnet.c's. */
#define POLL_TRIES 150
#define POLL_TICKS 10

int main(void)
{
struct MqttConnectOpts opts;
APTR client = NULL;
struct MqttMessage *msg = NULL;
int i;

raw_str("BEGIN\r\n");

MqttBase = OpenLibrary((STRPTR) "mqtt.library", 0);
check(MqttBase != NULL, "openlibrary-nonnull");
if (!MqttBase)
goto done;

memset(&opts, 0, sizeof(opts));
opts.mco_ClientID = (STRPTR) "midge-libtls";
opts.mco_KeepAlive = 30;
opts.mco_CleanSession = TRUE;
opts.mco_TLS = TRUE;
/* Self-signed test broker (tls-run.sh) - not a production posture, see
* mco_TLSInsecure's own doc comment in <libraries/mqtt.h>. */
opts.mco_TLSInsecure = TRUE;

client = MQTT_CreateClient((STRPTR) TEST_HOST, TEST_PORT, &opts);
check(client != NULL, "createclient-nonnull");
if (!client)
goto close_lib;

check(MQTT_Connect(client) == 0, "connect-tls-ok");
check(MQTT_Subscribe(client, (STRPTR) TOPIC_IN, 1) == 0, "subscribe-ok");

for (i = 0; i < POLL_TRIES; i++) {
msg = MQTT_GetMessage(client);
if (msg)
break;
Delay(POLL_TICKS);
}
check(msg != NULL, "getmessage-received");

if (msg) {
check(strcmp((const char *)msg->mm_Topic, TOPIC_IN) == 0,
"message-topic");
check(strcmp((const char *)msg->mm_Payload, RETAINED_PAYLOAD) == 0,
"message-payload");
MQTT_FreeMessage(client, msg);
} else {
check(0, "message-topic");
check(0, "message-payload");
}

check(MQTT_Publish(client, (STRPTR) TOPIC_OUT, (APTR) OUT_PAYLOAD,
(ULONG) strlen(OUT_PAYLOAD), 0, 1) == 0,
"publish-qos1-ok");

MQTT_Disconnect(client);
MQTT_DeleteClient(client);

close_lib:
CloseLibrary(MqttBase);

done:
raw_str(g_fails == 0 ? "RESULT=OK\r\n" : "RESULT=FAIL\r\n");
raw_str("END\r\n");
return g_fails;
}
Loading