Merge branch stable-3.14 into master Change-Id: I6892d63055c2d7008fca06b9e722a46ad7e3a972
diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 0000000..47da986 --- /dev/null +++ b/.bazelversion
@@ -0,0 +1 @@ +9.1.0
diff --git a/BUILD b/BUILD index da759b9..581e688 100644 --- a/BUILD +++ b/BUILD
@@ -1,20 +1,9 @@ load( "@com_googlesource_gerrit_bazlets//:gerrit_plugin.bzl", "gerrit_plugin", + "gerrit_plugin_dependency_tests", "gerrit_plugin_tests", ) -load( - "@com_googlesource_gerrit_bazlets//tools:in_gerrit_tree.bzl", - "in_gerrit_tree_enabled", -) -load( - "@com_googlesource_gerrit_bazlets//tools:runtime_jars_allowlist.bzl", - "runtime_jars_allowlist_test", -) -load( - "@com_googlesource_gerrit_bazlets//tools:runtime_jars_overlap.bzl", - "runtime_jars_overlap_test", -) load("@rules_java//java:defs.bzl", "java_library") gerrit_plugin( @@ -23,6 +12,7 @@ manifest_entries = [ "Gerrit-PluginName: high-availability", "Gerrit-Module: com.ericsson.gerrit.plugins.highavailability.Module", + "Gerrit-ApiModule: com.ericsson.gerrit.plugins.highavailability.ApiModule", "Gerrit-HttpModule: com.ericsson.gerrit.plugins.highavailability.HttpModule", "Gerrit-InitStep: com.ericsson.gerrit.plugins.highavailability.Setup", "Gerrit-ReloadMode: restart", @@ -71,17 +61,4 @@ ], ) -runtime_jars_allowlist_test( - name = "check_high-availability_third_party_runtime_jars", - allowlist = ":high-availability_third_party_runtime_jars.allowlist.txt", - hint = "plugins/high-availability:check_high-availability_third_party_runtime_jars_manifest", - target = ":high-availability__plugin", -) - -runtime_jars_overlap_test( - name = "high-availability_no_overlap_with_gerrit", - against = "//:headless.war.jars.txt", - hint = "Exclude overlaps via maven.install(excluded_artifacts=[...]) and re-run this test.", - target = ":high-availability__plugin", - target_compatible_with = in_gerrit_tree_enabled(), -) +gerrit_plugin_dependency_tests(plugin = "high-availability")
diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 8c48193..0ff8811 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock
@@ -1,5 +1,5 @@ { - "lockFileVersion": 13, + "lockFileVersion": 26, "registryFileHashes": { "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", @@ -11,15 +11,21 @@ "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed", "https://bcr.bazel.build/modules/abseil-cpp/20240116.2/MODULE.bazel": "73939767a4686cd9a520d16af5ab440071ed75cec1a876bf2fcfaf1f71987a16", "https://bcr.bazel.build/modules/abseil-cpp/20250127.0/MODULE.bazel": "d1086e248cda6576862b4b3fe9ad76a214e08c189af5b42557a6e1888812c5d5", - "https://bcr.bazel.build/modules/abseil-cpp/20250127.0/source.json": "1b996859f840d8efc7c720efc61dcf2a84b1261cb3974cbbe9b6666ebf567775", + "https://bcr.bazel.build/modules/abseil-cpp/20250127.1/MODULE.bazel": "c4a89e7ceb9bf1e25cf84a9f830ff6b817b72874088bf5141b314726e46a57c1", + "https://bcr.bazel.build/modules/abseil-cpp/20250512.1/MODULE.bazel": "d209fdb6f36ffaf61c509fcc81b19e81b411a999a934a032e10cd009a0226215", + "https://bcr.bazel.build/modules/abseil-cpp/20250814.1/MODULE.bazel": "51f2312901470cdab0dbdf3b88c40cd21c62a7ed58a3de45b365ddc5b11bcab2", + "https://bcr.bazel.build/modules/abseil-cpp/20250814.1/source.json": "cea3901d7e299da7320700abbaafe57a65d039f10d0d7ea601c4a66938ea4b0c", "https://bcr.bazel.build/modules/abseil-py/2.1.0/MODULE.bazel": "5ebe5bf853769c65707e5c28f216798f7a4b1042015e6a36e6d03094d94bec8a", "https://bcr.bazel.build/modules/abseil-py/2.1.0/source.json": "0e8fc4f088ce07099c1cd6594c20c7ddbb48b4b3c0849b7d94ba94be88ff042b", "https://bcr.bazel.build/modules/apple_support/1.11.1/MODULE.bazel": "1843d7cd8a58369a444fc6000e7304425fba600ff641592161d9f15b179fb896", "https://bcr.bazel.build/modules/apple_support/1.15.1/MODULE.bazel": "a0556fefca0b1bb2de8567b8827518f94db6a6e7e7d632b4c48dc5f865bc7c85", - "https://bcr.bazel.build/modules/apple_support/1.15.1/source.json": "517f2b77430084c541bc9be2db63fdcbb7102938c5f64c17ee60ffda2e5cf07b", - "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel": "50341a62efbc483e8a2a6aec30994a58749bd7b885e18dd96aa8c33031e558ef", + "https://bcr.bazel.build/modules/apple_support/1.21.0/MODULE.bazel": "ac1824ed5edf17dee2fdd4927ada30c9f8c3b520be1b5fd02a5da15bc10bff3e", + "https://bcr.bazel.build/modules/apple_support/1.21.1/MODULE.bazel": "5809fa3efab15d1f3c3c635af6974044bac8a4919c62238cce06acee8a8c11f1", + "https://bcr.bazel.build/modules/apple_support/1.24.2/MODULE.bazel": "0e62471818affb9f0b26f128831d5c40b074d32e6dda5a0d3852847215a41ca4", + "https://bcr.bazel.build/modules/apple_support/1.24.2/source.json": "2c22c9827093250406c5568da6c54e6fdf0ef06238def3d99c71b12feb057a8d", "https://bcr.bazel.build/modules/bazel_features/1.1.0/MODULE.bazel": "cfd42ff3b815a5f39554d97182657f8c4b9719568eb7fded2b9135f084bf760b", "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", + "https://bcr.bazel.build/modules/bazel_features/1.10.0/MODULE.bazel": "f75e8807570484a99be90abcd52b5e1f390362c258bcb73106f4544957a48101", "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", "https://bcr.bazel.build/modules/bazel_features/1.13.0/MODULE.bazel": "c14c33c7c3c730612bdbe14ebbb5e61936b6f11322ea95a6e91cd1ba962f94df", "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", @@ -28,11 +34,14 @@ "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", "https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": "675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b", "https://bcr.bazel.build/modules/bazel_features/1.23.0/MODULE.bazel": "fd1ac84bc4e97a5a0816b7fd7d4d4f6d837b0047cf4cbd81652d616af3a6591a", + "https://bcr.bazel.build/modules/bazel_features/1.27.0/MODULE.bazel": "621eeee06c4458a9121d1f104efb80f39d34deff4984e778359c60eaf1a8cb65", "https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d", "https://bcr.bazel.build/modules/bazel_features/1.3.0/MODULE.bazel": "cdcafe83ec318cda34e02948e81d790aab8df7a929cec6f6969f13a489ccecd9", "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87", - "https://bcr.bazel.build/modules/bazel_features/1.30.0/source.json": "b07e17f067fe4f69f90b03b36ef1e08fe0d1f3cac254c1241a1818773e3423bc", + "https://bcr.bazel.build/modules/bazel_features/1.33.0/MODULE.bazel": "8b8dc9d2a4c88609409c3191165bccec0e4cb044cd7a72ccbe826583303459f6", "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", + "https://bcr.bazel.build/modules/bazel_features/1.42.1/MODULE.bazel": "275a59b5406ff18c01739860aa70ad7ccb3cfb474579411decca11c93b951080", + "https://bcr.bazel.build/modules/bazel_features/1.42.1/source.json": "fcd4396b2df85f64f2b3bb436ad870793ecf39180f1d796f913cc9276d355309", "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", @@ -45,6 +54,7 @@ "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d", "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6", "https://bcr.bazel.build/modules/bazel_skylib/1.8.2/MODULE.bazel": "69ad6927098316848b34a9142bcc975e018ba27f08c4ff403f50c1b6e646ca67", "https://bcr.bazel.build/modules/bazel_skylib/1.9.0/MODULE.bazel": "72997b29dfd95c3fa0d0c48322d05590418edef451f8db8db5509c57875fb4b7", "https://bcr.bazel.build/modules/bazel_skylib/1.9.0/source.json": "7ad77c1e8c1b84222d9b3f3cae016a76639435744c19330b0b37c0a3c9da7dc0", @@ -53,8 +63,8 @@ "https://bcr.bazel.build/modules/bazel_worker_api/0.0.4/source.json": "d353c410d47a8b65d09fa98e83d57ebec257a2c2b9c6e42d6fda1cb25e5464a5", "https://bcr.bazel.build/modules/bazel_worker_java/0.0.4/MODULE.bazel": "82494a01018bb7ef06d4a17ec4cd7a758721f10eb8b6c820a818e70d669500db", "https://bcr.bazel.build/modules/bazel_worker_java/0.0.4/source.json": "a2d30458fd86cf022c2b6331e652526fa08e17573b2f5034a9dbcacdf9c2583c", - "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", - "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/buildozer/8.5.1/MODULE.bazel": "a35d9561b3fc5b18797c330793e99e3b834a473d5fbd3d7d7634aafc9bdb6f8f", + "https://bcr.bazel.build/modules/buildozer/8.5.1/source.json": "e3386e6ff4529f2442800dee47ad28d3e6487f36a1f75ae39ae56c70f0cd2fbd", "https://bcr.bazel.build/modules/gazelle/0.32.0/MODULE.bazel": "b499f58a5d0d3537f3cf5b76d8ada18242f64ec474d8391247438bf04f58c7b8", "https://bcr.bazel.build/modules/gazelle/0.33.0/MODULE.bazel": "a13a0f279b462b784fb8dd52a4074526c4a2afe70e114c7d09066097a46b3350", "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel": "abdd8ce4d70978933209db92e436deb3a8b737859e9354fb5fd11fb5c2004c8a", @@ -66,7 +76,8 @@ "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", "https://bcr.bazel.build/modules/googletest/1.15.2/MODULE.bazel": "6de1edc1d26cafb0ea1a6ab3f4d4192d91a312fd2d360b63adaa213cd00b2108", - "https://bcr.bazel.build/modules/googletest/1.15.2/source.json": "dbdda654dcb3a0d7a8bc5d0ac5fc7e150b58c2a986025ae5bc634bb2cb61f470", + "https://bcr.bazel.build/modules/googletest/1.17.0/MODULE.bazel": "dbec758171594a705933a29fcf69293d2468c49ec1f2ebca65c36f504d72df46", + "https://bcr.bazel.build/modules/googletest/1.17.0/source.json": "38e4454b25fc30f15439c0378e57909ab1fd0a443158aa35aec685da727cd713", "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", "https://bcr.bazel.build/modules/jsoncpp/1.9.6/MODULE.bazel": "2f8d20d3b7d54143213c4dfc3d98225c42de7d666011528dc8fe91591e2e17b0", "https://bcr.bazel.build/modules/jsoncpp/1.9.6/source.json": "a04756d367a2126c3541682864ecec52f92cdee80a35735a3cb249ce015ca000", @@ -77,13 +88,14 @@ "https://bcr.bazel.build/modules/package_metadata/0.0.7/source.json": "50639625e937b56115012674c797cca7a05a96b4878c87d803c13dc2b31de8a0", "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", "https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f", - "https://bcr.bazel.build/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29", "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc", + "https://bcr.bazel.build/modules/platforms/1.0.0/MODULE.bazel": "f05feb42b48f1b3c225e4ccf351f367be0371411a803198ec34a389fb22aa580", + "https://bcr.bazel.build/modules/platforms/1.0.0/source.json": "f4ff1fd412e0246fd38c82328eb209130ead81d62dcd5a9e40910f867f733d96", "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", "https://bcr.bazel.build/modules/protobuf/23.1/MODULE.bazel": "88b393b3eb4101d18129e5db51847cd40a5517a53e81216144a8c32dfeeca52a", "https://bcr.bazel.build/modules/protobuf/24.4/MODULE.bazel": "7bc7ce5f2abf36b3b7b7c8218d3acdebb9426aeb35c2257c96445756f970eb12", @@ -92,11 +104,14 @@ "https://bcr.bazel.build/modules/protobuf/27.2/MODULE.bazel": "32450b50673882e4c8c3d10a83f3bc82161b213ed2f80d17e38bece8f165c295", "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", "https://bcr.bazel.build/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92", + "https://bcr.bazel.build/modules/protobuf/29.1/MODULE.bazel": "557c3457560ff49e122ed76c0bc3397a64af9574691cb8201b4e46d4ab2ecb95", "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", "https://bcr.bazel.build/modules/protobuf/3.19.2/MODULE.bazel": "532ffe5f2186b69fdde039efe6df13ba726ff338c6bc82275ad433013fa10573", "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858", "https://bcr.bazel.build/modules/protobuf/31.1/MODULE.bazel": "379a389bb330b7b8c1cdf331cc90bf3e13de5614799b3b52cdb7c6f389f6b38e", - "https://bcr.bazel.build/modules/protobuf/31.1/source.json": "25af5d0219da0c0fc4d1191a24ce438e6ca7f49d2e1a94f354efeba6ef10426f", + "https://bcr.bazel.build/modules/protobuf/32.1/MODULE.bazel": "89cd2866a9cb07fee9ff74c41ceace11554f32e0d849de4e23ac55515cfada4d", + "https://bcr.bazel.build/modules/protobuf/33.4/MODULE.bazel": "114775b816b38b6d0ca620450d6b02550c60ceedfdc8d9a229833b34a223dc42", + "https://bcr.bazel.build/modules/protobuf/33.4/source.json": "555f8686b4c7d6b5ba731fbea13bf656b4bfd9a7ff629c1d9d3f6e1d6155de79", "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34", "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/source.json": "6900fdc8a9e95866b8c0d4ad4aba4d4236317b5c1cd04c502df3f0d33afed680", @@ -108,7 +123,8 @@ "https://bcr.bazel.build/modules/rules_android/0.6.6/MODULE.bazel": "b0fb569752aab65ab1a9db0a8f6cfaf5aa1754965e17e95dcf0e4d88e192a68d", "https://bcr.bazel.build/modules/rules_android/0.6.6/source.json": "a9d8dc2d5a102dc03269a94acc886a4cab82cdcb9ccbc77b0f665d6d17a6ae09", "https://bcr.bazel.build/modules/rules_apple/3.16.0/MODULE.bazel": "0d1caf0b8375942ce98ea944be754a18874041e4e0459401d925577624d3a54a", - "https://bcr.bazel.build/modules/rules_apple/3.16.0/source.json": "d8b5fe461272018cc07cfafce11fe369c7525330804c37eec5a82f84cd475366", + "https://bcr.bazel.build/modules/rules_apple/4.1.0/MODULE.bazel": "76e10fd4a48038d3fc7c5dc6e63b7063bbf5304a2e3bd42edda6ec660eebea68", + "https://bcr.bazel.build/modules/rules_apple/4.1.0/source.json": "8ee81e1708756f81b343a5eb2b2f0b953f1d25c4ab3d4a68dc02754872e80715", "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002", "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191", @@ -120,8 +136,13 @@ "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", "https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513", + "https://bcr.bazel.build/modules/rules_cc/0.1.2/MODULE.bazel": "557ddc3a96858ec0d465a87c0a931054d7dcfd6583af2c7ed3baf494407fd8d0", "https://bcr.bazel.build/modules/rules_cc/0.1.5/MODULE.bazel": "88dfc9361e8b5ae1008ac38f7cdfd45ad738e4fa676a3ad67d19204f045a1fd8", - "https://bcr.bazel.build/modules/rules_cc/0.1.5/source.json": "4bb4fed7f5499775d495739f785a5494a1f854645fa1bac5de131264f5acdf01", + "https://bcr.bazel.build/modules/rules_cc/0.2.0/MODULE.bazel": "b5c17f90458caae90d2ccd114c81970062946f49f355610ed89bebf954f5783c", + "https://bcr.bazel.build/modules/rules_cc/0.2.13/MODULE.bazel": "eecdd666eda6be16a8d9dc15e44b5c75133405e820f620a234acc4b1fdc5aa37", + "https://bcr.bazel.build/modules/rules_cc/0.2.17/MODULE.bazel": "1849602c86cb60da8613d2de887f9566a6d354a6df6d7009f9d04a14402f9a84", + "https://bcr.bazel.build/modules/rules_cc/0.2.17/source.json": "3832f45d145354049137c0090df04629d9c2b5493dc5c2bf46f1834040133a07", + "https://bcr.bazel.build/modules/rules_cc/0.2.8/MODULE.bazel": "f1df20f0bf22c28192a794f29b501ee2018fa37a3862a1a2132ae2940a23a642", "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", "https://bcr.bazel.build/modules/rules_go/0.41.0/MODULE.bazel": "55861d8e8bb0e62cbd2896f60ff303f62ffcb0eddb74ecb0e5c0cbe36fc292c8", @@ -140,13 +161,13 @@ "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab", "https://bcr.bazel.build/modules/rules_java/7.4.0/MODULE.bazel": "a592852f8a3dd539e82ee6542013bf2cadfc4c6946be8941e189d224500a8934", "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", - "https://bcr.bazel.build/modules/rules_java/7.6.5/MODULE.bazel": "481164be5e02e4cab6e77a36927683263be56b7e36fef918b458d7a8a1ebadb1", "https://bcr.bazel.build/modules/rules_java/8.13.0/MODULE.bazel": "0444ebf737d144cf2bb2ccb368e7f1cce735264285f2a3711785827c1686625e", - "https://bcr.bazel.build/modules/rules_java/8.13.0/source.json": "4605c0f676b87dd9d1fabd4d743b71f04d97503bd1a79aad53f87399fb5396de", "https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017", "https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939", "https://bcr.bazel.build/modules/rules_java/8.6.0/MODULE.bazel": "9c064c434606d75a086f15ade5edb514308cccd1544c2b2a89bbac4310e41c71", "https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2", + "https://bcr.bazel.build/modules/rules_java/9.1.0/MODULE.bazel": "ee63f27e36a3fada80342869361182f120a9819c74320e8e65b1e04ba0cd7a9d", + "https://bcr.bazel.build/modules/rules_java/9.1.0/source.json": "da589573c1dee2c9ac4a568b301269a2e8191110ff0345c1a959fa7ea6c4dfd6", "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", @@ -173,9 +194,9 @@ "https://bcr.bazel.build/modules/rules_proto/6.0.0/MODULE.bazel": "b531d7f09f58dce456cd61b4579ce8c86b38544da75184eadaf0a7cb7966453f", "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73", "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2", - "https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1", + "https://bcr.bazel.build/modules/rules_proto/7.1.0/MODULE.bazel": "002d62d9108f75bb807cd56245d45648f38275cb3a99dcd45dfb864c5d74cb96", + "https://bcr.bazel.build/modules/rules_proto/7.1.0/source.json": "39f89066c12c24097854e8f57ab8558929f9c8d474d34b2c00ac04630ad8940e", "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", - "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7", "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", @@ -185,6 +206,9 @@ "https://bcr.bazel.build/modules/rules_python/0.37.2/MODULE.bazel": "b5ffde91410745750b6c13be1c5dc4555ef5bc50562af4a89fd77807fdde626a", "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", "https://bcr.bazel.build/modules/rules_python/1.0.0/MODULE.bazel": "898a3d999c22caa585eb062b600f88654bf92efb204fa346fb55f6f8edffca43", + "https://bcr.bazel.build/modules/rules_python/1.3.0/MODULE.bazel": "8361d57eafb67c09b75bf4bbe6be360e1b8f4f18118ab48037f2bd50aa2ccb13", + "https://bcr.bazel.build/modules/rules_python/1.4.1/MODULE.bazel": "8991ad45bdc25018301d6b7e1d3626afc3c8af8aaf4bc04f23d0b99c938b73a6", + "https://bcr.bazel.build/modules/rules_python/1.6.0/MODULE.bazel": "7e04ad8f8d5bea40451cf80b1bd8262552aa73f841415d20db96b7241bd027d8", "https://bcr.bazel.build/modules/rules_python/1.7.0/MODULE.bazel": "d01f995ecd137abf30238ad9ce97f8fc3ac57289c8b24bd0bf53324d937a14f8", "https://bcr.bazel.build/modules/rules_python/1.7.0/source.json": "028a084b65dcf8f4dc4f82f8778dbe65df133f234b316828a82e060d81bdce32", "https://bcr.bazel.build/modules/rules_robolectric/4.14.1.2/MODULE.bazel": "d44fec647d0aeb67b9f3b980cf68ba634976f3ae7ccd6c07d790b59b87a4f251", @@ -193,10 +217,13 @@ "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", "https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b", "https://bcr.bazel.build/modules/rules_shell/0.4.1/MODULE.bazel": "00e501db01bbf4e3e1dd1595959092c2fadf2087b2852d3f553b5370f5633592", - "https://bcr.bazel.build/modules/rules_shell/0.4.1/source.json": "4757bd277fe1567763991c4425b483477bb82e35e777a56fd846eb5cceda324a", + "https://bcr.bazel.build/modules/rules_shell/0.6.1/MODULE.bazel": "72e76b0eea4e81611ef5452aa82b3da34caca0c8b7b5c0c9584338aa93bae26b", + "https://bcr.bazel.build/modules/rules_shell/0.6.1/source.json": "20ec05cd5e592055e214b2da8ccb283c7f2a421ea0dc2acbf1aa792e11c03d0c", "https://bcr.bazel.build/modules/rules_swift/1.16.0/MODULE.bazel": "4a09f199545a60d09895e8281362b1ff3bb08bbde69c6fc87aff5b92fcc916ca", "https://bcr.bazel.build/modules/rules_swift/2.1.1/MODULE.bazel": "494900a80f944fc7aa61500c2073d9729dff0b764f0e89b824eb746959bc1046", - "https://bcr.bazel.build/modules/rules_swift/2.1.1/source.json": "40fc69dfaac64deddbb75bd99cdac55f4427d9ca0afbe408576a65428427a186", + "https://bcr.bazel.build/modules/rules_swift/2.4.0/MODULE.bazel": "1639617eb1ede28d774d967a738b4a68b0accb40650beadb57c21846beab5efd", + "https://bcr.bazel.build/modules/rules_swift/3.1.2/MODULE.bazel": "72c8f5cf9d26427cee6c76c8e3853eb46ce6b0412a081b2b6db6e8ad56267400", + "https://bcr.bazel.build/modules/rules_swift/3.1.2/source.json": "e85761f3098a6faf40b8187695e3de6d97944e98abd0d8ce579cb2daf6319a66", "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", "https://bcr.bazel.build/modules/stardoc/0.6.2/MODULE.bazel": "7060193196395f5dd668eda046ccbeacebfd98efc77fed418dbe2b82ffaa39fd", @@ -204,254 +231,99 @@ "https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5", "https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216", "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/MODULE.bazel": "5e463fbfba7b1701d957555ed45097d7f984211330106ccd1352c6e0af0dcf91", - "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/source.json": "32bd87e5f4d7acc57c5b2ff7c325ae3061d5e242c0c4c214ae87e0f1c13e54cb", + "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.2/MODULE.bazel": "75aab2373a4bbe2a1260b9bf2a1ebbdbf872d3bd36f80bff058dccd82e89422f", + "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.2/source.json": "5fba48bbe0ba48761f9e9f75f92876cafb5d07c0ce059cc7a8027416de94a05b", "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", "https://bcr.bazel.build/modules/upb/0.0.0-20230516-61a97ef/MODULE.bazel": "c0df5e35ad55e264160417fd0875932ee3c9dda63d9fccace35ac62f45e1b6f9", "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", - "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" }, "selectedYankedVersions": {}, "moduleExtensions": { - "@@apple_support~//crosstool:setup.bzl%apple_cc_configure_extension": { + "@@pybind11_bazel+//:internal_configure.bzl%internal_configure_extension": { "general": { - "bzlTransitiveDigest": "ltCGFbl/LQQZXn/LEMXfKX7pGwyqNiOCHcmiQW0tmjM=", - "usagesDigest": "eXsWd8YDJDt7+F94YtjKuTAIRMWBi9JLS8hUiqynRIY=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_config_apple_cc_toolchains": { - "bzlFile": "@@apple_support~//crosstool:setup.bzl", - "ruleClassName": "_apple_cc_autoconf_toolchains", - "attributes": {} - }, - "local_config_apple_cc": { - "bzlFile": "@@apple_support~//crosstool:setup.bzl", - "ruleClassName": "_apple_cc_autoconf", - "attributes": {} - } - }, - "recordedRepoMappingEntries": [ - [ - "apple_support~", - "bazel_tools", - "bazel_tools" - ] - ] - } - }, - "@@pybind11_bazel~//:internal_configure.bzl%internal_configure_extension": { - "general": { - "bzlTransitiveDigest": "CyAKLVVonohnkTSqg9II/HA7M49sOlnMkgMHL3CmDuc=", - "usagesDigest": "mFrTHX5eCiNU/OIIGVHH3cOILY9Zmjqk8RQYv8o6Thk=", - "recordedFileInputs": { - "@@pybind11_bazel~//MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34" - }, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "b+RP7Sgl8KN0VHamrgTqzGLuYPcQ/Mo4ptNkkHUIIlA=", + "usagesDigest": "D1r3lfzMuUBFxgG8V6o0bQTLMk3GkaGOaPzw53wrwyw=", + "recordedInputs": [ + "REPO_MAPPING:pybind11_bazel+,bazel_tools bazel_tools", + "FILE:@@pybind11_bazel+//MODULE.bazel e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34" + ], "generatedRepoSpecs": { "pybind11": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "build_file": "@@pybind11_bazel~//:pybind11-BUILD.bazel", + "build_file": "@@pybind11_bazel+//:pybind11-BUILD.bazel", "strip_prefix": "pybind11-2.12.0", "urls": [ "https://github.com/pybind/pybind11/archive/v2.12.0.zip" ] } } - }, - "recordedRepoMappingEntries": [ - [ - "pybind11_bazel~", - "bazel_tools", - "bazel_tools" - ] - ] + } } }, - "@@rules_android~//bzlmod_extensions:apksig.bzl%apksig_extension": { + "@@rules_android+//bzlmod_extensions:apksig.bzl%apksig_extension": { "general": { - "bzlTransitiveDigest": "+fNvC5PNWx1aA64JjkW33+1zGbG9xgfi70xQhxbglhY=", - "usagesDigest": "TaGkNxVMBZxl1ANdUNPmIjKrA33bO+BpI06yTlpHdos=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "IiT2UgJGnHaKiyP2A1yh3U/QWN4W9g/Byolrm78hC/s=", + "usagesDigest": "xq6OVkELeJvOgYo3oY/sUBsGFbcqdV+9BYiNgSPV/po=", + "recordedInputs": [ + "REPO_MAPPING:rules_android+,bazel_tools bazel_tools" + ], "generatedRepoSpecs": { "apksig": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://android.googlesource.com/platform/tools/apksig/+archive/24e3075e68ebe17c0b529bb24bfda819db5e2f3b.tar.gz", - "build_file": "@@rules_android~//bzlmod_extensions:apksig.BUILD" + "build_file": "@@rules_android+//bzlmod_extensions:apksig.BUILD" } } - }, - "recordedRepoMappingEntries": [ - [ - "rules_android~", - "bazel_tools", - "bazel_tools" - ] - ] + } } }, - "@@rules_android~//bzlmod_extensions:com_android_dex.bzl%com_android_dex_extension": { + "@@rules_android+//bzlmod_extensions:com_android_dex.bzl%com_android_dex_extension": { "general": { - "bzlTransitiveDigest": "/KJvxHLYhvSLJihEHN0e5Uzdd7OOMvpFb0BFUl1RUTs=", - "usagesDigest": "fh77SU1OUlWN5ivrGpY93+t0MipuVj89/MMUgfTpSa8=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "toD4gOZwGNfBEM+xec6eRi3BM2Z9EZ4oQrORZQH3sNY=", + "usagesDigest": "toF8IFMu98H/VU2p1sfVC5fVXVYJunpbbmtM6tOsQXY=", + "recordedInputs": [ + "REPO_MAPPING:rules_android+,bazel_tools bazel_tools" + ], "generatedRepoSpecs": { "com_android_dex": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://android.googlesource.com/platform/dalvik/+archive/5a81c499a569731e2395f7c8d13c0e0d4e17a2b6.tar.gz", - "build_file": "@@rules_android~//bzlmod_extensions:com_android_dex.BUILD" + "build_file": "@@rules_android+//bzlmod_extensions:com_android_dex.BUILD" } } - }, - "recordedRepoMappingEntries": [ - [ - "rules_android~", - "bazel_tools", - "bazel_tools" - ] - ] + } } }, - "@@rules_android~//rules/android_sdk_repository:rule.bzl%android_sdk_repository_extension": { + "@@rules_android+//rules/android_sdk_repository:rule.bzl%android_sdk_repository_extension": { "general": { "bzlTransitiveDigest": "NAy+0M15JNVEBb8Tny6t7j3lKqTnsAMjoBB6LJ+C370=", - "usagesDigest": "weZLGEpNa+fTJZ9CEljWxpN3/kuPzj/ULgebzOt2h4g=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "usagesDigest": "g9Ur6X6qhf9a8MmY9qXU/jFjkyk/aZVBegI0yVMF0z4=", + "recordedInputs": [], "generatedRepoSpecs": { "androidsdk": { - "bzlFile": "@@rules_android~//rules/android_sdk_repository:rule.bzl", - "ruleClassName": "_android_sdk_repository", + "repoRuleId": "@@rules_android+//rules/android_sdk_repository:rule.bzl%_android_sdk_repository", "attributes": {} } - }, - "recordedRepoMappingEntries": [] + } } }, - "@@rules_apple~//apple:apple.bzl%provisioning_profile_repository_extension": { + "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { "general": { - "bzlTransitiveDigest": "69pHX7bLYS/DuYEt2ts3jHV2ut8C5uih4oI+b/tjJZk=", - "usagesDigest": "cLx5XGjlbSDOpyA053y/jlr4GcaXFVTeHQic6eyG38E=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_provisioning_profiles": { - "bzlFile": "@@rules_apple~//apple/internal:local_provisioning_profiles.bzl", - "ruleClassName": "provisioning_profile_repository", - "attributes": {} - } - }, - "recordedRepoMappingEntries": [ - [ - "apple_support~", - "bazel_skylib", - "bazel_skylib~" - ], - [ - "rules_apple~", - "bazel_skylib", - "bazel_skylib~" - ], - [ - "rules_apple~", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_apple~", - "build_bazel_apple_support", - "apple_support~" - ], - [ - "rules_apple~", - "build_bazel_rules_swift", - "rules_swift~" - ], - [ - "rules_swift~", - "bazel_skylib", - "bazel_skylib~" - ], - [ - "rules_swift~", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_swift~", - "build_bazel_apple_support", - "apple_support~" - ], - [ - "rules_swift~", - "build_bazel_rules_swift", - "rules_swift~" - ], - [ - "rules_swift~", - "build_bazel_rules_swift_local_config", - "rules_swift~~non_module_deps~build_bazel_rules_swift_local_config" - ] - ] - } - }, - "@@rules_apple~//apple:extensions.bzl%non_module_deps": { - "general": { - "bzlTransitiveDigest": "LJ3bhNqfW9y6MZFgtKQoPJyUMg/aEZ8H9QXSzK1VOBk=", - "usagesDigest": "5FfEPy/Z0Y2V9RbdJRDabgADFdvlfIIrps/5XYOnMNI=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "xctestrunner": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/google/xctestrunner/archive/b7698df3d435b6491b4b4c0f9fc7a63fbed5e3a6.tar.gz" - ], - "strip_prefix": "xctestrunner-b7698df3d435b6491b4b4c0f9fc7a63fbed5e3a6", - "sha256": "ae3a063c985a8633cb7eb566db21656f8db8eb9a0edb8c182312c7f0db53730d" - } - } - }, - "recordedRepoMappingEntries": [ - [ - "rules_apple~", - "bazel_tools", - "bazel_tools" - ] - ] - } - }, - "@@rules_kotlin~//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { - "general": { - "bzlTransitiveDigest": "BSndOxBXlbe5qZf1NRxf828dpEK6tM429pCnaFoUFYs=", - "usagesDigest": "Dg5Nih77FaLAipQB7wgwsAy553a3po0eNGQVTZKgCM8=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "1r52/tc/bAGKspbAAb3WPDdgb3K3Yfb4gZibMxvAaIs=", + "usagesDigest": "qTwqmKKUfWcPdvM0waG+CPWrxsbeAWVeUxavm7tEk9E=", + "recordedInputs": [ + "REPO_MAPPING:rules_kotlin+,bazel_tools bazel_tools" + ], "generatedRepoSpecs": { "com_github_jetbrains_kotlin_git": { - "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl", - "ruleClassName": "kotlin_compiler_git_repository", + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_compiler_git_repository", "attributes": { "urls": [ "https://github.com/JetBrains/kotlin/releases/download/v2.1.0/kotlin-compiler-2.1.0.zip" @@ -460,16 +332,14 @@ } }, "com_github_jetbrains_kotlin": { - "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl", - "ruleClassName": "kotlin_capabilities_repository", + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_capabilities_repository", "attributes": { "git_repository_name": "com_github_jetbrains_kotlin_git", "compiler_version": "2.1.0" } }, "com_github_google_ksp": { - "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:ksp.bzl", - "ruleClassName": "ksp_compiler_plugin_repository", + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:ksp.bzl%ksp_compiler_plugin_repository", "attributes": { "urls": [ "https://github.com/google/ksp/releases/download/2.1.0-1.0.28/artifacts.zip" @@ -479,8 +349,7 @@ } }, "com_github_pinterest_ktlint": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_file", "attributes": { "sha256": "a9f923be58fbd32670a17f0b729b1df804af882fa57402165741cb26e5440ca1", "urls": [ @@ -490,8 +359,7 @@ } }, "kotlinx_serialization_core_jvm": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_jar", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_jar", "attributes": { "sha256": "29c821a8d4e25cbfe4f2ce96cdd4526f61f8f4e69a135f9612a34a81d93b65f1", "urls": [ @@ -500,8 +368,7 @@ } }, "kotlinx_serialization_json": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_jar", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_jar", "attributes": { "sha256": "8c0016890a79ab5980dd520a5ab1a6738023c29aa3b6437c482e0e5fdc06dab1", "urls": [ @@ -510,8 +377,7 @@ } }, "kotlinx_serialization_json_jvm": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_jar", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_jar", "attributes": { "sha256": "d3234179bcff1886d53d67c11eca47f7f3cf7b63c349d16965f6db51b7f3dd9a", "urls": [ @@ -519,35 +385,41 @@ ] } } - }, - "recordedRepoMappingEntries": [ - [ - "rules_kotlin~", - "bazel_tools", - "bazel_tools" - ] - ] + } } }, - "@@rules_python~//python/extensions:config.bzl%config": { + "@@rules_python+//python/extensions:config.bzl%config": { "general": { - "bzlTransitiveDigest": "JEJFuaDD7VQV641t2xy3kzc2EBtIxzHUAHwUerkS5RM=", - "usagesDigest": "n1K7/nlkMpUURDkWJsNS8Nr0tmxSDkFevx8GXKG82eA=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "iibnRYgg8LpcfmH7EAnVwYePC3jsVaJ6Id8XxUjSZps=", + "usagesDigest": "ZVSXMAGpD+xzVNPuvF1IoLBkty7TROO0+akMapt1pAg=", + "recordedInputs": [ + "REPO_MAPPING:rules_python+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_python+,pypi__build rules_python++config+pypi__build", + "REPO_MAPPING:rules_python+,pypi__click rules_python++config+pypi__click", + "REPO_MAPPING:rules_python+,pypi__colorama rules_python++config+pypi__colorama", + "REPO_MAPPING:rules_python+,pypi__importlib_metadata rules_python++config+pypi__importlib_metadata", + "REPO_MAPPING:rules_python+,pypi__installer rules_python++config+pypi__installer", + "REPO_MAPPING:rules_python+,pypi__more_itertools rules_python++config+pypi__more_itertools", + "REPO_MAPPING:rules_python+,pypi__packaging rules_python++config+pypi__packaging", + "REPO_MAPPING:rules_python+,pypi__pep517 rules_python++config+pypi__pep517", + "REPO_MAPPING:rules_python+,pypi__pip rules_python++config+pypi__pip", + "REPO_MAPPING:rules_python+,pypi__pip_tools rules_python++config+pypi__pip_tools", + "REPO_MAPPING:rules_python+,pypi__pyproject_hooks rules_python++config+pypi__pyproject_hooks", + "REPO_MAPPING:rules_python+,pypi__setuptools rules_python++config+pypi__setuptools", + "REPO_MAPPING:rules_python+,pypi__tomli rules_python++config+pypi__tomli", + "REPO_MAPPING:rules_python+,pypi__wheel rules_python++config+pypi__wheel", + "REPO_MAPPING:rules_python+,pypi__zipp rules_python++config+pypi__zipp" + ], "generatedRepoSpecs": { "rules_python_internal": { - "bzlFile": "@@rules_python~//python/private:internal_config_repo.bzl", - "ruleClassName": "internal_config_repo", + "repoRuleId": "@@rules_python+//python/private:internal_config_repo.bzl%internal_config_repo", "attributes": { "transition_setting_generators": {}, "transition_settings": [] } }, "pypi__build": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/e2/03/f3c8ba0a6b6e30d7d18c40faab90807c9bb5e9a1e3b2fe2008af624a9c97/build-1.2.1-py3-none-any.whl", "sha256": "75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4", @@ -556,8 +428,7 @@ } }, "pypi__click": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", "sha256": "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", @@ -566,8 +437,7 @@ } }, "pypi__colorama": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", "sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", @@ -576,8 +446,7 @@ } }, "pypi__importlib_metadata": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/2d/0a/679461c511447ffaf176567d5c496d1de27cbe34a87df6677d7171b2fbd4/importlib_metadata-7.1.0-py3-none-any.whl", "sha256": "30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570", @@ -586,8 +455,7 @@ } }, "pypi__installer": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl", "sha256": "05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53", @@ -596,8 +464,7 @@ } }, "pypi__more_itertools": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/50/e2/8e10e465ee3987bb7c9ab69efb91d867d93959095f4807db102d07995d94/more_itertools-10.2.0-py3-none-any.whl", "sha256": "686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684", @@ -606,8 +473,7 @@ } }, "pypi__packaging": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl", "sha256": "2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", @@ -616,8 +482,7 @@ } }, "pypi__pep517": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/25/6e/ca4a5434eb0e502210f591b97537d322546e4833dcb4d470a48c375c5540/pep517-0.13.1-py3-none-any.whl", "sha256": "31b206f67165b3536dd577c5c3f1518e8fbaf38cbc57efff8369a392feff1721", @@ -626,8 +491,7 @@ } }, "pypi__pip": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/8a/6a/19e9fe04fca059ccf770861c7d5721ab4c2aebc539889e97c7977528a53b/pip-24.0-py3-none-any.whl", "sha256": "ba0d021a166865d2265246961bec0152ff124de910c5cc39f1156ce3fa7c69dc", @@ -636,8 +500,7 @@ } }, "pypi__pip_tools": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/0d/dc/38f4ce065e92c66f058ea7a368a9c5de4e702272b479c0992059f7693941/pip_tools-7.4.1-py3-none-any.whl", "sha256": "4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9", @@ -646,8 +509,7 @@ } }, "pypi__pyproject_hooks": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/ae/f3/431b9d5fe7d14af7a32340792ef43b8a714e7726f1d7b69cc4e8e7a3f1d7/pyproject_hooks-1.1.0-py3-none-any.whl", "sha256": "7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2", @@ -656,8 +518,7 @@ } }, "pypi__setuptools": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/90/99/158ad0609729111163fc1f674a5a42f2605371a4cf036d0441070e2f7455/setuptools-78.1.1-py3-none-any.whl", "sha256": "c3a9c4211ff4c309edb8b8c4f1cbfa7ae324c4ba9f91ff254e3d305b9fd54561", @@ -666,8 +527,7 @@ } }, "pypi__tomli": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", "sha256": "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", @@ -676,8 +536,7 @@ } }, "pypi__wheel": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/7d/cd/d7460c9a869b16c3dd4e1e403cce337df165368c71d6af229a74699622ce/wheel-0.43.0-py3-none-any.whl", "sha256": "55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81", @@ -686,8 +545,7 @@ } }, "pypi__zipp": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://files.pythonhosted.org/packages/da/55/a03fd7240714916507e1fcf7ae355bd9d9ed2e6db492595f1a67f61681be/zipp-3.18.2-py3-none-any.whl", "sha256": "dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e", @@ -695,109 +553,27 @@ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } } - }, - "recordedRepoMappingEntries": [ - [ - "rules_python~", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_python~", - "pypi__build", - "rules_python~~config~pypi__build" - ], - [ - "rules_python~", - "pypi__click", - "rules_python~~config~pypi__click" - ], - [ - "rules_python~", - "pypi__colorama", - "rules_python~~config~pypi__colorama" - ], - [ - "rules_python~", - "pypi__importlib_metadata", - "rules_python~~config~pypi__importlib_metadata" - ], - [ - "rules_python~", - "pypi__installer", - "rules_python~~config~pypi__installer" - ], - [ - "rules_python~", - "pypi__more_itertools", - "rules_python~~config~pypi__more_itertools" - ], - [ - "rules_python~", - "pypi__packaging", - "rules_python~~config~pypi__packaging" - ], - [ - "rules_python~", - "pypi__pep517", - "rules_python~~config~pypi__pep517" - ], - [ - "rules_python~", - "pypi__pip", - "rules_python~~config~pypi__pip" - ], - [ - "rules_python~", - "pypi__pip_tools", - "rules_python~~config~pypi__pip_tools" - ], - [ - "rules_python~", - "pypi__pyproject_hooks", - "rules_python~~config~pypi__pyproject_hooks" - ], - [ - "rules_python~", - "pypi__setuptools", - "rules_python~~config~pypi__setuptools" - ], - [ - "rules_python~", - "pypi__tomli", - "rules_python~~config~pypi__tomli" - ], - [ - "rules_python~", - "pypi__wheel", - "rules_python~~config~pypi__wheel" - ], - [ - "rules_python~", - "pypi__zipp", - "rules_python~~config~pypi__zipp" - ] - ] + } } }, - "@@rules_python~//python/uv:uv.bzl%uv": { + "@@rules_python+//python/uv:uv.bzl%uv": { "general": { - "bzlTransitiveDigest": "K6zoA/u57+d21o50BApale3BrKDIB1vWM6q455k772s=", - "usagesDigest": "PAumpjVacknBm1rrOwOjhYqel5KPCDgZNHNmdVc9/WY=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "ijW9KS7qsIY+yBVvJ+Nr1mzwQox09j13DnE3iIwaeTM=", + "usagesDigest": "H8dQoNZcoqP+Mu0tHZTi4KHATzvNkM5ePuEqoQdklIU=", + "recordedInputs": [ + "REPO_MAPPING:rules_python+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_python+,platforms platforms" + ], "generatedRepoSpecs": { "uv": { - "bzlFile": "@@rules_python~//python/uv/private:uv_toolchains_repo.bzl", - "ruleClassName": "uv_toolchains_repo", + "repoRuleId": "@@rules_python+//python/uv/private:uv_toolchains_repo.bzl%uv_toolchains_repo", "attributes": { - "toolchain_type": "'@@rules_python~//python/uv:uv_toolchain_type'", + "toolchain_type": "'@@rules_python+//python/uv:uv_toolchain_type'", "toolchain_names": [ "none" ], "toolchain_implementations": { - "none": "'@@rules_python~//python:none'" + "none": "'@@rules_python+//python:none'" }, "toolchain_compatible_with": { "none": [ @@ -807,192 +583,9 @@ "toolchain_target_settings": {} } } - }, - "recordedRepoMappingEntries": [ - [ - "rules_python~", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_python~", - "platforms", - "platforms" - ] - ] - } - }, - "@@rules_swift~//swift:extensions.bzl%non_module_deps": { - "general": { - "bzlTransitiveDigest": "vhXfCi07IAmWf5hLHcxh5xCtTwvEGrmMkOavEMD5pzs=", - "usagesDigest": "/dVEtCLqIAaLXjfRXsJupTS9pTgmYVN/tFdJlGgE5NA=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "com_github_apple_swift_protobuf": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-protobuf/archive/1.20.2.tar.gz" - ], - "sha256": "3fb50bd4d293337f202d917b6ada22f9548a0a0aed9d9a4d791e6fbd8a246ebb", - "strip_prefix": "swift-protobuf-1.20.2/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_protobuf/BUILD.overlay" - } - }, - "com_github_grpc_grpc_swift": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/grpc/grpc-swift/archive/1.16.0.tar.gz" - ], - "sha256": "58b60431d0064969f9679411264b82e40a217ae6bd34e17096d92cc4e47556a5", - "strip_prefix": "grpc-swift-1.16.0/", - "build_file": "@@rules_swift~//third_party:com_github_grpc_grpc_swift/BUILD.overlay" - } - }, - "com_github_apple_swift_docc_symbolkit": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-docc-symbolkit/archive/refs/tags/swift-5.10-RELEASE.tar.gz" - ], - "sha256": "de1d4b6940468ddb53b89df7aa1a81323b9712775b0e33e8254fa0f6f7469a97", - "strip_prefix": "swift-docc-symbolkit-swift-5.10-RELEASE", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_docc_symbolkit/BUILD.overlay" - } - }, - "com_github_apple_swift_nio": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-nio/archive/2.42.0.tar.gz" - ], - "sha256": "e3304bc3fb53aea74a3e54bd005ede11f6dc357117d9b1db642d03aea87194a0", - "strip_prefix": "swift-nio-2.42.0/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio/BUILD.overlay" - } - }, - "com_github_apple_swift_nio_http2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-nio-http2/archive/1.26.0.tar.gz" - ], - "sha256": "f0edfc9d6a7be1d587e5b403f2d04264bdfae59aac1d74f7d974a9022c6d2b25", - "strip_prefix": "swift-nio-http2-1.26.0/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_http2/BUILD.overlay" - } - }, - "com_github_apple_swift_nio_transport_services": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-nio-transport-services/archive/1.15.0.tar.gz" - ], - "sha256": "f3498dafa633751a52b9b7f741f7ac30c42bcbeb3b9edca6d447e0da8e693262", - "strip_prefix": "swift-nio-transport-services-1.15.0/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_transport_services/BUILD.overlay" - } - }, - "com_github_apple_swift_nio_extras": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-nio-extras/archive/1.4.0.tar.gz" - ], - "sha256": "4684b52951d9d9937bb3e8ccd6b5daedd777021ef2519ea2f18c4c922843b52b", - "strip_prefix": "swift-nio-extras-1.4.0/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_extras/BUILD.overlay" - } - }, - "com_github_apple_swift_log": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-log/archive/1.4.4.tar.gz" - ], - "sha256": "48fe66426c784c0c20031f15dc17faf9f4c9037c192bfac2f643f65cb2321ba0", - "strip_prefix": "swift-log-1.4.4/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_log/BUILD.overlay" - } - }, - "com_github_apple_swift_nio_ssl": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-nio-ssl/archive/2.23.0.tar.gz" - ], - "sha256": "4787c63f61dd04d99e498adc3d1a628193387e41efddf8de19b8db04544d016d", - "strip_prefix": "swift-nio-ssl-2.23.0/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_ssl/BUILD.overlay" - } - }, - "com_github_apple_swift_collections": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-collections/archive/1.0.4.tar.gz" - ], - "sha256": "d9e4c8a91c60fb9c92a04caccbb10ded42f4cb47b26a212bc6b39cc390a4b096", - "strip_prefix": "swift-collections-1.0.4/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_collections/BUILD.overlay" - } - }, - "com_github_apple_swift_atomics": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-atomics/archive/1.1.0.tar.gz" - ], - "sha256": "1bee7f469f7e8dc49f11cfa4da07182fbc79eab000ec2c17bfdce468c5d276fb", - "strip_prefix": "swift-atomics-1.1.0/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_atomics/BUILD.overlay" - } - }, - "build_bazel_rules_swift_index_import": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "build_file": "@@rules_swift~//third_party:build_bazel_rules_swift_index_import/BUILD.overlay", - "canonical_id": "index-import-5.8", - "urls": [ - "https://github.com/MobileNativeFoundation/index-import/releases/download/5.8.0.1/index-import.tar.gz" - ], - "sha256": "28c1ffa39d99e74ed70623899b207b41f79214c498c603915aef55972a851a15" - } - }, - "build_bazel_rules_swift_local_config": { - "bzlFile": "@@rules_swift~//swift/internal:swift_autoconfiguration.bzl", - "ruleClassName": "swift_autoconfiguration", - "attributes": {} - } - }, - "recordedRepoMappingEntries": [ - [ - "rules_swift~", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_swift~", - "build_bazel_rules_swift", - "rules_swift~" - ] - ] + } } } - } + }, + "facts": {} }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/ApiModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/ApiModule.java new file mode 100644 index 0000000..fbf5ab5 --- /dev/null +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/ApiModule.java
@@ -0,0 +1,31 @@ +// Copyright (C) 2026 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.ericsson.gerrit.plugins.highavailability; + +import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.CommandProcessor; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.ForwarderCommandsModule; +import com.google.gerrit.extensions.registration.DynamicItem; +import com.google.inject.AbstractModule; + +public class ApiModule extends AbstractModule { + + @Override + protected void configure() { + DynamicItem.itemOf(binder(), Forwarder.class); + DynamicItem.itemOf(binder(), CommandProcessor.class); + install(new ForwarderCommandsModule()); + } +}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java index f75bdaa..15425d3 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
@@ -88,7 +88,8 @@ public enum Transport { HTTP, - JGROUPS + JGROUPS, + PROVIDED } @Inject @@ -515,6 +516,8 @@ static final String MAX_TRIES_KEY = "maxTries"; static final String RETRY_INTERVAL_KEY = "retryInterval"; static final String THREAD_POOL_SIZE_KEY = "threadPoolSize"; + static final String REUSE_CONNECTION_AFTER_503_KEY = "reuseConnectionAfter503"; + static final boolean DEFAULT_REUSE_CONNECTION_AFTER_503 = true; private final String user; private final String password; @@ -523,6 +526,7 @@ private final int maxTries; private final Duration retryInterval; private final int threadPoolSize; + private final boolean reuseConnectionAfter503; private Http(Config cfg) { user = Strings.nullToEmpty(cfg.getString(HTTP_SECTION, null, USER_KEY)); @@ -532,6 +536,9 @@ maxTries = getMaxTries(cfg, HTTP_SECTION, MAX_TRIES_KEY, DEFAULT_MAX_TRIES); retryInterval = getDuration(cfg, HTTP_SECTION, RETRY_INTERVAL_KEY, DEFAULT_RETRY_INTERVAL); threadPoolSize = getInt(cfg, HTTP_SECTION, THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE); + reuseConnectionAfter503 = + cfg.getBoolean( + HTTP_SECTION, REUSE_CONNECTION_AFTER_503_KEY, DEFAULT_REUSE_CONNECTION_AFTER_503); } public String user() { @@ -561,6 +568,10 @@ public int threadPoolSize() { return threadPoolSize; } + + public boolean reuseConnectionAfter503() { + return reuseConnectionAfter503; + } } /** Common parameters to cache, event, index and websession */
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java index 6a90e73..6227787 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
@@ -17,7 +17,11 @@ import com.ericsson.gerrit.plugins.highavailability.autoreindex.AutoReindexModule; import com.ericsson.gerrit.plugins.highavailability.cache.CacheModule; import com.ericsson.gerrit.plugins.highavailability.event.EventModule; +import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder; import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwarderModule; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.CommandProcessor; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.CommandProcessorImpl; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.ForwarderCommandsModule; import com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups.JGroupsForwarderModule; import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.RestForwarderModule; import com.ericsson.gerrit.plugins.highavailability.index.IndexModule; @@ -26,6 +30,7 @@ import com.ericsson.gerrit.plugins.highavailability.peers.PeerInfoModule; import com.gerritforge.gerrit.globalrefdb.validation.ProjectDeletedSharedDbCleanup; import com.google.gerrit.extensions.events.ProjectDeletedListener; +import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.lifecycle.LifecycleModule; import com.google.inject.Inject; @@ -49,16 +54,22 @@ install(new ForwarderModule()); install(new FileBasedLockManager.Module()); + DynamicItem.bind(binder(), CommandProcessor.class).to(CommandProcessorImpl.class); + switch (config.main().transport()) { - case HTTP: + case HTTP -> { install(new RestForwarderModule()); install(new PeerInfoModule(config.peerInfo().strategy())); - break; - case JGROUPS: + } + case JGROUPS -> { + install(new ForwarderCommandsModule()); install(new JGroupsForwarderModule()); - break; - default: - throw new IllegalArgumentException("Unsupported transport: " + config.main().transport()); + } + case PROVIDED -> { + // Bind default no-op implementation + // Transport will be provided by another plugin + DynamicItem.bind(binder(), Forwarder.class).to(NoForwarder.class); + } } if (config.cache().synchronize()) {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/NoForwarder.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/NoForwarder.java new file mode 100644 index 0000000..8e29fcf --- /dev/null +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/NoForwarder.java
@@ -0,0 +1,96 @@ +// Copyright (C) 2026 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.ericsson.gerrit.plugins.highavailability; + +import com.ericsson.gerrit.plugins.highavailability.forwarder.EventType; +import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder; +import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent; +import com.google.common.flogger.FluentLogger; +import com.google.gerrit.entities.Project.NameKey; +import com.google.gerrit.server.events.Event; +import java.util.concurrent.CompletableFuture; + +/** + * No-Op forwarder implementation + * + * <p>This is used only as a temporary placeholder to avoid null checks until another plugin + * provides a real Forwarder implementation + */ +public class NoForwarder implements Forwarder { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + + @Override + public CompletableFuture<Result> indexAccount(int accountId, IndexEvent indexEvent) { + logger.atWarning().log("NoForwarder: indexAccount called with accountId=%d", accountId); + return recoverableFailure(EventType.INDEX_ACCOUNT_UPDATE); + } + + @Override + public CompletableFuture<Result> indexChange( + String projectName, int changeId, IndexEvent indexEvent) { + return recoverableFailure(EventType.INDEX_CHANGE_UPDATE); + } + + @Override + public CompletableFuture<Result> batchIndexChange( + String projectName, int changeId, IndexEvent indexEvent) { + return recoverableFailure(EventType.INDEX_CHANGE_UPDATE_BATCH); + } + + @Override + public CompletableFuture<Result> deleteChangeFromIndex( + String projectName, int changeId, IndexEvent indexEvent) { + return recoverableFailure(EventType.INDEX_CHANGE_DELETION); + } + + @Override + public CompletableFuture<Result> indexGroup(String uuid, IndexEvent indexEvent) { + return recoverableFailure(EventType.INDEX_GROUP_UPDATE); + } + + @Override + public CompletableFuture<Result> indexProject(String projectName, IndexEvent indexEvent) { + return recoverableFailure(EventType.INDEX_PROJECT_UPDATE); + } + + @Override + public CompletableFuture<Result> send(Event event) { + return recoverableFailure(EventType.EVENT_SENT); + } + + @Override + public CompletableFuture<Result> evict(String cacheName, Object key) { + return recoverableFailure(EventType.CACHE_EVICTION); + } + + @Override + public CompletableFuture<Result> addToProjectList(String projectName) { + return recoverableFailure(EventType.PROJECT_LIST_ADDITION); + } + + @Override + public CompletableFuture<Result> removeFromProjectList(String projectName) { + return recoverableFailure(EventType.PROJECT_LIST_DELETION); + } + + @Override + public CompletableFuture<Result> deleteAllChangesForProject(NameKey projectName) { + return recoverableFailure(EventType.INDEX_CHANGE_DELETION_ALL_OF_PROJECT); + } + + private CompletableFuture<Result> recoverableFailure(EventType eventType) { + return CompletableFuture.completedFuture(new Result(eventType, false, true)); + } +}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java index 75a9681..23a568e 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java
@@ -146,7 +146,7 @@ } @Override - public void onChangeDeleted(int id) { + public void onChangeDeleted(String projectName, int id) { currCtx.onlyWithContext((ctx) -> update(IndexName.CHANGE, LocalDateTime.now())); }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionHandler.java index 53bc3a1..43b6e4c 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionHandler.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionHandler.java
@@ -17,15 +17,16 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.Context; import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder; import com.google.common.cache.RemovalNotification; +import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.server.cache.CacheRemovalListener; import com.google.inject.Inject; class CacheEvictionHandler<K, V> implements CacheRemovalListener<K, V> { - private final Forwarder forwarder; + private final DynamicItem<Forwarder> forwarder; private final CachePatternMatcher matcher; @Inject - CacheEvictionHandler(Forwarder forwarder, CachePatternMatcher matcher) { + CacheEvictionHandler(DynamicItem<Forwarder> forwarder, CachePatternMatcher matcher) { this.forwarder = forwarder; this.matcher = matcher; } @@ -33,7 +34,7 @@ @Override public void onRemoval(String plugin, String cache, RemovalNotification<K, V> notification) { if (!Context.isForwardedEvent() && !notification.wasEvicted() && matcher.matches(cache)) { - forwarder.evict(cache, notification.getKey()); + forwarder.get().evict(cache, notification.getKey()); } } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListUpdateHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListUpdateHandler.java index 9ce9536..4281226 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListUpdateHandler.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListUpdateHandler.java
@@ -19,16 +19,17 @@ import com.google.gerrit.extensions.events.NewProjectCreatedListener; import com.google.gerrit.extensions.events.ProjectDeletedListener; import com.google.gerrit.extensions.events.ProjectEvent; +import com.google.gerrit.extensions.registration.DynamicItem; import com.google.inject.Inject; import com.google.inject.Singleton; @Singleton public class ProjectListUpdateHandler implements NewProjectCreatedListener, ProjectDeletedListener { - private final Forwarder forwarder; + private final DynamicItem<Forwarder> forwarder; @Inject - public ProjectListUpdateHandler(Forwarder forwarder) { + public ProjectListUpdateHandler(DynamicItem<Forwarder> forwarder) { this.forwarder = forwarder; } @@ -47,9 +48,9 @@ private void process(ProjectEvent event, boolean delete) { if (!Context.isForwardedEvent()) { if (delete) { - forwarder.removeFromProjectList(event.getProjectName()); + forwarder.get().removeFromProjectList(event.getProjectName()); } else { - forwarder.addToProjectList(event.getProjectName()); + forwarder.get().addToProjectList(event.getProjectName()); } } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandler.java index 5ce12df..3060f5f 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandler.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandler.java
@@ -16,23 +16,24 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.Context; import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder; +import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.server.events.Event; import com.google.gerrit.server.events.EventListener; import com.google.gerrit.server.events.ProjectEvent; import com.google.inject.Inject; class EventHandler implements EventListener { - private final Forwarder forwarder; + private final DynamicItem<Forwarder> forwarder; @Inject - EventHandler(Forwarder forwarder) { + EventHandler(DynamicItem<Forwarder> forwarder) { this.forwarder = forwarder; } @Override public void onEvent(Event event) { if (!Context.isForwardedEvent() && event instanceof ProjectEvent) { - forwarder.send(event); + forwarder.get().send(event); } } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandler.java index b93ff18..3bf5872 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandler.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandler.java
@@ -104,7 +104,7 @@ } catch (Exception e) { if (isCausedByNoSuchChangeException(e)) { - indexer.delete(parseChangeId(id)); + indexer.delete(parseProject(id), parseChangeId(id)); log.atWarning().withCause(e).log("Error trying to index Change %s. Deleted from index", id); return true; } @@ -114,15 +114,15 @@ } private void reindex(ChangeNotes notes) { - notes.reload(); - indexer.reindexIfStale(notes.getProjectName(), notes.getChangeId()); + var unused = notes.reload(); + var unusedResult = indexer.reindexIfStale(notes.getProjectName(), notes.getChangeId()); } @Override protected CompletableFuture<Boolean> doDelete(String id, Optional<IndexEvent> indexEvent) throws IOException { + Project.NameKey projectName = parseProject(id); if (ALL_CHANGES_FOR_PROJECT.equals(extractChangeId(id))) { - Project.NameKey projectName = parseProject(id); try { indexer.deleteAllForProject(projectName); log.atFine().log("All %s changes successfully deleted from index", projectName.get()); @@ -133,7 +133,7 @@ } } else { try { - indexer.delete(parseChangeId(id)); + indexer.delete(projectName, parseChangeId(id)); log.atFine().log("Change %s successfully deleted from index", id); } catch (RuntimeException e) { log.atFine().log("Change %s could not be deleted from index", id);
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/Forwarder.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/Forwarder.java index 3bf08b4..088f0fa 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/Forwarder.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/Forwarder.java
@@ -68,7 +68,8 @@ * @return {@link CompletableFuture} of true if successful, otherwise {@link CompletableFuture} of * false. */ - CompletableFuture<Result> deleteChangeFromIndex(int changeId, IndexEvent indexEvent); + CompletableFuture<Result> deleteChangeFromIndex( + String projectName, int changeId, IndexEvent indexEvent); /** * Forward a group indexing event to the other primary.
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/AddToProjectList.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/AddToProjectList.java similarity index 93% rename from src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/AddToProjectList.java rename to src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/AddToProjectList.java index 6f47da3..4883dda 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/AddToProjectList.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/AddToProjectList.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import com.ericsson.gerrit.plugins.highavailability.forwarder.EventType; import java.time.Instant;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/Command.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/Command.java similarity index 92% rename from src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/Command.java rename to src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/Command.java index 3abad1e..1b7b86e 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/Command.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/Command.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import com.ericsson.gerrit.plugins.highavailability.forwarder.EventType; import java.time.Instant;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/CommandDeserializer.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandDeserializer.java similarity index 97% rename from src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/CommandDeserializer.java rename to src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandDeserializer.java index cdd217c..1100284 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/CommandDeserializer.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandDeserializer.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import com.ericsson.gerrit.plugins.highavailability.forwarder.EventType; import com.google.gson.JsonDeserializationContext;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandProcessor.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandProcessor.java new file mode 100644 index 0000000..6c40356 --- /dev/null +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandProcessor.java
@@ -0,0 +1,27 @@ +// Copyright (C) 2026 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; + +/** Processes commands received from other nodes */ +public interface CommandProcessor { + + /** + * Processes the given command. + * + * @param cmd the command to process + * @return true if the command was successfully processed, false otherwise + */ + boolean handle(Command cmd); +}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/MessageProcessor.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandProcessorImpl.java similarity index 88% rename from src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/MessageProcessor.java rename to src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandProcessorImpl.java index 489e070..cadfaea 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/MessageProcessor.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandProcessorImpl.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import com.ericsson.gerrit.plugins.highavailability.forwarder.CacheEntry; import com.ericsson.gerrit.plugins.highavailability.forwarder.Context; @@ -25,23 +25,20 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedProjectListUpdateHandler; import com.ericsson.gerrit.plugins.highavailability.forwarder.ProcessorMetrics; import com.ericsson.gerrit.plugins.highavailability.forwarder.ProcessorMetricsRegistry; +import com.google.common.annotations.VisibleForTesting; import com.google.common.flogger.FluentLogger; import com.google.gerrit.entities.Account; import com.google.gerrit.server.events.Event; -import com.google.gson.Gson; import com.google.inject.Inject; import com.google.inject.Singleton; import java.io.IOException; import java.time.Instant; import java.util.Optional; -import org.jgroups.Message; -import org.jgroups.blocks.RequestHandler; @Singleton -public class MessageProcessor implements RequestHandler { +public class CommandProcessorImpl implements CommandProcessor { private static final FluentLogger log = FluentLogger.forEnclosingClass(); - private final Gson gson; private final ForwardedIndexChangeHandler indexChangeHandler; private final ForwardedIndexBatchChangeHandler indexBatchChangeHandler; private final ForwardedIndexAccountHandler indexAccountHandler; @@ -51,8 +48,8 @@ private final ProcessorMetricsRegistry metricRegistry; @Inject - MessageProcessor( - @JGroupsGson Gson gson, + @VisibleForTesting + public CommandProcessorImpl( ForwardedIndexChangeHandler indexChangeHandler, ForwardedIndexBatchChangeHandler indexBatchChangeHandler, ForwardedIndexAccountHandler indexAccountHandler, @@ -60,7 +57,6 @@ ForwardedEventHandler eventHandler, ForwardedProjectListUpdateHandler projectListUpdateHandler, ProcessorMetricsRegistry metricRegistry) { - this.gson = gson; this.indexChangeHandler = indexChangeHandler; this.indexBatchChangeHandler = indexBatchChangeHandler; this.indexAccountHandler = indexAccountHandler; @@ -71,8 +67,7 @@ } @Override - public Object handle(Message msg) { - Command cmd = getCommand(msg); + public boolean handle(Command cmd) { ProcessorMetrics metrics = metricRegistry.get(cmd.type); Instant startTime = Instant.now(); boolean success = false; @@ -117,7 +112,7 @@ } else if (cmd instanceof PostEvent) { Event event = ((PostEvent) cmd).getEvent(); eventHandler.dispatch(event); - + log.atFine().log("Dispatching event %s done", event); } else if (cmd instanceof AddToProjectList) { String projectName = ((AddToProjectList) cmd).getProjectName(); projectListUpdateHandler.update(projectName, false); @@ -145,15 +140,4 @@ throw new IllegalArgumentException("Unknown type of IndexChange command " + cmd.getClass()); } } - - private Command getCommand(Message msg) { - try { - String s = (String) msg.getObject(); - log.atFine().log("Received message: %s", s); - return gson.fromJson(s, Command.class); - } catch (RuntimeException e) { - log.atSevere().withCause(e).log("Error parsing message %s", msg.getObject()); - throw e; - } - } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsGson.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandsGson.java similarity index 87% rename from src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsGson.java rename to src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandsGson.java index a4ca15a..d381402 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsGson.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandsGson.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -21,4 +21,4 @@ @BindingAnnotation @Retention(RUNTIME) -public @interface JGroupsGson {} +public @interface CommandsGson {}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/DeleteAllProjectChangesFromIndex.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/DeleteAllProjectChangesFromIndex.java similarity index 86% rename from src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/DeleteAllProjectChangesFromIndex.java rename to src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/DeleteAllProjectChangesFromIndex.java index 81ce445..532708b 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/DeleteAllProjectChangesFromIndex.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/DeleteAllProjectChangesFromIndex.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import com.ericsson.gerrit.plugins.highavailability.forwarder.EventType; import com.google.gerrit.entities.Project; @@ -23,7 +23,7 @@ private final Project.NameKey projectName; - protected DeleteAllProjectChangesFromIndex(Project.NameKey projectName, Instant createdOn) { + public DeleteAllProjectChangesFromIndex(Project.NameKey projectName, Instant createdOn) { super(TYPE, createdOn); this.projectName = projectName; }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/EvictCache.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/EvictCache.java similarity index 82% rename from src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/EvictCache.java rename to src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/EvictCache.java index 9ca05f1..151b839 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/EvictCache.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/EvictCache.java
@@ -12,18 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import com.ericsson.gerrit.plugins.highavailability.forwarder.EventType; import java.time.Instant; public class EvictCache extends Command { - static final EventType TYPE = EventType.CACHE_EVICTION; + public static final EventType TYPE = EventType.CACHE_EVICTION; private final String cacheName; private final String keyJson; - protected EvictCache(String cacheName, String keyJson, Instant eventCreatedOn) { + public EvictCache(String cacheName, String keyJson, Instant eventCreatedOn) { super(TYPE, eventCreatedOn); this.cacheName = cacheName; this.keyJson = keyJson;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/ForwarderCommandsModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/ForwarderCommandsModule.java new file mode 100644 index 0000000..7a1b039 --- /dev/null +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/ForwarderCommandsModule.java
@@ -0,0 +1,38 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; + +import com.ericsson.gerrit.plugins.highavailability.forwarder.InstantTypeAdapter; +import com.google.common.annotations.VisibleForTesting; +import com.google.gerrit.server.events.EventGson; +import com.google.gson.Gson; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import java.time.Instant; + +public class ForwarderCommandsModule extends AbstractModule { + @Provides + @Singleton + @CommandsGson + @VisibleForTesting + public Gson buildCommandsGson(@EventGson Gson eventGson) { + return eventGson + .newBuilder() + .registerTypeAdapter(Command.class, new CommandDeserializer()) + .registerTypeAdapter(Instant.class, new InstantTypeAdapter()) + .create(); + } +}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/IndexAccount.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexAccount.java similarity index 92% rename from src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/IndexAccount.java rename to src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexAccount.java index 55cadda..6c95d1d 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/IndexAccount.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexAccount.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import com.ericsson.gerrit.plugins.highavailability.forwarder.EventType; import java.time.Instant;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/IndexChange.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexChange.java similarity index 92% rename from src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/IndexChange.java rename to src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexChange.java index 075bfd7..df79eca 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/IndexChange.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexChange.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import com.ericsson.gerrit.plugins.highavailability.forwarder.EventType; import com.google.common.base.Strings; @@ -58,10 +58,6 @@ public static class Delete extends IndexChange { static final EventType TYPE = EventType.INDEX_CHANGE_DELETION; - public Delete(int id, Instant eventCreatedOn) { - this("", id, eventCreatedOn); - } - public Delete(String projectName, int id, Instant eventCreatedOn) { super(TYPE, projectName, id, false, eventCreatedOn); }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/IndexGroup.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexGroup.java similarity index 87% rename from src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/IndexGroup.java rename to src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexGroup.java index 9f49060..3ae8458 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/IndexGroup.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexGroup.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import com.ericsson.gerrit.plugins.highavailability.forwarder.EventType; import java.time.Instant; @@ -22,7 +22,7 @@ private final String uuid; - protected IndexGroup(String uuid, Instant eventCreatedOn) { + public IndexGroup(String uuid, Instant eventCreatedOn) { super(TYPE, eventCreatedOn); this.uuid = uuid; }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/IndexProject.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexProject.java similarity index 87% rename from src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/IndexProject.java rename to src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexProject.java index 40e400d..7feffc4 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/IndexProject.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexProject.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import com.ericsson.gerrit.plugins.highavailability.forwarder.EventType; import java.time.Instant; @@ -22,7 +22,7 @@ private String projectName; - protected IndexProject(String projectName, Instant eventCreatedOn) { + public IndexProject(String projectName, Instant eventCreatedOn) { super(TYPE, eventCreatedOn); this.projectName = projectName; }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/PostEvent.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/PostEvent.java similarity index 88% rename from src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/PostEvent.java rename to src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/PostEvent.java index 3f50b0a..18c17c7 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/PostEvent.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/PostEvent.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import com.ericsson.gerrit.plugins.highavailability.forwarder.EventType; import com.google.gerrit.server.events.Event; @@ -23,7 +23,7 @@ private final Event event; - protected PostEvent(Event event, Instant eventCreatedOn) { + public PostEvent(Event event, Instant eventCreatedOn) { super(TYPE, eventCreatedOn); this.event = event; }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/RemoveFromProjectList.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/RemoveFromProjectList.java similarity index 93% rename from src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/RemoveFromProjectList.java rename to src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/RemoveFromProjectList.java index 1a43ac8..b1ee7df 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/RemoveFromProjectList.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/RemoveFromProjectList.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import com.ericsson.gerrit.plugins.highavailability.forwarder.EventType; import java.time.Instant;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarder.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarder.java index 0bd8c5d..225738f 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarder.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarder.java
@@ -19,6 +19,17 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder; import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwarderMetricsRegistry; import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.AddToProjectList; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.Command; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.CommandsGson; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.DeleteAllProjectChangesFromIndex; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.EvictCache; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.IndexAccount; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.IndexChange; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.IndexGroup; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.IndexProject; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.PostEvent; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.RemoveFromProjectList; import com.google.common.flogger.FluentLogger; import com.google.gerrit.entities.Project; import com.google.gerrit.server.events.Event; @@ -53,7 +64,7 @@ JGroupsForwarder( MessageDispatcher dispatcher, Configuration cfg, - @JGroupsGson Gson gson, + @CommandsGson Gson gson, @JGroupsForwarderExecutor FailsafeExecutor<Result> executor, ForwarderMetricsRegistry metricsRegistry) { this.dispatcher = dispatcher; @@ -86,8 +97,9 @@ } @Override - public CompletableFuture<Result> deleteChangeFromIndex(int changeId, IndexEvent indexEvent) { - return execute(new IndexChange.Delete(changeId, indexEvent.eventCreatedOn)); + public CompletableFuture<Result> deleteChangeFromIndex( + String projectName, int changeId, IndexEvent indexEvent) { + return execute(new IndexChange.Delete(projectName, changeId, indexEvent.eventCreatedOn)); } @Override
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarderModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarderModule.java index 0895088..3d3a5b7 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarderModule.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarderModule.java
@@ -16,17 +16,12 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder; import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder.Result; -import com.ericsson.gerrit.plugins.highavailability.forwarder.InstantTypeAdapter; import com.ericsson.gerrit.plugins.highavailability.peers.jgroups.JChannelProviderModule; +import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.lifecycle.LifecycleModule; -import com.google.gerrit.server.events.EventGson; -import com.google.gson.Gson; -import com.google.inject.Provides; import com.google.inject.Scopes; -import com.google.inject.Singleton; import com.google.inject.TypeLiteral; import dev.failsafe.FailsafeExecutor; -import java.time.Instant; import org.jgroups.blocks.MessageDispatcher; import org.jgroups.blocks.RequestHandler; @@ -34,9 +29,9 @@ @Override protected void configure() { - bind(Forwarder.class).to(JGroupsForwarder.class); + DynamicItem.bind(binder(), Forwarder.class).to(JGroupsForwarder.class); bind(MessageDispatcher.class).toProvider(MessageDispatcherProvider.class).in(Scopes.SINGLETON); - bind(RequestHandler.class).to(MessageProcessor.class); + bind(RequestHandler.class).to(JGroupsMessageProcessor.class); install(new JChannelProviderModule()); listener().to(OnStartStop.class); @@ -45,15 +40,4 @@ .toProvider(FailsafeExecutorProvider.class) .in(Scopes.SINGLETON); } - - @Provides - @Singleton - @JGroupsGson - Gson buildJGroupsGson(@EventGson Gson eventGson) { - return eventGson - .newBuilder() - .registerTypeAdapter(Command.class, new CommandDeserializer()) - .registerTypeAdapter(Instant.class, new InstantTypeAdapter()) - .create(); - } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsMessageProcessor.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsMessageProcessor.java new file mode 100644 index 0000000..ff091b9 --- /dev/null +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsMessageProcessor.java
@@ -0,0 +1,55 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; + +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.Command; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.CommandProcessor; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.CommandsGson; +import com.google.common.flogger.FluentLogger; +import com.google.gson.Gson; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import org.jgroups.Message; +import org.jgroups.blocks.RequestHandler; + +@Singleton +public class JGroupsMessageProcessor implements RequestHandler { + private static final FluentLogger log = FluentLogger.forEnclosingClass(); + + private final Gson gson; + private final CommandProcessor processor; + + @Inject + JGroupsMessageProcessor(@CommandsGson Gson gson, CommandProcessor processor) { + this.gson = gson; + this.processor = processor; + } + + @Override + public Object handle(Message msg) { + return processor.handle(getCommand(msg)); + } + + private Command getCommand(Message msg) { + try { + String s = (String) msg.getObject(); + log.atFine().log("Received message: %s", s); + return gson.fromJson(s, Command.class); + } catch (RuntimeException e) { + log.atSevere().withCause(e).log("Error parsing message %s", msg.getObject()); + throw e; + } + } +}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java index a71e03f..fc90a10 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java
@@ -14,6 +14,8 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder.rest; +import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE; + import com.ericsson.gerrit.plugins.highavailability.Configuration; import com.google.common.flogger.FluentLogger; import com.google.inject.Inject; @@ -24,6 +26,7 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; +import org.apache.http.ConnectionReuseStrategy; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.config.RequestConfig; @@ -34,6 +37,7 @@ import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.DefaultConnectionReuseStrategy; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; @@ -64,6 +68,7 @@ .setConnectionManager(customConnectionManager()) .setDefaultCredentialsProvider(buildCredentials()) .setDefaultRequestConfig(customRequestConfig()) + .setConnectionReuseStrategy(customConnectionReuseStrategy()) .build(); } @@ -77,6 +82,10 @@ } private HttpClientConnectionManager customConnectionManager() { + return buildConnectionManager(); + } + + PoolingHttpClientConnectionManager buildConnectionManager() { Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("https", sslSocketFactory) @@ -90,6 +99,16 @@ return connManager; } + private ConnectionReuseStrategy customConnectionReuseStrategy() { + return (response, context) -> { + if (response.getStatusLine().getStatusCode() == SC_SERVICE_UNAVAILABLE + && !cfg.http().reuseConnectionAfter503()) { + return false; + } + return DefaultConnectionReuseStrategy.INSTANCE.keepAlive(response, context); + }; + } + private static SSLConnectionSocketFactory buildSslSocketFactory() { return new SSLConnectionSocketFactory(buildSslContext(), NoopHostnameVerifier.INSTANCE); }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java index ea783a6..06df702 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java
@@ -120,13 +120,14 @@ } @Override - public CompletableFuture<Result> deleteChangeFromIndex(final int changeId, IndexEvent event) { + public CompletableFuture<Result> deleteChangeFromIndex( + String projectName, final int changeId, IndexEvent event) { return execute( RequestMethod.DELETE, EventType.INDEX_CHANGE_DELETION, "delete change", "index/change", - buildIndexEndpoint(changeId), + buildIndexEndpoint(projectName, changeId), event, event.eventCreatedOn); } @@ -143,10 +144,6 @@ event.eventCreatedOn); } - private String buildIndexEndpoint(int changeId) { - return buildIndexEndpoint("", changeId); - } - private String buildIndexEndpoint(String projectName, int changeId) { String escapedProjectName = Url.encode(projectName); return escapedProjectName + '~' + changeId;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderModule.java index 712e7f4..f1c58e6 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderModule.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderModule.java
@@ -17,6 +17,7 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder; import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder.Result; import com.ericsson.gerrit.plugins.highavailability.forwarder.InstantTypeAdapter; +import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.server.events.EventGson; import com.google.gson.Gson; import com.google.inject.AbstractModule; @@ -34,7 +35,7 @@ protected void configure() { bind(CloseableHttpClient.class).toProvider(HttpClientProvider.class).in(Scopes.SINGLETON); bind(HttpSession.class); - bind(Forwarder.class).to(RestForwarder.class); + DynamicItem.bind(binder(), Forwarder.class).to(RestForwarder.class); bind(new TypeLiteral<FailsafeExecutor<Result>>() {}) .annotatedWith(RestForwarderExecutor.class)
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java index e4de705..32d425d 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java
@@ -27,7 +27,6 @@ import com.google.inject.assistedinject.Assisted; import java.io.IOException; import java.time.Instant; -import java.util.Objects; import java.util.Optional; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; @@ -101,8 +100,8 @@ try (Repository repo = gitRepoMgr.openRepository(changeNotes.get().getProjectName())) { IndexEvent indexEvent = indexEventOption.get(); return computedChangeTs.get().compareTo(indexEvent.eventCreatedOn) >= 0 - && (Objects.isNull(indexEvent.targetSha) || repositoryHas(repo, indexEvent.targetSha)) - && (Objects.isNull(indexEvent.metaSha) || repositoryHas(repo, indexEvent.metaSha)); + && (indexEvent.targetSha == null || repositoryHas(repo, indexEvent.targetSha)) + && (indexEvent.metaSha == null || repositoryHas(repo, indexEvent.metaSha)); } } return true;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandler.java index 6475d99..d69bb42 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandler.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandler.java
@@ -23,6 +23,7 @@ import com.google.gerrit.extensions.events.ChangeIndexedListener; import com.google.gerrit.extensions.events.GroupIndexedListener; import com.google.gerrit.extensions.events.ProjectIndexedListener; +import com.google.gerrit.extensions.registration.DynamicItem; import com.google.inject.Inject; import java.util.Optional; @@ -32,13 +33,15 @@ GroupIndexedListener, ProjectIndexedListener { private static final FluentLogger log = FluentLogger.forEnclosingClass(); - private final Forwarder forwarder; + private final DynamicItem<Forwarder> forwarder; private final ChangeCheckerImpl.Factory changeChecker; private final CurrentRequestContext currCtx; @Inject IndexEventHandler( - Forwarder forwarder, ChangeCheckerImpl.Factory changeChecker, CurrentRequestContext currCtx) { + DynamicItem<Forwarder> forwarder, + ChangeCheckerImpl.Factory changeChecker, + CurrentRequestContext currCtx) { this.forwarder = forwarder; this.changeChecker = changeChecker; this.currCtx = currCtx; @@ -49,7 +52,7 @@ currCtx.onlyWithContext( (ctx) -> { if (!Context.isForwardedEvent()) { - forwarder.indexAccount(id, new IndexEvent()); + forwarder.get().indexAccount(id, new IndexEvent()); } }); } @@ -66,7 +69,7 @@ private void executeAllChangesDeletedForProject(String projectName) { if (!Context.isForwardedEvent()) { - forwarder.deleteAllChangesForProject(Project.nameKey(projectName)); + forwarder.get().deleteAllChangesForProject(Project.nameKey(projectName)); } } @@ -80,9 +83,9 @@ } if (Thread.currentThread().getName().contains("Batch")) { - forwarder.batchIndexChange(projectName, id, indexEvent.get()); + forwarder.get().batchIndexChange(projectName, id, indexEvent.get()); } else { - forwarder.indexChange(projectName, id, indexEvent.get()); + forwarder.get().indexChange(projectName, id, indexEvent.get()); } } catch (Exception e) { log.atWarning().withCause(e).log("Unable to create task to reindex change %s", changeId); @@ -91,23 +94,23 @@ } @Override - public void onChangeDeleted(int id) { + public void onChangeDeleted(String projectName, int id) { if (!Context.isForwardedEvent()) { - forwarder.deleteChangeFromIndex(id, new IndexEvent()); + forwarder.get().deleteChangeFromIndex(projectName, id, new IndexEvent()); } } @Override public void onProjectIndexed(String projectName) { if (!Context.isForwardedEvent()) { - forwarder.indexProject(projectName, new IndexEvent()); + forwarder.get().indexProject(projectName, new IndexEvent()); } } @Override public void onGroupIndexed(String groupUUID) { if (!Context.isForwardedEvent()) { - forwarder.indexGroup(groupUUID, new IndexEvent()); + forwarder.get().indexGroup(groupUUID, new IndexEvent()); } } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/indexsync/IndexSyncRunner.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/indexsync/IndexSyncRunner.java index 69bc2e4..c0e6451 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/indexsync/IndexSyncRunner.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/indexsync/IndexSyncRunner.java
@@ -203,7 +203,7 @@ Project.NameKey project = Project.nameKey(parts.get(0)); Change.Id changeId = Change.id(Integer.parseInt(parts.get(1))); log.atInfo().log("Change %s present in index but not in noteDb. Deleting from index", id); - indexer.deleteAsync(project, changeId); + var unused = indexer.deleteAsync(project, changeId); } } }
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md index b089091..1a3a498 100644 --- a/src/main/resources/Documentation/config.md +++ b/src/main/resources/Documentation/config.md
@@ -73,6 +73,18 @@ maxTries = 100 ``` +### Transport implementation provided by another plugin + +In this case another plugin extends the @PLUGIN@ plugin and provides messaging +implementation. +``` +[main] + transport = provided + sharedDirectory = /directory/accessible/from/both/instances +[autoReindex] + enabled = false +``` + ```main.sharedDirectory``` : Path to a directory accessible from both instances. When given as a relative path, then it is resolved against the $SITE_PATH @@ -82,9 +94,10 @@ is "shared". ```main.transport``` -: Message transport layer. Could be: `http` or `jgroups`. +: Message transport layer. Could be: `http`, `jgroups` or `provided`. When not specificed the default is `http`. - When set to `jgroups` then all `peerInfo.*` sections are unnecessary and ignored. + When set to `jgroups` or `provided` then all `peerInfo.*` sections are + unnecessary and ignored. ```autoReindex.enabled``` : Enable the tracking of the latest change indexed under data/high-availability @@ -281,6 +294,14 @@ Value is expressed in Gerrit time values as in [websession.cleanupInterval](#websessioncleanupInterval). When not specified, the default value is set to 10 seconds. +```http.reuseConnectionAfter503``` +: Whether to reuse the HTTP connection to the peer instance after receiving a + 503 (Service Unavailable) response over it. When set to `false`, the plugin + will close the connection immediately on a 503 response and open a fresh one + for the next retry, which can help recover from situations where a peer has + transiently become unavailable without properly closing existing connections. + When not specified, the default value is `true`. + ```http.threadPoolSize``` : Maximum number of threads used to execute REST calls towards target instances.
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionHandlerTest.java index 3d091a0..cd5a477 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionHandlerTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionHandlerTest.java
@@ -20,6 +20,7 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder; import com.google.common.cache.RemovalCause; import com.google.common.cache.RemovalNotification; +import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.server.config.PluginConfigFactory; import com.google.gerrit.server.config.SitePaths; import java.io.IOException; @@ -34,7 +35,7 @@ @RunWith(MockitoJUnitRunner.class) public class CacheEvictionHandlerTest { - @Mock private Forwarder forwarder; + @Mock private DynamicItem<Forwarder> forwarder; @Mock private PluginConfigFactory pluginConfigFactoryMock; private static final Path SITE_PATH = Paths.get("/site_path");
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java index 180c68f..f44be49 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java
@@ -48,6 +48,7 @@ @UseSsh @TestPlugin( name = "high-availability", + apiModule = "com.ericsson.gerrit.plugins.highavailability.ApiModule", sysModule = "com.ericsson.gerrit.plugins.highavailability.Module", httpModule = "com.ericsson.gerrit.plugins.highavailability.HttpModule") public class CacheEvictionIT extends LightweightPluginDaemonTest {
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java index 36c775c..6fa508e 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java
@@ -38,6 +38,7 @@ @TestPlugin( name = "high-availability", + apiModule = "com.ericsson.gerrit.plugins.highavailability.ApiModule", sysModule = "com.ericsson.gerrit.plugins.highavailability.Module", httpModule = "com.ericsson.gerrit.plugins.highavailability.HttpModule") public class ProjectListIT extends LightweightPluginDaemonTest {
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListUpdateHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListUpdateHandlerTest.java index 1bd2aed..e4fea74 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListUpdateHandlerTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListUpdateHandlerTest.java
@@ -23,6 +23,8 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder; import com.google.gerrit.extensions.events.NewProjectCreatedListener; import com.google.gerrit.extensions.events.ProjectDeletedListener; +import com.google.gerrit.extensions.registration.DynamicItem; +import com.google.inject.Inject; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,10 +36,12 @@ private ProjectListUpdateHandler handler; @Mock private Forwarder forwarder; + @Inject DynamicItem<Forwarder> forwarderItem; @Before public void setUp() { - handler = new ProjectListUpdateHandler(forwarder); + forwarderItem = DynamicItem.itemOf(Forwarder.class, forwarder); + handler = new ProjectListUpdateHandler(forwarderItem); } @Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandlerTest.java index 988064e..6c12b1d 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandlerTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandlerTest.java
@@ -20,8 +20,10 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.Context; import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder; +import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.server.events.Event; import com.google.gerrit.server.events.ProjectEvent; +import com.google.inject.Inject; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,10 +35,12 @@ private EventHandler eventHandler; @Mock private Forwarder forwarder; + @Inject DynamicItem<Forwarder> forwarderItem; @Before public void setUp() { - eventHandler = new EventHandler(forwarder); + forwarderItem = DynamicItem.itemOf(Forwarder.class, forwarder); + eventHandler = new EventHandler(forwarderItem); } @Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandlerTest.java index 446a1e9..2ad8fed 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandlerTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandlerTest.java
@@ -64,7 +64,6 @@ @Mock private ChangeIndexer indexerMock; @Mock private ChangeNotes changeNotes; - @Mock private Project.NameKey projectName; @Mock(answer = RETURNS_DEEP_STUBS) private Configuration configMock; @@ -76,10 +75,12 @@ @Mock private ForwardedIndexExecutorProvider indexExecutorProviderMock; private ForwardedIndexChangeHandler handler; private Change.Id id; + private Project.NameKey projectName; @Before public void setUp() throws Exception { id = Change.id(TEST_CHANGE_NUMBER); + projectName = Project.nameKey(TEST_PROJECT); when(configMock.index().threadPoolSize()).thenReturn(4); when(configMock.index().maxTries()).thenReturn(3); when(configMock.index().retryInterval()).thenReturn(Duration.ofMillis(10)); @@ -129,7 +130,7 @@ @Test public void changeIsDeletedFromIndex() throws Exception { handler.index(TEST_CHANGE_ID, Operation.DELETE, Optional.empty()).get(10, SECONDS); - verify(indexerMock, times(1)).delete(id); + verify(indexerMock, times(1)).delete(projectName, id); } @Test @@ -144,7 +145,7 @@ public void changeToIndexDoesNotExist() throws Exception { setupChangeAccessRelatedMocks(CHANGE_DOES_NOT_EXIST, CHANGE_OUTDATED); handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty()).get(10, SECONDS); - verify(indexerMock, times(0)).delete(id); + verify(indexerMock, times(0)).delete(projectName, id); } @Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/CommandDeserializerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandDeserializerTest.java similarity index 97% rename from src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/CommandDeserializerTest.java rename to src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandDeserializerTest.java index 63e6f46..8818905 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/CommandDeserializerTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandDeserializerTest.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.ericsson.gerrit.plugins.highavailability.forwarder.jgroups; +package com.ericsson.gerrit.plugins.highavailability.forwarder.commands; import static com.google.common.truth.Truth.assertThat; @@ -36,7 +36,7 @@ @Before public void setUp() { Gson eventGson = new EventGsonProvider().get(); - this.gson = new JGroupsForwarderModule().buildJGroupsGson(eventGson); + this.gson = new ForwarderCommandsModule().buildCommandsGson(eventGson); this.cacheKeyParser = new CacheKeyJsonParser(eventGson, DynamicMap.emptyMap()); }
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarderTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarderTest.java index e7542b4..1a926bf 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarderTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarderTest.java
@@ -27,6 +27,7 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwarderMetrics; import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwarderMetricsRegistry; import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.ForwarderCommandsModule; import com.google.gerrit.server.events.EventGsonProvider; import com.google.gerrit.server.git.WorkQueue; import com.google.gson.Gson; @@ -65,7 +66,7 @@ @Before public void setUp() throws Exception { Gson eventGson = new EventGsonProvider().get(); - Gson gson = new JGroupsForwarderModule().buildJGroupsGson(eventGson); + Gson gson = new ForwarderCommandsModule().buildCommandsGson(eventGson); Configuration cfg = mock(Configuration.class, RETURNS_DEEP_STUBS); when(cfg.jgroups().maxTries()).thenReturn(MAX_TRIES); when(cfg.jgroups().retryInterval()).thenReturn(Duration.ofMillis(1));
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/MessageProcessorTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/MessageProcessorTest.java index 91d291c..bca7801 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/MessageProcessorTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/MessageProcessorTest.java
@@ -33,6 +33,14 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedProjectListUpdateHandler; import com.ericsson.gerrit.plugins.highavailability.forwarder.ProcessorMetrics; import com.ericsson.gerrit.plugins.highavailability.forwarder.ProcessorMetricsRegistry; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.AddToProjectList; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.CommandProcessorImpl; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.EvictCache; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.ForwarderCommandsModule; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.IndexAccount; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.IndexChange; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.PostEvent; +import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.RemoveFromProjectList; import com.google.gerrit.entities.Account; import com.google.gerrit.entities.Change; import com.google.gerrit.server.events.Event; @@ -55,7 +63,7 @@ @RunWith(org.mockito.junit.MockitoJUnitRunner.class) public class MessageProcessorTest { - private MessageProcessor processor; + private JGroupsMessageProcessor processor; private Gson gson; private ForwardedIndexChangeHandler indexChangeHandler; @@ -74,7 +82,7 @@ public void setUp() { when(metricsRegistry.get(any())).thenReturn(processorMetrics); Gson eventGson = new EventGsonProvider().get(); - gson = new JGroupsForwarderModule().buildJGroupsGson(eventGson); + gson = new ForwarderCommandsModule().buildCommandsGson(eventGson); indexChangeHandler = createHandlerMock(ForwardedIndexChangeHandler.class); indexBatchChangeHandler = createHandlerMock(ForwardedIndexBatchChangeHandler.class); @@ -84,15 +92,16 @@ projectListUpdateHandler = createHandlerMock(ForwardedProjectListUpdateHandler.class); processor = - new MessageProcessor( + new JGroupsMessageProcessor( gson, - indexChangeHandler, - indexBatchChangeHandler, - indexAccountHandler, - cacheEvictionHandler, - eventHandler, - projectListUpdateHandler, - metricsRegistry); + new CommandProcessorImpl( + indexChangeHandler, + indexBatchChangeHandler, + indexAccountHandler, + cacheEvictionHandler, + eventHandler, + projectListUpdateHandler, + metricsRegistry)); } private <T> T createHandlerMock(Class<T> handlerClass) {
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ForwardedCacheEvictionHandlerIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ForwardedCacheEvictionHandlerIT.java index 1e5cc3d..4488cc4 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ForwardedCacheEvictionHandlerIT.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ForwardedCacheEvictionHandlerIT.java
@@ -40,6 +40,7 @@ @TestPlugin( name = "high-availability", + apiModule = "com.ericsson.gerrit.plugins.highavailability.ApiModule", sysModule = "com.ericsson.gerrit.plugins.highavailability.Module", httpModule = "com.ericsson.gerrit.plugins.highavailability.HttpModule") public class ForwardedCacheEvictionHandlerIT extends LightweightPluginDaemonTest {
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProviderConnectionReuseTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProviderConnectionReuseTest.java new file mode 100644 index 0000000..3bd3b14 --- /dev/null +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProviderConnectionReuseTest.java
@@ -0,0 +1,121 @@ +// Copyright (C) 2026 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.ericsson.gerrit.plugins.highavailability.forwarder.rest; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.ericsson.gerrit.plugins.highavailability.Configuration; +import com.github.tomakehurst.wiremock.junit.WireMockRule; +import java.time.Duration; +import java.util.List; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Answers; + +public class HttpClientProviderConnectionReuseTest { + + private static final String ENDPOINT = "/test"; + private static final Duration TIMEOUT = Duration.ofMillis(1000); + + @Rule public WireMockRule wireMock = new WireMockRule(0); + + private Configuration mockConfig(boolean reuseConnectionAfter503) { + Configuration cfg = mock(Configuration.class, Answers.RETURNS_DEEP_STUBS); + when(cfg.http().user()).thenReturn(""); + when(cfg.http().password()).thenReturn(""); + when(cfg.http().connectionTimeout()).thenReturn(TIMEOUT); + when(cfg.http().socketTimeout()).thenReturn(TIMEOUT); + when(cfg.http().reuseConnectionAfter503()).thenReturn(reuseConnectionAfter503); + return cfg; + } + + @Test + public void connectionIsReturnedToPoolAfter503WhenReuseIsEnabled() throws Exception { + wireMock.givenThat(get(urlEqualTo(ENDPOINT)).willReturn(aResponse().withStatus(503))); + + TestableHttpClientProvider provider = new TestableHttpClientProvider(mockConfig(true)); + try (CloseableHttpClient client = provider.get()) { + executeConsuming(client); + // Connection must be back in the pool (available == 1) because reuseConnectionAfter503=true + assertThat(provider.connectionManager().getTotalStats().getAvailable()).isEqualTo(1); + } + } + + @Test + public void connectionIsDiscardedAfter503WhenReuseIsDisabled() throws Exception { + wireMock.givenThat(get(urlEqualTo(ENDPOINT)).willReturn(aResponse().withStatus(503))); + + TestableHttpClientProvider provider = new TestableHttpClientProvider(mockConfig(false)); + try (CloseableHttpClient client = provider.get()) { + executeConsuming(client); + // Connection must have been discarded (available == 0) because reuseConnectionAfter503=false + assertThat(provider.connectionManager().getTotalStats().getAvailable()).isEqualTo(0); + } + } + + @Test + public void connectionIsReturnedToPoolAfter500RegardlessOfReuseOption() throws Exception { + wireMock.givenThat(get(urlEqualTo(ENDPOINT)).willReturn(aResponse().withStatus(500))); + + for (boolean reuseFlag : List.of(true, false)) { + TestableHttpClientProvider provider = new TestableHttpClientProvider(mockConfig(reuseFlag)); + try (CloseableHttpClient client = provider.get()) { + executeConsuming(client); + // 500 is not 503 — the reuseConnectionAfter503 option must have no effect + assertThat(provider.connectionManager().getTotalStats().getAvailable()).isEqualTo(1); + } + } + } + + private void executeConsuming(CloseableHttpClient client) throws Exception { + String url = "http://localhost:" + wireMock.port() + ENDPOINT; + try (CloseableHttpResponse response = client.execute(new HttpGet(url))) { + if (response.getEntity() != null) { + response.getEntity().getContent().close(); + } + } + } + + /** + * Extends HttpClientProvider to capture the PoolingHttpClientConnectionManager so tests can + * inspect pool statistics after requests complete. + */ + private static class TestableHttpClientProvider extends HttpClientProvider { + private PoolingHttpClientConnectionManager connManager; + + TestableHttpClientProvider(Configuration cfg) { + super(cfg); + } + + @Override + PoolingHttpClientConnectionManager buildConnectionManager() { + connManager = super.buildConnectionManager(); + return connManager; + } + + PoolingHttpClientConnectionManager connectionManager() { + return connManager; + } + } +}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ProjectListRestApiServletIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ProjectListRestApiServletIT.java index e838cb3..caea2aa 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ProjectListRestApiServletIT.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ProjectListRestApiServletIT.java
@@ -25,6 +25,7 @@ @TestPlugin( name = "high-availability", + apiModule = "com.ericsson.gerrit.plugins.highavailability.ApiModule", sysModule = "com.ericsson.gerrit.plugins.highavailability.Module", httpModule = "com.ericsson.gerrit.plugins.highavailability.HttpModule") public class ProjectListRestApiServletIT extends LightweightPluginDaemonTest {
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderServletModuleIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderServletModuleIT.java index 2406443..880ec04 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderServletModuleIT.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderServletModuleIT.java
@@ -25,6 +25,7 @@ @TestPlugin( name = "high-availability", + apiModule = "com.ericsson.gerrit.plugins.highavailability.ApiModule", sysModule = "com.ericsson.gerrit.plugins.highavailability.Module", httpModule = "com.ericsson.gerrit.plugins.highavailability.HttpModule") public class RestForwarderServletModuleIT extends LightweightPluginDaemonTest {
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderTest.java index 78d21ef..88318bc 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderTest.java
@@ -82,8 +82,6 @@ PLUGIN_NAME, "index/change/batch", PROJECT_NAME_URL_END + "~" + CHANGE_NUMBER); - private static final String DELETE_CHANGE_ENDPOINT = - Joiner.on("/").join(URL, PLUGINS, PLUGIN_NAME, "index/change", "~" + CHANGE_NUMBER); private static final String DELETE_ALL_CHANGES_ENDPOINT = Joiner.on("/") .join( @@ -283,11 +281,11 @@ @Test public void testChangeDeletedFromIndexOK() throws Exception { - when(httpSessionMock.delete(eq(DELETE_CHANGE_ENDPOINT), any())) + when(httpSessionMock.delete(eq(INDEX_CHANGE_ENDPOINT), any())) .thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG)); assertThat( forwarder - .deleteChangeFromIndex(CHANGE_NUMBER, new IndexEvent()) + .deleteChangeFromIndex(PROJECT_NAME, CHANGE_NUMBER, new IndexEvent()) .get(TEST_TIMEOUT, TEST_TIMEOUT_UNITS) .result()) .isTrue(); @@ -307,11 +305,11 @@ @Test public void testChangeDeletedFromIndexFailed() throws Exception { - when(httpSessionMock.delete(eq(DELETE_CHANGE_ENDPOINT), any())) + when(httpSessionMock.delete(eq(INDEX_CHANGE_ENDPOINT), any())) .thenReturn(new HttpResult(FAILED, EMPTY_MSG)); assertThat( forwarder - .deleteChangeFromIndex(CHANGE_NUMBER, new IndexEvent()) + .deleteChangeFromIndex(PROJECT_NAME, CHANGE_NUMBER, new IndexEvent()) .get(TEST_TIMEOUT, TEST_TIMEOUT_UNITS) .result()) .isFalse(); @@ -319,10 +317,10 @@ @Test public void testChangeDeletedFromThrowsException() throws Exception { - when(httpSessionMock.delete(eq(DELETE_CHANGE_ENDPOINT), any())).thenThrow(IOException.class); + when(httpSessionMock.delete(eq(INDEX_CHANGE_ENDPOINT), any())).thenThrow(IOException.class); assertThat( forwarder - .deleteChangeFromIndex(CHANGE_NUMBER, new IndexEvent()) + .deleteChangeFromIndex(PROJECT_NAME, CHANGE_NUMBER, new IndexEvent()) .get(TEST_TIMEOUT, TEST_TIMEOUT_UNITS) .result()) .isFalse();
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java index fe6cfce..3010d9c 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java
@@ -46,6 +46,7 @@ @NoHttpd @TestPlugin( name = "high-availability", + apiModule = "com.ericsson.gerrit.plugins.highavailability.ApiModule", sysModule = "com.ericsson.gerrit.plugins.highavailability.Module", httpModule = "com.ericsson.gerrit.plugins.highavailability.HttpModule") public abstract class AbstractIndexForwardingIT extends LightweightPluginDaemonTest {
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerIT.java index febf8f0..ebf966f 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerIT.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerIT.java
@@ -20,6 +20,7 @@ import com.google.gerrit.acceptance.LightweightPluginDaemonTest; import com.google.gerrit.acceptance.PushOneCommit.Result; import com.google.gerrit.acceptance.TestPlugin; +import com.google.gerrit.acceptance.UseLocalDisk; import com.google.gerrit.entities.RefNames; import java.io.IOException; import java.util.Optional; @@ -29,6 +30,7 @@ @TestPlugin( name = "high-availability", + apiModule = "com.ericsson.gerrit.plugins.highavailability.ApiModule", sysModule = "com.ericsson.gerrit.plugins.highavailability.Module", httpModule = "com.ericsson.gerrit.plugins.highavailability.HttpModule") public class ChangeCheckerIT extends LightweightPluginDaemonTest { @@ -42,6 +44,7 @@ } @Test + @UseLocalDisk public void shouldPopulateMetaSha() throws Exception { Result change = createChange(); ChangeChecker changeChecker = changeCheckerFactory.create(change.getChangeId()); @@ -54,6 +57,7 @@ } @Test + @UseLocalDisk public void shouldReturnIsUpToDateTrueWhenEventContainsCorrectMetaAndTargetSha() throws Exception { Result change = createChange(); @@ -64,6 +68,7 @@ } @Test + @UseLocalDisk public void shouldReturnIsUpToDateTrueWhenTargetShaIsNull() throws Exception { Result change = createChange(); ChangeChecker changeChecker = changeCheckerFactory.create(change.getChangeId()); @@ -80,6 +85,7 @@ } @Test + @UseLocalDisk public void shouldReturnFalseWhenMetaShaIsNotUpToDate() throws Exception { String testMetaRefSha = "6212efebe6e8b9f439a8ad013243e602afab7441"; Result change = createChange(); @@ -97,6 +103,7 @@ } @Test + @UseLocalDisk public void shouldReturnFalseWhenTargetShaIsNotUpToDate() throws Exception { String testTargetRefSha = "abed47baf2818a86b68cf712073a748a6b5b293e"; Result change = createChange();
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandlerTest.java index a986b90..95e627b 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandlerTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandlerTest.java
@@ -31,9 +31,11 @@ import com.google.gerrit.entities.Account; import com.google.gerrit.entities.AccountGroup; import com.google.gerrit.entities.Change; +import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.server.util.OneOffRequestContext; import com.google.gerrit.server.util.RequestContext; import com.google.gerrit.server.util.ThreadLocalRequestContext; +import com.google.inject.Inject; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -52,6 +54,7 @@ private IndexEventHandler indexEventHandler; @Mock private Forwarder forwarder; + @Inject private DynamicItem<Forwarder> forwarderItem; @Mock private ChangeCheckerImpl.Factory changeCheckerFactoryMock; @Mock private ChangeChecker changeCheckerMock; private Change.Id changeId; @@ -79,7 +82,7 @@ when(forwarder.indexAccount(eq(ACCOUNT_ID), any())) .thenReturn( CompletableFuture.completedFuture(new Result(EventType.INDEX_ACCOUNT_UPDATE, true))); - when(forwarder.deleteChangeFromIndex(eq(CHANGE_ID), any())) + when(forwarder.deleteChangeFromIndex(eq(PROJECT_NAME), eq(CHANGE_ID), any())) .thenReturn( CompletableFuture.completedFuture(new Result(EventType.INDEX_CHANGE_DELETION, true))); when(forwarder.indexGroup(eq(UUID), any())) @@ -89,11 +92,12 @@ .thenReturn( CompletableFuture.completedFuture(new Result(EventType.INDEX_CHANGE_UPDATE, true))); + forwarderItem = DynamicItem.itemOf(Forwarder.class, forwarder); setUpIndexEventHandler(currCtx); } public void setUpIndexEventHandler(CurrentRequestContext currCtx) throws Exception { - indexEventHandler = new IndexEventHandler(forwarder, changeCheckerFactoryMock, currCtx); + indexEventHandler = new IndexEventHandler(forwarderItem, changeCheckerFactoryMock, currCtx); } @Test @@ -137,8 +141,8 @@ @Test public void shouldDeleteFromIndexInRemoteOnChangeDeletedEvent() throws Exception { - indexEventHandler.onChangeDeleted(changeId.get()); - verify(forwarder).deleteChangeFromIndex(eq(CHANGE_ID), any()); + indexEventHandler.onChangeDeleted(PROJECT_NAME, changeId.get()); + verify(forwarder).deleteChangeFromIndex(eq(PROJECT_NAME), eq(CHANGE_ID), any()); verifyNoInteractions(changeCheckerMock); // Deleted changes should not be checked against NoteDb } @@ -152,7 +156,7 @@ public void shouldNotCallRemoteWhenChangeEventIsForwarded() throws Exception { Context.setForwardedEvent(true); indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get()); - indexEventHandler.onChangeDeleted(changeId.get()); + indexEventHandler.onChangeDeleted(PROJECT_NAME, changeId.get()); Context.unsetForwardedEvent(); verifyNoInteractions(forwarder); }
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsKubernetesPeerInfoProviderTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsKubernetesPeerInfoProviderTest.java index 0c53959..b1cd172 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsKubernetesPeerInfoProviderTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsKubernetesPeerInfoProviderTest.java
@@ -29,14 +29,19 @@ import static org.mockito.Mockito.when; import com.ericsson.gerrit.plugins.highavailability.Configuration; +import com.github.rholder.retry.RetryerBuilder; +import com.github.rholder.retry.StopStrategies; +import com.github.rholder.retry.WaitStrategies; import com.github.tomakehurst.wiremock.junit.WireMockRule; +import com.google.common.base.Predicates; import com.google.common.io.Resources; import com.google.gerrit.extensions.restapi.Url; import java.net.Inet4Address; -import java.net.NetworkInterface; import java.util.List; import java.util.Optional; +import java.util.concurrent.TimeUnit; import org.apache.http.HttpStatus; +import org.jgroups.JChannel; import org.jgroups.Message; import org.junit.After; import org.junit.Before; @@ -57,24 +62,33 @@ @Mock private InetAddressFinder finder; private JGroupsPeerInfoProvider firstJGroupsPeerInfoProvider; private JGroupsPeerInfoProvider secondJGroupsPeerInfoProvider; + private JChannel firstChannel; + private JChannel secondChannel; @Mock private MyUrlProvider myUrlProvider; @Rule public WireMockRule kubeApiMock = new WireMockRule(options().port(48443)); @Before public void setUp() throws Exception { - System.setProperty("KUBERNETES_MASTER_PROTOCOL", "http"); - System.setProperty("KUBERNETES_SERVICE_HOST", "localhost"); - System.setProperty("KUBERNETES_SERVICE_PORT", "48443"); System.setProperty("java.net.preferIPv4Stack", "true"); } @After - public void shutdown() { - System.clearProperty("KUBERNETES_MASTER_PROTOCOL"); - System.clearProperty("KUBERNETES_SERVICE_HOST"); - System.clearProperty("KUBERNETES_SERVICE_PORT"); + public void shutdown() throws Exception { System.clearProperty("java.net.preferIPv4Stack"); + + if (firstJGroupsPeerInfoProvider != null) { + firstJGroupsPeerInfoProvider.stop(); + } + if (secondJGroupsPeerInfoProvider != null) { + secondJGroupsPeerInfoProvider.stop(); + } + if (firstChannel != null && firstChannel.isConnected()) { + firstChannel.close(); + } + if (secondChannel != null && secondChannel.isConnected()) { + secondChannel.close(); + } } @Test @@ -89,21 +103,20 @@ when(myUrlProvider.get()).thenReturn("http://127.0.0.1:7800"); - NetworkInterface eth0 = NetworkInterface.getByName("eth0"); - if (eth0 != null) { - when(finder.findAddress()).thenReturn(eth0.inetAddresses().findFirst()); - } else { - when(finder.findAddress()).thenReturn(Optional.of(Inet4Address.getByName("127.0.0.1"))); - } - JChannelProvider channelProvider = new JChannelProvider(pluginConfigurationMock); + when(finder.findAddress()).thenReturn(Optional.of(Inet4Address.getByName("127.0.0.1"))); + + // Create two separate channels with different ports + firstChannel = new JChannel(getClass().getResource("test_kubernetes.xml").toString()); + secondChannel = new JChannel(getClass().getResource("test_kubernetes.xml").toString()); + firstJGroupsPeerInfoProvider = Mockito.spy( new JGroupsPeerInfoProvider( - pluginConfigurationMock, finder, myUrlProvider, channelProvider.get())); + pluginConfigurationMock, finder, myUrlProvider, firstChannel)); secondJGroupsPeerInfoProvider = Mockito.spy( new JGroupsPeerInfoProvider( - pluginConfigurationMock, finder, myUrlProvider, channelProvider.get())); + pluginConfigurationMock, finder, myUrlProvider, secondChannel)); StringBuilder kubeApiUrlBuilder = new StringBuilder(); kubeApiUrlBuilder.append("/api/v1/namespaces/"); @@ -121,11 +134,21 @@ aResponse() .withJsonBody(new ObjectMapper().readTree(respJson)) .withStatus(HttpStatus.SC_OK))); + firstJGroupsPeerInfoProvider.connect(); verify(getRequestedFor(urlEqualTo(kubeApiUrl))); + + RetryerBuilder.<Boolean>newBuilder() + .retryIfResult(Predicates.equalTo(false)) + .withStopStrategy(StopStrategies.stopAfterDelay(10, TimeUnit.SECONDS)) + .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS)) + .build() + .call(() -> firstChannel.isConnected()); + secondJGroupsPeerInfoProvider.connect(); - verify(firstJGroupsPeerInfoProvider, timeout(10000)).receive(any(Message.class)); + verify(firstJGroupsPeerInfoProvider, timeout(10000).atLeastOnce()).receive(any(Message.class)); + verify(secondJGroupsPeerInfoProvider, timeout(10000).atLeastOnce()).receive(any(Message.class)); assertThat(firstJGroupsPeerInfoProvider.get()).isNotEmpty(); assertThat(firstJGroupsPeerInfoProvider.get()).hasSize(1);
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProviderTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProviderTest.java index a098be6..1e64918 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProviderTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProviderTest.java
@@ -169,7 +169,7 @@ public void testStop() throws Exception { jGroupsPeerInfoProvider.addPeer(peerAddress, peerInfo); jGroupsPeerInfoProvider.stop(); - assertThat(jGroupsPeerInfoProvider.getPeers().isEmpty()); + assertThat(jGroupsPeerInfoProvider.getPeers()).isEmpty(); Set<PeerInfo> testPeerInfoSet = jGroupsPeerInfoProvider.get(); assertThat(testPeerInfoSet).isEmpty(); }
diff --git a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/pod-list.json b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/pod-list.json index 4be7c10..e7efdd1 100644 --- a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/pod-list.json +++ b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/pod-list.json
@@ -17,7 +17,14 @@ "containers": [ { "image": "gerrit:test", - "name": "gerrit" + "name": "gerrit", + "ports": [ + { + "containerPort": 7800, + "name": "jgroups", + "protocol": "TCP" + } + ] } ], "hostname": "gerrit-primary-0" @@ -67,7 +74,14 @@ "containers": [ { "image": "gerrit:test", - "name": "gerrit" + "name": "gerrit", + "ports": [ + { + "containerPort": 7801, + "name": "jgroups", + "protocol": "TCP" + } + ] } ], "hostname": "gerrit-primary-1"
diff --git a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/test_kubernetes.xml b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/test_kubernetes.xml new file mode 100644 index 0000000..ff1bebf --- /dev/null +++ b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/test_kubernetes.xml
@@ -0,0 +1,53 @@ +<!-- + Based on a configuration written by Bela Ban [1]. + + [1] https://koudingspawn.de/jgroups-on-kubernetes/ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="urn:org:jgroups" + xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/jgroups.xsd" +> + <TCP bind_addr="127.0.0.1" + bind_port="7800" + port_range="2" + external_addr="127.0.0.1" + thread_pool.min_threads="0" + thread_pool.max_threads="200" + thread_pool.keep_alive_time="30000" /> + <RED /> + + <org.jgroups.protocols.kubernetes.KUBE_PING + port_range="2" + namespace="gerrit" + labels="app=gerrit,mode=primary" + masterProtocol="http" + masterHost="localhost" + masterPort="48443" + /> + + <MERGE3 max_interval="30000" + min_interval="10000" /> + <FD_SOCK external_addr="${JGROUPS_EXTERNAL_ADDR}" + start_port="${FD_SOCK_PORT:9000}" /> + <FD_ALL timeout="30000" interval="5000" /> + <VERIFY_SUSPECT timeout="1500" /> + <BARRIER /> + <pbcast.NAKACK2 xmit_interval="500" + xmit_table_num_rows="100" + xmit_table_msgs_per_row="2000" + xmit_table_max_compaction_time="30000" + use_mcast_xmit="false" + discard_delivered_msgs="true" /> + <UNICAST3 + xmit_table_num_rows="100" + xmit_table_msgs_per_row="1000" + xmit_table_max_compaction_time="30000" /> + <pbcast.STABLE desired_avg_gossip="50000" max_bytes="8m" /> + <pbcast.GMS print_local_addr="true" print_physical_addrs="true" join_timeout="3000" /> + <MFC max_credits="2M" + min_threshold="0.4" /> + <FRAG2 frag_size="60K" /> + <pbcast.STATE_TRANSFER /> + <CENTRAL_LOCK /> + <COUNTER /> +</config>