|
@@ -0,0 +1,89 @@
|
|
|
|
|
+// v2.4.5 client/server boundary test.
|
|
|
|
|
+//
|
|
|
|
|
+// Covers the gap that let TWO namespacing bugs ship. v2.4.2's createView break
|
|
|
|
|
+// and v2.4.5's createCollection/dropCollection/getCollectionInfo break were
|
|
|
|
|
+// both invisible to the unit suite, because tests/test_views.cpp only exercises
|
|
|
|
|
+// applyProjection() in-process and nothing drove a real Client against a real
|
|
|
|
|
+// server with a non-default project. Everything here runs over gRPC with
|
|
|
|
|
+// Config::project set, which is the only place these bugs are observable.
|
|
|
|
|
+//
|
|
|
|
|
+// Part 1 — collection management must be project-namespaced like insert/get/
|
|
|
|
|
+// find. Unqualified, createCollection created a phantom that swallowed the
|
|
|
|
|
+// options (vector_dimension is immutable, so that was unrecoverable) and
|
|
|
|
|
+// dropCollection returned true while leaving every document readable.
|
|
|
|
|
+//
|
|
|
|
|
+// Part 2 — versioning can be switched on an existing collection, is durable,
|
|
|
|
|
+// is reversible, and a precision-only configure must not clobber it.
|
|
|
|
|
+
|
|
|
|
|
+#include <smartbotic/database/client.hpp>
|
|
|
|
|
+#include <iostream>
|
|
|
|
|
+using namespace smartbotic::database;
|
|
|
|
|
+static int pass=0, fail=0;
|
|
|
|
|
+static void ck(bool c, const char* m){ if(c){++pass;} else {++fail; std::cerr<<"FAIL: "<<m<<"\n";} }
|
|
|
|
|
+
|
|
|
|
|
+int main() {
|
|
|
|
|
+ Client c({.address="127.0.0.1:9011", .project="proj1"});
|
|
|
|
|
+ c.connect();
|
|
|
|
|
+
|
|
|
|
|
+ // ---- Part 1: createCollection / dropCollection / getCollectionInfo namespacing
|
|
|
|
|
+ ck(c.createCollection("things", 0, false, 0, 4), "createCollection returns created");
|
|
|
|
|
+ auto cols = c.listCollections();
|
|
|
|
|
+ int bare=0, qual=0;
|
|
|
|
|
+ for (auto& n : cols) { if(n=="things") ++bare; if(n=="proj1:things") ++qual; }
|
|
|
|
|
+ ck(bare==1, "listCollections shows the collection under its BARE name (round-trip)");
|
|
|
|
|
+ ck(qual==0, "listCollections does NOT show a qualified duplicate");
|
|
|
|
|
+
|
|
|
|
|
+ c.insert("things", nlohmann::json{{"a",1}});
|
|
|
|
|
+ auto info = c.getCollectionInfo("things");
|
|
|
|
|
+ ck(info.has_value(), "getCollectionInfo finds the collection");
|
|
|
|
|
+ ck(info && info->documentCount==1, "getCollectionInfo counts the doc the caller inserted");
|
|
|
|
|
+
|
|
|
|
|
+ // vector_dimension must have landed on the collection that holds the data
|
|
|
|
|
+ c.insert("things", nlohmann::json{{"_vector", {1.0,0.0,0.0,0.0}},{"tag","x"}});
|
|
|
|
|
+ auto hits = c.similaritySearch("things", {1.0f,0.0f,0.0f,0.0f}, 5);
|
|
|
|
|
+ ck(!hits.empty(), "similaritySearch works => vector_dimension reached the real collection");
|
|
|
|
|
+
|
|
|
|
|
+ // drop must actually delete
|
|
|
|
|
+ c.insert("gone", nlohmann::json{{"pii","alice"}});
|
|
|
|
|
+ ck(c.dropCollection("gone"), "dropCollection returns true");
|
|
|
|
|
+ auto after = c.getCollectionInfo("gone");
|
|
|
|
|
+ ck(!after || after->documentCount==0, "dropCollection actually removed the data");
|
|
|
|
|
+
|
|
|
|
|
+ // ---- Part 2: versioning toggle on an EXISTING collection
|
|
|
|
|
+ c.createCollection("v", 0, false, 0, 0);
|
|
|
|
|
+ auto id = c.insert("v", nlohmann::json{{"n",1}});
|
|
|
|
|
+ c.update("v", id, nlohmann::json{{"n",2}});
|
|
|
|
|
+ c.update("v", id, nlohmann::json{{"n",3}});
|
|
|
|
|
+ auto h1 = c.getVersionHistory("v", id);
|
|
|
|
|
+ ck(h1.totalCount >= 2, "versioning ON by default records history");
|
|
|
|
|
+
|
|
|
|
|
+ Client::CollectionConfig off; off.timestampPrecision=""; off.versioningEnabled=false;
|
|
|
|
|
+ ck(c.configureCollection("v", off), "configureCollection(versioningEnabled=false) accepted");
|
|
|
|
|
+ auto cfg = c.getCollectionConfig("v");
|
|
|
|
|
+ ck(cfg.versioningEnabled.has_value() && *cfg.versioningEnabled==false, "config reads back disabled");
|
|
|
|
|
+
|
|
|
|
|
+ auto before = c.getVersionHistory("v", id).totalCount;
|
|
|
|
|
+ c.update("v", id, nlohmann::json{{"n",4}});
|
|
|
|
|
+ c.update("v", id, nlohmann::json{{"n",5}});
|
|
|
|
|
+ auto afterN = c.getVersionHistory("v", id).totalCount;
|
|
|
|
|
+ ck(afterN == before, "disabled: no NEW versions recorded");
|
|
|
|
|
+ ck(afterN >= 2, "disabled: existing history still readable (reversible)");
|
|
|
|
|
+
|
|
|
|
|
+ // partial update must not clobber versioning
|
|
|
|
|
+ Client::CollectionConfig justPrec; justPrec.timestampPrecision="ms";
|
|
|
|
|
+ ck(c.configureCollection("v", justPrec), "precision-only configure accepted");
|
|
|
|
|
+ auto cfg2 = c.getCollectionConfig("v");
|
|
|
|
|
+ ck(cfg2.versioningEnabled.has_value() && *cfg2.versioningEnabled==false,
|
|
|
|
|
+ "precision-only configure did NOT re-enable versioning (partial update)");
|
|
|
|
|
+ ck(cfg2.timestampPrecision=="ms", "precision-only configure applied precision");
|
|
|
|
|
+
|
|
|
|
|
+ // re-enable
|
|
|
|
|
+ Client::CollectionConfig on; on.timestampPrecision=""; on.versioningEnabled=true;
|
|
|
|
|
+ c.configureCollection("v", on);
|
|
|
|
|
+ auto b2 = c.getVersionHistory("v", id).totalCount;
|
|
|
|
|
+ c.update("v", id, nlohmann::json{{"n",6}});
|
|
|
|
|
+ ck(c.getVersionHistory("v", id).totalCount > b2, "re-enabled: versions recorded again");
|
|
|
|
|
+
|
|
|
|
|
+ std::cout << "\npassed=" << pass << " failed=" << fail << "\n";
|
|
|
|
|
+ return fail==0?0:1;
|
|
|
|
|
+}
|