fix: stats flush ensures schema, query flushes pending, add sqlite round-trip test
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include "realtime/expose/claim.h"
|
||||
#include "realtime/expose/hello.h"
|
||||
#include "realtime/expose/tunnel.h"
|
||||
#include "realtime/expose/proxy.h"
|
||||
#include "realtime/expose/stats.h"
|
||||
#include <atomic>
|
||||
#include "realtime/expose/upstream.h"
|
||||
using namespace molo::realtime::expose;
|
||||
int main() {
|
||||
std::string r;
|
||||
// claim grammar
|
||||
assert(ParseClaim("/hook1", r) && ParseClaim("example.com/hook1", r));
|
||||
assert(ParseClaim("example.com", r)->whole_host);
|
||||
assert(!ParseClaim("/../x", r));
|
||||
// upstream table: longest prefix wins, concurrent entries
|
||||
UpstreamTable t;
|
||||
UpstreamEntry a, b;
|
||||
assert(ParseUpstream("http://127.0.0.1:3001=/api", r));
|
||||
auto e1 = ParseUpstream("http://127.0.0.1:3001=/api", r);
|
||||
auto e2 = ParseUpstream("http://127.0.0.1:3002=/", r);
|
||||
assert(e1 && e2 && t.Add(*e1, r) && t.Add(*e2, r));
|
||||
assert(t.Route("/api/u")->port == 3001 && t.Route("/other")->port == 3002);
|
||||
// hello v1+v2
|
||||
std::string e;
|
||||
auto h2 = ParseHello(R"({"v":2,"claim":"/a","upstreams":[{"upstream":"http://127.0.0.1:1","prefix":"/"}],"agent":"t"})", "", e);
|
||||
auto h1 = ParseHello(R"({"v":1,"claim":"/a","upstream":"8080","agent":"t"})", "", e);
|
||||
assert(h2 && h1 && h1->upstreams.size() == 1);
|
||||
// registry: auth, conflict, takeover, concurrent register
|
||||
ClaimRegistry reg("s1");
|
||||
auto c = ParseClaim("/app", r);
|
||||
UpstreamTable u0;
|
||||
std::shared_ptr<Tunnel> out; std::string d;
|
||||
assert(reg.Register(*c, Sha256Hex("k1"), std::move(u0), false, out, d) == RegisterResult::kOk);
|
||||
UpstreamTable u1;
|
||||
std::shared_ptr<Tunnel> o2;
|
||||
assert(reg.Register(*c, Sha256Hex("k1"), std::move(u1), false, o2, d) == RegisterResult::kConflict);
|
||||
UpstreamTable u2;
|
||||
std::shared_ptr<Tunnel> o3;
|
||||
assert(reg.Register(*c, Sha256Hex("k1"), std::move(u2), true, o3, d) == RegisterResult::kOk);
|
||||
assert(reg.Find("", "/app/x") && reg.Find("", "/app/x")->id == o3->id);
|
||||
// concurrent Find/List under threads
|
||||
std::vector<std::thread> th;
|
||||
for (int i = 0; i < 8; ++i) th.emplace_back([&]{ for (int j = 0; j < 200; ++j) { reg.Find("", "/app"); reg.List(); } });
|
||||
for (auto& t : th) t.join();
|
||||
|
||||
// proxy glue: strip prefix, hop-by-hop, stream ids, per-IP cap
|
||||
assert(StripClaimPrefix("/app", false, "/app/x") == "/x");
|
||||
assert(StripClaimPrefix("/app", false, "/app") == "/");
|
||||
assert(StripClaimPrefix("/", false, "/a") == "/a");
|
||||
assert(StripClaimPrefix("/app", true, "/app/x") == "/app/x");
|
||||
assert(IsHopByHop("Connection") && IsHopByHop("Transfer-Encoding") && !IsHopByHop("X-Custom"));
|
||||
assert(ForwardedFor("", "1.2.3.4") == "1.2.3.4");
|
||||
assert(ForwardedFor("a", "b") == "a, b");
|
||||
assert(kH2RefusedStream == 0x7 && kH2Cancel == 0x8);
|
||||
std::atomic<uint32_t> nx{3};
|
||||
assert(NextProxyStreamId(nx) == 3 && NextProxyStreamId(nx) == 5);
|
||||
PerIpCounter ipc; for (int i = 0; i < 128; ++i) assert(ipc.Admit("9.9.9.9"));
|
||||
assert(!ipc.Admit("9.9.9.9")); ipc.Release("9.9.9.9"); assert(ipc.Admit("9.9.9.9"));
|
||||
// concurrent streams across N upstreams: route from threads
|
||||
{
|
||||
UpstreamTable ct;
|
||||
std::string rr;
|
||||
ct.Add(*ParseUpstream("http://127.0.0.1:3001=/api", rr), rr);
|
||||
ct.Add(*ParseUpstream("http://127.0.0.1:3002=/static", rr), rr);
|
||||
ct.Add(*ParseUpstream("http://127.0.0.1:3003=/", rr), rr);
|
||||
std::atomic<int> ok{0};
|
||||
std::vector<std::thread> w;
|
||||
for (int i = 0; i < 16; ++i) w.emplace_back([&, i]{
|
||||
const char* p[3] = {"/api/x", "/static/y", "/other"};
|
||||
auto* e = ct.Route(p[i % 3]);
|
||||
if (e) ok.fetch_add(1);
|
||||
std::atomic<uint32_t> sn{3u + (uint32_t)(i * 2)};
|
||||
(void)NextProxyStreamId(sn);
|
||||
});
|
||||
for (auto& th2 : w) th2.join();
|
||||
assert(ok == 16);
|
||||
}
|
||||
// stats: Note/Flush/Query sqlite round-trip (reverse.md 9)
|
||||
{
|
||||
std::string db = "/tmp/molo_stats_test.db";
|
||||
std::remove(db.c_str());
|
||||
StatsCollector sc;
|
||||
sc.Configure(MakeStatsStore("sqlite://" + db));
|
||||
sc.Note("GET", 2048, 4096, 2000);
|
||||
std::string err, out;
|
||||
assert(sc.Flush(err));
|
||||
assert(sc.Query(out, false, err));
|
||||
assert(out.find("GET") != std::string::npos && out.find("count=1") != std::string::npos);
|
||||
assert(sc.Query(out, true, err) && out.front() == '[');
|
||||
std::remove(db.c_str());
|
||||
}
|
||||
printf("expose_test PASS\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user