@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,238 @@
|
|
|
1
|
+
// Requests in flight at once on one client. Each resolves its operation
|
|
2
|
+
// through the cache the client's root context shares with every request, and
|
|
3
|
+
// registers and cleans secrets through the one registry the client holds.
|
|
4
|
+
|
|
5
|
+
using System.Collections.Concurrent;
|
|
6
|
+
|
|
7
|
+
using Xunit;
|
|
8
|
+
|
|
9
|
+
using ProjectNameSdk;
|
|
10
|
+
|
|
11
|
+
namespace ProjectNameSdk.Test;
|
|
12
|
+
|
|
13
|
+
public class ConcurrencyTest
|
|
14
|
+
{
|
|
15
|
+
private const int Rounds = 200;
|
|
16
|
+
private const int Width = 8;
|
|
17
|
+
private const int Ops = 32;
|
|
18
|
+
|
|
19
|
+
private static Dictionary<string, object?> Answer(string url, Dictionary<string, object?> fetchdef)
|
|
20
|
+
{
|
|
21
|
+
return new Dictionary<string, object?>
|
|
22
|
+
{
|
|
23
|
+
["status"] = 200,
|
|
24
|
+
["statusText"] = "OK",
|
|
25
|
+
["headers"] = new Dictionary<string, object?>(),
|
|
26
|
+
["json"] = (Func<object?>)(() => new Dictionary<string, object?> { ["ok"] = true }),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// A live client whose transport answers at once.
|
|
31
|
+
private static ProjectNameSDK LiveClient()
|
|
32
|
+
{
|
|
33
|
+
return new ProjectNameSDK(new Dictionary<string, object?>
|
|
34
|
+
{
|
|
35
|
+
["base"] = "http://concurrency.test/api",
|
|
36
|
+
["allow"] = new Dictionary<string, object?> { ["op"] = "direct" },
|
|
37
|
+
["system"] = new Dictionary<string, object?>
|
|
38
|
+
{
|
|
39
|
+
["fetch"] = (Func<string, Dictionary<string, object?>,
|
|
40
|
+
Dictionary<string, object?>>)Answer,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Runs body on Width threads released together, and returns what they threw.
|
|
46
|
+
private static List<Exception> AtOnce(Action<int> body)
|
|
47
|
+
{
|
|
48
|
+
var start = new Barrier(Width);
|
|
49
|
+
var thrown = new ConcurrentQueue<Exception>();
|
|
50
|
+
var threads = new List<Thread>();
|
|
51
|
+
for (var i = 0; i < Width; i++)
|
|
52
|
+
{
|
|
53
|
+
var n = i;
|
|
54
|
+
var thread = new Thread(() =>
|
|
55
|
+
{
|
|
56
|
+
try
|
|
57
|
+
{
|
|
58
|
+
start.SignalAndWait();
|
|
59
|
+
body(n);
|
|
60
|
+
}
|
|
61
|
+
catch (Exception e)
|
|
62
|
+
{
|
|
63
|
+
thrown.Enqueue(e);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
thread.Start();
|
|
67
|
+
threads.Add(thread);
|
|
68
|
+
}
|
|
69
|
+
threads.ForEach(t => t.Join());
|
|
70
|
+
return thrown.ToList();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
[Fact]
|
|
74
|
+
public void ConcurrentFirstRequestsSucceed()
|
|
75
|
+
{
|
|
76
|
+
for (var round = 0; round < Rounds; round++)
|
|
77
|
+
{
|
|
78
|
+
// A fresh client each round, so every request in it is a first request.
|
|
79
|
+
var client = LiveClient();
|
|
80
|
+
var results = new Dictionary<string, object?>?[Width];
|
|
81
|
+
var thrown = AtOnce(n =>
|
|
82
|
+
results[n] = client.Direct(new Dictionary<string, object?> { ["path"] = "p" + n }));
|
|
83
|
+
|
|
84
|
+
Assert.True(0 == thrown.Count, "round " + round + " threw:\n" + string.Join("\n", thrown));
|
|
85
|
+
for (var n = 0; n < Width; n++)
|
|
86
|
+
{
|
|
87
|
+
var res = results[n];
|
|
88
|
+
Assert.True(Equals(true, res?["ok"]), "round " + round + ", request " + n +
|
|
89
|
+
" failed: " + (res?.GetValueOrDefault("err") ?? "no result"));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
[Fact]
|
|
95
|
+
public void ConcurrentResolutionsShareOneCachedOperation()
|
|
96
|
+
{
|
|
97
|
+
for (var round = 0; round < Rounds; round++)
|
|
98
|
+
{
|
|
99
|
+
var client = LiveClient();
|
|
100
|
+
var utility = client.GetUtility();
|
|
101
|
+
var root = client.GetRootCtx();
|
|
102
|
+
var ops = new Operation?[Width, Ops];
|
|
103
|
+
var thrown = AtOnce(n =>
|
|
104
|
+
{
|
|
105
|
+
for (var k = 0; k < Ops; k++)
|
|
106
|
+
{
|
|
107
|
+
ops[n, k] = utility.MakeContext(
|
|
108
|
+
new Dictionary<string, object?> { ["opname"] = "op" + k }, root).Op;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
Assert.True(0 == thrown.Count, "round " + round + " threw:\n" + string.Join("\n", thrown));
|
|
113
|
+
for (var k = 0; k < Ops; k++)
|
|
114
|
+
{
|
|
115
|
+
var cached = utility.MakeContext(
|
|
116
|
+
new Dictionary<string, object?> { ["opname"] = "op" + k }, root).Op;
|
|
117
|
+
for (var n = 0; n < Width; n++)
|
|
118
|
+
{
|
|
119
|
+
Assert.True(ReferenceEquals(cached, ops[n, k]),
|
|
120
|
+
"round " + round + ": op" + k + " resolved to more than one Operation");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private static string AddedSecret(int round, int n, int k)
|
|
127
|
+
{
|
|
128
|
+
return "ADDED-SECRET-" + round + "-" + n + "-" + k;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Registers thread n's secrets, then counts the thread out of registering.
|
|
132
|
+
private static void RegisterSecrets(Utility utility, Context root, int round, int n,
|
|
133
|
+
CountdownEvent registering)
|
|
134
|
+
{
|
|
135
|
+
try
|
|
136
|
+
{
|
|
137
|
+
for (var k = 0; k < Ops; k++)
|
|
138
|
+
{
|
|
139
|
+
utility.CleanAdd(root, AddedSecret(round, n, k));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
finally
|
|
143
|
+
{
|
|
144
|
+
registering.Signal();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private static void AssertEverySecretMasked(Utility utility, Context root, int round)
|
|
149
|
+
{
|
|
150
|
+
for (var n = 0; n < Width / 2; n++)
|
|
151
|
+
{
|
|
152
|
+
for (var k = 0; k < Ops; k++)
|
|
153
|
+
{
|
|
154
|
+
var added = AddedSecret(round, n, k);
|
|
155
|
+
Assert.True("[redacted]" == utility.Clean(root, added) as string,
|
|
156
|
+
"round " + round + ": " + added + " was registered but not masked");
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Secrets registered on some threads while others clean: every clean
|
|
162
|
+
// masks what was registered before it, the longer secret whole, and no
|
|
163
|
+
// registration is lost.
|
|
164
|
+
[Fact]
|
|
165
|
+
public void ConcurrentRegistrationKeepsEverySecretMasked()
|
|
166
|
+
{
|
|
167
|
+
for (var round = 0; round < Rounds / 4; round++)
|
|
168
|
+
{
|
|
169
|
+
var client = LiveClient();
|
|
170
|
+
var utility = client.GetUtility();
|
|
171
|
+
var root = client.GetRootCtx();
|
|
172
|
+
var inner = "INNER-SECRET-" + round;
|
|
173
|
+
utility.CleanAdd(root, inner);
|
|
174
|
+
utility.CleanAdd(root, "OUTER-" + inner + "-TAIL");
|
|
175
|
+
var text = "a " + inner + " b OUTER-" + inner + "-TAIL c";
|
|
176
|
+
Assert.Equal("a [redacted] b [redacted] c", utility.Clean(root, text));
|
|
177
|
+
|
|
178
|
+
var registering = new CountdownEvent(Width / 2);
|
|
179
|
+
var wrong = new ConcurrentQueue<string>();
|
|
180
|
+
var thrown = AtOnce(n =>
|
|
181
|
+
{
|
|
182
|
+
if (n < Width / 2)
|
|
183
|
+
{
|
|
184
|
+
RegisterSecrets(utility, root, round, n, registering);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
while (!registering.IsSet)
|
|
188
|
+
{
|
|
189
|
+
var got = utility.Clean(root, text) as string;
|
|
190
|
+
if ("a [redacted] b [redacted] c" != got)
|
|
191
|
+
{
|
|
192
|
+
wrong.Enqueue(got ?? "null");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
Assert.True(0 == thrown.Count, "round " + round + " threw:\n" + string.Join("\n", thrown));
|
|
198
|
+
Assert.True(wrong.IsEmpty, "round " + round + " cleaned to: " + string.Join(" | ", wrong));
|
|
199
|
+
AssertEverySecretMasked(utility, root, round);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Requests on one client while secrets register on it: each request
|
|
204
|
+
// copies the client's options, the registry among them.
|
|
205
|
+
[Fact]
|
|
206
|
+
public void ConcurrentRequestsSurviveRegistration()
|
|
207
|
+
{
|
|
208
|
+
for (var round = 0; round < Rounds / 4; round++)
|
|
209
|
+
{
|
|
210
|
+
var client = LiveClient();
|
|
211
|
+
var utility = client.GetUtility();
|
|
212
|
+
var root = client.GetRootCtx();
|
|
213
|
+
var registering = new CountdownEvent(Width / 2);
|
|
214
|
+
var failed = new ConcurrentQueue<string>();
|
|
215
|
+
var thrown = AtOnce(n =>
|
|
216
|
+
{
|
|
217
|
+
if (n < Width / 2)
|
|
218
|
+
{
|
|
219
|
+
RegisterSecrets(utility, root, round, n, registering);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
while (!registering.IsSet)
|
|
223
|
+
{
|
|
224
|
+
var res = client.Direct(new Dictionary<string, object?> { ["path"] = "p" + n });
|
|
225
|
+
if (!Equals(true, res.GetValueOrDefault("ok")))
|
|
226
|
+
{
|
|
227
|
+
failed.Enqueue(Convert.ToString(res.GetValueOrDefault("err")) ?? "no error");
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
Assert.True(0 == thrown.Count, "round " + round + " threw:\n" + string.Join("\n", thrown));
|
|
234
|
+
Assert.True(failed.IsEmpty, "round " + round + ", a request failed: " + string.Join(" | ", failed));
|
|
235
|
+
AssertEverySecretMasked(utility, root, round);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
@@ -21,10 +21,13 @@ public sealed class CleanConfig
|
|
|
21
21
|
{
|
|
22
22
|
public bool Active = true;
|
|
23
23
|
public List<string> Keys = new();
|
|
24
|
+
// Requests on other threads clean while one registers, so a registration
|
|
25
|
+
// publishes a new list and never changes a published one.
|
|
24
26
|
public List<string> Values = new();
|
|
25
27
|
public string Mask = "[redacted]";
|
|
26
28
|
public int Hint;
|
|
27
29
|
public int Min = 4;
|
|
30
|
+
internal readonly object Registering = new();
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
public static partial class SdkUtility
|
|
@@ -152,18 +155,17 @@ public static partial class SdkUtility
|
|
|
152
155
|
{
|
|
153
156
|
return;
|
|
154
157
|
}
|
|
155
|
-
|
|
156
|
-
foreach (var form in CleanForms(s))
|
|
158
|
+
lock (cfg.Registering)
|
|
157
159
|
{
|
|
158
|
-
|
|
160
|
+
var added = CleanForms(s).Where(f => f.Length >= cfg.Min && !cfg.Values.Contains(f)).ToList();
|
|
161
|
+
if (0 == added.Count)
|
|
159
162
|
{
|
|
160
|
-
|
|
161
|
-
changed = true;
|
|
163
|
+
return;
|
|
162
164
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
cfg.Values
|
|
165
|
+
var values = new List<string>(cfg.Values);
|
|
166
|
+
values.AddRange(added);
|
|
167
|
+
values.Sort((a, b) => b.Length.CompareTo(a.Length));
|
|
168
|
+
Volatile.Write(ref cfg.Values, values);
|
|
167
169
|
}
|
|
168
170
|
}
|
|
169
171
|
|
|
@@ -179,7 +181,7 @@ public static partial class SdkUtility
|
|
|
179
181
|
private static string CleanString(CleanConfig cfg, string text)
|
|
180
182
|
{
|
|
181
183
|
var out_ = text;
|
|
182
|
-
foreach (var value in cfg.Values)
|
|
184
|
+
foreach (var value in Volatile.Read(ref cfg.Values))
|
|
183
185
|
{
|
|
184
186
|
if (out_.Contains(value))
|
|
185
187
|
{
|
|
@@ -49,7 +49,7 @@ public static partial class SdkUtility
|
|
|
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
|
private static List<string> RoutedArgNames(Context ctx)
|
|
54
54
|
{
|
|
55
55
|
return CallArgs(ctx, "header").Concat(CallArgs(ctx, "cookie")).Concat(CallArgs(ctx, "query"))
|
|
@@ -150,6 +150,9 @@ defmodule ProjectName.Context do
|
|
|
150
150
|
S.jm(["entity", entname, "name", opname, "input", inpt, "points", points])
|
|
151
151
|
)
|
|
152
152
|
|
|
153
|
+
# Racing processes may each build and store an Operation, and an entry
|
|
154
|
+
# lost to a concurrent write is rebuilt; an Operation is a read-only
|
|
155
|
+
# descriptor, so a duplicate is harmless.
|
|
153
156
|
S.setprop(opmap, cache_key, op)
|
|
154
157
|
op
|
|
155
158
|
end
|
|
@@ -108,7 +108,8 @@ defmodule ProjectName.EntityBase do
|
|
|
108
108
|
# materialises the whole result). When the streaming feature is active the
|
|
109
109
|
# result carries a `stream` closure and this yields from it (honouring
|
|
110
110
|
# chunkSize); otherwise it falls back to the materialised items, so stream
|
|
111
|
-
# always yields.
|
|
111
|
+
# always yields. An entity is yielded as its record, the struct map its
|
|
112
|
+
# data_get/1 returns.
|
|
112
113
|
# `callopts` parameterises the call:
|
|
113
114
|
# - ctrl: per-call pipeline control (threaded onto the op ctx);
|
|
114
115
|
# - body: an enumerable/list payload for outbound (upload) streaming,
|
|
@@ -204,24 +204,45 @@ defmodule ProjectName.Utility do
|
|
|
204
204
|
def clean_add_impl(ctx, value) do
|
|
205
205
|
cfg = clean_config(ctx)
|
|
206
206
|
minlen = numof(S.getprop(cfg, "min"), 4)
|
|
207
|
-
values = S.getprop(cfg, "values")
|
|
208
207
|
|
|
209
|
-
if is_binary(value) and String.length(value) >= minlen and S.islist(values) do
|
|
210
|
-
|
|
208
|
+
if is_binary(value) and String.length(value) >= minlen and S.islist(S.getprop(cfg, "values")) do
|
|
209
|
+
forms = Enum.filter(clean_forms(value), &(String.length(&1) >= minlen))
|
|
211
210
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
211
|
+
# A registration reads the registry and writes a new one, so a request
|
|
212
|
+
# in another process registering at once would drop it; they take turns.
|
|
213
|
+
have = list_values(S.getprop(cfg, "values"))
|
|
215
214
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
S.setprop(cfg, "values", S.jt(Enum.sort_by(have ++ add, &(-String.length(&1)))))
|
|
215
|
+
if Enum.any?(forms, &(&1 not in have)) do
|
|
216
|
+
registering(fn -> publish(cfg, forms) end)
|
|
219
217
|
end
|
|
220
218
|
end
|
|
221
219
|
|
|
222
220
|
nil
|
|
223
221
|
end
|
|
224
222
|
|
|
223
|
+
# Retried after a millisecond rather than after global's back-off sleep,
|
|
224
|
+
# which grows to seconds; the lock is released if its holder dies.
|
|
225
|
+
defp registering(fun) do
|
|
226
|
+
case :global.trans({{__MODULE__, :clean_registry}, self()}, fun, [node()], 0) do
|
|
227
|
+
:aborted ->
|
|
228
|
+
Process.sleep(1)
|
|
229
|
+
registering(fun)
|
|
230
|
+
|
|
231
|
+
done ->
|
|
232
|
+
done
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
defp publish(cfg, forms) do
|
|
237
|
+
have = list_values(S.getprop(cfg, "values"))
|
|
238
|
+
add = Enum.reject(forms, &(&1 in have))
|
|
239
|
+
|
|
240
|
+
# Longest first, so a value is never masked by a substring of itself.
|
|
241
|
+
if add != [] do
|
|
242
|
+
S.setprop(cfg, "values", S.jt(Enum.sort_by(have ++ add, &(-String.length(&1)))))
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
225
246
|
defp mask_value(cfg, value) do
|
|
226
247
|
hint = numof(S.getprop(cfg, "hint"), 0)
|
|
227
248
|
mask = strof(S.getprop(cfg, "mask"))
|
|
@@ -2280,7 +2301,7 @@ defmodule ProjectName.Utility do
|
|
|
2280
2301
|
|
|
2281
2302
|
# A header, cookie or query argument travels where prepare_headers_impl or
|
|
2282
2303
|
# prepare_query_impl sends it, so the body is built from the request data
|
|
2283
|
-
# without it, unless the
|
|
2304
|
+
# without it, unless the point marks it as a field the body keeps.
|
|
2284
2305
|
defp routed_arg_names(ctx) do
|
|
2285
2306
|
(call_args(ctx, "header") ++ call_args(ctx, "cookie") ++ call_args(ctx, "query"))
|
|
2286
2307
|
|> Enum.map(&elem(&1, 0))
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# ProjectName SDK concurrency test
|
|
2
|
+
#
|
|
3
|
+
# Requests in flight at once on one client, each in its own process, register
|
|
4
|
+
# and clean secrets through the one registry the client holds.
|
|
5
|
+
|
|
6
|
+
defmodule ProjectName.ConcurrencyTest do
|
|
7
|
+
use ExUnit.Case
|
|
8
|
+
|
|
9
|
+
alias ProjectName.Utility
|
|
10
|
+
alias Voxgig.Struct, as: S
|
|
11
|
+
|
|
12
|
+
@rounds 3
|
|
13
|
+
@width 8
|
|
14
|
+
@added 16
|
|
15
|
+
@masked "a [redacted] b [redacted] c"
|
|
16
|
+
|
|
17
|
+
# Runs body in @width processes, released once every one is waiting, and
|
|
18
|
+
# returns what they raised.
|
|
19
|
+
defp at_once(body) do
|
|
20
|
+
parent = self()
|
|
21
|
+
waiting = :counters.new(1, [:atomics])
|
|
22
|
+
|
|
23
|
+
tasks =
|
|
24
|
+
for n <- 0..(@width - 1) do
|
|
25
|
+
Task.async(fn ->
|
|
26
|
+
:counters.add(waiting, 1, 1)
|
|
27
|
+
send(parent, {:ready, self()})
|
|
28
|
+
|
|
29
|
+
receive do
|
|
30
|
+
:go -> :ok
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
seen = :counters.get(waiting, 1)
|
|
34
|
+
|
|
35
|
+
try do
|
|
36
|
+
body.(n)
|
|
37
|
+
{seen, nil}
|
|
38
|
+
rescue
|
|
39
|
+
err -> {seen, err}
|
|
40
|
+
end
|
|
41
|
+
end)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
ready =
|
|
45
|
+
for _ <- tasks do
|
|
46
|
+
receive do
|
|
47
|
+
{:ready, pid} -> pid
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
Enum.each(ready, &send(&1, :go))
|
|
52
|
+
outcomes = Task.await_many(tasks, :infinity)
|
|
53
|
+
|
|
54
|
+
for {seen, _} <- outcomes do
|
|
55
|
+
assert @width == seen, "a process was released with #{seen} of #{@width} waiting"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
for {_, err} <- outcomes, nil != err, do: err
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# A live client whose transport answers at once.
|
|
62
|
+
defp live_client do
|
|
63
|
+
fetch = fn _url, _fetchdef ->
|
|
64
|
+
{S.jm([
|
|
65
|
+
"status", 200,
|
|
66
|
+
"statusText", "OK",
|
|
67
|
+
"headers", S.jm([]),
|
|
68
|
+
"json", fn -> S.jm(["ok", true]) end
|
|
69
|
+
]), nil}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
ProjectName.new(
|
|
73
|
+
S.jm([
|
|
74
|
+
"base", "http://concurrency.test/api",
|
|
75
|
+
"allow", S.jm(["op", "direct"]),
|
|
76
|
+
"system", S.jm(["fetch", fetch])
|
|
77
|
+
])
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
defp register_secrets(root, round, n, registering) do
|
|
82
|
+
try do
|
|
83
|
+
for k <- 1..@added, do: Utility.clean_add(root, "ADDED-SECRET-#{round}-#{n}-#{k}")
|
|
84
|
+
after
|
|
85
|
+
:counters.sub(registering, 1, 1)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
defp assert_every_secret_masked(root, round) do
|
|
90
|
+
for n <- 0..(div(@width, 2) - 1), k <- 1..@added do
|
|
91
|
+
added = "ADDED-SECRET-#{round}-#{n}-#{k}"
|
|
92
|
+
|
|
93
|
+
assert "[redacted]" == Utility.clean(root, added),
|
|
94
|
+
"round #{round}: #{added} was registered but not masked"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# A cleaner pauses between passes, so the registrars contend with each other.
|
|
99
|
+
defp clean_while(root, text, registering) do
|
|
100
|
+
if 0 < :counters.get(registering, 1) do
|
|
101
|
+
got = Utility.clean(root, text)
|
|
102
|
+
|
|
103
|
+
if @masked != got do
|
|
104
|
+
raise "cleaned to: " <> inspect(got)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
Process.sleep(1)
|
|
108
|
+
clean_while(root, text, registering)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Secrets registered in some processes while others clean: every clean masks
|
|
113
|
+
# what was registered before it, the longer secret whole, and no
|
|
114
|
+
# registration is lost.
|
|
115
|
+
test "concurrent registration keeps every secret masked" do
|
|
116
|
+
for round <- 1..@rounds do
|
|
117
|
+
client = ProjectName.test()
|
|
118
|
+
root = ProjectName.get_root_ctx(client)
|
|
119
|
+
inner = "INNER-SECRET-#{round}"
|
|
120
|
+
Utility.clean_add(root, inner)
|
|
121
|
+
Utility.clean_add(root, "OUTER-#{inner}-TAIL")
|
|
122
|
+
text = "a #{inner} b OUTER-#{inner}-TAIL c"
|
|
123
|
+
assert @masked == Utility.clean(root, text)
|
|
124
|
+
|
|
125
|
+
registering = :counters.new(1, [:atomics])
|
|
126
|
+
:counters.put(registering, 1, div(@width, 2))
|
|
127
|
+
|
|
128
|
+
raised =
|
|
129
|
+
at_once(fn n ->
|
|
130
|
+
if n < div(@width, 2) do
|
|
131
|
+
register_secrets(root, round, n, registering)
|
|
132
|
+
else
|
|
133
|
+
clean_while(root, text, registering)
|
|
134
|
+
end
|
|
135
|
+
end)
|
|
136
|
+
|
|
137
|
+
assert [] == raised, "round #{round} raised: #{inspect(raised)}"
|
|
138
|
+
assert_every_secret_masked(root, round)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
defp request_while(client, n, registering) do
|
|
143
|
+
if 0 < :counters.get(registering, 1) do
|
|
144
|
+
res = ProjectName.direct(client, S.jm(["path", "p#{n}"]))
|
|
145
|
+
|
|
146
|
+
if true != S.getprop(res, "ok") do
|
|
147
|
+
raise "a request failed: " <> inspect(S.getprop(res, "err"))
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
request_while(client, n, registering)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Requests on one client while secrets register on it: each request copies
|
|
155
|
+
# the client's options, the registry among them.
|
|
156
|
+
test "concurrent requests survive registration" do
|
|
157
|
+
for round <- 1..@rounds do
|
|
158
|
+
client = live_client()
|
|
159
|
+
root = ProjectName.get_root_ctx(client)
|
|
160
|
+
registering = :counters.new(1, [:atomics])
|
|
161
|
+
:counters.put(registering, 1, div(@width, 2))
|
|
162
|
+
|
|
163
|
+
raised =
|
|
164
|
+
at_once(fn n ->
|
|
165
|
+
if n < div(@width, 2) do
|
|
166
|
+
register_secrets(root, round, n, registering)
|
|
167
|
+
else
|
|
168
|
+
request_while(client, n, registering)
|
|
169
|
+
end
|
|
170
|
+
end)
|
|
171
|
+
|
|
172
|
+
assert [] == raised, "round #{round} raised: #{inspect(raised)}"
|
|
173
|
+
assert_every_secret_masked(root, round)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
@@ -280,9 +280,13 @@ func (ctx *Context) resolveOp(opname string) *Operation {
|
|
|
280
280
|
"points": targets,
|
|
281
281
|
})
|
|
282
282
|
|
|
283
|
+
// Every request racing to build this Operation gets the one stored first.
|
|
283
284
|
ctx.Opmu.Lock()
|
|
285
|
+
defer ctx.Opmu.Unlock()
|
|
286
|
+
if stored, ok := ctx.Opmap[cacheKey]; ok && stored != nil {
|
|
287
|
+
return stored
|
|
288
|
+
}
|
|
284
289
|
ctx.Opmap[cacheKey] = op
|
|
285
|
-
ctx.Opmu.Unlock()
|
|
286
290
|
return op
|
|
287
291
|
}
|
|
288
292
|
|