Skip to content
Open
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
43 changes: 43 additions & 0 deletions .env.whaletag
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Whale Tag Simulator Configuration
# Choose ONE network configuration below by uncommenting the relevant section

# =============================================================================
# OPTION 1: Bridge Network (Default - Recommended for Most Users)
# =============================================================================
# Container gets its own IP on Docker's bridge network
# Pro: Works out of the box, no network configuration needed
# Con: Not discoverable by 'ceti whaletag -l' (use container IP directly)
#
# To use: Uncomment the lines below
WHALETAG_HOSTNAME=wt-b827eb123456
WHALETAG_PASSWORD=ceticeti
NETWORK_MODE=bridge

# =============================================================================
# OPTION 2: Host Network (Simple but Port Conflicts)
# =============================================================================
# Container uses host's network stack directly
# Pro: Simple, discoverable on LAN
# Con: Port 22 conflicts with host SSH server (NOT RECOMMENDED)
#
# To use: Comment out Option 1, uncomment lines below
# WHALETAG_HOSTNAME=wt-b827eb123456
# WHALETAG_PASSWORD=ceticeti
# NETWORK_MODE=host

# =============================================================================
# OPTION 3: MacVLAN Network (Advanced - Real LAN IP via DHCP)
# =============================================================================
# Container gets a real IP address on your LAN (like a physical device)
# Pro: Discoverable by 'ceti whaletag -l', most realistic simulation
# Con: Requires network interface configuration, host can't directly access container
#
# To use: Comment out Option 1, uncomment and configure lines below
# WHALETAG_HOSTNAME=wt-b827eb123456
# WHALETAG_PASSWORD=ceticeti
# NETWORK_MODE=macvlan
#
# Find your network interface: ip addr | grep -E '^[0-9]+: (eth|wlan|enp)'
# NETWORK_INTERFACE=eth0

# Container will get IP via DHCP from your router (no manual IP needed)
46 changes: 46 additions & 0 deletions COMMIT_MESSAGE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
Add whale tag simulator for local testing

Implements a Docker-based whale tag simulator that allows developers to test
`ceti whaletag` commands locally without physical hardware. This enables faster
development iteration and automated testing of whale tag data download workflows.

Features:
- Alpine Linux container (~12 MB) with SSH server and test data
- Bridge network mode (default) - works out of the box
- Macvlan mode (advanced) - for LAN discovery testing
- Automated pytest integration with custom marker to exclude tests by default
- Sample test files (audio .raw/.flac, sensors CSV) mimicking real whale tag data

Changes:
- Add Dockerfile.whaletag: Alpine-based image with openssh-server and dhcpcd
- Add docker-compose.whaletag.yml: Container orchestration with network mode support
- Add scripts/init-whaletag.sh: Container initialization (user setup, test data, SSH)
- Add .env.whaletag: Configuration file with three network mode options
- Add tests/test_whaletag_integration.py: 6 integration tests for SSH, SFTP, hostname
- Add pytest.ini: Configure @pytest.mark.whaletag marker to exclude tests by default
- Update Makefile: Add whaletag-up, whaletag-down, whaletag-clean, test-whaletag targets
- Update README.md: Add whale tag simulator quick start guide
- Add docs/TESTING.md: Comprehensive testing documentation

Usage:
make whaletag-up
CONTAINER_IP=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' wt-b827eb123456)
ceti whaletag -t $CONTAINER_IP
make whaletag-down

Testing:
make test-whaletag # Automated tests
pytest -m whaletag # Run whale tag tests only
pytest # Default - excludes whale tag tests

Network modes:
- Bridge (default): Container gets Docker IP, accessible from host
- Host: Container shares host network (may conflict with SSH port 22)
- Macvlan (advanced): Container gets real LAN IP via DHCP, discoverable by other machines

Limitations:
- Network discovery (ceti whaletag -l) only works in macvlan mode
- Bridge mode requires direct connection via IP (ceti whaletag -t <IP>)
- Macvlan mode requires manual network interface configuration

Related issue: Enables local development and CI/CD testing without physical whale tags
30 changes: 30 additions & 0 deletions Dockerfile.whaletag
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Whale Tag Mockup Docker Image
# Pre-installs SSH server and utilities for network configuration

FROM alpine:latest

# Install dependencies (SSH server, DHCP client for macvlan mode, basic utils)
RUN apk add --no-cache \
openssh-server \
dhcpcd \
bash \
python3 \
sudo \
&& \
# Pre-configure SSH
ssh-keygen -A && \
sed -i 's/#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config && \
sed -i 's/#PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config && \
# Create SSH runtime directory
mkdir -p /run/sshd && \
# Configure sudo for passwordless access (for ceti whaletag -ct command)
echo "pi ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

# Create data directory
RUN mkdir -p /data && chmod 755 /data

COPY scripts/init-whaletag.sh /docker-entrypoint.sh
COPY scripts/generate-syslog.py /generate-syslog.py
RUN chmod +x /docker-entrypoint.sh /generate-syslog.py

