235 lines
8.6 KiB
Markdown
235 lines
8.6 KiB
Markdown
# Shared Test Environments
|
|
|
|
NomadCode milestones can reference this document when a verification step needs a shared machine or platform SDK that is not expected to exist in every agent workspace.
|
|
|
|
## Android SDK Remote Runner
|
|
|
|
Use the Toki Labs host for Android SDK dependent checks.
|
|
|
|
### Access
|
|
|
|
```bash
|
|
ssh toki@toki-labs.com
|
|
```
|
|
|
|
After connecting, use the NomadCode checkout prepared on that host. If the checkout is under the same workspace convention as local agent workspaces, start here:
|
|
|
|
```bash
|
|
cd /config/workspace/nomadcode
|
|
```
|
|
|
|
If that path is absent, use the active NomadCode checkout on the host and make sure it is on the branch or commit that contains the change being verified.
|
|
|
|
### Environment Check
|
|
|
|
Run these before Android-specific verification:
|
|
|
|
```bash
|
|
flutter doctor -v
|
|
echo "$ANDROID_HOME"
|
|
echo "$ANDROID_SDK_ROOT"
|
|
flutter devices
|
|
```
|
|
|
|
`flutter doctor -v` should show an Android toolchain with an installed SDK. `flutter devices` is allowed to show no physical device when the check only needs a build. A device or emulator is required only for an interactive smoke run.
|
|
|
|
### Standard Checks
|
|
|
|
For Android SDK dependent client milestones, run from the Flutter host:
|
|
|
|
```bash
|
|
cd apps/client
|
|
flutter pub get
|
|
flutter build apk --debug
|
|
```
|
|
|
|
`flutter build apk --debug` is the default Android SDK validation for roadmap completion when no device smoke is explicitly required. It verifies Gradle, Android SDK, plugin registration, Firebase Android config wiring, and Dart bootstrap compilation for Android.
|
|
|
|
Generic Dart/widget checks such as `flutter test` and `flutter analyze --no-fatal-infos` may be run locally or on the remote host when the milestone explicitly asks for them. Do not treat the remote host as the source of truth for non-Android SDK checks unless its Flutter SDK version is part of the milestone evidence.
|
|
|
|
### Optional Device Smoke
|
|
|
|
Run this only when the milestone asks for an Android runtime smoke or notification/device behavior:
|
|
|
|
```bash
|
|
cd apps/client
|
|
flutter devices
|
|
flutter run -d <device-id>
|
|
```
|
|
|
|
For Mattermost push work, confirm the app boots, Firebase initialization does not crash, and notification navigation callbacks remain observable. Do not record tokens, credentials, signing keys, or private server values in roadmap or docs.
|
|
|
|
## Mattermost Server-Generated Push Smoke
|
|
|
|
Use this when NomadCode needs to reproduce the same signed FCM path that was verified from the sibling `../nexo` messaging plugin environment.
|
|
|
|
### Roadmap Target
|
|
|
|
The current matching roadmap target is:
|
|
|
|
- Phase: `agent-roadmap/phase/external-integration/PHASE.md`
|
|
- Milestone: `agent-roadmap/phase/external-integration/milestones/external-integration.md`
|
|
- Task fit: `[mattermost-adapter]` and Mattermost notification evidence for external integration validation.
|
|
|
|
### Private Inputs
|
|
|
|
Before running this smoke, read `agent-test/local/rules.md` and the routed local Mattermost smoke rule. Use the local-only secret file referenced there. Do not print or commit raw bot tokens, passwords, FCM tokens, signing keys, or push signatures.
|
|
|
|
Create the ignored credential asset used by `apps/client`:
|
|
|
|
```json
|
|
{
|
|
"serverUrl": "<mattermost-base-url-from-local-test-secrets>",
|
|
"loginId": "<receiver-test-account-email-from-local-test-secrets>",
|
|
"password": "<receiver-test-account-password-from-local-test-secrets>"
|
|
}
|
|
```
|
|
|
|
Write it to:
|
|
|
|
```bash
|
|
apps/client/assets/mattermost_credentials.json
|
|
```
|
|
|
|
This asset is intentionally ignored by `apps/client/.gitignore`. It lets `MattermostAuthService` login, call `setAuthToken`, fetch the server signing public key, call `setSigningKey`, and register the current FCM device token.
|
|
|
|
If the private environment provides a Mattermost server identifier that appears in FCM payloads as `server_id`, add it as `serverId` or `serverIdentifier` in the ignored credential asset. The host passes it through `setAuthToken(..., identifier:)` so `nexo_messaging` can resolve `server_url` even when more than one server is registered.
|
|
|
|
### Workspace Shape
|
|
|
|
The remote Android runner needs the same sibling workspace layout as the local agent workspace:
|
|
|
|
```text
|
|
<workspace>/
|
|
nomadcode/
|
|
nexo/
|
|
proto-socket/
|
|
```
|
|
|
|
`apps/client/pubspec.yaml` depends on:
|
|
|
|
```yaml
|
|
nexo_messaging:
|
|
path: ../../../nexo/packages/messaging_flutter
|
|
proto_socket:
|
|
path: ../../../proto-socket/dart
|
|
```
|
|
|
|
Make sure the remote `../nexo` checkout contains the current `packages/messaging_flutter` changes, especially the Android opened-intent fix that converts nested `Bundle` extras into Flutter codec-safe values. Without that fix, tapping a notification can crash with `Unsupported value: 'Bundle[EMPTY_PARCEL]'`.
|
|
|
|
NomadCode already uses Android `applicationId = "com.tokilabs.mattermost"` in `apps/client/android/app/build.gradle.kts`; unlike the standalone Nexo test harness, no Gradle application-id override is expected.
|
|
|
|
### Run App
|
|
|
|
On the Android remote runner:
|
|
|
|
```bash
|
|
cd <workspace>/nomadcode/apps/client
|
|
flutter pub get
|
|
flutter analyze --no-fatal-infos
|
|
flutter test
|
|
flutter run -d emulator-5554 --no-resident
|
|
```
|
|
|
|
Expected app-side setup logs include:
|
|
|
|
```text
|
|
FirebaseApp initialization successful
|
|
[MattermostAuth] Logging in to ...
|
|
[MattermostAuth] Login OK ...
|
|
[MattermostAuth] Signing key stored.
|
|
[MattermostAuth] FCM device token registered successfully.
|
|
```
|
|
|
|
If login or signing-key storage is skipped, fix the ignored credential asset or private environment before triggering the push. A valid server-generated push should not require manually injecting server URL rows or signing keys.
|
|
|
|
### Trigger Signed Push
|
|
|
|
Use the bot token from local test secrets to send a normal Mattermost DM or mention to the receiver test account through the Mattermost REST API. The important property is that the message is created by the server, then delivered through push-proxy to FCM; do not use a hand-built placeholder signature as the positive test.
|
|
|
|
The generic API flow is:
|
|
|
|
```bash
|
|
# 1. Resolve bot user and receiver user.
|
|
GET /api/v4/users/me
|
|
GET /api/v4/users/email/<receiver-email>
|
|
|
|
# 2. Open or create a direct channel.
|
|
POST /api/v4/channels/direct
|
|
# body: ["<bot-user-id>", "<receiver-user-id>"]
|
|
|
|
# 3. Post the smoke message.
|
|
POST /api/v4/posts
|
|
# body: {"channel_id":"<direct-channel-id>","message":"nomadcode signed push smoke <timestamp>"}
|
|
```
|
|
|
|
All calls use:
|
|
|
|
```text
|
|
Authorization: Bearer <bot-access-token-from-local-test-secrets>
|
|
```
|
|
|
|
### Expected Evidence
|
|
|
|
Collect redacted evidence only. Good evidence is logcat snippets, sanitized UI text, or `dumpsys notification` excerpts that omit raw payload signatures and tokens.
|
|
|
|
The positive signed path should show:
|
|
|
|
```text
|
|
NexoFCM : >>> onMessageReceived ENTER
|
|
NexoFCM : onMessageReceived type=message ... serverUrl=<mattermost-base-url>
|
|
ReceiptDelivery: Send ACK=...
|
|
NexoFCM : Sending notification event to Flutter: type=message
|
|
```
|
|
|
|
It should not show:
|
|
|
|
```text
|
|
Cannot verify
|
|
No signing key
|
|
Notification skipped: signature verification failed
|
|
```
|
|
|
|
Then verify:
|
|
|
|
- System notification displays the server-generated message and has a `Reply` action.
|
|
- Tapping the notification invokes the host channel navigation callback.
|
|
- Inline reply sends successfully. NomadCode should be able to test this fully because `MattermostAuthService` calls `setAuthToken`; if reply fails, inspect auth-token handoff before treating plugin behavior as failed.
|
|
- Dismiss/clear path logs the dismiss or cancel event.
|
|
- Device registration uses the `android_rn-v2:` prefix before the raw FCM token is registered with Mattermost.
|
|
|
|
### Negative Controls
|
|
|
|
If direct push-proxy access is available, send one placeholder-signature payload and one unsigned payload as negative controls. Both may reach `onMessageReceived` and ACK, but must stop before notification display with:
|
|
|
|
```text
|
|
Notification skipped: signature verification failed
|
|
```
|
|
|
|
### Evidence Checklist
|
|
|
|
Record these outcomes in the relevant `agent-task` review stub or milestone evidence. Use `PASS`, `PARTIAL`, `BLOCKED`, or `N/A` rather than overstating results.
|
|
|
|
| 항목 | 기대 |
|
|
|------|------|
|
|
| FCM payload wakes / receipt | PASS |
|
|
| valid server-generated signature 처리 | PASS |
|
|
| invalid / unsigned drop | PASS |
|
|
| notification display | PASS |
|
|
| ACK request | PASS |
|
|
| opened event | PASS |
|
|
| channel navigation | PASS |
|
|
| thread navigation | N/A unless the payload has `root_id` |
|
|
| inline reply | PASS expected for NomadCode host auth wiring |
|
|
| dismiss / clear | PASS |
|
|
| device token prefix | PASS |
|
|
|
|
### Roadmap Evidence
|
|
|
|
When a milestone depends on this environment, leave only a short evidence note in the milestone, for example:
|
|
|
|
```text
|
|
Android SDK check: see docs/test-environments.md#android-sdk-remote-runner; flutter build apk --debug passed on toki@toki-labs.com.
|
|
```
|
|
|
|
Keep detailed reusable environment instructions in this document, not in individual milestone files.
|