#include "versiond/versiond.hpp" #include #include #include #include #include #include #include #include #include #include #include int main() { versiond::Config c = versiond::load_config("/tmp/vtest"); versiond::Db db(c.index_file); versiond::Store st(c.spool_dir); FILE* f = fopen("/tmp/vt.txt", "w"); fputs("hi", f); fclose(f); long long id = versiond::ingest_file(db, st, c, "/tmp/vt.txt"); assert(id > 0); versiond::ApiResp a = versiond::api_build_response(db, "/api/stats"); assert(a.code == 200); assert(a.body.find("versions") != std::string::npos); versiond::ApiResp b = versiond::api_build_response(db, "/api/versions"); assert(b.code == 200); versiond::ApiResp h = versiond::api_build_response(db, "/"); assert(h.code == 200); versiond::ApiResp n = versiond::api_build_response(db, "/nope"); assert(n.code == 404); int sv[2]; assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); const char* q = "GET /api/stats HTTP/1.0\r\n\r\n"; assert(send(sv[0], q, strlen(q), MSG_NOSIGNAL) > 0); char buf[4096]; ssize_t k = recv(sv[1], buf, sizeof(buf) - 1, 0); assert(k > 0 && k < (ssize_t)sizeof(buf)); std::string req(buf, (size_t)(k > 0 ? k : 0)); std::istringstream rs(req); std::string m, path; rs >> m >> path; assert(m == "GET" && path == "/api/stats"); versiond::ApiResp r = versiond::api_build_response(db, path); std::ostringstream hh; hh << "HTTP/1.1 " << r.code << " OK\r\nContent-Length: " << r.body.size() << "\r\nConnection: close\r\n\r\n"; std::string head = hh.str(); assert(send(sv[1], head.data(), head.size(), MSG_NOSIGNAL) > 0); assert(send(sv[1], r.body.data(), r.body.size(), MSG_NOSIGNAL) > 0); shutdown(sv[1], SHUT_WR); std::string resp; ssize_t nn; while ((nn = recv(sv[0], buf, sizeof(buf), 0)) > 0) { assert(nn <= (ssize_t)sizeof(buf)); resp.append(buf, (size_t)nn); } close(sv[0]); close(sv[1]); assert(resp.find("200") != std::string::npos); assert(resp.find("versions") != std::string::npos); versiond::ApiResp s = versiond::api_build_response(db, "/api/stats"); std::string full = versiond::api_format_response(s); auto pos = full.find("Content-Length:"); assert(pos != std::string::npos); versiond::ApiResp h2 = versiond::api_build_response(db, "/api/health"); assert(h2.code == 200); versiond::ApiResp b2 = versiond::api_build_response(db, "/api/blobs"); assert(b2.code == 200); int sv2[2]; assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv2) == 0); assert(send(sv2[1], full.data(), full.size(), MSG_NOSIGNAL) == (ssize_t)full.size()); shutdown(sv2[1], SHUT_WR); std::string got; ssize_t m2; while ((m2 = recv(sv2[0], buf, sizeof(buf), 0)) > 0) got.append(buf, (size_t)m2); close(sv2[0]); close(sv2[1]); assert(got == full); {int ls=socket(AF_INET,SOCK_STREAM,0);assert(ls>=0);int o=1;setsockopt(ls,SOL_SOCKET,SO_REUSEADDR,&o,sizeof(o));sockaddr_in sa{};sa.sin_family=AF_INET;sa.sin_addr.s_addr=htonl(INADDR_LOOPBACK);sa.sin_port=htons(0);assert(bind(ls,(sockaddr*)&sa,sizeof(sa))==0);assert(listen(ls,1)==0);sockaddr_in ga{};socklen_t gl=sizeof(ga);assert(getsockname(ls,(sockaddr*)&ga,&gl)==0);int tp=ntohs(ga.sin_port);std::string ef=versiond::api_format_response(versiond::api_build_response(db,"/api/health"));std::thread th([ls,ef]{int fd=accept(ls,nullptr,nullptr);if(fd>=0){char b[1024];(void)recv(fd,b,sizeof(b),0);size_t n=0;while(n0);std::string tg;ssize_t tn;while((tn=recv(cl,buf,sizeof(buf),0))>0)tg.append(buf,(size_t)tn);close(cl);close(ls);th.join();assert(tg==ef);} {int NC=50000; std::string ef2=versiond::api_format_response(versiond::api_build_response(db,"/api/stats")); int ls2=socket(AF_INET,SOCK_STREAM,0); assert(ls2>=0); int o2=1; setsockopt(ls2,SOL_SOCKET,SO_REUSEADDR,&o2,sizeof(o2)); sockaddr_in sa2{}; sa2.sin_family=AF_INET; sa2.sin_addr.s_addr=htonl(INADDR_LOOPBACK); sa2.sin_port=htons(0); assert(bind(ls2,(sockaddr*)&sa2,sizeof(sa2))==0); assert(listen(ls2,2048)==0); sockaddr_in ga2{}; socklen_t gl2=sizeof(ga2); assert(getsockname(ls2,(sockaddr*)&ga2,&gl2)==0); int tp2=ntohs(ga2.sin_port); std::thread srv([ls2,ef2,NC]{ for(int i=0;i outs((size_t)NC); std::vector cls; for(int i=0;i=0); sockaddr_in ca{}; ca.sin_family=AF_INET; ca.sin_addr.s_addr=htonl(INADDR_LOOPBACK); ca.sin_port=htons((uint16_t)tp2); assert(connect(cl,(sockaddr*)&ca,sizeof(ca))==0); const char* q="GET /api/stats HTTP/1.0\r\n\r\n"; assert(send(cl,q,strlen(q),MSG_NOSIGNAL)>0); char bb[4096]; ssize_t tn; while((tn=recv(cl,bb,sizeof(bb),0))>0) outs[(size_t)i].append(bb,(size_t)tn); close(cl); }); } for(auto& th: cls) th.join(); close(ls2); srv.join(); for(auto& s: outs) assert(s==ef2); } {int NC=50000; std::string ef2=versiond::api_format_response(versiond::api_build_response(db,"/api/stats")); int ls2=socket(AF_INET,SOCK_STREAM,0); assert(ls2>=0); int o2=1; setsockopt(ls2,SOL_SOCKET,SO_REUSEADDR,&o2,sizeof(o2)); sockaddr_in sa2{}; sa2.sin_family=AF_INET; sa2.sin_addr.s_addr=htonl(INADDR_LOOPBACK); sa2.sin_port=htons(0); assert(bind(ls2,(sockaddr*)&sa2,sizeof(sa2))==0); assert(listen(ls2,2048)==0); sockaddr_in ga2{}; socklen_t gl2=sizeof(ga2); assert(getsockname(ls2,(sockaddr*)&ga2,&gl2)==0); int tp2=ntohs(ga2.sin_port); std::thread srv([ls2,ef2,NC]{ for(int i=0;i outs((size_t)NC); std::vector cls; for(int i=0;i=0); sockaddr_in ca{}; ca.sin_family=AF_INET; ca.sin_addr.s_addr=htonl(INADDR_LOOPBACK); ca.sin_port=htons((uint16_t)tp2); assert(connect(cl,(sockaddr*)&ca,sizeof(ca))==0); const char* q="GET /api/stats HTTP/1.0\r\n\r\n"; assert(send(cl,q,strlen(q),MSG_NOSIGNAL)>0); char bb[4096]; ssize_t tn; while((tn=recv(cl,bb,sizeof(bb),0))>0) outs[(size_t)i].append(bb,(size_t)tn); close(cl); }); } for(auto& th: cls) th.join(); close(ls2); srv.join(); for(auto& s: outs) assert(s==ef2); } printf("ok http-smoke live\n"); return 0; }