mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-18 12:52:44 +01:00
tests/gcoap_fileserver: add integration test for GCoAP fileserver
This commit is contained in:
parent
66452d15ae
commit
c5282bb2ad
46
tests/gcoap_fileserver/Makefile
Normal file
46
tests/gcoap_fileserver/Makefile
Normal file
@ -0,0 +1,46 @@
|
||||
include ../Makefile.tests_common
|
||||
|
||||
USEMODULE += auto_init_gnrc_netif
|
||||
USEMODULE += auto_init_gnrc_rpl
|
||||
USEMODULE += gnrc_ipv6_router_default
|
||||
USEMODULE += gnrc_icmpv6_echo
|
||||
USEMODULE += gnrc_rpl
|
||||
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
|
||||
USEMODULE += gcoap_fileserver
|
||||
USEMODULE += nanocoap_vfs
|
||||
|
||||
USEMODULE += constfs
|
||||
USEMODULE += vfs_default
|
||||
USEMODULE += vfs_auto_format
|
||||
|
||||
USEMODULE += md5sum
|
||||
|
||||
# automated test only works on native
|
||||
TEST_ON_CI_WHITELIST += native
|
||||
|
||||
# use small blocksize for test to increase chance for errors
|
||||
CFLAGS += -DCONFIG_NANOCOAP_BLOCKSIZE_DEFAULT=COAP_BLOCKSIZE_16
|
||||
CFLAGS += -DCONFIG_COAP_ACK_TIMEOUT_MS=100UL
|
||||
CFLAGS += -DCONFIG_COAP_MAX_RETRANSMIT=10
|
||||
|
||||
ifeq (native, $(BOARD))
|
||||
USEMODULE += socket_zep
|
||||
USEMODULE += socket_zep_hello
|
||||
USEMODULE += netdev
|
||||
TERMFLAGS += -z 127.0.0.1:17754 # Murdock has no IPv6 support
|
||||
else
|
||||
USEMODULE += netdev_default
|
||||
endif
|
||||
|
||||
.PHONY: host-tools
|
||||
|
||||
# Build zep_dispatch
|
||||
host-tools:
|
||||
$(Q)env -u CC -u CFLAGS $(MAKE) -C $(RIOTTOOLS)
|
||||
|
||||
TERMDEPS += host-tools
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
46
tests/gcoap_fileserver/Makefile.ci
Normal file
46
tests/gcoap_fileserver/Makefile.ci
Normal file
@ -0,0 +1,46 @@
|
||||
BOARD_INSUFFICIENT_MEMORY := \
|
||||
arduino-duemilanove \
|
||||
arduino-leonardo \
|
||||
arduino-mega2560 \
|
||||
arduino-nano \
|
||||
arduino-uno \
|
||||
atmega1284p \
|
||||
atmega328p \
|
||||
atmega328p-xplained-mini \
|
||||
atxmega-a3bu-xplained \
|
||||
blackpill \
|
||||
bluepill \
|
||||
bluepill-stm32f030c8 \
|
||||
derfmega128 \
|
||||
i-nucleo-lrwan1 \
|
||||
im880b \
|
||||
m1284p \
|
||||
mega-xplained \
|
||||
microduino-corerf \
|
||||
msb-430 \
|
||||
msb-430h \
|
||||
nucleo-f030r8 \
|
||||
nucleo-f031k6 \
|
||||
nucleo-f042k6 \
|
||||
nucleo-f302r8 \
|
||||
nucleo-f303k8 \
|
||||
nucleo-f334r8 \
|
||||
nucleo-l011k4 \
|
||||
nucleo-l031k6 \
|
||||
nucleo-l053r8 \
|
||||
samd10-xmini \
|
||||
saml10-xpro \
|
||||
saml11-xpro \
|
||||
slstk3400a \
|
||||
stk3200 \
|
||||
stm32f030f4-demo \
|
||||
stm32f0discovery \
|
||||
stm32f7508-dk \
|
||||
stm32g0316-disco \
|
||||
stm32l0538-disco \
|
||||
stm32mp157c-dk2 \
|
||||
telosb \
|
||||
waspmote-pro \
|
||||
z1 \
|
||||
zigduino \
|
||||
#
|
94
tests/gcoap_fileserver/main.c
Normal file
94
tests/gcoap_fileserver/main.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2022 ML!PA Consulting GmbH
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief test application for the GCoAP file server
|
||||
*
|
||||
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "fs/constfs.h"
|
||||
#include "net/gcoap.h"
|
||||
#include "net/gcoap/fileserver.h"
|
||||
#include "shell.h"
|
||||
#include "vfs_default.h"
|
||||
|
||||
#define MAIN_QUEUE_SIZE (4)
|
||||
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];
|
||||
|
||||
/* CoAP resources. Must be sorted by path (ASCII order). */
|
||||
static const coap_resource_t _resources[] = {
|
||||
{ "/const", COAP_GET | COAP_MATCH_SUBTREE, gcoap_fileserver_handler, "/const" },
|
||||
};
|
||||
|
||||
static gcoap_listener_t _listener = {
|
||||
.resources = _resources,
|
||||
.resources_len = ARRAY_SIZE(_resources),
|
||||
};
|
||||
|
||||
static const char song[] =
|
||||
"Join us now and share the software;\n"
|
||||
"You'll be free, hackers, you'll be free.\n"
|
||||
"Join us now and share the software;\n"
|
||||
"You'll be free, hackers, you'll be free.\n"
|
||||
"\n"
|
||||
"Hoarders can get piles of money,\n"
|
||||
"That is true, hackers, that is true.\n"
|
||||
"But they cannot help their neighbors;\n"
|
||||
"That's not good, hackers, that's not good.\n"
|
||||
"\n"
|
||||
"When we have enough free software\n"
|
||||
"At our call, hackers, at our call,\n"
|
||||
"We'll kick out those dirty licenses\n"
|
||||
"Ever more, hackers, ever more.\n"
|
||||
"\n"
|
||||
"Join us now and share the software;\n"
|
||||
"You'll be free, hackers, you'll be free.\n"
|
||||
"Join us now and share the software;\n"
|
||||
"You'll be free, hackers, you'll be free.\n";
|
||||
|
||||
/* this defines two const files in the constfs */
|
||||
static constfs_file_t constfs_files[] = {
|
||||
{
|
||||
.path = "/song.txt",
|
||||
.size = sizeof(song),
|
||||
.data = song,
|
||||
},
|
||||
};
|
||||
|
||||
/* this is the constfs specific descriptor */
|
||||
static constfs_t constfs_desc = {
|
||||
.nfiles = ARRAY_SIZE(constfs_files),
|
||||
.files = constfs_files,
|
||||
};
|
||||
|
||||
/* constfs mount point, as for previous example, it needs a file system driver,
|
||||
* a mount point and private_data as a pointer to the constfs descriptor */
|
||||
static vfs_mount_t const_mount = {
|
||||
.fs = &constfs_file_system,
|
||||
.mount_point = "/const",
|
||||
.private_data = &constfs_desc,
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
vfs_mount(&const_mount);
|
||||
|
||||
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
|
||||
gcoap_register_listener(&_listener);
|
||||
|
||||
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||
|
||||
return 0;
|
||||
}
|
122
tests/gcoap_fileserver/tests/01-run.py
Executable file
122
tests/gcoap_fileserver/tests/01-run.py
Executable file
@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2022 Benjamin Valentin
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU Lesser
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
# directory for more details.
|
||||
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
from subprocess import Popen
|
||||
from riotctrl_shell.gnrc import GNRCICMPv6Echo, GNRCICMPv6EchoParser
|
||||
from riotctrl_shell.netif import Ifconfig
|
||||
from riotctrl.ctrl import RIOTCtrlBoardFactory
|
||||
from riotctrl_ctrl import native
|
||||
from riotctrl_shell.netif import IfconfigListParser
|
||||
|
||||
PARSERS = {
|
||||
"ping6": GNRCICMPv6EchoParser(),
|
||||
"ifconfig": IfconfigListParser(),
|
||||
}
|
||||
|
||||
|
||||
class RIOTCtrlAppFactory(RIOTCtrlBoardFactory):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(board_cls={
|
||||
'native': native.NativeRIOTCtrl,
|
||||
})
|
||||
self.ctrl_list = list()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *exc):
|
||||
for ctrl in self.ctrl_list:
|
||||
ctrl.stop_term()
|
||||
|
||||
def get_shell(self, application_directory='.', env={'BOARD': 'native'}):
|
||||
# retrieve a RIOTCtrl Object
|
||||
ctrl = super().get_ctrl(
|
||||
env=env,
|
||||
application_directory=application_directory
|
||||
)
|
||||
# append ctrl to list
|
||||
self.ctrl_list.append(ctrl)
|
||||
# start terminal
|
||||
ctrl.start_term()
|
||||
# return ctrl with started terminal
|
||||
return Shell(ctrl)
|
||||
|
||||
def get_shells(self, num=1):
|
||||
terms = []
|
||||
for i in range(num):
|
||||
terms.append(self.get_shell())
|
||||
return terms
|
||||
|
||||
|
||||
class Shell(Ifconfig, GNRCICMPv6Echo):
|
||||
pass
|
||||
|
||||
|
||||
def first_netif_and_addr_by_scope(ifconfig_out, scope):
|
||||
netifs = PARSERS["ifconfig"].parse(ifconfig_out)
|
||||
key = next(iter(netifs))
|
||||
netif = netifs[key]
|
||||
return (
|
||||
key,
|
||||
[addr["addr"] for addr in netif["ipv6_addrs"] if addr["scope"] == scope][0],
|
||||
)
|
||||
|
||||
|
||||
def global_addr(ifconfig_out):
|
||||
return first_netif_and_addr_by_scope(ifconfig_out, "global")
|
||||
|
||||
|
||||
def test_linear_topology(factory, zep_dispatch):
|
||||
|
||||
# linear topology with 3 nodes and 25% packet loss
|
||||
topology = ("A C 0.75\n"
|
||||
"C B 0.75\n")
|
||||
zep_dispatch.stdin.write(topology.encode())
|
||||
zep_dispatch.stdin.close()
|
||||
|
||||
# create native instances
|
||||
nodes = factory.get_shells(3)
|
||||
A = nodes[0]
|
||||
B = nodes[2]
|
||||
|
||||
# add prefix to root node
|
||||
A.cmd("nib prefix add 7 2001:db8::/32")
|
||||
A.cmd("ifconfig 7 add 2001:db8::1/32")
|
||||
A.cmd("rpl root 0 2001:db8::1")
|
||||
|
||||
# wait for the creation of the DODAG
|
||||
time.sleep(10)
|
||||
|
||||
# Download file from CoAP server
|
||||
B.cmd("vfs rm /nvm0/song.txt")
|
||||
B.cmd("ncget coap://[2001:db8::1]/const/song.txt", timeout=60)
|
||||
|
||||
# make sure the content matches
|
||||
assert A.cmd("md5sum /const/song.txt").split()[2] == B.cmd("md5sum /nvm0/song.txt").split()[2]
|
||||
|
||||
# terminate nodes
|
||||
for n in nodes:
|
||||
n.stop_term()
|
||||
|
||||
|
||||
def run_test(func, factory):
|
||||
with Popen(['../../dist/tools/zep_dispatch/bin/zep_dispatch',
|
||||
'-t', '-', '127.0.0.1', '17754'], stdin=subprocess.PIPE) as zep_dispatch:
|
||||
try:
|
||||
func(factory, zep_dispatch)
|
||||
finally:
|
||||
zep_dispatch.terminate()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
with RIOTCtrlAppFactory() as factory:
|
||||
run_test(test_linear_topology, factory)
|
Loading…
Reference in New Issue
Block a user