diff --git a/tests/riotboot/Makefile b/tests/riotboot/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..c4b90fa4e37902fbb9797527daa8baf38c1d5798
--- /dev/null
+++ b/tests/riotboot/Makefile
@@ -0,0 +1,34 @@
+# If no BOARD is found in the environment, use this default:
+BOARD ?= samr21-xpro
+
+TEST_ON_CI_WHITELIST += all
+
+# Select the boards with riotboot feature
+FEATURES_REQUIRED += riotboot
+
+# Include modules to test the bootloader
+USEMODULE += riotboot_slot
+USEMODULE += shell
+
+# Comment this out to disable code in RIOT that does safety checking
+# which is not needed in a production environment but helps in the
+# development process:
+DEVELHELP ?= 1
+
+# Change this to 0 show compiler invocation lines by default:
+QUIET ?= 1
+
+all: riotboot
+
+include ../Makefile.tests_common
+include $(RIOTBASE)/Makefile.include
+
+# Make 'flash' and 'flash-only' work without specific command.
+# This is currently hacky as there is no way of specifiying a FLASHFILE
+all: riotboot/combined-slot0
+# openocd
+ELFFILE = $(BINDIR_APP)-slot0-combined.bin
+# edbg
+HEXFILE = $(BINDIR_APP)-slot0-combined.bin
+# murdock uses ':=' to get the flashfile variable so should also be overwritten
+FLASHFILE = $(BINDIR_APP)-slot0-combined.bin
diff --git a/tests/riotboot/README.md b/tests/riotboot/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..09ae0e25f9fca1b3b9a3052bff51d2d901e7eaaa
--- /dev/null
+++ b/tests/riotboot/README.md
@@ -0,0 +1,18 @@
+RIOT bootloader test
+====================
+
+This is a basic example how to use RIOT bootloader in your embedded
+application.
+
+This test should foremost give you an overview how to use riotboot:
+
+  - `make all` build the test using the target riotboot, which generates
+  a binary file of the application with a header on top of it, used by
+  the bootloader to recognise a bootable image.
+
+  - `make riotboot/flash` creates the binary files and flashes both
+  riotboot and the RIOT image with headers included. This should boot
+  as a normal application.
+
+In this test two modules `riot_hdr` and `slot_util` are used to showcase
+the access to riotboot shared functions.
diff --git a/tests/riotboot/main.c b/tests/riotboot/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..8064b41d2bb57f03b7eaabcadfae22c2dca81f98
--- /dev/null
+++ b/tests/riotboot/main.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 Inria
+ *                    Federico Pellegrin <fede@evolware.org>
+ *
+ * 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       riotboot bootloader test
+ *
+ * @author      Francisco Acosta <francisco.acosta@inria.fr>
+ * @author      Federico Pellegrin <fede@evolware.org>
+ *
+ * @}
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include "riotboot/slot.h"
+#include "shell.h"
+
+static int cmd_print_slot_nr(int argc, char **argv)
+{
+    (void)argc;
+    (void)argv;
+
+    printf("Current slot=%d\n", riotboot_slot_current());
+    return 0;
+}
+
+static int cmd_print_slot_hdr(int argc, char **argv)
+{
+    (void)argc;
+    (void)argv;
+
+    int current_slot = riotboot_slot_current();
+    riotboot_slot_print_hdr(current_slot);
+    return 0;
+}
+
+static int cmd_print_slot_addr(int argc, char **argv)
+{
+    (void)argc;
+
+    int reqslot=atoi(argv[1]);
+    printf("Slot %d address=0x%08" PRIx32 "\n",
+           reqslot, riotboot_slot_get_image_startaddr(reqslot));
+    return 0;
+}
+
+static int cmd_dumpaddrs(int argc, char **argv)
+{
+    (void)argc;
+    (void)argv;
+
+    riotboot_slot_dump_addrs();
+    return 0;
+}
+
+static const shell_command_t shell_commands[] = {
+    { "curslotnr", "Print current slot number", cmd_print_slot_nr },
+    { "curslothdr", "Print current slot header", cmd_print_slot_hdr },
+    { "getslotaddr", "Print address of requested slot", cmd_print_slot_addr },
+    { "dumpaddrs", "Prints all slot data in header", cmd_dumpaddrs },
+    { NULL, NULL, NULL }
+};
+
+int main(void)
+{
+    int current_slot;
+
+    puts("Hello riotboot!");
+
+    printf("You are running RIOT on a(n) %s board.\n", RIOT_BOARD);
+    printf("This board features a(n) %s MCU.\n", RIOT_MCU);
+
+    /* print some information about the running image */
+    current_slot = riotboot_slot_current();
+    if (current_slot != -1) {
+        printf("riotboot_test: running from slot %d\n", current_slot);
+        riotboot_slot_print_hdr(current_slot);
+    }
+    else {
+        printf("[FAILED] You're not running riotboot\n");
+    }
+
+    /* run the shell */
+    char line_buf[SHELL_DEFAULT_BUFSIZE];
+    shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
+    return 0;
+}