@voxgig/sdkgen 4.34.1 → 4.34.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/voxgig-sdkgen +1 -1
- package/dist/cmp/ReadmeErrors.js +3 -3
- package/dist/cmp/ReadmeErrors.js.map +1 -1
- package/dist/cmp/ReadmeExplanation.js +3 -3
- package/dist/cmp/ReadmeExplanation.js.map +1 -1
- package/dist/cmp/ReadmeQuick.js +3 -1
- package/dist/cmp/ReadmeQuick.js.map +1 -1
- package/dist/cmp/ReadmeTop.js +9 -8
- package/dist/cmp/ReadmeTop.js.map +1 -1
- package/dist/helpers/definitionPlan.js +8 -4
- package/dist/helpers/definitionPlan.js.map +1 -1
- package/dist/helpers/naming.d.ts +2 -1
- package/dist/helpers/naming.js +11 -4
- package/dist/helpers/naming.js.map +1 -1
- package/dist/helpers/opExample.d.ts +16 -2
- package/dist/helpers/opExample.js +80 -21
- package/dist/helpers/opExample.js.map +1 -1
- package/dist/helpers/opShape.d.ts +3 -1
- package/dist/helpers/opShape.js +21 -8
- package/dist/helpers/opShape.js.map +1 -1
- package/dist/sdkgen.d.ts +4 -4
- package/dist/sdkgen.js +12 -4
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utility.d.ts +2 -1
- package/dist/utility.js +29 -3
- package/dist/utility.js.map +1 -1
- package/package.json +2 -2
- package/project/.sdk/src/cmp/c/ReadmeEntity_c.ts +3 -2
- package/project/.sdk/src/cmp/c/ReadmeHowto_c.ts +7 -3
- package/project/.sdk/src/cmp/c/ReadmeQuick_c.ts +3 -2
- package/project/.sdk/src/cmp/c/ReadmeRef_c.ts +5 -4
- package/project/.sdk/src/cmp/c/ReadmeTopQuick_c.ts +3 -2
- package/project/.sdk/src/cmp/c/ReadmeTopTest_c.ts +8 -7
- package/project/.sdk/src/cmp/c/utility_c.ts +21 -2
- package/project/.sdk/src/cmp/clojure/ReadmeEntity_clojure.ts +4 -1
- package/project/.sdk/src/cmp/clojure/ReadmeHowto_clojure.ts +17 -6
- package/project/.sdk/src/cmp/clojure/ReadmeModel_clojure.ts +6 -6
- package/project/.sdk/src/cmp/clojure/ReadmeQuick_clojure.ts +13 -8
- package/project/.sdk/src/cmp/clojure/ReadmeRef_clojure.ts +21 -18
- package/project/.sdk/src/cmp/clojure/ReadmeTopQuick_clojure.ts +6 -3
- package/project/.sdk/src/cmp/clojure/ReadmeTopTest_clojure.ts +16 -9
- package/project/.sdk/src/cmp/clojure/TestClean_clojure.ts +4 -4
- package/project/.sdk/src/cmp/clojure/fragment/Entity.fragment.clj +2 -1
- package/project/.sdk/src/cmp/clojure/utility_clojure.ts +14 -0
- package/project/.sdk/src/cmp/cpp/ReadmeEntity_cpp.ts +3 -2
- package/project/.sdk/src/cmp/cpp/ReadmeHowto_cpp.ts +7 -3
- package/project/.sdk/src/cmp/cpp/ReadmeQuick_cpp.ts +3 -2
- package/project/.sdk/src/cmp/cpp/ReadmeRef_cpp.ts +6 -5
- package/project/.sdk/src/cmp/cpp/ReadmeTopQuick_cpp.ts +3 -2
- package/project/.sdk/src/cmp/cpp/ReadmeTopTest_cpp.ts +8 -7
- package/project/.sdk/src/cmp/cpp/utility_cpp.ts +13 -0
- package/project/.sdk/src/cmp/csharp/ReadmeEntity_csharp.ts +3 -2
- package/project/.sdk/src/cmp/csharp/ReadmeHowto_csharp.ts +20 -8
- package/project/.sdk/src/cmp/csharp/ReadmeQuick_csharp.ts +13 -8
- package/project/.sdk/src/cmp/csharp/ReadmeRef_csharp.ts +10 -5
- package/project/.sdk/src/cmp/csharp/ReadmeTopQuick_csharp.ts +14 -7
- package/project/.sdk/src/cmp/csharp/ReadmeTopTest_csharp.ts +18 -10
- package/project/.sdk/src/cmp/csharp/utility_csharp.ts +13 -0
- package/project/.sdk/src/cmp/elixir/ReadmeEntity_elixir.ts +4 -4
- package/project/.sdk/src/cmp/elixir/ReadmeExplanation_elixir.ts +2 -1
- package/project/.sdk/src/cmp/elixir/ReadmeHowto_elixir.ts +13 -6
- package/project/.sdk/src/cmp/elixir/ReadmeModel_elixir.ts +5 -5
- package/project/.sdk/src/cmp/elixir/ReadmeQuick_elixir.ts +13 -10
- package/project/.sdk/src/cmp/elixir/ReadmeRef_elixir.ts +11 -11
- package/project/.sdk/src/cmp/elixir/ReadmeTopQuick_elixir.ts +8 -6
- package/project/.sdk/src/cmp/elixir/ReadmeTopTest_elixir.ts +14 -10
- package/project/.sdk/src/cmp/elixir/fragment/EntityCreateOp.fragment.ex +4 -3
- package/project/.sdk/src/cmp/elixir/fragment/EntityListOp.fragment.ex +4 -3
- package/project/.sdk/src/cmp/elixir/fragment/EntityLoadOp.fragment.ex +4 -3
- package/project/.sdk/src/cmp/elixir/fragment/EntityPatchOp.fragment.ex +4 -3
- package/project/.sdk/src/cmp/elixir/fragment/EntityRemoveOp.fragment.ex +4 -3
- package/project/.sdk/src/cmp/elixir/fragment/EntityUpdateOp.fragment.ex +4 -3
- package/project/.sdk/src/cmp/elixir/utility_elixir.ts +12 -0
- package/project/.sdk/src/cmp/go/ReadmeEntity_go.ts +8 -5
- package/project/.sdk/src/cmp/go/ReadmeExplanation_go.ts +3 -1
- package/project/.sdk/src/cmp/go/ReadmeHowto_go.ts +20 -8
- package/project/.sdk/src/cmp/go/ReadmeModel_go.ts +16 -13
- package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +14 -13
- package/project/.sdk/src/cmp/go/ReadmeRef_go.ts +14 -13
- package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +10 -8
- package/project/.sdk/src/cmp/go/ReadmeTopTest_go.ts +6 -2
- package/project/.sdk/src/cmp/go/utility_go.ts +1 -1
- package/project/.sdk/src/cmp/java/ReadmeEntity_java.ts +8 -19
- package/project/.sdk/src/cmp/java/ReadmeHowto_java.ts +19 -22
- package/project/.sdk/src/cmp/java/ReadmeModel_java.ts +10 -9
- package/project/.sdk/src/cmp/java/ReadmeQuick_java.ts +24 -28
- package/project/.sdk/src/cmp/java/ReadmeRef_java.ts +27 -35
- package/project/.sdk/src/cmp/java/ReadmeTopQuick_java.ts +22 -25
- package/project/.sdk/src/cmp/java/ReadmeTopTest_java.ts +18 -24
- package/project/.sdk/src/cmp/java/utility_java.ts +25 -0
- package/project/.sdk/src/cmp/js/EntityOperation_js.ts +3 -1
- package/project/.sdk/src/cmp/js/ReadmeEntity_js.ts +2 -8
- package/project/.sdk/src/cmp/js/ReadmeHowto_js.ts +11 -9
- package/project/.sdk/src/cmp/js/ReadmeModel_js.ts +9 -9
- package/project/.sdk/src/cmp/js/ReadmeQuick_js.ts +7 -13
- package/project/.sdk/src/cmp/js/ReadmeRef_js.ts +14 -15
- package/project/.sdk/src/cmp/js/ReadmeTopQuick_js.ts +16 -11
- package/project/.sdk/src/cmp/js/ReadmeTopTest_js.ts +11 -7
- package/project/.sdk/src/cmp/js/fragment/EntityCreateOp.fragment.js +1 -1
- package/project/.sdk/src/cmp/js/fragment/EntityListOp.fragment.js +1 -1
- package/project/.sdk/src/cmp/js/fragment/EntityLoadOp.fragment.js +1 -1
- package/project/.sdk/src/cmp/js/fragment/EntityPatchOp.fragment.js +1 -1
- package/project/.sdk/src/cmp/js/fragment/EntityRemoveOp.fragment.js +1 -1
- package/project/.sdk/src/cmp/js/fragment/EntityUpdateOp.fragment.js +1 -1
- package/project/.sdk/src/cmp/js/utility_js.ts +2 -1
- package/project/.sdk/src/cmp/kotlin/ReadmeEntity_kotlin.ts +3 -2
- package/project/.sdk/src/cmp/kotlin/ReadmeHowto_kotlin.ts +19 -9
- package/project/.sdk/src/cmp/kotlin/ReadmeModel_kotlin.ts +10 -9
- package/project/.sdk/src/cmp/kotlin/ReadmeQuick_kotlin.ts +14 -9
- package/project/.sdk/src/cmp/kotlin/ReadmeRef_kotlin.ts +18 -15
- package/project/.sdk/src/cmp/kotlin/ReadmeTopQuick_kotlin.ts +14 -8
- package/project/.sdk/src/cmp/kotlin/ReadmeTopTest_kotlin.ts +17 -10
- package/project/.sdk/src/cmp/kotlin/utility_kotlin.ts +21 -1
- package/project/.sdk/src/cmp/lua/ReadmeEntity_lua.ts +3 -2
- package/project/.sdk/src/cmp/lua/ReadmeExamplesTest_lua.ts +7 -4
- package/project/.sdk/src/cmp/lua/ReadmeHowto_lua.ts +9 -7
- package/project/.sdk/src/cmp/lua/ReadmeModel_lua.ts +13 -13
- package/project/.sdk/src/cmp/lua/ReadmeQuick_lua.ts +20 -9
- package/project/.sdk/src/cmp/lua/ReadmeRef_lua.ts +9 -8
- package/project/.sdk/src/cmp/lua/ReadmeTopQuick_lua.ts +15 -7
- package/project/.sdk/src/cmp/lua/ReadmeTopTest_lua.ts +6 -5
- package/project/.sdk/src/cmp/lua/fragment/Entity.fragment.lua +1 -0
- package/project/.sdk/src/cmp/lua/fragment/EntityCreateOp.fragment.lua +1 -1
- package/project/.sdk/src/cmp/lua/fragment/EntityListOp.fragment.lua +1 -1
- package/project/.sdk/src/cmp/lua/fragment/EntityLoadOp.fragment.lua +1 -1
- package/project/.sdk/src/cmp/lua/fragment/EntityPatchOp.fragment.lua +1 -1
- package/project/.sdk/src/cmp/lua/fragment/EntityRemoveOp.fragment.lua +1 -1
- package/project/.sdk/src/cmp/lua/fragment/EntityUpdateOp.fragment.lua +1 -1
- package/project/.sdk/src/cmp/ocaml/ReadmeEntity_ocaml.ts +3 -2
- package/project/.sdk/src/cmp/ocaml/ReadmeHowto_ocaml.ts +3 -2
- package/project/.sdk/src/cmp/ocaml/ReadmeModel_ocaml.ts +1 -0
- package/project/.sdk/src/cmp/ocaml/ReadmeQuick_ocaml.ts +5 -3
- package/project/.sdk/src/cmp/ocaml/ReadmeRef_ocaml.ts +10 -8
- package/project/.sdk/src/cmp/ocaml/ReadmeTopQuick_ocaml.ts +4 -2
- package/project/.sdk/src/cmp/ocaml/ReadmeTopTest_ocaml.ts +3 -2
- package/project/.sdk/src/cmp/ocaml/utility_ocaml.ts +13 -1
- package/project/.sdk/src/cmp/perl/ReadmeEntity_perl.ts +4 -1
- package/project/.sdk/src/cmp/perl/ReadmeHowto_perl.ts +10 -5
- package/project/.sdk/src/cmp/perl/ReadmeModel_perl.ts +6 -6
- package/project/.sdk/src/cmp/perl/ReadmeQuick_perl.ts +8 -5
- package/project/.sdk/src/cmp/perl/ReadmeRef_perl.ts +21 -18
- package/project/.sdk/src/cmp/perl/ReadmeTopQuick_perl.ts +6 -3
- package/project/.sdk/src/cmp/perl/ReadmeTopTest_perl.ts +11 -8
- package/project/.sdk/src/cmp/perl/fragment/Entity.fragment.pm +1 -1
- package/project/.sdk/src/cmp/perl/fragment/EntityCreateOp.fragment.pm +2 -2
- package/project/.sdk/src/cmp/perl/fragment/EntityLoadOp.fragment.pm +2 -2
- package/project/.sdk/src/cmp/perl/fragment/EntityPatchOp.fragment.pm +2 -2
- package/project/.sdk/src/cmp/perl/fragment/EntityRemoveOp.fragment.pm +1 -1
- package/project/.sdk/src/cmp/perl/fragment/EntityUpdateOp.fragment.pm +2 -2
- package/project/.sdk/src/cmp/perl/utility_perl.ts +11 -1
- package/project/.sdk/src/cmp/php/EntityOperation_php.ts +3 -1
- package/project/.sdk/src/cmp/php/ReadmeEntity_php.ts +4 -3
- package/project/.sdk/src/cmp/php/ReadmeHowto_php.ts +12 -6
- package/project/.sdk/src/cmp/php/ReadmeModel_php.ts +9 -9
- package/project/.sdk/src/cmp/php/ReadmeQuick_php.ts +3 -2
- package/project/.sdk/src/cmp/php/ReadmeRef_php.ts +15 -14
- package/project/.sdk/src/cmp/php/ReadmeTopQuick_php.ts +5 -4
- package/project/.sdk/src/cmp/php/ReadmeTopTest_php.ts +13 -7
- package/project/.sdk/src/cmp/php/fragment/EntityCreateOp.fragment.php +2 -2
- package/project/.sdk/src/cmp/php/fragment/EntityListOp.fragment.php +2 -2
- package/project/.sdk/src/cmp/php/fragment/EntityLoadOp.fragment.php +2 -2
- package/project/.sdk/src/cmp/php/fragment/EntityPatchOp.fragment.php +2 -2
- package/project/.sdk/src/cmp/php/fragment/EntityRemoveOp.fragment.php +2 -2
- package/project/.sdk/src/cmp/php/fragment/EntityUpdateOp.fragment.php +2 -2
- package/project/.sdk/src/cmp/py/EntityOperation_py.ts +3 -1
- package/project/.sdk/src/cmp/py/ReadmeEntity_py.ts +3 -8
- package/project/.sdk/src/cmp/py/ReadmeHowto_py.ts +9 -9
- package/project/.sdk/src/cmp/py/ReadmeModel_py.ts +9 -9
- package/project/.sdk/src/cmp/py/ReadmeQuick_py.ts +9 -14
- package/project/.sdk/src/cmp/py/ReadmeRef_py.ts +23 -30
- package/project/.sdk/src/cmp/py/ReadmeTopQuick_py.ts +7 -12
- package/project/.sdk/src/cmp/py/ReadmeTopTest_py.ts +8 -7
- package/project/.sdk/src/cmp/py/fragment/EntityCreateOp.fragment.py +1 -1
- package/project/.sdk/src/cmp/py/fragment/EntityListOp.fragment.py +1 -1
- package/project/.sdk/src/cmp/py/fragment/EntityLoadOp.fragment.py +1 -1
- package/project/.sdk/src/cmp/py/fragment/EntityPatchOp.fragment.py +1 -1
- package/project/.sdk/src/cmp/py/fragment/EntityRemoveOp.fragment.py +1 -1
- package/project/.sdk/src/cmp/py/fragment/EntityUpdateOp.fragment.py +1 -1
- package/project/.sdk/src/cmp/rb/EntityOperation_rb.ts +3 -1
- package/project/.sdk/src/cmp/rb/EntityTypes_rb.ts +2 -1
- package/project/.sdk/src/cmp/rb/ReadmeEntity_rb.ts +4 -1
- package/project/.sdk/src/cmp/rb/ReadmeExamplesTest_rb.ts +3 -2
- package/project/.sdk/src/cmp/rb/ReadmeHowto_rb.ts +20 -10
- package/project/.sdk/src/cmp/rb/ReadmeModel_rb.ts +10 -9
- package/project/.sdk/src/cmp/rb/ReadmeQuick_rb.ts +6 -3
- package/project/.sdk/src/cmp/rb/ReadmeRef_rb.ts +14 -11
- package/project/.sdk/src/cmp/rb/ReadmeTopQuick_rb.ts +6 -3
- package/project/.sdk/src/cmp/rb/ReadmeTopTest_rb.ts +14 -10
- package/project/.sdk/src/cmp/rb/fragment/EntityCreateOp.fragment.rb +2 -1
- package/project/.sdk/src/cmp/rb/fragment/EntityListOp.fragment.rb +1 -1
- package/project/.sdk/src/cmp/rb/fragment/EntityLoadOp.fragment.rb +2 -1
- package/project/.sdk/src/cmp/rb/fragment/EntityPatchOp.fragment.rb +2 -1
- package/project/.sdk/src/cmp/rb/fragment/EntityRemoveOp.fragment.rb +2 -1
- package/project/.sdk/src/cmp/rb/fragment/EntityUpdateOp.fragment.rb +2 -1
- package/project/.sdk/src/cmp/rb/utility_rb.ts +10 -0
- package/project/.sdk/src/cmp/rust/ReadmeEntity_rust.ts +3 -2
- package/project/.sdk/src/cmp/rust/ReadmeHowto_rust.ts +6 -2
- package/project/.sdk/src/cmp/rust/ReadmeQuick_rust.ts +3 -2
- package/project/.sdk/src/cmp/rust/ReadmeRef_rust.ts +5 -4
- package/project/.sdk/src/cmp/rust/ReadmeTopQuick_rust.ts +3 -2
- package/project/.sdk/src/cmp/rust/ReadmeTopTest_rust.ts +7 -6
- package/project/.sdk/src/cmp/rust/utility_rust.ts +13 -1
- package/project/.sdk/src/cmp/scala/EntityTypes_scala.ts +5 -2
- package/project/.sdk/src/cmp/scala/ReadmeEntity_scala.ts +8 -19
- package/project/.sdk/src/cmp/scala/ReadmeHowto_scala.ts +17 -22
- package/project/.sdk/src/cmp/scala/ReadmeModel_scala.ts +10 -9
- package/project/.sdk/src/cmp/scala/ReadmeQuick_scala.ts +18 -28
- package/project/.sdk/src/cmp/scala/ReadmeRef_scala.ts +25 -35
- package/project/.sdk/src/cmp/scala/ReadmeTopQuick_scala.ts +14 -25
- package/project/.sdk/src/cmp/scala/ReadmeTopTest_scala.ts +16 -24
- package/project/.sdk/src/cmp/scala/utility_scala.ts +25 -0
- package/project/.sdk/src/cmp/swift/EntityTypes_swift.ts +1 -1
- package/project/.sdk/src/cmp/swift/ReadmeEntity_swift.ts +3 -2
- package/project/.sdk/src/cmp/swift/ReadmeHowto_swift.ts +22 -8
- package/project/.sdk/src/cmp/swift/ReadmeModel_swift.ts +10 -9
- package/project/.sdk/src/cmp/swift/ReadmeQuick_swift.ts +16 -8
- package/project/.sdk/src/cmp/swift/ReadmeRef_swift.ts +20 -15
- package/project/.sdk/src/cmp/swift/ReadmeTopQuick_swift.ts +12 -7
- package/project/.sdk/src/cmp/swift/ReadmeTopTest_swift.ts +21 -10
- package/project/.sdk/src/cmp/swift/utility_swift.ts +14 -1
- package/project/.sdk/src/cmp/ts/ReadmeEntity_ts.ts +2 -8
- package/project/.sdk/src/cmp/ts/ReadmeHowto_ts.ts +11 -9
- package/project/.sdk/src/cmp/ts/ReadmeModel_ts.ts +9 -9
- package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +7 -13
- package/project/.sdk/src/cmp/ts/ReadmeRef_ts.ts +14 -23
- package/project/.sdk/src/cmp/ts/ReadmeTopQuick_ts.ts +8 -14
- package/project/.sdk/src/cmp/ts/ReadmeTopTest_ts.ts +29 -14
- package/project/.sdk/src/cmp/ts/fragment/EntityCreateOp.fragment.ts +1 -1
- package/project/.sdk/src/cmp/ts/fragment/EntityListOp.fragment.ts +1 -1
- package/project/.sdk/src/cmp/ts/fragment/EntityLoadOp.fragment.ts +1 -1
- package/project/.sdk/src/cmp/ts/fragment/EntityPatchOp.fragment.ts +1 -1
- package/project/.sdk/src/cmp/ts/fragment/EntityUpdateOp.fragment.ts +1 -1
- package/project/.sdk/src/cmp/ts/utility_ts.ts +2 -1
- package/project/.sdk/src/cmp/zig/ReadmeEntity_zig.ts +3 -2
- package/project/.sdk/src/cmp/zig/ReadmeHowto_zig.ts +6 -2
- package/project/.sdk/src/cmp/zig/ReadmeQuick_zig.ts +4 -3
- package/project/.sdk/src/cmp/zig/ReadmeRef_zig.ts +5 -4
- package/project/.sdk/src/cmp/zig/ReadmeTopQuick_zig.ts +3 -2
- package/project/.sdk/src/cmp/zig/ReadmeTopTest_zig.ts +7 -6
- package/project/.sdk/src/cmp/zig/utility_zig.ts +13 -0
- package/project/.sdk/tm/c/utility/transform_request.c +1 -1
- package/project/.sdk/tm/clojure/src/sdk/core.clj +32 -26
- package/project/.sdk/tm/clojure/test/sdk/test/concurrency.clj +136 -0
- package/project/.sdk/tm/clojure/test/sdk/test_runner.clj +3 -1
- package/project/.sdk/tm/cpp/core/types.hpp +36 -6
- package/project/.sdk/tm/cpp/test/concurrency_test.cpp +348 -0
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +42 -25
- package/project/.sdk/tm/csharp/core/Context.cs +8 -5
- package/project/.sdk/tm/csharp/test/ConcurrencyTest.cs +238 -0
- package/project/.sdk/tm/csharp/utility/Clean.cs +12 -10
- package/project/.sdk/tm/csharp/utility/TransformRequest.cs +1 -1
- package/project/.sdk/tm/elixir/lib/projectname/context.ex +3 -0
- package/project/.sdk/tm/elixir/lib/projectname/entity_base.ex +2 -1
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +31 -10
- package/project/.sdk/tm/elixir/test/concurrency_test.exs +176 -0
- package/project/.sdk/tm/go/core/context.go +5 -1
- package/project/.sdk/tm/go/test/concurrency_test.go +214 -0
- package/project/.sdk/tm/go/utility/transform_request.go +1 -1
- package/project/.sdk/tm/java/core/Context.java +6 -3
- package/project/.sdk/tm/java/test/ConcurrencyTest.java +221 -0
- package/project/.sdk/tm/java/utility/Clean.java +22 -17
- package/project/.sdk/tm/java/utility/TransformRequest.java +1 -1
- package/project/.sdk/tm/js/src/utility/TransformRequestUtility.js +1 -1
- package/project/.sdk/tm/kotlin/core/Context.kt +5 -3
- package/project/.sdk/tm/kotlin/test/ConcurrencyTest.kt +193 -0
- package/project/.sdk/tm/kotlin/utility/ResultTransform.kt +1 -1
- package/project/.sdk/tm/lua/utility/transform_request.lua +1 -1
- package/project/.sdk/tm/ocaml/Makefile +21 -8
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +27 -12
- package/project/.sdk/tm/ocaml/sdk_types.ml +6 -2
- package/project/.sdk/tm/ocaml/test/concurrency_test.ml +148 -0
- package/project/.sdk/tm/perl/utility/transform_request.pm +1 -1
- package/project/.sdk/tm/php/feature/TestFeature.php +9 -9
- package/project/.sdk/tm/php/utility/TransformRequest.php +1 -1
- package/project/.sdk/tm/py/pkg/core/context.py +2 -2
- package/project/.sdk/tm/py/pkg/utility/clean.py +12 -8
- package/project/.sdk/tm/py/pkg/utility/transform_request.py +1 -1
- package/project/.sdk/tm/py/test/test_concurrency.py +177 -0
- package/project/.sdk/tm/rb/core/context.rb +8 -3
- package/project/.sdk/tm/rb/test/concurrency_test.rb +160 -0
- package/project/.sdk/tm/rb/utility/clean.rb +8 -7
- package/project/.sdk/tm/rb/utility/transform_request.rb +1 -1
- package/project/.sdk/tm/rust/utility/transform_request.rs +1 -1
- package/project/.sdk/tm/scala/Makefile +2 -0
- package/project/.sdk/tm/scala/core/Context.scala +6 -4
- package/project/.sdk/tm/scala/sdktest/ConcurrencyTest.scala +186 -0
- package/project/.sdk/tm/scala/utility/Transform.scala +1 -1
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/core/Context.swift +2 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/ResultUtil.swift +35 -12
- package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/ConcurrencyTest.swift +214 -0
- package/project/.sdk/tm/ts/src/utility/TransformRequestUtility.ts +1 -1
- package/project/.sdk/tm/zig/core/utility.zig +1 -1
- package/project/.sdk/tm/zig/feature/test.zig +10 -8
- package/project/sdkgen-package.json +1 -1
- package/src/cmp/ReadmeErrors.ts +5 -5
- package/src/cmp/ReadmeExplanation.ts +4 -5
- package/src/cmp/ReadmeQuick.ts +3 -1
- package/src/cmp/ReadmeTop.ts +10 -12
- package/src/helpers/definitionPlan.ts +8 -4
- package/src/helpers/naming.ts +12 -4
- package/src/helpers/opExample.ts +97 -25
- package/src/helpers/opShape.ts +25 -9
- package/src/sdkgen.ts +14 -3
- package/src/utility.ts +31 -4
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
package sdktest
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"sync"
|
|
6
|
+
"testing"
|
|
7
|
+
|
|
8
|
+
sdk "GOMODULE"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// Requests in flight at once on one client. Each resolves its operation
|
|
12
|
+
// through the cache the client's root context shares with every request, and
|
|
13
|
+
// registers and cleans secrets through the one registry the client holds.
|
|
14
|
+
|
|
15
|
+
const concurrencyRounds = 200
|
|
16
|
+
const concurrencyWidth = 8
|
|
17
|
+
const concurrencyOps = 32
|
|
18
|
+
|
|
19
|
+
// concurrencyClient is a live client whose transport answers at once.
|
|
20
|
+
func concurrencyClient() *sdk.ProjectNameSDK {
|
|
21
|
+
return sdk.NewProjectNameSDK(map[string]any{
|
|
22
|
+
"base": "http://concurrency.test/api",
|
|
23
|
+
"allow": map[string]any{"op": "direct"},
|
|
24
|
+
"system": map[string]any{
|
|
25
|
+
"fetch": func(url string, fetchdef map[string]any) (map[string]any, error) {
|
|
26
|
+
return map[string]any{
|
|
27
|
+
"status": 200,
|
|
28
|
+
"statusText": "OK",
|
|
29
|
+
"headers": map[string]any{},
|
|
30
|
+
"json": func() any { return map[string]any{"ok": true} },
|
|
31
|
+
}, nil
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// atOnce runs body on concurrencyWidth goroutines released together.
|
|
38
|
+
func atOnce(body func(n int)) {
|
|
39
|
+
var ready, done sync.WaitGroup
|
|
40
|
+
start := make(chan struct{})
|
|
41
|
+
ready.Add(concurrencyWidth)
|
|
42
|
+
done.Add(concurrencyWidth)
|
|
43
|
+
for i := 0; i < concurrencyWidth; i++ {
|
|
44
|
+
go func(n int) {
|
|
45
|
+
defer done.Done()
|
|
46
|
+
ready.Done()
|
|
47
|
+
<-start
|
|
48
|
+
body(n)
|
|
49
|
+
}(i)
|
|
50
|
+
}
|
|
51
|
+
ready.Wait()
|
|
52
|
+
close(start)
|
|
53
|
+
done.Wait()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
func TestConcurrentFirstRequests(t *testing.T) {
|
|
57
|
+
for round := 0; round < concurrencyRounds; round++ {
|
|
58
|
+
// A fresh client each round, so every request in it is a first request.
|
|
59
|
+
client := concurrencyClient()
|
|
60
|
+
results := make([]map[string]any, concurrencyWidth)
|
|
61
|
+
errs := make([]error, concurrencyWidth)
|
|
62
|
+
atOnce(func(n int) {
|
|
63
|
+
results[n], errs[n] = client.Direct(map[string]any{"path": fmt.Sprintf("p%d", n)})
|
|
64
|
+
})
|
|
65
|
+
for n := range results {
|
|
66
|
+
if errs[n] != nil || results[n]["ok"] != true {
|
|
67
|
+
t.Fatalf("round %d, request %d failed: %v %v", round, n, errs[n], results[n])
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
func TestConcurrentOperationResolution(t *testing.T) {
|
|
74
|
+
for round := 0; round < concurrencyRounds; round++ {
|
|
75
|
+
client := concurrencyClient()
|
|
76
|
+
utility := client.GetUtility()
|
|
77
|
+
root := client.GetRootCtx()
|
|
78
|
+
ops := make([][]*sdk.Operation, concurrencyWidth)
|
|
79
|
+
atOnce(func(n int) {
|
|
80
|
+
ops[n] = make([]*sdk.Operation, concurrencyOps)
|
|
81
|
+
for k := range ops[n] {
|
|
82
|
+
ops[n][k] = utility.MakeContext(map[string]any{"opname": fmt.Sprintf("op%d", k)}, root).Op
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
for k := 0; k < concurrencyOps; k++ {
|
|
86
|
+
cached := utility.MakeContext(map[string]any{"opname": fmt.Sprintf("op%d", k)}, root).Op
|
|
87
|
+
for n := range ops {
|
|
88
|
+
if ops[n][k] != cached {
|
|
89
|
+
t.Fatalf("round %d: op%d resolved to more than one Operation", round, k)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
func addedSecret(round, n, k int) string {
|
|
97
|
+
return fmt.Sprintf("ADDED-SECRET-%d-%d-%d", round, n, k)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// registerSecrets registers goroutine n's secrets.
|
|
101
|
+
func registerSecrets(utility *sdk.Utility, root *sdk.Context, round, n int) {
|
|
102
|
+
for k := 0; k < concurrencyOps; k++ {
|
|
103
|
+
utility.CleanAdd(root, addedSecret(round, n, k))
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// unmaskedSecret is the first secret registered in the round that a clean
|
|
108
|
+
// leaves raw, or "".
|
|
109
|
+
func unmaskedSecret(utility *sdk.Utility, root *sdk.Context, round int) string {
|
|
110
|
+
for n := 0; n < concurrencyWidth/2; n++ {
|
|
111
|
+
for k := 0; k < concurrencyOps; k++ {
|
|
112
|
+
added := addedSecret(round, n, k)
|
|
113
|
+
if got := utility.Clean(root, added); got != "[redacted]" {
|
|
114
|
+
return added
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return ""
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// whileRegistering has half the goroutines register their secrets, and the
|
|
122
|
+
// rest run body until those are done or body returns false.
|
|
123
|
+
func whileRegistering(utility *sdk.Utility, root *sdk.Context, round int, body func(n int) bool) {
|
|
124
|
+
var registering sync.WaitGroup
|
|
125
|
+
registering.Add(concurrencyWidth / 2)
|
|
126
|
+
registered := make(chan struct{})
|
|
127
|
+
go func() {
|
|
128
|
+
registering.Wait()
|
|
129
|
+
close(registered)
|
|
130
|
+
}()
|
|
131
|
+
atOnce(func(n int) {
|
|
132
|
+
if n < concurrencyWidth/2 {
|
|
133
|
+
defer registering.Done()
|
|
134
|
+
registerSecrets(utility, root, round, n)
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
for {
|
|
138
|
+
select {
|
|
139
|
+
case <-registered:
|
|
140
|
+
return
|
|
141
|
+
default:
|
|
142
|
+
}
|
|
143
|
+
if !body(n) {
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Secrets registered on some goroutines while others clean: every clean masks
|
|
151
|
+
// what was registered before it, the longer secret whole, and no registration
|
|
152
|
+
// is lost.
|
|
153
|
+
func TestConcurrentCleanRegistry(t *testing.T) {
|
|
154
|
+
const masked = "a [redacted] b [redacted] c"
|
|
155
|
+
for round := 0; round < concurrencyRounds/4; round++ {
|
|
156
|
+
client := concurrencyClient()
|
|
157
|
+
utility := client.GetUtility()
|
|
158
|
+
root := client.GetRootCtx()
|
|
159
|
+
inner := fmt.Sprintf("INNER-SECRET-%d", round)
|
|
160
|
+
utility.CleanAdd(root, inner)
|
|
161
|
+
utility.CleanAdd(root, "OUTER-"+inner+"-TAIL")
|
|
162
|
+
text := "a " + inner + " b OUTER-" + inner + "-TAIL c"
|
|
163
|
+
if got := utility.Clean(root, text); got != masked {
|
|
164
|
+
t.Fatalf("round %d cleaned to: %v", round, got)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
wrong := make([]any, concurrencyWidth)
|
|
168
|
+
whileRegistering(utility, root, round, func(n int) bool {
|
|
169
|
+
if got := utility.Clean(root, text); got != masked {
|
|
170
|
+
wrong[n] = got
|
|
171
|
+
return false
|
|
172
|
+
}
|
|
173
|
+
return true
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
for n, got := range wrong {
|
|
177
|
+
if got != nil {
|
|
178
|
+
t.Fatalf("round %d, cleaner %d cleaned to: %v", round, n, got)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if raw := unmaskedSecret(utility, root, round); raw != "" {
|
|
182
|
+
t.Fatalf("round %d: %s was registered but not masked", round, raw)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Requests on one client while secrets register on it: each request copies
|
|
188
|
+
// the client's options, the registry among them.
|
|
189
|
+
func TestConcurrentRequestsWhileRegistering(t *testing.T) {
|
|
190
|
+
for round := 0; round < concurrencyRounds/4; round++ {
|
|
191
|
+
client := concurrencyClient()
|
|
192
|
+
utility := client.GetUtility()
|
|
193
|
+
root := client.GetRootCtx()
|
|
194
|
+
|
|
195
|
+
failed := make([]any, concurrencyWidth)
|
|
196
|
+
whileRegistering(utility, root, round, func(n int) bool {
|
|
197
|
+
res, err := client.Direct(map[string]any{"path": fmt.Sprintf("p%d", n)})
|
|
198
|
+
if err != nil || res["ok"] != true {
|
|
199
|
+
failed[n] = fmt.Sprint(err, res)
|
|
200
|
+
return false
|
|
201
|
+
}
|
|
202
|
+
return true
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
for n, got := range failed {
|
|
206
|
+
if got != nil {
|
|
207
|
+
t.Fatalf("round %d, request %d failed: %v", round, n, got)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if raw := unmaskedSecret(utility, root, round); raw != "" {
|
|
211
|
+
t.Fatalf("round %d: %s was registered but not masked", round, raw)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -49,7 +49,7 @@ func stripAction(reqdata any) any {
|
|
|
49
49
|
|
|
50
50
|
// A header, cookie or query argument travels where prepareHeadersUtil or
|
|
51
51
|
// prepareQueryUtil sends it, so the body is built from the request data
|
|
52
|
-
// without it, unless the
|
|
52
|
+
// without it, unless the point marks it as a field the body keeps.
|
|
53
53
|
func routedArgNames(ctx *core.Context) []string {
|
|
54
54
|
names := []string{}
|
|
55
55
|
for _, arg := range append(append(callArgs(ctx, "header"), callArgs(ctx, "cookie")...), callArgs(ctx, "query")...) {
|
|
@@ -4,6 +4,7 @@ import java.util.ArrayList;
|
|
|
4
4
|
import java.util.LinkedHashMap;
|
|
5
5
|
import java.util.List;
|
|
6
6
|
import java.util.Map;
|
|
7
|
+
import java.util.concurrent.ConcurrentHashMap;
|
|
7
8
|
import java.util.concurrent.ThreadLocalRandom;
|
|
8
9
|
|
|
9
10
|
import JAVAPACKAGE.utility.struct.Struct;
|
|
@@ -151,7 +152,7 @@ public class Context {
|
|
|
151
152
|
this.opmap = basectx.opmap;
|
|
152
153
|
}
|
|
153
154
|
if (this.opmap == null) {
|
|
154
|
-
this.opmap = new
|
|
155
|
+
this.opmap = new ConcurrentHashMap<>();
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
// Data
|
|
@@ -260,8 +261,10 @@ public class Context {
|
|
|
260
261
|
|
|
261
262
|
Operation op = new Operation(opdef);
|
|
262
263
|
|
|
263
|
-
this
|
|
264
|
-
|
|
264
|
+
// Requests on other threads share this cache; every one of them gets
|
|
265
|
+
// the Operation stored first.
|
|
266
|
+
Operation stored = this.opmap.putIfAbsent(cacheKey, op);
|
|
267
|
+
return null == stored ? op : stored;
|
|
265
268
|
}
|
|
266
269
|
|
|
267
270
|
public SdkError makeError(String code, String msg) {
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
package JAVAPACKAGE.sdktest;
|
|
2
|
+
|
|
3
|
+
// Requests in flight at once on one client. Each resolves its operation
|
|
4
|
+
// through the cache the client's root context shares with every request, and
|
|
5
|
+
// registers and cleans secrets through the one registry the client holds.
|
|
6
|
+
|
|
7
|
+
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
8
|
+
import static org.junit.jupiter.api.Assertions.assertSame;
|
|
9
|
+
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
10
|
+
|
|
11
|
+
import java.util.ArrayList;
|
|
12
|
+
import java.util.LinkedHashMap;
|
|
13
|
+
import java.util.List;
|
|
14
|
+
import java.util.Map;
|
|
15
|
+
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
16
|
+
import java.util.concurrent.CountDownLatch;
|
|
17
|
+
import java.util.concurrent.CyclicBarrier;
|
|
18
|
+
import java.util.function.BiFunction;
|
|
19
|
+
import java.util.function.IntConsumer;
|
|
20
|
+
import java.util.function.Supplier;
|
|
21
|
+
|
|
22
|
+
import org.junit.jupiter.api.Test;
|
|
23
|
+
|
|
24
|
+
import JAVAPACKAGE.core.Context;
|
|
25
|
+
import JAVAPACKAGE.core.Operation;
|
|
26
|
+
import JAVAPACKAGE.core.ProjectNameSDK;
|
|
27
|
+
import JAVAPACKAGE.core.Utility;
|
|
28
|
+
|
|
29
|
+
public class ConcurrencyTest {
|
|
30
|
+
|
|
31
|
+
static final int ROUNDS = 200;
|
|
32
|
+
static final int WIDTH = 8;
|
|
33
|
+
static final int OPS = 32;
|
|
34
|
+
|
|
35
|
+
static Map<String, Object> map(Object... kv) {
|
|
36
|
+
Map<String, Object> out = new LinkedHashMap<>();
|
|
37
|
+
for (int i = 0; i + 1 < kv.length; i += 2) {
|
|
38
|
+
out.put((String) kv[i], kv[i + 1]);
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// A live client whose transport answers at once.
|
|
44
|
+
static ProjectNameSDK liveClient() {
|
|
45
|
+
BiFunction<String, Map<String, Object>, Map<String, Object>> fetch =
|
|
46
|
+
(url, fetchdef) -> map(
|
|
47
|
+
"status", 200,
|
|
48
|
+
"statusText", "OK",
|
|
49
|
+
"headers", new LinkedHashMap<String, Object>(),
|
|
50
|
+
"json", (Supplier<Object>) () -> map("ok", true));
|
|
51
|
+
return new ProjectNameSDK(map(
|
|
52
|
+
"base", "http://concurrency.test/api",
|
|
53
|
+
"allow", map("op", "direct"),
|
|
54
|
+
"system", map("fetch", fetch)));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Runs body on WIDTH threads released together, and returns what they threw.
|
|
58
|
+
static List<Throwable> atOnce(IntConsumer body) throws InterruptedException {
|
|
59
|
+
CyclicBarrier start = new CyclicBarrier(WIDTH);
|
|
60
|
+
ConcurrentLinkedQueue<Throwable> thrown = new ConcurrentLinkedQueue<>();
|
|
61
|
+
List<Thread> threads = new ArrayList<>();
|
|
62
|
+
for (int i = 0; i < WIDTH; i++) {
|
|
63
|
+
final int n = i;
|
|
64
|
+
Thread thread = new Thread(() -> {
|
|
65
|
+
try {
|
|
66
|
+
start.await();
|
|
67
|
+
body.accept(n);
|
|
68
|
+
}
|
|
69
|
+
catch (Throwable t) {
|
|
70
|
+
thrown.add(t);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
thread.start();
|
|
74
|
+
threads.add(thread);
|
|
75
|
+
}
|
|
76
|
+
for (Thread thread : threads) {
|
|
77
|
+
thread.join();
|
|
78
|
+
}
|
|
79
|
+
return new ArrayList<>(thrown);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@Test
|
|
83
|
+
public void concurrentFirstRequestsSucceed() throws InterruptedException {
|
|
84
|
+
for (int round = 0; round < ROUNDS; round++) {
|
|
85
|
+
// A fresh client each round, so every request in it is a first request.
|
|
86
|
+
ProjectNameSDK client = liveClient();
|
|
87
|
+
List<Map<String, Object>> results = new ArrayList<>();
|
|
88
|
+
for (int n = 0; n < WIDTH; n++) {
|
|
89
|
+
results.add(null);
|
|
90
|
+
}
|
|
91
|
+
List<Throwable> thrown = atOnce(n -> results.set(n, client.direct(map("path", "p" + n))));
|
|
92
|
+
|
|
93
|
+
assertTrue(thrown.isEmpty(), "round " + round + " threw: " + thrown);
|
|
94
|
+
for (int n = 0; n < WIDTH; n++) {
|
|
95
|
+
Map<String, Object> res = results.get(n);
|
|
96
|
+
assertEquals(true, null == res ? null : res.get("ok"),
|
|
97
|
+
"round " + round + ", request " + n + " failed: " + res);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@Test
|
|
103
|
+
public void concurrentResolutionsShareOneCachedOperation() throws InterruptedException {
|
|
104
|
+
for (int round = 0; round < ROUNDS; round++) {
|
|
105
|
+
ProjectNameSDK client = liveClient();
|
|
106
|
+
Utility utility = client.getUtility();
|
|
107
|
+
Context root = client.getRootCtx();
|
|
108
|
+
Operation[][] ops = new Operation[WIDTH][OPS];
|
|
109
|
+
List<Throwable> thrown = atOnce(n -> {
|
|
110
|
+
for (int k = 0; k < OPS; k++) {
|
|
111
|
+
ops[n][k] = utility.makeContext.apply(map("opname", "op" + k), root).op;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
assertTrue(thrown.isEmpty(), "round " + round + " threw: " + thrown);
|
|
116
|
+
for (int k = 0; k < OPS; k++) {
|
|
117
|
+
Operation cached = utility.makeContext.apply(map("opname", "op" + k), root).op;
|
|
118
|
+
for (int n = 0; n < WIDTH; n++) {
|
|
119
|
+
assertSame(cached, ops[n][k],
|
|
120
|
+
"round " + round + ": op" + k + " resolved to more than one Operation");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static String addedSecret(int round, int n, int k) {
|
|
127
|
+
return "ADDED-SECRET-" + round + "-" + n + "-" + k;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Registers thread n's secrets, then counts the thread out of registering.
|
|
131
|
+
static void registerSecrets(Utility utility, Context root, int round, int n,
|
|
132
|
+
CountDownLatch registering) {
|
|
133
|
+
try {
|
|
134
|
+
for (int k = 0; k < OPS; k++) {
|
|
135
|
+
utility.cleanAdd.apply(root, addedSecret(round, n, k));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
registering.countDown();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
static void assertEverySecretMasked(Utility utility, Context root, int round) {
|
|
144
|
+
for (int n = 0; n < WIDTH / 2; n++) {
|
|
145
|
+
for (int k = 0; k < OPS; k++) {
|
|
146
|
+
String added = addedSecret(round, n, k);
|
|
147
|
+
assertEquals("[redacted]", utility.clean.apply(root, added),
|
|
148
|
+
"round " + round + ": " + added + " was registered but not masked");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Secrets registered on some threads while others clean: every clean masks
|
|
154
|
+
// what was registered before it, the longer secret whole, and no
|
|
155
|
+
// registration is lost.
|
|
156
|
+
@Test
|
|
157
|
+
public void concurrentRegistrationKeepsEverySecretMasked() throws InterruptedException {
|
|
158
|
+
for (int round = 0; round < ROUNDS / 4; round++) {
|
|
159
|
+
final int r = round;
|
|
160
|
+
ProjectNameSDK client = liveClient();
|
|
161
|
+
Utility utility = client.getUtility();
|
|
162
|
+
Context root = client.getRootCtx();
|
|
163
|
+
String inner = "INNER-SECRET-" + round;
|
|
164
|
+
utility.cleanAdd.apply(root, inner);
|
|
165
|
+
utility.cleanAdd.apply(root, "OUTER-" + inner + "-TAIL");
|
|
166
|
+
String text = "a " + inner + " b OUTER-" + inner + "-TAIL c";
|
|
167
|
+
String masked = "a [redacted] b [redacted] c";
|
|
168
|
+
assertEquals(masked, utility.clean.apply(root, text));
|
|
169
|
+
|
|
170
|
+
CountDownLatch registering = new CountDownLatch(WIDTH / 2);
|
|
171
|
+
ConcurrentLinkedQueue<Object> wrong = new ConcurrentLinkedQueue<>();
|
|
172
|
+
List<Throwable> thrown = atOnce(n -> {
|
|
173
|
+
if (n < WIDTH / 2) {
|
|
174
|
+
registerSecrets(utility, root, r, n, registering);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
while (0 < registering.getCount()) {
|
|
178
|
+
Object got = utility.clean.apply(root, text);
|
|
179
|
+
if (!masked.equals(got)) {
|
|
180
|
+
wrong.add(String.valueOf(got));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
assertTrue(thrown.isEmpty(), "round " + round + " threw: " + thrown);
|
|
186
|
+
assertTrue(wrong.isEmpty(), "round " + round + " cleaned to: " + wrong);
|
|
187
|
+
assertEverySecretMasked(utility, root, round);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Requests on one client while secrets register on it: each request copies
|
|
192
|
+
// the client's options, the registry among them.
|
|
193
|
+
@Test
|
|
194
|
+
public void concurrentRequestsSurviveRegistration() throws InterruptedException {
|
|
195
|
+
for (int round = 0; round < ROUNDS / 4; round++) {
|
|
196
|
+
final int r = round;
|
|
197
|
+
ProjectNameSDK client = liveClient();
|
|
198
|
+
Utility utility = client.getUtility();
|
|
199
|
+
Context root = client.getRootCtx();
|
|
200
|
+
CountDownLatch registering = new CountDownLatch(WIDTH / 2);
|
|
201
|
+
ConcurrentLinkedQueue<Object> failed = new ConcurrentLinkedQueue<>();
|
|
202
|
+
List<Throwable> thrown = atOnce(n -> {
|
|
203
|
+
if (n < WIDTH / 2) {
|
|
204
|
+
registerSecrets(utility, root, r, n, registering);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
while (0 < registering.getCount()) {
|
|
208
|
+
Map<String, Object> res = client.direct(map("path", "p" + n));
|
|
209
|
+
if (!Boolean.TRUE.equals(res.get("ok"))) {
|
|
210
|
+
failed.add(String.valueOf(res));
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
assertTrue(thrown.isEmpty(), "round " + round + " threw: " + thrown);
|
|
217
|
+
assertTrue(failed.isEmpty(), "round " + round + ", a request failed: " + failed);
|
|
218
|
+
assertEverySecretMasked(utility, root, round);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
@@ -14,6 +14,7 @@ import java.util.LinkedHashMap;
|
|
|
14
14
|
import java.util.List;
|
|
15
15
|
import java.util.Locale;
|
|
16
16
|
import java.util.Map;
|
|
17
|
+
import java.util.concurrent.ConcurrentHashMap;
|
|
17
18
|
import java.util.function.BiFunction;
|
|
18
19
|
import java.util.function.Consumer;
|
|
19
20
|
import java.util.function.Function;
|
|
@@ -37,8 +38,8 @@ import JAVAPACKAGE.utility.struct.Struct;
|
|
|
37
38
|
//
|
|
38
39
|
// The configuration is the derived block MakeOptions builds
|
|
39
40
|
// (`options.__derived__.clean`): active, keys, values, mask, hint, min. It
|
|
40
|
-
// is a
|
|
41
|
-
//
|
|
41
|
+
// is a map so the registry can grow after construction - the auth step and
|
|
42
|
+
// the features register what they handle later.
|
|
42
43
|
@SuppressWarnings({"unchecked"})
|
|
43
44
|
final class Clean {
|
|
44
45
|
|
|
@@ -67,7 +68,9 @@ final class Clean {
|
|
|
67
68
|
|
|
68
69
|
static Map<String, Object> makeCleanConfig(Map<String, Object> cleanopts) {
|
|
69
70
|
Map<String, Object> opts = cleanopts == null ? new LinkedHashMap<>() : cleanopts;
|
|
70
|
-
|
|
71
|
+
// Read without the monitor add() holds, by a clean or a request copying
|
|
72
|
+
// the options: each read sees the list the last registration put.
|
|
73
|
+
Map<String, Object> cfg = new ConcurrentHashMap<>();
|
|
71
74
|
cfg.put("active", !Boolean.FALSE.equals(opts.get("active")));
|
|
72
75
|
cfg.put("keys", splitkeys(opts.get("keys")));
|
|
73
76
|
cfg.put("values", new ArrayList<String>());
|
|
@@ -148,10 +151,8 @@ final class Clean {
|
|
|
148
151
|
}
|
|
149
152
|
|
|
150
153
|
private static List<String> values(Map<String, Object> cfg) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
return (List<String>) cfg.get("values");
|
|
154
|
+
Object values = cfg.get("values");
|
|
155
|
+
return values instanceof List ? (List<String>) values : List.of();
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
private static String mask(Map<String, Object> cfg) {
|
|
@@ -193,21 +194,25 @@ final class Clean {
|
|
|
193
194
|
}
|
|
194
195
|
|
|
195
196
|
// Register a secret value. Idempotent; shorter than `min` is not a secret
|
|
196
|
-
// the SDK can mask without blanking ordinary text.
|
|
197
|
+
// the SDK can mask without blanking ordinary text. Requests on other
|
|
198
|
+
// threads clean while one registers, so a registration publishes a new
|
|
199
|
+
// list and never changes a published one.
|
|
197
200
|
static void add(Map<String, Object> cfg, Object value) {
|
|
198
201
|
if (!(value instanceof String) || ((String) value).length() < min(cfg)) {
|
|
199
202
|
return;
|
|
200
203
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
values.
|
|
206
|
-
|
|
204
|
+
synchronized (cfg) {
|
|
205
|
+
List<String> values = new ArrayList<>(values(cfg));
|
|
206
|
+
int had = values.size();
|
|
207
|
+
for (String form : forms((String) value)) {
|
|
208
|
+
if (form.length() >= min(cfg) && !values.contains(form)) {
|
|
209
|
+
values.add(form);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (had < values.size()) {
|
|
213
|
+
values.sort((a, b) -> b.length() - a.length());
|
|
214
|
+
cfg.put("values", List.copyOf(values));
|
|
207
215
|
}
|
|
208
|
-
}
|
|
209
|
-
if (changed) {
|
|
210
|
-
values.sort((a, b) -> b.length() - a.length());
|
|
211
216
|
}
|
|
212
217
|
}
|
|
213
218
|
|
|
@@ -45,7 +45,7 @@ final class TransformRequest {
|
|
|
45
45
|
|
|
46
46
|
// A header, cookie or query argument travels where PrepareHeaders or
|
|
47
47
|
// PrepareQuery sends it, so the body is built from the request data without
|
|
48
|
-
// it, unless the
|
|
48
|
+
// it, unless the point marks it as a field the body keeps.
|
|
49
49
|
private static List<String> routedArgNames(Context ctx) {
|
|
50
50
|
List<String> names = new ArrayList<>();
|
|
51
51
|
for (String kind : List.of("header", "cookie", "query")) {
|
|
@@ -50,7 +50,7 @@ function stripAction(reqdata) {
|
|
|
50
50
|
|
|
51
51
|
// A header, cookie or query argument travels where prepareHeaders or
|
|
52
52
|
// prepareQuery sends it, so the body is built from the request data without
|
|
53
|
-
// it, unless the
|
|
53
|
+
// it, unless the point marks it as a field the body keeps.
|
|
54
54
|
function routedArgNames(ctx) {
|
|
55
55
|
return callArgs(ctx, 'header').concat(callArgs(ctx, 'cookie'), callArgs(ctx, 'query'))
|
|
56
56
|
.map((arg) => arg.name)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package KOTLINPACKAGE.core
|
|
2
2
|
|
|
3
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
3
4
|
import java.util.concurrent.ThreadLocalRandom
|
|
4
5
|
|
|
5
6
|
import KOTLINPACKAGE.utility.struct.Struct
|
|
@@ -143,7 +144,7 @@ class Context(ctxmap: MutableMap<String, Any?>?, basectx: Context?) {
|
|
|
143
144
|
this.opmap = basectx.opmap
|
|
144
145
|
}
|
|
145
146
|
if (this.opmap == null) {
|
|
146
|
-
this.opmap =
|
|
147
|
+
this.opmap = ConcurrentHashMap()
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
// Data
|
|
@@ -237,8 +238,9 @@ class Context(ctxmap: MutableMap<String, Any?>?, basectx: Context?) {
|
|
|
237
238
|
|
|
238
239
|
val op = Operation(opdef)
|
|
239
240
|
|
|
240
|
-
this
|
|
241
|
-
|
|
241
|
+
// Requests on other threads share this cache; every one of them gets
|
|
242
|
+
// the Operation stored first.
|
|
243
|
+
return this.opmap!!.putIfAbsent(cacheKey, op) ?: op
|
|
242
244
|
}
|
|
243
245
|
|
|
244
246
|
fun makeError(code: String, msg: String): SdkError {
|