/ e2e_acceptor_echo.q
/ Connect to a kdb_codec acceptor that echoes (`echo; x) back to caller.
/
/ Required env vars:
/ - KDBCODEC_E2E_HOST
/ - KDBCODEC_E2E_PORT
/ - KDBCODEC_E2E_USER
/ - KDBCODEC_E2E_PASS
assertEq:{[name; sent; recv]
if[not sent ~ recv;
-2 "assert failed: ", name;
-2 " sent: ", -3!sent;
-2 " recv: ", -3!recv;
'"assertion failed";
];
::
};
assertIpcEq:{[name; sent; recv]
if[not (-8!sent) ~ -8!recv;
-2 "assert failed: ", name;
-2 " sent(-8!): ", -3!(-8!sent);
-2 " recv(-8!): ", -3!(-8!recv);
'"assertion failed";
];
::
};
run:{
host:getenv `KDBCODEC_E2E_HOST;
port:"I"$getenv `KDBCODEC_E2E_PORT;
user:getenv `KDBCODEC_E2E_USER;
pass:getenv `KDBCODEC_E2E_PASS;
if[0=count host; -2 "missing env KDBCODEC_E2E_HOST"; '"missing env"];
if[0=port; -2 "missing/invalid env KDBCODEC_E2E_PORT"; '"missing env"];
connStr:raze (":",host,":",string port,":",user,":",pass);
conn:hsym `$connStr;
/ retry connect (bounded)
tryConnect:{[c]
@[hopen; c; {()}]
};
h:();
i:0;
while[()~h & i<100;
h:tryConnect conn;
i+:1;
if[()~h; system "sleep 0.05"];
];
if[()~h; -2 "failed to connect to ", string conn; '"connect failed"];
send:{[hh; x] hh (`echo; x)};
/ ---- Atoms ----
assertEq["null"; (::); send[h; (::)]];
assertEq["bool"; 1b; send[h; 1b]];
assertEq["guid"; ("G"$"01020304-0506-0708-090a-0b0c0d0e0f10"); send[h; ("G"$"01020304-0506-0708-090a-0b0c0d0e0f10")]];
assertEq["byte"; 0x9e; send[h; 0x9e]];
assertEq["short"; -17h; send[h; -17h]];
assertEq["int"; -256i; send[h; -256i]];
assertEq["long"; 86400000000000j; send[h; 86400000000000j]];
assertEq["real"; 0.25e; send[h; 0.25e]];
assertEq["float"; 113.0456; send[h; 113.0456]];
/ char atom (type -10). NOTE: "r" is a char vector (string).
assertEq["char"; first "r"; send[h; first "r"]];
assertEq["symbol"; `Jordan; send[h; `Jordan]];
assertEq["string"; "super"; send[h; "super"]]; / type 10
assertEq["timestamp"; 2019.05.09D00:39:02.000194756; send[h; 2019.05.09D00:39:02.000194756]];
assertEq["month"; 2019.12m; send[h; 2019.12m]];
assertEq["date"; 2012.03.12; send[h; 2012.03.12]];
assertEq["datetime"; 2013.01.10T00:09:50.038; send[h; 2013.01.10T00:09:50.038]];
assertEq["timespan"; 1D04:34:59.277539844; send[h; 1D04:34:59.277539844]];
assertEq["minute"; 00:42; send[h; 00:42]];
assertEq["second"; 00:00:37; send[h; 00:00:37]];
assertEq["time"; 00:00:12.345; send[h; 00:00:12.345]];
/ ---- Null/Inf/NInf samples ----
assertEq["int null"; 0Ni; send[h; 0Ni]];
assertEq["long inf"; 0W; send[h; 0W]];
assertEq["float null"; 0n; send[h; 0n]];
assertEq["float inf"; 0w; send[h; 0w]];
assertEq["float ninf"; -0w; send[h; -0w]];
assertEq["timestamp null"; 0Np; send[h; 0Np]];
assertEq["timespan null"; 0Nn; send[h; 0Nn]];
/ ---- Lists ----
assertEq["bool list"; 101b; send[h; 101b]];
assertEq["byte list"; 0x00019eff; send[h; 0x00019eff]];
assertEq["short list"; -3 0 7 12h; send[h; -3 0 7 12h]];
assertEq["int list"; -256 0 3 1024i; send[h; -256 0 3 1024i]];
assertEq["long list"; 0 1 2 3 4; send[h; 0 1 2 3 4]];
assertEq["real list"; 30.2 5.002e; send[h; 30.2 5.002e]];
assertEq["float list"; 100.23 0.4268 15.882; send[h; 100.23 0.4268 15.882]];
assertEq["symbol list"; `a`b`c; send[h; `a`b`c]];
/ attribute-bearing list
assertEq["sorted int list"; `s#1 2 3i; send[h; `s#1 2 3i]];
/ ---- Compound list ----
assertEq["compound list"; (`alpha; 42i; "bravo"; 1.25); send[h; (`alpha; 42i; "bravo"; 1.25)]];
/ ---- Dictionary ----
assertEq["dictionary"; (20 30 40i)!001b; send[h; (20 30 40i)!001b]];
/ ---- Table ----
assertEq["table"; ([] a:10 20 30i; b:`honey`sugar`maple; c:001b); send[h; ([] a:10 20 30i; b:`honey`sugar`maple; c:001b)]];
/ table with attribute
assertEq["sorted table"; `s#([] a:10 20 30i; b:`honey`sugar`maple; c:001b); send[h; `s#([] a:10 20 30i; b:`honey`sugar`maple; c:001b)]];
/ ---- Keyed table ----
assertEq["keyed table"; ([a:10 20i] b:100 200i); send[h; ([a:10 20i] b:100 200i)]];
/ ---- Functions ----
f:{x+y};
assertIpcEq["lambda root"; f; send[h; f]];
.d.g:{x+y};
assertIpcEq["lambda non-root context"; .d.g; send[h; .d.g]];
/ primitive functions (roundtrip by IPC bytes)
assertIpcEq["unary primitive neg"; value "neg"; send[h; value "neg"]];
assertIpcEq["binary primitive +"; value "+"; send[h; value "+"]];
/ projections (roundtrip by IPC bytes)
assertIpcEq["projection (1+)"; (1+); send[h; (1+)]];
assertIpcEq["projection (+[;2])"; (+[;2]); send[h; (+[;2])]];
/ compositions (roundtrip by IPC bytes)
assertIpcEq["composition (0|+)"; (0|+); send[h; (0|+)]];
/ dynamic load (type 112) / optional
/ Provide these env vars to enable this check:
/ - KDBCODEC_E2E_DYLIB (string for file symbol, e.g. ":/absolute/path/to/lib.dylib")
/ - KDBCODEC_E2E_CFUNC (C function name, e.g. "q_read_cycles_of_this_cpu")
/ - KDBCODEC_E2E_RANK (int, e.g. "1")
dylib:getenv `KDBCODEC_E2E_DYLIB;
cfn:getenv `KDBCODEC_E2E_CFUNC;
rnkstr:getenv `KDBCODEC_E2E_RANK;
if[(0<count dylib) & (0<count cfn) & (0<count rnkstr);
rnk:"I"$rnkstr;
fs:`$dylib;
fn:@[fs 2: (`$cfn; rnk); (); {()}];
if[not ()~fn;
assertIpcEq["dynamic load (2:)"; fn; send[h; fn]];
];
];
/ derived functions (roundtrip by IPC bytes)
assertIpcEq["derived over (+/)"; (+/); send[h; (+/)]];
assertIpcEq["derived scan (+\\)"; (+\\); send[h; (+\\)]];
// derived/adverbs (roundtrip-only)
assertIpcEq["derived each (neg')"; (neg'); send[h; (neg')]];
assertIpcEq["derived each (+')"; (+'); send[h; (+')]];
assertIpcEq["derived each-prior (+':)"; (+':); send[h; (+':)]];
assertIpcEq["derived each-left (+/:)"; (+/:); send[h; (+/:)]];
assertIpcEq["derived each-right (+\\:)"; (+\\:); send[h; (+\\:)]];
hclose h;
-1 "ok";
::
};
@[run; (); {-2 "e2e script error: ", x; '"e2e failed"}];