diff --git a/emper/io/IoContext.cpp b/emper/io/IoContext.cpp
index df9eb29b5f8cc1e30dcd798a2101a0dffda122c3..627794785ed2844dd8359cdde8c7db36648ff99e 100644
--- a/emper/io/IoContext.cpp
+++ b/emper/io/IoContext.cpp
@@ -12,7 +12,6 @@
 #include <cerrno>		// for errno, ECANCELED, EBUSY, EAGAIN, EINTR
 #include <chrono>		// for nanoseconds
 #include <cstdio>		// for perror
-#include <cstdlib>	// for exit
 #include <cstring>	// for memset
 #include <memory>		// for allocator
 
@@ -319,12 +318,14 @@ IoContext::IoContext(size_t uring_entries) {
 
 	auto ret = io_uring_queue_init_params(uring_entries, &ring, &params);
 	if (ret < 0) {
-		// skip tests if we are not able to setup an io_uring
-		perror("io_uring_queue_init failed");
-		exit(77);
+		DIE_MSG_ERRNO("io_uring_queue_init failed");
 	}
 	LOGD("Ring fd is " << ring.ring_fd);
 
+	if (!(params.features & IORING_FEAT_NODROP)) {
+		LOGW("kernel das not support IORING_FEAT_NODROP. We may loose IO requests");
+	}
+
 	if constexpr (emper::IO_URING_SQPOLL) {
 		// included in liburing since 41e0d97cb23667df000ce76789297f4e06134a28
 #ifndef IORING_FEAT_SQPOLL_NONFIXED
diff --git a/tests/ConcurrentNetworkEchoTest.cpp b/tests/ConcurrentNetworkEchoTest.cpp
index 864065c082a3e18be1ae73c2cc4b799d54454348..0ccfddabd741ac38be3ecad82dbaa08826f6f35a 100644
--- a/tests/ConcurrentNetworkEchoTest.cpp
+++ b/tests/ConcurrentNetworkEchoTest.cpp
@@ -6,6 +6,7 @@
 #include <vector>
 
 #include "CountingPrivateSemaphore.hpp"
+#include "Emper.hpp"
 #include "Fiber.hpp"
 #include "Runtime.hpp"
 #include "emper.hpp"
@@ -16,6 +17,10 @@
 #define BUF_SIZE 1024
 
 auto main(int argc, char* argv[]) -> int {
+	if constexpr (!emper::IO) {
+		exit(77);
+	}
+
 	unsigned int client_count = 10;
 	unsigned int echos = 1000;
 	int port = PORT;
diff --git a/tests/fixtures/meson.build b/tests/fixtures/meson.build
index 9b3f3c133e3edf7bbccd46b316ee54e831e64e1a..37deaeff07faae79617246e90f2e76481ffa0c14 100644
--- a/tests/fixtures/meson.build
+++ b/tests/fixtures/meson.build
@@ -1,9 +1,6 @@
 test_fixtures_include_dir = include_directories('.')
 
-test_fixtures_sources = []
-if get_option('io')
-	test_fixtures_sources += ['network.cpp']
-endif
+test_fixtures_sources = ['network.cpp']
 
 test_fixtures_lib = library(
 	'test-fixtures',
diff --git a/tests/meson.build b/tests/meson.build
index 264746c299180b903ee127e88d7a0fcdc5e39d37..59ef94140ee78c7597ef35b7764eef9ace4d0093 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -32,7 +32,7 @@ tests = {
 		  'ReuseBpsTest.cpp':
 		  {
 			'description': 'Test resetting of BPSs',
-			'emper_test_runner': true,
+			'test_runner': 'emper',
 		  },
 
 		  'SimpleActorTest.cpp':
@@ -64,92 +64,82 @@ tests = {
 			'description': 'Simple test for PrivateSemaphore:signalFromAnywhere()',
 			'test_suite': 'smoke',
 #			'is_parallel': true,
-			'emper_test_runner': true,
+			'test_runner': 'emper',
 		  },
 		  'TellActorFromAnywhereTest.cpp':
 		  {
 			'description': 'Simple test for Actor:tellFromAnywhere()',
 			'test_suite': 'smoke',
 #			'is_parallel': true,
-			'emper_test_runner': true,
+			'test_runner': 'emper',
 		  },
 
 		  'IncrementalCompletionTest.cpp':
 		  {
-			'feature_flags': ['io'],
 			'description': 'Test incremental completion for hugre reads/writes',
 			'test_suite': 'io',
-			'emper_test_runner': true,
+			'test_runner': 'io',
 		  },
 
 		  'ReuseFutureTest.cpp':
 		  {
-			'feature_flags': ['io'],
 			'description': 'Test reusing Future objects',
 			'test_suite': 'io',
-			'emper_test_runner': true,
+			'test_runner': 'io',
 		  },
 
 		  'LinkFutureTest.cpp':
 		  {
-			'feature_flags': ['io'],
 			'description': 'Test linking Future objects',
 			'test_suite': 'io',
-			'emper_test_runner': true,
+			'test_runner': 'io',
 		  },
 
 		  'TooLongFutureChain.cpp':
 		  {
-			'feature_flags': ['io'],
 			'description': 'Test linking Future objects',
 			'test_suite': 'io',
 			'should_fail': true,
-			'emper_test_runner': true,
+			'test_runner': 'io',
 		  },
 
 		  'AlarmFutureTest.cpp':
 		  {
-			'feature_flags': ['io'],
 			'description': 'Test AlarmFuture object based timeouts',
 			'test_suite': 'io',
-			'emper_test_runner': true,
+			'test_runner': 'io',
 		  },
 
 		  'TimeoutWrapperTest.cpp':
 		  {
-			'feature_flags': ['io'],
 			'description': 'Test TimeoutWrapper object based IO request timeouts',
 			'test_suite': 'io',
-			'emper_test_runner': true,
+			'test_runner': 'io',
 		  },
 
 		  'CancelFutureTest.cpp':
 		  {
-			'feature_flags': ['io'],
 			'description': 'Test Future cancellation',
 			'test_suite': 'io',
-			'emper_test_runner': true,
+			'test_runner': 'io',
 		  },
 
 		  'SimpleNetworkTest.cpp':
 		  {
-			'feature_flags': ['io'],
 			'description': 'Simple network test',
 			'test_suite': 'io',
-			'emper_test_runner': true,
+			'test_runner': 'io',
 		  },
 
 		  'SimpleDiskAndNetworkTest.cpp':
 		  {
-			'feature_flags': ['io'],
 			'description': 'Simple network and disk IO test',
 			'test_suite': 'io',
-			'emper_test_runner': true,
+			'test_runner': 'io',
 		  },
 
 		  'ConcurrentNetworkEchoTest.cpp':
 		  {
-			'feature_flags': ['io'],
 			'description': 'Concurrent network echo test with 10 clients',
 			'test_suite': 'io',
 			'args': ['10', '10000'],
@@ -170,20 +160,6 @@ test_env = environment(
 subdir('test-runner')
 
 foreach source, test_dict : tests
-  # check feature flags
-  if test_dict.has_key('feature_flags')
-    include_test = true
-    foreach flag : test_dict.get('feature_flags')
-      if not get_option(flag)
-        include_test = false
-        break
-      endif
-    endforeach
-
-    if not include_test
-      continue
-    endif
-  endif
   # TODO: Use meson fs (filesystem) module once meson >= 0.53 is in
   # buster-backports, instead of split('.')[0]
   # test_name = fs.replace_suffix(source, '')
@@ -195,8 +171,8 @@ foreach source, test_dict : tests
   	test_deps += test_dict['dependencies']
   endif
 
-  if test_dict.get('emper_test_runner', false)
-	test_deps += emper_test_runner_dep
+  if test_dict.has_key('test_runner')
+	test_deps += test_runners[test_dict['test_runner']]
   endif
 
   test_exe = executable(test_name,
diff --git a/tests/test-runner/emper-test-runner.cpp b/tests/test-runner/emper-test-runner.cpp
index 711e757ff931b0d931905de52e15f6e5050cbf8a..b212119fe7853946bcf8e840d57d03617a177d9f 100644
--- a/tests/test-runner/emper-test-runner.cpp
+++ b/tests/test-runner/emper-test-runner.cpp
@@ -1,33 +1,6 @@
 // SPDX-License-Identifier: LGPL-3.0-or-later
 // Copyright © 2020 Florian Schmaus
-#include <cstdlib>
-#include <iostream>
-
-#include "Fiber.hpp"
-#include "Runtime.hpp"
 #include "emper-common.h"
+#include "test-runner.hpp"
 
-void emperTest() __attribute__((weak));
-
-static void invokeTest() {
-	emperTest();
-
-	exit(EXIT_SUCCESS);
-}
-
-auto main(UNUSED_ARG int argc, UNUSED_ARG char* argv[]) -> int {
-	if (!&emperTest) {
-		std::cerr << "ERROR: The emperTest() method is not defined.";
-		return EXIT_FAILURE;
-	}
-
-	Runtime runtime;
-
-	Fiber* alphaFiber = Fiber::from(&invokeTest);
-
-	runtime.scheduleFromAnywhere(*alphaFiber);
-
-	runtime.waitUntilFinished();
-
-	return EXIT_FAILURE;
-}
+auto main(UNUSED_ARG int argc, UNUSED_ARG char* argv[]) -> int { return testMain(); }
diff --git a/tests/test-runner/io-test-runner.cpp b/tests/test-runner/io-test-runner.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ed4a4b68590af53513254ffa52b20cd8a6b353ce
--- /dev/null
+++ b/tests/test-runner/io-test-runner.cpp
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// Copyright © 2020-2021 Florian Schmaus, Florian Fischer
+#include <cstdlib>
+
+#include "Emper.hpp"
+#include "emper-common.h"
+#include "test-runner.hpp"
+
+auto main(UNUSED_ARG int argc, UNUSED_ARG char* argv[]) -> int {
+	if constexpr (!emper::IO) {
+		exit(77);
+	}
+	return testMain();
+}
diff --git a/tests/test-runner/meson.build b/tests/test-runner/meson.build
index 151b2cab19e3e5e86fc15a1b67ffb173660ddcd8..a949890e9ae87fda8bc020fdb3b2aebe84dee393 100644
--- a/tests/test-runner/meson.build
+++ b/tests/test-runner/meson.build
@@ -1,8 +1,18 @@
-emper_test_runner_lib = library('emper-test-runner',
-								'emper-test-runner.cpp',
-								dependencies: emper_dep
-							   )
+test_runners = {}
 
-emper_test_runner_dep = declare_dependency(
-  link_with : emper_test_runner_lib
-)
+avail_test_runners = {
+	'emper': {
+		'sources': ['emper-test-runner.cpp'],
+	},
+	'io': {
+		'sources': ['io-test-runner.cpp'],
+	},
+}
+
+foreach runner, runner_dict : avail_test_runners
+	  runner_lib = library(runner + '-test-runner',
+	                       ['test-runner.cpp'] + runner_dict['sources'],
+	                       dependencies: [emper_dep] + runner_dict.get('deps', []))
+
+	test_runners += {runner: declare_dependency(link_with: runner_lib)}
+endforeach
diff --git a/tests/test-runner/test-runner.cpp b/tests/test-runner/test-runner.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b78c7615eeda81ebc88ab6b7e81967cd02de896f
--- /dev/null
+++ b/tests/test-runner/test-runner.cpp
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// Copyright © 2020-2021 Florian Schmaus, Florian Fischer
+#include "test-runner.hpp"
+
+#include <cstdlib>
+#include <iostream>
+
+#include "Fiber.hpp"
+#include "Runtime.hpp"
+
+void invokeTest() {
+	emperTest();
+
+	exit(EXIT_SUCCESS);
+}
+
+auto testMain() -> int {
+	if (!&emperTest) {
+		std::cerr << "ERROR: The emperTest() method is not defined.";
+		return EXIT_FAILURE;
+	}
+
+	Runtime runtime;
+
+	Fiber* alphaFiber = Fiber::from(&invokeTest);
+
+	runtime.scheduleFromAnywhere(*alphaFiber);
+
+	runtime.waitUntilFinished();
+
+	return EXIT_FAILURE;
+}
diff --git a/tests/test-runner/test-runner.hpp b/tests/test-runner/test-runner.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3819bafcee771741d98fbaafd14fbaa160658cc8
--- /dev/null
+++ b/tests/test-runner/test-runner.hpp
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// Copyright © 2020-2021 Florian Schmaus, Florian Fischer
+#pragma once
+void emperTest() __attribute__((weak));
+
+void invokeTest();
+
+auto testMain() -> int;