aboutsummaryrefslogtreecommitdiff
path: root/tests/unit/libutil/pool.cc
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2023-08-25 10:20:28 -0400
committerJohn Ericson <John.Ericson@Obsidian.Systems>2023-12-01 13:05:03 -0500
commitf7f37035c81fa825a4dfc2df1ad2589013ac6380 (patch)
treebfcfef3efeb73cb0c3c6d812280191d03bda1233 /tests/unit/libutil/pool.cc
parent30dcc19d1f30fc203be460134c4578509cce704f (diff)
Move tests to separate directories, and document
Today, with the tests inside a `tests` intermingled with the corresponding library's source code, we have a few problems: - We have to be careful that wildcards don't end up with tests being built as part of Nix proper, or test headers being installed as part of Nix proper. - Tests in libraries but not executables is not right: - It means each executable runs the previous unit tests again, because it needs the libraries. - It doesn't work right on Windows, which doesn't want you to load a DLL just for the side global variable . It could be made to work with the dlopen equivalent, but that's gross! This reorg solves these problems. There is a remaining problem which is that sibbling headers (like `hash.hh` the test header vs `hash.hh` the main `libnixutil` header) end up shadowing each other. This PR doesn't solve that. That is left as future work for a future PR. Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io> (cherry picked from commit 91b6833686a6a6d9eac7f3f66393ec89ef1d3b57) (cherry picked from commit a61e42adb528b3d40ce43e07c79368d779a8b624)
Diffstat (limited to 'tests/unit/libutil/pool.cc')
-rw-r--r--tests/unit/libutil/pool.cc127
1 files changed, 127 insertions, 0 deletions
diff --git a/tests/unit/libutil/pool.cc b/tests/unit/libutil/pool.cc
new file mode 100644
index 000000000..127e42dda
--- /dev/null
+++ b/tests/unit/libutil/pool.cc
@@ -0,0 +1,127 @@
+#include "pool.hh"
+#include <gtest/gtest.h>
+
+namespace nix {
+
+ struct TestResource
+ {
+
+ TestResource() {
+ static int counter = 0;
+ num = counter++;
+ }
+
+ int dummyValue = 1;
+ bool good = true;
+ int num;
+ };
+
+ /* ----------------------------------------------------------------------------
+ * Pool
+ * --------------------------------------------------------------------------*/
+
+ TEST(Pool, freshPoolHasZeroCountAndSpecifiedCapacity) {
+ auto isGood = [](const ref<TestResource> & r) { return r->good; };
+ auto createResource = []() { return make_ref<TestResource>(); };
+
+ Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
+
+ ASSERT_EQ(pool.count(), 0);
+ ASSERT_EQ(pool.capacity(), 1);
+ }
+
+ TEST(Pool, freshPoolCanGetAResource) {
+ auto isGood = [](const ref<TestResource> & r) { return r->good; };
+ auto createResource = []() { return make_ref<TestResource>(); };
+
+ Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
+ ASSERT_EQ(pool.count(), 0);
+
+ TestResource r = *(pool.get());
+
+ ASSERT_EQ(pool.count(), 1);
+ ASSERT_EQ(pool.capacity(), 1);
+ ASSERT_EQ(r.dummyValue, 1);
+ ASSERT_EQ(r.good, true);
+ }
+
+ TEST(Pool, capacityCanBeIncremented) {
+ auto isGood = [](const ref<TestResource> & r) { return r->good; };
+ auto createResource = []() { return make_ref<TestResource>(); };
+
+ Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
+ ASSERT_EQ(pool.capacity(), 1);
+ pool.incCapacity();
+ ASSERT_EQ(pool.capacity(), 2);
+ }
+
+ TEST(Pool, capacityCanBeDecremented) {
+ auto isGood = [](const ref<TestResource> & r) { return r->good; };
+ auto createResource = []() { return make_ref<TestResource>(); };
+
+ Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
+ ASSERT_EQ(pool.capacity(), 1);
+ pool.decCapacity();
+ ASSERT_EQ(pool.capacity(), 0);
+ }
+
+ TEST(Pool, flushBadDropsOutOfScopeResources) {
+ auto isGood = [](const ref<TestResource> & r) { return false; };
+ auto createResource = []() { return make_ref<TestResource>(); };
+
+ Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
+
+ {
+ auto _r = pool.get();
+ ASSERT_EQ(pool.count(), 1);
+ }
+
+ pool.flushBad();
+ ASSERT_EQ(pool.count(), 0);
+ }
+
+ // Test that the resources we allocate are being reused when they are still good.
+ TEST(Pool, reuseResource) {
+ auto isGood = [](const ref<TestResource> & r) { return true; };
+ auto createResource = []() { return make_ref<TestResource>(); };
+
+ Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
+
+ // Compare the instance counter between the two handles. We expect them to be equal
+ // as the pool should hand out the same (still) good one again.
+ int counter = -1;
+ {
+ Pool<TestResource>::Handle h = pool.get();
+ counter = h->num;
+ } // the first handle goes out of scope
+
+ { // the second handle should contain the same resource (with the same counter value)
+ Pool<TestResource>::Handle h = pool.get();
+ ASSERT_EQ(h->num, counter);
+ }
+ }
+
+ // Test that the resources we allocate are being thrown away when they are no longer good.
+ TEST(Pool, badResourceIsNotReused) {
+ auto isGood = [](const ref<TestResource> & r) { return false; };
+ auto createResource = []() { return make_ref<TestResource>(); };
+
+ Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
+
+ // Compare the instance counter between the two handles. We expect them
+ // to *not* be equal as the pool should hand out a new instance after
+ // the first one was returned.
+ int counter = -1;
+ {
+ Pool<TestResource>::Handle h = pool.get();
+ counter = h->num;
+ } // the first handle goes out of scope
+
+ {
+ // the second handle should contain a different resource (with a
+ //different counter value)
+ Pool<TestResource>::Handle h = pool.get();
+ ASSERT_NE(h->num, counter);
+ }
+ }
+}