add tests
This commit is contained in:
14
tests/Dockerfile.tests
Normal file
14
tests/Dockerfile.tests
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
FROM python:3.10-slim
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y build-essential libssl-dev && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY . /app
|
||||||
|
RUN pip install --no-cache-dir .
|
||||||
|
|
||||||
|
WORKDIR /app/tests
|
||||||
|
|
||||||
|
RUN chmod +x run_tests.sh
|
||||||
|
|
||||||
|
CMD ["bash", "run_tests.sh"]
|
||||||
44
tests/run_tests.sh
Normal file
44
tests/run_tests.sh
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||||
|
|
||||||
|
# Remove previous test artifacts
|
||||||
|
rm -rf config node-config pages files node.log
|
||||||
|
|
||||||
|
# Create directories for config, node identity, pages, and files
|
||||||
|
mkdir -p config node-config pages files
|
||||||
|
|
||||||
|
# Create a sample page and a test file
|
||||||
|
cat > pages/index.mu << EOF
|
||||||
|
>Test Page
|
||||||
|
This is a test page.
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > files/text.txt << EOF
|
||||||
|
This is a test file.
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Start the page node in the background
|
||||||
|
python3 ../rns_page_node/main.py -c config -i node-config -p pages -f files > node.log 2>&1 &
|
||||||
|
NODE_PID=$!
|
||||||
|
|
||||||
|
# Wait for node to generate its identity file
|
||||||
|
echo "Waiting for node identity..."
|
||||||
|
for i in {1..40}; do
|
||||||
|
if [ -f node-config/identity ]; then
|
||||||
|
echo "Identity file found"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 0.25
|
||||||
|
done
|
||||||
|
if [ ! -f node-config/identity ]; then
|
||||||
|
echo "Error: node identity file not found" >&2
|
||||||
|
kill $NODE_PID
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run the client test
|
||||||
|
python3 test_client.py
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
kill $NODE_PID
|
||||||
104
tests/test_client.py
Normal file
104
tests/test_client.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
import RNS
|
||||||
|
|
||||||
|
# Determine base directory for tests
|
||||||
|
dir_path = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
config_dir = os.path.join(dir_path, 'config')
|
||||||
|
identity_dir = os.path.join(dir_path, 'node-config')
|
||||||
|
|
||||||
|
# Initialize Reticulum with shared config
|
||||||
|
RNS.Reticulum(config_dir)
|
||||||
|
|
||||||
|
# Load server identity (created by the page node)
|
||||||
|
identity_file = os.path.join(identity_dir, 'identity')
|
||||||
|
server_identity = RNS.Identity.from_file(identity_file)
|
||||||
|
|
||||||
|
# Create a destination to the server node
|
||||||
|
destination = RNS.Destination(
|
||||||
|
server_identity,
|
||||||
|
RNS.Destination.OUT,
|
||||||
|
RNS.Destination.SINGLE,
|
||||||
|
'nomadnetwork',
|
||||||
|
'node'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure we know a path to the destination
|
||||||
|
if not RNS.Transport.has_path(destination.hash):
|
||||||
|
RNS.Transport.request_path(destination.hash)
|
||||||
|
while not RNS.Transport.has_path(destination.hash):
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
# Establish a link to the server
|
||||||
|
global_link = RNS.Link(destination)
|
||||||
|
|
||||||
|
# Containers for responses
|
||||||
|
responses = {}
|
||||||
|
done_event = threading.Event()
|
||||||
|
|
||||||
|
# Callback for page response
|
||||||
|
def on_page(response):
|
||||||
|
data = response.response
|
||||||
|
if isinstance(data, bytes):
|
||||||
|
text = data.decode('utf-8')
|
||||||
|
else:
|
||||||
|
text = str(data)
|
||||||
|
print('Received page:')
|
||||||
|
print(text)
|
||||||
|
responses['page'] = text
|
||||||
|
if 'file' in responses:
|
||||||
|
done_event.set()
|
||||||
|
|
||||||
|
# Callback for file response
|
||||||
|
def on_file(response):
|
||||||
|
data = response.response
|
||||||
|
# Handle response as [fileobj, headers]
|
||||||
|
if isinstance(data, list) and len(data) == 2 and hasattr(data[0], 'read'):
|
||||||
|
fileobj, headers = data
|
||||||
|
file_data = fileobj.read()
|
||||||
|
filename = headers.get(b'name', b'').decode('utf-8')
|
||||||
|
print(f'Received file ({filename}):')
|
||||||
|
print(file_data.decode('utf-8'))
|
||||||
|
responses['file'] = file_data.decode('utf-8')
|
||||||
|
# Handle response as a raw file object
|
||||||
|
elif hasattr(data, 'read'):
|
||||||
|
file_data = data.read()
|
||||||
|
filename = os.path.basename('text.txt')
|
||||||
|
print(f'Received file ({filename}):')
|
||||||
|
print(file_data.decode('utf-8'))
|
||||||
|
responses['file'] = file_data.decode('utf-8')
|
||||||
|
# Handle response as raw bytes
|
||||||
|
elif isinstance(data, bytes):
|
||||||
|
text = data.decode('utf-8')
|
||||||
|
print('Received file:')
|
||||||
|
print(text)
|
||||||
|
responses['file'] = text
|
||||||
|
else:
|
||||||
|
print('Received file (unhandled format):', data)
|
||||||
|
responses['file'] = str(data)
|
||||||
|
if 'page' in responses:
|
||||||
|
done_event.set()
|
||||||
|
|
||||||
|
# Request the page and file once the link is established
|
||||||
|
def on_link_established(link):
|
||||||
|
link.request('/page/index.mu', None, response_callback=on_page)
|
||||||
|
link.request('/file/text.txt', None, response_callback=on_file)
|
||||||
|
|
||||||
|
# Register callbacks
|
||||||
|
global_link.set_link_established_callback(on_link_established)
|
||||||
|
global_link.set_link_closed_callback(lambda l: done_event.set())
|
||||||
|
|
||||||
|
# Wait for responses or timeout
|
||||||
|
if not done_event.wait(timeout=30):
|
||||||
|
print('Test timed out.', file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if responses.get('page') and responses.get('file'):
|
||||||
|
print('Tests passed!')
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print('Tests failed.', file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
59
tests/test_client2.py
Normal file
59
tests/test_client2.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
import RNS
|
||||||
|
|
||||||
|
dir_path = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
config_dir = os.path.join(dir_path, 'config')
|
||||||
|
|
||||||
|
RNS.Reticulum(config_dir)
|
||||||
|
|
||||||
|
DESTINATION_HEX = '49b2d959db8528347d0a38083aec1042' # Ivans Node that runs rns-page-node
|
||||||
|
|
||||||
|
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH // 8) * 2
|
||||||
|
if len(DESTINATION_HEX) != dest_len:
|
||||||
|
print(f"Invalid destination length (got {len(DESTINATION_HEX)}, expected {dest_len})", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
destination_hash = bytes.fromhex(DESTINATION_HEX)
|
||||||
|
|
||||||
|
if not RNS.Transport.has_path(destination_hash):
|
||||||
|
print("Requesting path to server...")
|
||||||
|
RNS.Transport.request_path(destination_hash)
|
||||||
|
while not RNS.Transport.has_path(destination_hash):
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
server_identity = RNS.Identity.recall(destination_hash)
|
||||||
|
print(f"Recalled server identity for {DESTINATION_HEX}")
|
||||||
|
|
||||||
|
destination = RNS.Destination(
|
||||||
|
server_identity,
|
||||||
|
RNS.Destination.OUT,
|
||||||
|
RNS.Destination.SINGLE,
|
||||||
|
'nomadnetwork',
|
||||||
|
'node'
|
||||||
|
)
|
||||||
|
link = RNS.Link(destination)
|
||||||
|
|
||||||
|
done_event = threading.Event()
|
||||||
|
|
||||||
|
def on_page(response):
|
||||||
|
data = response.response
|
||||||
|
if isinstance(data, bytes):
|
||||||
|
text = data.decode('utf-8')
|
||||||
|
else:
|
||||||
|
text = str(data)
|
||||||
|
print('Fetched page content:')
|
||||||
|
print(text)
|
||||||
|
done_event.set()
|
||||||
|
|
||||||
|
link.set_link_established_callback(lambda l: l.request('/page/index.mu', None, response_callback=on_page))
|
||||||
|
link.set_link_closed_callback(lambda l: done_event.set())
|
||||||
|
|
||||||
|
if not done_event.wait(timeout=30):
|
||||||
|
print('Timed out waiting for page', file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print('Done fetching page.')
|
||||||
|
sys.exit(0)
|
||||||
Reference in New Issue
Block a user