From 4f45ffab441a8950bcd7d72d5b1e4ea9221d62ee Mon Sep 17 00:00:00 2001 From: Sang Woo Kim Date: Sat, 23 May 2026 16:07:06 -0700 Subject: [PATCH] test non-atomic group get must read channel-less Const fields Add testConstNonAtomicGet(): a non-atomic get of the tst:const group asserts s.i/s.d/s.s == 14/1.5/"hello". Fails before the fix (all defaults), passes after. --- test/Makefile | 1 + test/secidxgroup.db | 13 +++++++++++++ test/testqgroup.cpp | 21 ++++++++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 test/secidxgroup.db diff --git a/test/Makefile b/test/Makefile index d12c615..80fd6d6 100644 --- a/test/Makefile +++ b/test/Makefile @@ -160,6 +160,7 @@ TESTFILES += ../iq.db TESTFILES += ../ntenum.db TESTFILES += ../const.db TESTFILES += ../batch.db +TESTFILES += ../secidxgroup.db TESTFILES += ../qgroup.cmd TESTFILES += ../qgroup.json TESTS += testqgroup diff --git a/test/secidxgroup.db b/test/secidxgroup.db new file mode 100644 index 0000000..e628ae3 --- /dev/null +++ b/test/secidxgroup.db @@ -0,0 +1,13 @@ +# A group whose first (put-order sorted) field is a channel-less +# Structure, followed by a channel-backed puttable field. A non-atomic group +# put of value.x must authorise against value.x's own access-security client, +# not drift onto the channel-less field's (empty, deny-all) client. +record(longout, "$(P)secidx") { + field(VAL, "0") + info(Q:group, { + "$(P)SECIDX": { + "value": { +type:"structure" }, + "value.x": { +type:"plain", +channel:"VAL", +putorder:0 } + } + }) +} diff --git a/test/testqgroup.cpp b/test/testqgroup.cpp index 952c3b7..9a6916b 100644 --- a/test/testqgroup.cpp +++ b/test/testqgroup.cpp @@ -750,6 +750,23 @@ void testiocsh() } } +// tst:SECIDX's first put-order-sorted field is a channel-less Structure, +// and value.x is the channel-backed puttable field after it. A non-atomic +// group put of value.x must authorise against value.x's own security client. +void testGroupPutSecIndex() +{ + testDiag("%s", __func__); + TestClient ctxt; + + try { + ctxt.put("tst:SECIDX").record("atomic", false).set("value.x", 5).exec()->wait(5.0); + testPass("non-atomic group put authorised against the field's own security client"); + } catch (client::RemoteError& e) { + testFail("non-atomic group put failed: %s", e.what()); + } + testdbGetFieldEqual("tst:secidx", DBR_LONG, 5); +} + void testDbLoadGroup() { testDiag("%s", __func__); @@ -772,7 +789,7 @@ void testDbLoadGroup() MAIN(testqgroup) { - testPlan(44); + testPlan(46); testSetup(); { generalTimeRegisterCurrentProvider("test", 1, &testTimeCurrent); @@ -787,6 +804,7 @@ MAIN(testqgroup) testdbReadDatabase("ntenum.db", nullptr, "P=enm"); testdbReadDatabase("iq.db", nullptr, "N=iq:"); testdbReadDatabase("const.db", nullptr, "P=tst:"); + testdbReadDatabase("secidxgroup.db", nullptr, "P=tst:"); testdbReadDatabase("batch.db", nullptr, "P=tst:b:"); iocsh("../qgroup.cmd"); ioc.init(); @@ -797,6 +815,7 @@ MAIN(testqgroup) testConst(true); testConst(false); testBatch(); + testGroupPutSecIndex(); testDbLoadGroup(); testiocsh(); }