CMD ["/bin/bash", "/docker-entrypoint.sh"]
38 changes: 38 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,41 @@ release: bumpversion

publish: build_tools build login_twine
@python -m twine upload --repository codeartifact dist/ceti-*

# Whale Tag Simulator targets
whaletag-up:
@echo "Starting whale tag simulator..."
@set -a && . $(CURDIR)/.env.whaletag && set +a && docker-compose -f docker-compose.whaletag.yml up -d 2>&1
@echo "Waiting for SSH server to start..."
@sleep 3
@echo ""
@echo "Whale tag simulator is ready!"
@echo " Container: $${WHALETAG_HOSTNAME:-wt-b827eb123456}"
@echo " Hostname: $${WHALETAG_HOSTNAME:-wt-b827eb123456}"
@echo " SSH Port: 22"
@echo " SSH User: pi"
@echo " SSH Password: $${WHALETAG_PASSWORD:-ceticeti}"
@echo ""
@echo "Get container IP:"
@echo " docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $${WHALETAG_HOSTNAME:-wt-b827eb123456}"
@echo ""
@echo "Test connection:"
@echo " ssh pi@$$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $${WHALETAG_HOSTNAME:-wt-b827eb123456})"

whaletag-down:
@echo "Stopping whale tag simulator..."
@docker-compose -f docker-compose.whaletag.yml down 2>&1
@echo "Whale tag simulator stopped"

whaletag-clean:
@echo "Cleaning whale tag data..."
@docker-compose -f docker-compose.whaletag.yml down -v 2>&1
@echo "Whale tag data cleaned"

test-whaletag:
@echo "Testing whale tag simulator..."
@$(MAKE) whaletag-up
@echo "Running whale tag tests..."
@pytest -m whaletag -v || ($(MAKE) whaletag-down && exit 1)
@$(MAKE) whaletag-down
@echo "Whale tag tests completed"
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,37 @@ There's also a convemnience script scripts/tag.sh that does the following automa
5) copy the back-up of compressed data to /data-backup folder
6) upload all downloaded and compressed data to s3
7) clean all tags

### Testing

#### Whale Tag Simulator

Test `ceti whaletag` commands locally without physical hardware using a Docker-based simulator:

```console
# Start whale tag simulator
make whaletag-up

# Get container IP
CONTAINER_IP=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' wt-b827eb123456)

# Test ceti whaletag command
ceti whaletag -t $CONTAINER_IP

# Or run automated tests
make test-whaletag

# Stop simulator
make whaletag-down
```

The simulator creates a lightweight Alpine Linux container (~12 MB) with:
- SSH server on port 22
- Docker bridge network IP
- User `pi` with password `ceticeti`
- Hostname `wt-b827eb123456`
- Sample test files in `/data/` (audio .raw/.flac, sensors CSV)

**Note:** Whale tag tests are excluded from default `pytest` runs. Use `make test-whaletag` or `pytest -m whaletag` to run them explicitly.

See [docs/TESTING.md](docs/TESTING.md) for complete testing documentation.
56 changes: 56 additions & 0 deletions docker-compose.whaletag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
services:
whaletag-mockup:
build:
context: .
dockerfile: Dockerfile.whaletag
image: ceti-whaletag-mockup:latest
container_name: ${WHALETAG_HOSTNAME:-wt-b827eb123456}
hostname: ${WHALETAG_HOSTNAME:-wt-b827eb123456}
environment:
- WHALETAG_HOSTNAME=${WHALETAG_HOSTNAME:-wt-b827eb123456}
- WHALETAG_PASSWORD=${WHALETAG_PASSWORD:-ceticeti}
- NETWORK_MODE=${NETWORK_MODE:-bridge}
volumes:
- whaletag-data:/data
- whaletag-backup:/backup
- ./scripts/init-whaletag.sh:/docker-entrypoint.sh
command: /bin/sh /docker-entrypoint.sh
# Network configuration depends on NETWORK_MODE in .env.whaletag
# NOTE: You must manually edit this file to switch modes:
# - For 'bridge': uncomment 'networks: default' section
# - For 'host': uncomment 'network_mode: host' section
# - For 'macvlan': uncomment 'networks: macvlan_network' section

# BRIDGE MODE (Default - works out of the box)
networks:
- default

# HOST MODE (Uncomment this, comment out 'networks' above)
# network_mode: host

# MACVLAN MODE (Advanced - for real LAN discovery, uncomment and configure)
# networks:
# - macvlan_network
# # No static IP - container will use DHCP
# dns:
# - 8.8.8.8 # Google DNS
# - 192.168.0.1 # Your router (fallback)
# cap_add:
# - NET_ADMIN # Required for DHCP client to configure network interface

volumes:
whaletag-data:
whaletag-backup:

networks:
# Default bridge network (for bridge mode)
default:
driver: bridge

# MacVLAN network (for macvlan mode)
# Container gets IP via DHCP from your router
macvlan_network:
driver: macvlan
driver_opts:
parent: ${NETWORK_INTERFACE:-eth0}
# No ipam config - uses DHCP
Loading