aboutsummaryrefslogtreecommitdiff
path: root/test/native
diff options
context:
space:
mode:
authorJohannes Stoelp <johannes.stoelp@gmail.com>2022-01-14 23:51:05 +0100
committerJohannes Stoelp <johannes.stoelp@gmail.com>2022-01-14 23:51:05 +0100
commitf9928a1a08c57fe853888119a996c3acc98ee09d (patch)
treec9770b76ffcc281da141f3aa2c595600372c0fca /test/native
downloadpio-nodemcuv2-dhcp-server-f9928a1a08c57fe853888119a996c3acc98ee09d.tar.gz
pio-nodemcuv2-dhcp-server-f9928a1a08c57fe853888119a996c3acc98ee09d.zip
Initial version of nodemcuv2 dhcp serverHEADmain
Able to offer IP address + DNS/Gateway ... Worked with devices at my hand.
Diffstat (limited to 'test/native')
-rw-r--r--test/native/dhcp.cc65
-rw-r--r--test/native/hash.cc71
-rw-r--r--test/native/lease_db.cc85
3 files changed, 221 insertions, 0 deletions
diff --git a/test/native/dhcp.cc b/test/native/dhcp.cc
new file mode 100644
index 0000000..983c6c8
--- /dev/null
+++ b/test/native/dhcp.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2022 Johannes Stoelp
+
+#include <dhcp.h>
+#include <utils.h>
+
+#include <gtest/gtest.h>
+
+TEST(option, get_available_opt) {
+ u8 opts[] = {
+ into_raw(dhcp_option::PAD), into_raw(dhcp_option::PAD), into_raw(dhcp_option::DHCP_MESSAGE_TYPE), 5 /* len */, 0, 1, 2, 3, 4,
+ into_raw(dhcp_option::END),
+ };
+
+ auto ov = get_option(opts, sizeof(opts), dhcp_option::DHCP_MESSAGE_TYPE);
+
+ ASSERT_EQ(true, ov.has_value());
+ ASSERT_EQ(0, ov.value().data[0]);
+ ASSERT_EQ(1, ov.value().data[1]);
+ ASSERT_EQ(2, ov.value().data[2]);
+ ASSERT_EQ(3, ov.value().data[3]);
+ ASSERT_EQ(4, ov.value().data[4]);
+ ASSERT_EQ(5, ov.value().len);
+}
+
+TEST(option, maleformed_len) {
+ u8 opts[] = {
+ into_raw(dhcp_option::PAD), into_raw(dhcp_option::PAD), into_raw(dhcp_option::DHCP_MESSAGE_TYPE), 5 /* len */, 0,
+ into_raw(dhcp_option::END),
+ };
+
+ {
+ auto ov = get_option(opts, sizeof(opts), dhcp_option::DHCP_MESSAGE_TYPE);
+
+ ASSERT_EQ(false, ov.has_value());
+ }
+ {
+ auto ov = get_option(opts, sizeof(opts), dhcp_option::CLASS_ID);
+
+ ASSERT_EQ(false, ov.has_value());
+ }
+}
+
+TEST(option, maleformed_missing_end) {
+ u8 opts[] = {
+ into_raw(dhcp_option::PAD),
+ into_raw(dhcp_option::PAD),
+ };
+
+ auto ov = get_option(opts, sizeof(opts), dhcp_option::DHCP_MESSAGE_TYPE);
+
+ ASSERT_EQ(false, ov.has_value());
+}
+
+TEST(option, put_opt_val) {
+ u8 options[8] = {0};
+ u32 val = 0xdeadbeef;
+
+ u8* nextp = put_opt_val(options, val);
+
+ ASSERT_EQ(options + 4, nextp);
+ ASSERT_EQ(0xde, options[0]);
+ ASSERT_EQ(0xad, options[1]);
+ ASSERT_EQ(0xbe, options[2]);
+ ASSERT_EQ(0xef, options[3]);
+} \ No newline at end of file
diff --git a/test/native/hash.cc b/test/native/hash.cc
new file mode 100644
index 0000000..8aa0a35
--- /dev/null
+++ b/test/native/hash.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2022 Johannes Stoelp
+
+#include <types.h>
+#include <utils.h>
+
+#include <filesystem>
+#include <fstream>
+#include <gtest/gtest.h>
+#include <iostream>
+#include <vector>
+
+using ID = std::array<u8, 6>;
+namespace fs = std::filesystem;
+
+std::vector<ID> read_blob() {
+ if (!fs::exists("blob")) {
+ std::system("dd if=/dev/urandom of=blob count=16 bs=1M");
+ }
+
+ std::vector<ID> ids;
+ ids.reserve(fs::file_size("blob") / sizeof(ID));
+
+ auto ifs = std::ifstream("blob");
+ assert(ifs.is_open());
+ ID id;
+ while (ifs.read((char*)id.data(), sizeof(id))) {
+ ids.push_back(id);
+ }
+
+ return ids;
+}
+
+TEST(hash, uniform_distribuation) {
+ constexpr usize BUCKETS = 64;
+ constexpr float BUCKET_SIZE = static_cast<float>(100) / BUCKETS; // Bucket size in percent.
+ constexpr float BUCKET_ERR = BUCKET_SIZE * 0.05 /* 5% */; // Allowed distribution error.
+
+ const auto ids = read_blob();
+
+ usize cnt[BUCKETS] = {0};
+ for (const auto& id : ids) {
+ u32 h = hash(id.data(), id.size());
+ cnt[h % BUCKETS] += 1;
+ }
+
+ for (usize b = 0; b < BUCKETS; ++b) {
+ const float dist = static_cast<float>(cnt[b]) / ids.size() * 100;
+ ASSERT_GT(dist, BUCKET_SIZE - BUCKET_ERR);
+ ASSERT_LT(dist, BUCKET_SIZE + BUCKET_ERR);
+ // printf("bucket %2ld: %5.2f (%ld)\n", b, dist, cnt[b]);
+ }
+}
+
+TEST(hash, DISABLED_collisions) {
+ const auto ids = read_blob();
+
+ std::unordered_map<u32, usize> hits;
+ for (const auto& id : ids) {
+ u32 h = hash(id.data(), id.size());
+ hits[h] = hits[h] + 1;
+ }
+
+ usize collisions = 0;
+ for (const auto& hit : hits) {
+ if (hit.second > 1) {
+ ++collisions;
+ }
+ }
+
+ printf("Hashed %ld values got %ld collisions\n", ids.size(), collisions);
+}
diff --git a/test/native/lease_db.cc b/test/native/lease_db.cc
new file mode 100644
index 0000000..8f87912
--- /dev/null
+++ b/test/native/lease_db.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2022 Johannes Stoelp
+
+#include <lease_db.h>
+
+#include <gtest/gtest.h>
+
+TEST(lease_db, null_client_hash) {
+ lease_db<2> db;
+
+ ASSERT_EQ(std::nullopt, db.new_lease(0, 0));
+ ASSERT_EQ(std::nullopt, db.get_lease(0));
+ ASSERT_EQ(0, db.active_leases());
+}
+
+TEST(lease_db, get_new_lease) {
+ lease_db<2> db;
+
+ ASSERT_EQ(std::optional(0), db.new_lease(10, 0));
+ ASSERT_EQ(std::optional(1), db.new_lease(20, 0));
+ ASSERT_EQ(std::nullopt, db.new_lease(30, 0)); // exhausted
+
+ ASSERT_EQ(std::optional(0), db.get_lease(10));
+ ASSERT_EQ(std::optional(1), db.get_lease(20));
+ ASSERT_EQ(std::nullopt, db.get_lease(30)); // exhausted
+
+ ASSERT_EQ(2, db.active_leases());
+}
+
+TEST(lease_db, get_new_lease_twice) {
+ lease_db<2> db;
+
+ ASSERT_EQ(std::optional(0), db.new_lease(10, 0));
+ ASSERT_EQ(std::nullopt, db.new_lease(10, 0));
+
+ ASSERT_EQ(1, db.active_leases());
+}
+
+TEST(lease_db, flush_expired) {
+ lease_db<2> db;
+
+ ASSERT_EQ(std::optional(0), db.new_lease(10, 100 /* lease end */));
+ ASSERT_EQ(std::optional(1), db.new_lease(20, 200 /* lease end */));
+
+ db.flush_expired(50 /* current time */);
+ ASSERT_EQ(2, db.active_leases());
+ ASSERT_EQ(std::optional(0), db.get_lease(10));
+ ASSERT_EQ(std::optional(1), db.get_lease(20));
+
+ db.flush_expired(150 /* current time */);
+ ASSERT_EQ(1, db.active_leases());
+ ASSERT_EQ(std::nullopt, db.get_lease(10));
+ ASSERT_EQ(std::optional(1), db.get_lease(20));
+
+ db.flush_expired(250 /* current time */);
+ ASSERT_EQ(0, db.active_leases());
+ ASSERT_EQ(std::nullopt, db.get_lease(10));
+ ASSERT_EQ(std::nullopt, db.get_lease(20));
+}
+
+TEST(lease_db, update_lease) {
+ lease_db<2> db;
+
+ ASSERT_EQ(std::optional(0), db.new_lease(10, 100 /* lease end */));
+ ASSERT_EQ(std::optional(1), db.new_lease(20, 200 /* lease end */));
+
+ ASSERT_EQ(2, db.active_leases());
+
+ db.flush_expired(150 /* current time */);
+ ASSERT_EQ(1, db.active_leases());
+ ASSERT_EQ(std::nullopt, db.get_lease(10));
+ ASSERT_EQ(std::optional(1), db.get_lease(20));
+
+ ASSERT_EQ(false, db.update_lease(10, 300 /* lease end */));
+ ASSERT_EQ(true, db.update_lease(20, 300 /* lease end */));
+
+ db.flush_expired(250 /* current time */);
+ ASSERT_EQ(1, db.active_leases());
+ ASSERT_EQ(std::nullopt, db.get_lease(10));
+ ASSERT_EQ(std::optional(1), db.get_lease(20));
+
+ db.flush_expired(350 /* current time */);
+ ASSERT_EQ(0, db.active_leases());
+ ASSERT_EQ(std::nullopt, db.get_lease(10));
+ ASSERT_EQ(std::nullopt, db.get_lease(20));
+}