diff --git a/src/lib/salad/mhash.h b/src/lib/salad/mhash.h
index a9b0e4d90b3996a36b191b64400b67c77b1800d8..b555cad4ce0ab840e6c5c2bd4768df6f488d4c4f 100644
--- a/src/lib/salad/mhash.h
+++ b/src/lib/salad/mhash.h
@@ -238,13 +238,10 @@ _mh(get)(struct _mh(t) *h, const mh_node_t *node,
 static inline mh_int_t
 _mh(random)(struct _mh(t) *h, mh_int_t rnd)
 {
-	for (mh_int_t i = 0; i < mh_size(h); i++, rnd++) {
-		rnd %= h->n_buckets;
-		if (mh_exist(h, rnd))
-			return rnd;
-	}
-
-	return h->n_buckets;
+	mh_int_t res = mh_next(h, rnd % mh_end(h));
+	if (res != mh_end(h))
+		return res;
+	return mh_first(h);
 }
 
 static inline mh_int_t
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index 04bc659e792929d3e0224cf964874b8f84bf8d9b..c13528400c2f29b8ce0bc4622d81da94d3dcb9cc 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -25,7 +25,9 @@ add_executable(uri.test uri.c unit.c)
 target_link_libraries(uri.test uri unit)
 add_executable(queue.test queue.c)
 add_executable(mhash.test mhash.c)
+target_link_libraries(mhash.test unit)
 add_executable(mhash_bytemap.test mhash_bytemap.c)
+target_link_libraries(mhash_bytemap.test unit)
 add_executable(rope_basic.test rope_basic.c)
 target_link_libraries(rope_basic.test salad)
 add_executable(rope_avl.test rope_avl.c)
diff --git a/test/unit/mhash.c b/test/unit/mhash.c
index 72f9b57fa9c93cd8a83c6d13bf12ef46518391e9..5f37ae8d46addf176dc7cdbdfa7ada9efcd590fc 100644
--- a/test/unit/mhash.c
+++ b/test/unit/mhash.c
@@ -1,5 +1,6 @@
 #include <stdint.h>
 #include <stdio.h>
+#include <stdbool.h>
 #include "unit.h"
 
 #ifndef bytemap
@@ -38,6 +39,7 @@ struct mh_i32_collision_node_t {
 static void mhash_int32_id_test()
 {
 	header();
+	plan(0);
 	int k;
 	struct mh_i32_t *h;
 #define init()		({ mh_i32_new();		})
@@ -59,12 +61,14 @@ static void mhash_int32_id_test()
 
 #include "mhash_body.c"
 	footer();
+	check_plan();
 }
 
 
 static void mhash_int32_collision_test()
 {
 	header();
+	plan(0);
 	int k;
 	struct mh_i32_collision_t *h;
 #define init()		({ mh_i32_collision_new();		})
@@ -86,11 +90,69 @@ static void mhash_int32_collision_test()
 
 #include "mhash_body.c"
 	footer();
+	check_plan();
+}
+
+static void
+mhash_random_test(void)
+{
+	header();
+	plan(3);
+	struct mh_i32_t *h = mh_i32_new();
+	const int end = 100;
+	int i, size;
+	bool is_found[end], all_is_found[end];
+	memset(all_is_found, 1, sizeof(all_is_found));
+
+	for (i = 0; i < end; ++i) {
+		if (mh_i32_random(h, i) != mh_end(h))
+			break;
+	}
+	is(i, end, "empty random is always 'end'");
+
+	for (i = 0; i < end; ++i) {
+		struct mh_i32_node_t node = {i, i};
+		mh_int_t rc = mh_i32_put(h, &node, NULL, NULL);
+		int j;
+		for (j = 0; j < end; ++j) {
+			if (mh_i32_random(h, j) != rc)
+				break;
+		}
+		mh_i32_del(h, rc, NULL);
+		if (j != end)
+			break;
+	}
+	is(i, end, "one element is always found");
+
+	for (i = 0, size = sizeof(bool); i < end; ++i, size += sizeof(bool)) {
+		struct mh_i32_node_t *n, node = {i, i};
+		mh_i32_put(h, &node, NULL, NULL);
+		memset(is_found, 0, sizeof(is_found));
+		for (int j = 0; j < end; ++j) {
+			mh_int_t rc = mh_i32_random(h, j);
+			n = mh_i32_node(h, rc);
+			is_found[n->key] = true;
+		}
+		if (memcmp(is_found, all_is_found, size) != 0)
+			break;
+	}
+	is(i, end, "incremental random from mutable hash");
+
+	mh_i32_delete(h);
+	check_plan();
+	footer();
 }
 
 int main(void)
 {
+	header();
+	plan(3);
+
 	mhash_int32_id_test();
 	mhash_int32_collision_test();
-	return 0;
+	mhash_random_test();
+
+	int rc = check_plan();
+	footer();
+	return rc;
 }
diff --git a/test/unit/mhash.result b/test/unit/mhash.result
index ff958136abd1d455101934252ad2c8ad23f6e266..fc757fa3598b3a29342506da8ed31f5fd2d9d200 100644
--- a/test/unit/mhash.result
+++ b/test/unit/mhash.result
@@ -1,4 +1,18 @@
+	*** main ***
+1..3
 	*** mhash_int32_id_test ***
+    1..0
 	*** mhash_int32_id_test: done ***
+ok 1 - subtests
 	*** mhash_int32_collision_test ***
+    1..0
 	*** mhash_int32_collision_test: done ***
+ok 2 - subtests
+	*** mhash_random_test ***
+    1..3
+    ok 1 - empty random is always 'end'
+    ok 2 - one element is always found
+    ok 3 - incremental random from mutable hash
+ok 3 - subtests
+	*** mhash_random_test: done ***
+	*** main: done ***
diff --git a/test/unit/mhash_bytemap.result b/test/unit/mhash_bytemap.result
index ff958136abd1d455101934252ad2c8ad23f6e266..fc757fa3598b3a29342506da8ed31f5fd2d9d200 100644
--- a/test/unit/mhash_bytemap.result
+++ b/test/unit/mhash_bytemap.result
@@ -1,4 +1,18 @@
+	*** main ***
+1..3
 	*** mhash_int32_id_test ***
+    1..0
 	*** mhash_int32_id_test: done ***
+ok 1 - subtests
 	*** mhash_int32_collision_test ***
+    1..0
 	*** mhash_int32_collision_test: done ***
+ok 2 - subtests
+	*** mhash_random_test ***
+    1..3
+    ok 1 - empty random is always 'end'
+    ok 2 - one element is always found
+    ok 3 - incremental random from mutable hash
+ok 3 - subtests
+	*** mhash_random_test: done ***
+	*** main: done ***