diff options
193 files changed, 3792 insertions, 4792 deletions
diff --git a/client/js/app/yarn.lock b/client/js/app/yarn.lock index d6f0e6d1a1e..aa0d5f40b8d 100644 --- a/client/js/app/yarn.lock +++ b/client/js/app/yarn.lock @@ -1315,75 +1315,75 @@ dependencies: "@babel/runtime" "^7.13.10" -"@remix-run/router@1.15.2": - version "1.15.2" - resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.15.2.tgz#35726510d332ba5349c6398d13259d5da184553d" - integrity sha512-+Rnav+CaoTE5QJc4Jcwh5toUpnVLKYbpU6Ys0zqbakqbaLQHeglLVHPfxOiQqdNmUy5C2lXz5dwC6tQNX2JW2Q== - -"@rollup/rollup-android-arm-eabi@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz#38c3abd1955a3c21d492af6b1a1dca4bb1d894d6" - integrity sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w== - -"@rollup/rollup-android-arm64@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.0.tgz#3822e929f415627609e53b11cec9a4be806de0e2" - integrity sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ== - -"@rollup/rollup-darwin-arm64@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz#6c082de71f481f57df6cfa3701ab2a7afde96f69" - integrity sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ== - -"@rollup/rollup-darwin-x64@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.0.tgz#c34ca0d31f3c46a22c9afa0e944403eea0edcfd8" - integrity sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg== - -"@rollup/rollup-linux-arm-gnueabihf@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.0.tgz#48e899c1e438629c072889b824a98787a7c2362d" - integrity sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA== - -"@rollup/rollup-linux-arm64-gnu@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.0.tgz#788c2698a119dc229062d40da6ada8a090a73a68" - integrity sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA== - -"@rollup/rollup-linux-arm64-musl@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.0.tgz#3882a4e3a564af9e55804beeb67076857b035ab7" - integrity sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ== - -"@rollup/rollup-linux-riscv64-gnu@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.0.tgz#0c6ad792e1195c12bfae634425a3d2aa0fe93ab7" - integrity sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw== - -"@rollup/rollup-linux-x64-gnu@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz#9d62485ea0f18d8674033b57aa14fb758f6ec6e3" - integrity sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA== - -"@rollup/rollup-linux-x64-musl@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.0.tgz#50e8167e28b33c977c1f813def2b2074d1435e05" - integrity sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw== - -"@rollup/rollup-win32-arm64-msvc@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.0.tgz#68d233272a2004429124494121a42c4aebdc5b8e" - integrity sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw== - -"@rollup/rollup-win32-ia32-msvc@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.0.tgz#366ca62221d1689e3b55a03f4ae12ae9ba595d40" - integrity sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA== - -"@rollup/rollup-win32-x64-msvc@4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz#9ffdf9ed133a7464f4ae187eb9e1294413fab235" - integrity sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg== +"@remix-run/router@1.15.3": + version "1.15.3" + resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.15.3.tgz#d2509048d69dbb72d5389a14945339f1430b2d3c" + integrity sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w== + +"@rollup/rollup-android-arm-eabi@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz#b98786c1304b4ff8db3a873180b778649b5dff2b" + integrity sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg== + +"@rollup/rollup-android-arm64@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz#8833679af11172b1bf1ab7cb3bad84df4caf0c9e" + integrity sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q== + +"@rollup/rollup-darwin-arm64@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz#ef02d73e0a95d406e0eb4fd61a53d5d17775659b" + integrity sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g== + +"@rollup/rollup-darwin-x64@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz#3ce5b9bcf92b3341a5c1c58a3e6bcce0ea9e7455" + integrity sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg== + +"@rollup/rollup-linux-arm-gnueabihf@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz#3d3d2c018bdd8e037c6bfedd52acfff1c97e4be4" + integrity sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ== + +"@rollup/rollup-linux-arm64-gnu@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz#5fc8cc978ff396eaa136d7bfe05b5b9138064143" + integrity sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w== + +"@rollup/rollup-linux-arm64-musl@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz#f2ae7d7bed416ffa26d6b948ac5772b520700eef" + integrity sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw== + +"@rollup/rollup-linux-riscv64-gnu@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz#303d57a328ee9a50c85385936f31cf62306d30b6" + integrity sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA== + +"@rollup/rollup-linux-x64-gnu@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz#f672f6508f090fc73f08ba40ff76c20b57424778" + integrity sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA== + +"@rollup/rollup-linux-x64-musl@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz#d2f34b1b157f3e7f13925bca3288192a66755a89" + integrity sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw== + +"@rollup/rollup-win32-arm64-msvc@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz#8ffecc980ae4d9899eb2f9c4ae471a8d58d2da6b" + integrity sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA== + +"@rollup/rollup-win32-ia32-msvc@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz#a7505884f415662e088365b9218b2b03a88fc6f2" + integrity sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw== + +"@rollup/rollup-win32-x64-msvc@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz#6abd79db7ff8d01a58865ba20a63cfd23d9e2a10" + integrity sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw== "@sinclair/typebox@^0.27.8": version "0.27.8" @@ -4645,19 +4645,19 @@ react-refresh@^0.14.0: integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== react-router-dom@^6: - version "6.22.2" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.22.2.tgz#8233968a8a576f3006e5549c80f3527d2598fc9c" - integrity sha512-WgqxD2qySEIBPZ3w0sHH+PUAiamDeszls9tzqMPBDA1YYVucTBXLU7+gtRfcSnhe92A3glPnvSxK2dhNoAVOIQ== + version "6.22.3" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.22.3.tgz#9781415667fd1361a475146c5826d9f16752a691" + integrity sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw== dependencies: - "@remix-run/router" "1.15.2" - react-router "6.22.2" + "@remix-run/router" "1.15.3" + react-router "6.22.3" -react-router@6.22.2: - version "6.22.2" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.22.2.tgz#27e77e4c635a5697693b922d131d773451c98a5b" - integrity sha512-YD3Dzprzpcq+tBMHBS822tCjnWD3iIZbTeSXMY9LPSG541EfoBGyZ3bS25KEnaZjLcmQpw2AVLkFyfgXY8uvcw== +react-router@6.22.3: + version "6.22.3" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.22.3.tgz#9d9142f35e08be08c736a2082db5f0c9540a885e" + integrity sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ== dependencies: - "@remix-run/router" "1.15.2" + "@remix-run/router" "1.15.3" react-textarea-autosize@8.3.4: version "8.3.4" @@ -4813,25 +4813,25 @@ rimraf@^3.0.2: glob "^7.1.3" rollup@^4.2.0: - version "4.12.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.12.0.tgz#0b6d1e5f3d46bbcf244deec41a7421dc54cc45b5" - integrity sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q== + version "4.13.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.13.0.tgz#dd2ae144b4cdc2ea25420477f68d4937a721237a" + integrity sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg== dependencies: "@types/estree" "1.0.5" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.12.0" - "@rollup/rollup-android-arm64" "4.12.0" - "@rollup/rollup-darwin-arm64" "4.12.0" - "@rollup/rollup-darwin-x64" "4.12.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.12.0" - "@rollup/rollup-linux-arm64-gnu" "4.12.0" - "@rollup/rollup-linux-arm64-musl" "4.12.0" - "@rollup/rollup-linux-riscv64-gnu" "4.12.0" - "@rollup/rollup-linux-x64-gnu" "4.12.0" - "@rollup/rollup-linux-x64-musl" "4.12.0" - "@rollup/rollup-win32-arm64-msvc" "4.12.0" - "@rollup/rollup-win32-ia32-msvc" "4.12.0" - "@rollup/rollup-win32-x64-msvc" "4.12.0" + "@rollup/rollup-android-arm-eabi" "4.13.0" + "@rollup/rollup-android-arm64" "4.13.0" + "@rollup/rollup-darwin-arm64" "4.13.0" + "@rollup/rollup-darwin-x64" "4.13.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.13.0" + "@rollup/rollup-linux-arm64-gnu" "4.13.0" + "@rollup/rollup-linux-arm64-musl" "4.13.0" + "@rollup/rollup-linux-riscv64-gnu" "4.13.0" + "@rollup/rollup-linux-x64-gnu" "4.13.0" + "@rollup/rollup-linux-x64-musl" "4.13.0" + "@rollup/rollup-win32-arm64-msvc" "4.13.0" + "@rollup/rollup-win32-ia32-msvc" "4.13.0" + "@rollup/rollup-win32-x64-msvc" "4.13.0" fsevents "~2.3.2" rsvp@^4.8.4: @@ -5421,9 +5421,9 @@ use-composed-ref@^1.3.0: integrity sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ== use-context-selector@^1: - version "1.4.3" - resolved "https://registry.yarnpkg.com/use-context-selector/-/use-context-selector-1.4.3.tgz#cb13afa834331d689d6b045917d8b7dfdd7d8047" - integrity sha512-rFo2z14XipT7XvXfw0lB/GCbxaKp9LCJoW96VWbZTlzoe4/E1dlqufv8xDvXRMPh3aIjFtNlwoaofuKX1UwUNw== + version "1.4.4" + resolved "https://registry.yarnpkg.com/use-context-selector/-/use-context-selector-1.4.4.tgz#f5d65c7fcd78f994cb33cacd57651007a40595c0" + integrity sha512-pS790zwGxxe59GoBha3QYOwk8AFGp4DN6DOtH+eoqVmgBBRXVx4IlPDhJmmMiNQAgUaLlP+58aqRC3A4rdaSjg== use-isomorphic-layout-effect@^1.1.1: version "1.1.2" @@ -5452,9 +5452,9 @@ v8-to-istanbul@^9.0.1: convert-source-map "^1.6.0" vite@^5.0.5: - version "5.1.5" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.1.5.tgz#bdbc2b15e8000d9cc5172f059201178f9c9de5fb" - integrity sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q== + version "5.1.6" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.1.6.tgz#706dae5fab9e97f57578469eef1405fc483943e4" + integrity sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA== dependencies: esbuild "^0.19.3" postcss "^8.4.35" diff --git a/config-model/src/main/java/com/yahoo/schema/derived/AttributeFields.java b/config-model/src/main/java/com/yahoo/schema/derived/AttributeFields.java index e747235dc3c..92f7e87209a 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/AttributeFields.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/AttributeFields.java @@ -12,6 +12,7 @@ import com.yahoo.schema.document.Sorting; import com.yahoo.vespa.config.search.AttributesConfig; import com.yahoo.vespa.indexinglanguage.expressions.ToPositionExpression; +import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.Iterator; @@ -27,7 +28,7 @@ import static com.yahoo.schema.document.ComplexAttributeFieldUtils.isSupportedCo * * @author bratseth */ -public class AttributeFields extends Derived implements AttributesConfig.Producer { +public class AttributeFields extends Derived { public enum FieldSet {ALL, FAST_ACCESS} @@ -178,12 +179,16 @@ public class AttributeFields extends Derived implements AttributesConfig.Produce return "attributes"; } - @Override public void getConfig(AttributesConfig.Builder builder) { - //TODO This is just to get some exporting tests to work, Should be undone and removed getConfig(builder, FieldSet.ALL, 77777); } + public void export(String toDirectory) throws IOException { + var builder = new AttributesConfig.Builder(); + getConfig(builder); + export(toDirectory, builder.build()); + } + private boolean isAttributeInFieldSet(Attribute attribute, FieldSet fs) { return (fs == FieldSet.ALL) || ((fs == FieldSet.FAST_ACCESS) && attribute.isFastAccess()); } diff --git a/config-model/src/main/java/com/yahoo/schema/derived/Derived.java b/config-model/src/main/java/com/yahoo/schema/derived/Derived.java index 3ed9807b8f1..f4311912584 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/Derived.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/Derived.java @@ -2,7 +2,6 @@ package com.yahoo.schema.derived; import com.yahoo.config.ConfigInstance; -import com.yahoo.config.ConfigInstance.Builder; import com.yahoo.document.Field; import com.yahoo.io.IOUtils; import com.yahoo.schema.Index; @@ -14,7 +13,6 @@ import com.yahoo.text.StringUtilities; import java.io.IOException; import java.io.Writer; -import java.lang.reflect.Method; import java.util.List; /** @@ -22,7 +20,7 @@ import java.util.List; * * @author bratseth */ -public abstract class Derived implements Exportable { +public abstract class Derived { private String name; @@ -88,23 +86,13 @@ public abstract class Derived implements Exportable { return labels ? getName() : String.valueOf(number); } - /** - * Exports this derived configuration to its .cfg file - * in toDirectory - * - * @param toDirectory the directory to export to, or null - * - */ - public void export(String toDirectory) throws IOException { + protected void export(String toDirectory, ConfigInstance cfg) throws IOException { Writer writer = null; try { String fileName = getDerivedName() + ".cfg"; - if (toDirectory != null) - writer = IOUtils.createWriter(toDirectory + "/" + fileName,false); - try { - exportBuilderConfig(writer); - } catch (ReflectiveOperationException | SecurityException | IllegalArgumentException e) { - throw new RuntimeException(e); + if (toDirectory != null) { + writer = IOUtils.createWriter(toDirectory + "/" + fileName, false); + exportConfig(writer, cfg); } } finally { @@ -112,30 +100,10 @@ public abstract class Derived implements Exportable { } } - /** - * Checks what this is a producer of, instantiate that and export to writer - */ - // TODO move to ReflectionUtil, and move that to unexported pkg - private void exportBuilderConfig(Writer writer) throws ReflectiveOperationException, SecurityException, IllegalArgumentException, IOException { - for (Class<?> intf : getClass().getInterfaces()) { - if (ConfigInstance.Producer.class.isAssignableFrom(intf)) { - Class<?> configClass = intf.getEnclosingClass(); - String builderClassName = configClass.getCanonicalName()+"$Builder"; - Class<?> builderClass = Class.forName(builderClassName); - ConfigInstance.Builder builder = (Builder) builderClass.getDeclaredConstructor().newInstance(); - Method getConfig = getClass().getMethod("getConfig", builderClass); - getConfig.invoke(this, builder); - ConfigInstance inst = (ConfigInstance) configClass.getConstructor(builderClass).newInstance(builder); - List<String> payloadL = ConfigInstance.serialize(inst); - String payload = StringUtilities.implodeMultiline(payloadL); - writer.write(payload); - } - } - } - - @Override - public String getFileName() { - return getDerivedName() + ".cfg"; + private void exportConfig(Writer writer, ConfigInstance cfg) throws IOException { + List<String> payloadL = ConfigInstance.serialize(cfg); + String payload = StringUtilities.implodeMultiline(payloadL); + writer.write(payload); } } diff --git a/config-model/src/main/java/com/yahoo/schema/derived/DerivedConfiguration.java b/config-model/src/main/java/com/yahoo/schema/derived/DerivedConfiguration.java index bc1c097ea4b..b35918b3460 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/DerivedConfiguration.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/DerivedConfiguration.java @@ -12,6 +12,7 @@ import com.yahoo.schema.RankProfileRegistry; import com.yahoo.schema.Schema; import com.yahoo.schema.derived.validation.Validation; import com.yahoo.vespa.config.search.AttributesConfig; +import com.yahoo.vespa.config.search.core.OnnxModelsConfig; import com.yahoo.vespa.config.search.core.RankingConstantsConfig; import com.yahoo.vespa.model.container.search.QueryProfiles; @@ -27,6 +28,7 @@ import java.io.Writer; public class DerivedConfiguration { private final Schema schema; + private final boolean isStreaming; private Summaries summaries; private Juniperrc juniperrc; private AttributeFields attributeFields; @@ -66,6 +68,7 @@ public class DerivedConfiguration { * schema is later modified. */ public DerivedConfiguration(Schema schema, DeployState deployState, boolean isStreaming) { + this.isStreaming = isStreaming; try { Validator.ensureNotNull("Schema", schema); this.schema = schema; @@ -126,10 +129,15 @@ public class DerivedConfiguration { } public void exportConstants(String toDirectory) throws IOException { - RankingConstantsConfig.Builder b = new RankingConstantsConfig.Builder(); - rankProfileList.getConfig(b); + var b = new RankingConstantsConfig.Builder() + .constant(rankProfileList.getConstantsConfig()); exportCfg(b.build(), toDirectory + "/" + "ranking-constants.cfg"); } + public void exportOnnxModels(String toDirectory) throws IOException { + var b = new OnnxModelsConfig.Builder() + .model(rankProfileList.getOnnxConfig()); + exportCfg(b.build(), toDirectory + "/" + "onnx-models.cfg"); + } private static void exportCfg(ConfigInstance instance, String fileName) throws IOException { Writer writer = null; @@ -144,6 +152,10 @@ public class DerivedConfiguration { } } + public boolean isStreaming() { + return isStreaming; + } + public Summaries getSummaries() { return summaries; } diff --git a/config-model/src/main/java/com/yahoo/schema/derived/Exportable.java b/config-model/src/main/java/com/yahoo/schema/derived/Exportable.java deleted file mode 100644 index 983be8bf13a..00000000000 --- a/config-model/src/main/java/com/yahoo/schema/derived/Exportable.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.schema.derived; - -/** - * Classes exportable to configurations - * - * @author bratseth - */ -public interface Exportable { - - /** - * Exports the configuration of this object - * - * - * @param toDirectory the directory to export to, does not write to disk if null - * @throws java.io.IOException if exporting fails, some files may still be created - */ - public void export(String toDirectory) throws java.io.IOException; - - /** - * The (short) name of the exported file - * @return a String with the (short) name of the exported file - */ - public String getFileName(); - -} diff --git a/config-model/src/main/java/com/yahoo/schema/derived/FileDistributedConstants.java b/config-model/src/main/java/com/yahoo/schema/derived/FileDistributedConstants.java index 91ab1ad9172..275fbe82ad4 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/FileDistributedConstants.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/FileDistributedConstants.java @@ -10,6 +10,7 @@ import com.yahoo.vespa.config.search.core.RankingConstantsConfig; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; /** @@ -25,7 +26,7 @@ public class FileDistributedConstants { public FileDistributedConstants(FileRegistry fileRegistry, Collection<RankProfile.Constant> constants) { Map<String, DistributableConstant> distributableConstants = new LinkedHashMap<>(); for (var constant : constants) { - if ( ! constant.valuePath().isPresent()) continue; + if (constant.valuePath().isEmpty()) continue; var distributableConstant = new DistributableConstant(constant.name().simpleArgument().get(), constant.type(), @@ -41,23 +42,21 @@ public class FileDistributedConstants { /** Returns a read-only map of the constants in this indexed by name. */ public Map<String, DistributableConstant> asMap() { return constants; } - public void getConfig(RankingConstantsConfig.Builder builder) { - for (var constant : constants.values()) { - builder.constant(new RankingConstantsConfig.Constant.Builder() - .name(constant.getName()) - .fileref(constant.getFileReference()) - .type(constant.getType())); - } + private static RankingConstantsConfig.Constant.Builder toConfig(DistributableConstant constant) { + return new RankingConstantsConfig.Constant.Builder() + .name(constant.getName()) + .fileref(constant.getFileReference()) + .type(constant.getType()); + } + + public List<RankingConstantsConfig.Constant.Builder> getConfig() { + return constants.values().stream().map(FileDistributedConstants::toConfig).toList(); } public static class DistributableConstant extends DistributableResource { private final TensorType tensorType; - public DistributableConstant(String name, TensorType type, String fileName) { - this(name, type, fileName, PathType.FILE); - } - public DistributableConstant(String name, TensorType type, String fileName, PathType pathType) { super(name, fileName, pathType); this.tensorType = type; diff --git a/config-model/src/main/java/com/yahoo/schema/derived/FileDistributedOnnxModels.java b/config-model/src/main/java/com/yahoo/schema/derived/FileDistributedOnnxModels.java index 1cc33cc4180..6e50e3c094c 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/FileDistributedOnnxModels.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/FileDistributedOnnxModels.java @@ -5,9 +5,11 @@ import com.yahoo.config.application.api.FileRegistry; import com.yahoo.schema.OnnxModel; import com.yahoo.vespa.config.search.core.OnnxModelsConfig; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.logging.Logger; @@ -16,13 +18,10 @@ import java.util.logging.Logger; * * @author bratseth */ -public class FileDistributedOnnxModels extends Derived implements OnnxModelsConfig.Producer { +public class FileDistributedOnnxModels { private static final Logger log = Logger.getLogger(FileDistributedOnnxModels.class.getName()); - @Override - public String getDerivedName() { return "onnx-models"; } - private final Map<String, OnnxModel> models; public FileDistributedOnnxModels(FileRegistry fileRegistry, Collection<OnnxModel> models) { @@ -47,30 +46,36 @@ public class FileDistributedOnnxModels extends Derived implements OnnxModelsConf public Map<String, OnnxModel> asMap() { return models; } - public void getConfig(OnnxModelsConfig.Builder builder) { + private static OnnxModelsConfig.Model.Builder toConfig(OnnxModel model) { + OnnxModelsConfig.Model.Builder builder = new OnnxModelsConfig.Model.Builder(); + builder.dry_run_on_setup(true); + builder.name(model.getName()); + builder.fileref(model.getFileReference()); + model.getInputMap().forEach((name, source) -> builder.input(new OnnxModelsConfig.Model.Input.Builder().name(name).source(source))); + model.getOutputMap().forEach((name, as) -> builder.output(new OnnxModelsConfig.Model.Output.Builder().name(name).as(as))); + if (model.getStatelessExecutionMode().isPresent()) + builder.stateless_execution_mode(model.getStatelessExecutionMode().get()); + if (model.getStatelessInterOpThreads().isPresent()) + builder.stateless_interop_threads(model.getStatelessInterOpThreads().get()); + if (model.getStatelessIntraOpThreads().isPresent()) + builder.stateless_intraop_threads(model.getStatelessIntraOpThreads().get()); + if (model.getGpuDevice().isPresent()) { + builder.gpu_device(model.getGpuDevice().get().deviceNumber()); + builder.gpu_device_required(model.getGpuDevice().get().required()); + } + return builder; + } + + public List<OnnxModelsConfig.Model.Builder> getConfig() { + List<OnnxModelsConfig.Model.Builder> cfgList = new ArrayList<>(); for (OnnxModel model : models.values()) { if ("".equals(model.getFileReference())) log.warning("Illegal file reference " + model); // Let tests pass ... we should find a better way else { - OnnxModelsConfig.Model.Builder modelBuilder = new OnnxModelsConfig.Model.Builder(); - modelBuilder.dry_run_on_setup(true); - modelBuilder.name(model.getName()); - modelBuilder.fileref(model.getFileReference()); - model.getInputMap().forEach((name, source) -> modelBuilder.input(new OnnxModelsConfig.Model.Input.Builder().name(name).source(source))); - model.getOutputMap().forEach((name, as) -> modelBuilder.output(new OnnxModelsConfig.Model.Output.Builder().name(name).as(as))); - if (model.getStatelessExecutionMode().isPresent()) - modelBuilder.stateless_execution_mode(model.getStatelessExecutionMode().get()); - if (model.getStatelessInterOpThreads().isPresent()) - modelBuilder.stateless_interop_threads(model.getStatelessInterOpThreads().get()); - if (model.getStatelessIntraOpThreads().isPresent()) - modelBuilder.stateless_intraop_threads(model.getStatelessIntraOpThreads().get()); - if (model.getGpuDevice().isPresent()) { - modelBuilder.gpu_device(model.getGpuDevice().get().deviceNumber()); - modelBuilder.gpu_device_required(model.getGpuDevice().get().required()); - } - builder.model(modelBuilder); + cfgList.add(toConfig(model)); } } + return cfgList; } } diff --git a/config-model/src/main/java/com/yahoo/schema/derived/ImportedFields.java b/config-model/src/main/java/com/yahoo/schema/derived/ImportedFields.java index a781adcefb7..e5e28ccea27 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/ImportedFields.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/ImportedFields.java @@ -9,6 +9,7 @@ import com.yahoo.schema.document.ImportedComplexField; import com.yahoo.schema.document.ImportedField; import com.yahoo.vespa.config.search.ImportedFieldsConfig; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -22,7 +23,7 @@ import static com.yahoo.schema.document.ComplexAttributeFieldUtils.isMapOfSimple * * @author geirst */ -public class ImportedFields extends Derived implements ImportedFieldsConfig.Producer { +public class ImportedFields extends Derived { private Optional<com.yahoo.schema.document.ImportedFields> importedFields = Optional.empty(); @@ -40,7 +41,6 @@ public class ImportedFields extends Derived implements ImportedFieldsConfig.Prod return "imported-fields"; } - @Override public void getConfig(ImportedFieldsConfig.Builder builder) { // Replace if (importedFields.isPresent()) { @@ -50,6 +50,12 @@ public class ImportedFields extends Derived implements ImportedFieldsConfig.Prod } } + public void export(String toDirectory) throws IOException { + var builder = new ImportedFieldsConfig.Builder(); + getConfig(builder); + export(toDirectory, builder.build()); + } + private static boolean isNestedFieldName(String fieldName) { return fieldName.indexOf('.') != -1; } diff --git a/config-model/src/main/java/com/yahoo/schema/derived/IndexInfo.java b/config-model/src/main/java/com/yahoo/schema/derived/IndexInfo.java index b0cf4a0013c..c1b698df55f 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/IndexInfo.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/IndexInfo.java @@ -24,6 +24,7 @@ import com.yahoo.schema.processing.NGramMatch; import com.yahoo.vespa.documentmodel.SummaryField; import com.yahoo.search.config.IndexInfoConfig; +import java.io.IOException; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -34,7 +35,7 @@ import java.util.Set; * * @author bratseth */ -public class IndexInfo extends Derived implements IndexInfoConfig.Producer { +public class IndexInfo extends Derived { private static final String CMD_ATTRIBUTE = "attribute"; private static final String CMD_DEFAULT_POSITION = "default-position"; @@ -314,7 +315,6 @@ public class IndexInfo extends Derived implements IndexInfoConfig.Producer { return true; } - @Override public void getConfig(IndexInfoConfig.Builder builder) { // Append IndexInfoConfig.Indexinfo.Builder iiB = new IndexInfoConfig.Indexinfo.Builder(); @@ -335,6 +335,12 @@ public class IndexInfo extends Derived implements IndexInfoConfig.Producer { builder.indexinfo(iiB); } + public void export(String toDirectory) throws IOException { + var builder = new IndexInfoConfig.Builder(); + getConfig(builder); + export(toDirectory, builder.build()); + } + // TODO: Move this to the FieldSetSettings processor (and rename it) as that already has to look at this. private void addFieldSetCommands(IndexInfoConfig.Indexinfo.Builder iiB, FieldSet fieldSet) { for (String qc : fieldSet.queryCommands()) { diff --git a/config-model/src/main/java/com/yahoo/schema/derived/IndexSchema.java b/config-model/src/main/java/com/yahoo/schema/derived/IndexSchema.java index 1c22e80e579..34ed9f2f60c 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/IndexSchema.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/IndexSchema.java @@ -12,6 +12,7 @@ import com.yahoo.schema.document.FieldSet; import com.yahoo.schema.document.ImmutableSDField; import com.yahoo.vespa.config.search.IndexschemaConfig; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; @@ -24,7 +25,7 @@ import java.util.Map; * * @author geirst */ -public class IndexSchema extends Derived implements IndexschemaConfig.Producer { +public class IndexSchema extends Derived { private final List<IndexField> fields = new ArrayList<>(); private final Map<String, FieldCollection> collections = new LinkedHashMap<>(); @@ -131,13 +132,18 @@ public class IndexSchema extends Derived implements IndexschemaConfig.Producer { return fsB; } - @Override public void getConfig(IndexschemaConfig.Builder icB) { // Replace icB.indexfield(fields.stream().map(IndexSchema::createIndexFieldConfig).toList()); icB.fieldset(fieldSets.values().stream().map(IndexSchema::createFieldSetConfig).toList()); } + public void export(String toDirectory) throws IOException { + var builder = new IndexschemaConfig.Builder(); + getConfig(builder); + export(toDirectory, builder.build()); + } + static List<Field> flattenField(Field field) { DataType fieldType = field.getDataType(); if (fieldType.getPrimitiveType() != null){ diff --git a/config-model/src/main/java/com/yahoo/schema/derived/IndexingScript.java b/config-model/src/main/java/com/yahoo/schema/derived/IndexingScript.java index 7245e3f266d..60d27c617f1 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/IndexingScript.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/IndexingScript.java @@ -11,7 +11,6 @@ import com.yahoo.vespa.indexinglanguage.ExpressionVisitor; import com.yahoo.vespa.indexinglanguage.expressions.AttributeExpression; import com.yahoo.vespa.indexinglanguage.expressions.ClearStateExpression; import com.yahoo.vespa.indexinglanguage.expressions.Expression; -import com.yahoo.vespa.indexinglanguage.expressions.ForEachExpression; import com.yahoo.vespa.indexinglanguage.expressions.GuardExpression; import com.yahoo.vespa.indexinglanguage.expressions.InputExpression; import com.yahoo.vespa.indexinglanguage.expressions.OutputExpression; @@ -22,6 +21,7 @@ import com.yahoo.vespa.indexinglanguage.expressions.StatementExpression; import com.yahoo.vespa.indexinglanguage.expressions.TokenizeExpression; import com.yahoo.vespa.indexinglanguage.expressions.ZCurveExpression; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -35,7 +35,7 @@ import java.util.Set; * * @author bratseth */ -public final class IndexingScript extends Derived implements IlscriptsConfig.Producer { +public final class IndexingScript extends Derived { private final List<String> docFields = new ArrayList<>(); private final List<Expression> expressions = new ArrayList<>(); @@ -93,7 +93,6 @@ public final class IndexingScript extends Derived implements IlscriptsConfig.Pro return "ilscripts"; } - @Override public void getConfig(IlscriptsConfig.Builder configBuilder) { // Append IlscriptsConfig.Ilscript.Builder ilscriptBuilder = new IlscriptsConfig.Ilscript.Builder(); @@ -103,6 +102,12 @@ public final class IndexingScript extends Derived implements IlscriptsConfig.Pro configBuilder.ilscript(ilscriptBuilder); } + public void export(String toDirectory) throws IOException { + var builder = new IlscriptsConfig.Builder(); + getConfig(builder); + export(toDirectory, builder.build()); + } + private static class DropTokenize extends ExpressionConverter { @Override protected boolean shouldConvert(Expression exp) { diff --git a/config-model/src/main/java/com/yahoo/schema/derived/Juniperrc.java b/config-model/src/main/java/com/yahoo/schema/derived/Juniperrc.java index a39fa642f34..58e77cedaf1 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/Juniperrc.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/Juniperrc.java @@ -6,6 +6,7 @@ import com.yahoo.vespa.documentmodel.SummaryField; import com.yahoo.vespa.documentmodel.SummaryTransform; import com.yahoo.vespa.config.search.summary.JuniperrcConfig; +import java.io.IOException; import java.util.ArrayList; import java.util.Set; import java.util.stream.Collectors; @@ -15,7 +16,7 @@ import java.util.stream.Collectors; * * @author Simon Thoresen Hult */ -public class Juniperrc extends Derived implements JuniperrcConfig.Producer { +public class Juniperrc extends Derived { private static final int Mb = 1024 * 1024; @@ -43,8 +44,13 @@ public class Juniperrc extends Derived implements JuniperrcConfig.Producer { } } - @Override - protected String getDerivedName() { return "juniperrc"; } + public void export(String toDirectory) throws IOException { + var builder = new JuniperrcConfig.Builder(); + getConfig(builder); + export(toDirectory, builder.build()); + } + + @Override protected String getDerivedName() { return "juniperrc"; } private static JuniperrcConfig.Override.Builder createOverride(String name) { return new JuniperrcConfig.Override.Builder() @@ -55,7 +61,6 @@ public class Juniperrc extends Derived implements JuniperrcConfig.Producer { .surround_max(64*Mb); } - @Override public void getConfig(JuniperrcConfig.Builder builder) { // Replace if (!boldingFields.isEmpty()) { diff --git a/config-model/src/main/java/com/yahoo/schema/derived/RankProfileList.java b/config-model/src/main/java/com/yahoo/schema/derived/RankProfileList.java index 0a419768aaf..b08629d68a3 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/RankProfileList.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/RankProfileList.java @@ -4,6 +4,7 @@ package com.yahoo.schema.derived; import ai.vespa.rankingexpression.importer.configmodelview.ImportedMlModels; import com.yahoo.config.model.api.ModelContext; import com.yahoo.config.model.deploy.DeployState; +import com.yahoo.schema.RankingExpressionBody; import com.yahoo.search.query.profile.QueryProfileRegistry; import com.yahoo.schema.LargeRankingExpressions; import com.yahoo.schema.OnnxModel; @@ -16,6 +17,7 @@ import com.yahoo.vespa.config.search.core.OnnxModelsConfig; import com.yahoo.vespa.config.search.core.RankingConstantsConfig; import com.yahoo.vespa.config.search.core.RankingExpressionsConfig; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -32,7 +34,7 @@ import java.util.concurrent.Future; * * @author bratseth */ -public class RankProfileList extends Derived implements RankProfilesConfig.Producer { +public class RankProfileList extends Derived { private final Map<String, RawRankProfile> rankProfiles; private final FileDistributedConstants constants; @@ -190,32 +192,32 @@ public class RankProfileList extends Derived implements RankProfilesConfig.Produ public FileDistributedConstants constants() { return constants; } public FileDistributedOnnxModels getOnnxModels() { return onnxModels; } - @Override - public String getDerivedName() { return "rank-profiles"; } + @Override public String getDerivedName() { return "rank-profiles"; } - @Override - public void export(String toDirectory) throws java.io.IOException { - super.export(toDirectory); - onnxModels.export(toDirectory); + public void export(String toDirectory) throws IOException { + export(toDirectory, new RankProfilesConfig.Builder().rankprofile(getRankProfilesConfig()).build()); } - @Override - public void getConfig(RankProfilesConfig.Builder builder) { - for (RawRankProfile rank : rankProfiles.values() ) { - rank.getConfig(builder); - } + public List<RankProfilesConfig.Rankprofile.Builder> getRankProfilesConfig() { + return rankProfiles.values().stream().map(RawRankProfile::getConfig).toList(); + } + + private static RankingExpressionsConfig.Expression.Builder toConfig(RankingExpressionBody expr) { + return new RankingExpressionsConfig.Expression.Builder() + .name(expr.getName()) + .fileref(expr.getFileReference()); } - public void getConfig(RankingExpressionsConfig.Builder builder) { - largeRankingExpressions.expressions().forEach((expr) -> builder.expression.add(new RankingExpressionsConfig.Expression.Builder().name(expr.getName()).fileref(expr.getFileReference()))); + public List<RankingExpressionsConfig.Expression.Builder> getExpressionsConfig() { + return largeRankingExpressions.expressions().stream().map(RankProfileList::toConfig).toList(); } - public void getConfig(RankingConstantsConfig.Builder builder) { - constants.getConfig(builder); + public List<RankingConstantsConfig.Constant.Builder> getConstantsConfig() { + return constants.getConfig(); } - public void getConfig(OnnxModelsConfig.Builder builder) { - onnxModels.getConfig(builder); + public List<OnnxModelsConfig.Model.Builder> getOnnxConfig() { + return onnxModels.getConfig(); } } diff --git a/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java b/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java index db76d6397fc..b057624f055 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java @@ -43,7 +43,7 @@ import java.util.Set; * * @author bratseth */ -public class RawRankProfile implements RankProfilesConfig.Producer { +public class RawRankProfile { /** A reusable compressor with default settings */ private static final Compressor compressor = new Compressor(); @@ -130,12 +130,11 @@ public class RawRankProfile implements RankProfilesConfig.Producer { */ public List<Pair<String, String>> configProperties() { return decompress(compressedProperties); } - @Override - public void getConfig(RankProfilesConfig.Builder builder) { + public RankProfilesConfig.Rankprofile.Builder getConfig() { RankProfilesConfig.Rankprofile.Builder b = new RankProfilesConfig.Rankprofile.Builder().name(getName()); getRankProperties(b); buildNormalizers(b); - builder.rankprofile(b); + return b; } @Override diff --git a/config-model/src/main/java/com/yahoo/schema/derived/SchemaInfo.java b/config-model/src/main/java/com/yahoo/schema/derived/SchemaInfo.java index fb6d7fb70ec..19a045ac444 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/SchemaInfo.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/SchemaInfo.java @@ -21,6 +21,7 @@ import com.yahoo.schema.RankProfileRegistry; import com.yahoo.schema.Schema; import com.yahoo.searchlib.rankingexpression.Reference; +import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.Iterator; @@ -32,7 +33,7 @@ import java.util.Map; * * @author bratseth */ -public final class SchemaInfo extends Derived implements SchemaInfoConfig.Producer { +public final class SchemaInfo extends Derived { private final Schema schema; @@ -63,7 +64,6 @@ public final class SchemaInfo extends Derived implements SchemaInfoConfig.Produc return rankProfileInfos; } - @Override public void getConfig(SchemaInfoConfig.Builder builder) { // Append var schemaBuilder = new SchemaInfoConfig.Schema.Builder(); @@ -75,6 +75,12 @@ public final class SchemaInfo extends Derived implements SchemaInfoConfig.Produc builder.schema(schemaBuilder); } + public void export(String toDirectory) throws IOException { + var builder = new SchemaInfoConfig.Builder(); + getConfig(builder); + export(toDirectory, builder.build()); + } + private void addFieldsConfig(SchemaInfoConfig.Schema.Builder schemaBuilder) { for (var field : schema.allFieldsList()) { addFieldConfig(field, schemaBuilder); diff --git a/config-model/src/main/java/com/yahoo/schema/derived/Summaries.java b/config-model/src/main/java/com/yahoo/schema/derived/Summaries.java index 51c648aa1be..1f0c6f7e761 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/Summaries.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/Summaries.java @@ -7,6 +7,7 @@ import com.yahoo.schema.Schema; import com.yahoo.vespa.documentmodel.DocumentSummary; import com.yahoo.vespa.config.search.SummaryConfig; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -15,7 +16,7 @@ import java.util.List; * * @author bratseth */ -public class Summaries extends Derived implements SummaryConfig.Producer { +public class Summaries extends Derived { private final boolean useV8GeoPositions; private final List<SummaryClass> summaries; @@ -36,15 +37,18 @@ public class Summaries extends Derived implements SummaryConfig.Producer { public List<SummaryClass> asList() { return summaries; } - @Override - protected String getDerivedName() { return "summary"; } + @Override protected String getDerivedName() { return "summary"; } - @Override public void getConfig(SummaryConfig.Builder builder) { // Replace builder.defaultsummaryid(summaries.isEmpty() ? -1 : summaries.get(0).hashCode()); builder.usev8geopositions(useV8GeoPositions); builder.classes(summaries.stream().map(SummaryClass::getSummaryClassConfig).toList()); - } + } + public void export(String toDirectory) throws IOException { + var builder = new SummaryConfig.Builder(); + getConfig(builder); + export(toDirectory, builder.build()); + } } diff --git a/config-model/src/main/java/com/yahoo/schema/derived/SummaryClass.java b/config-model/src/main/java/com/yahoo/schema/derived/SummaryClass.java index 799324d26e9..398897c6b78 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/SummaryClass.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/SummaryClass.java @@ -11,6 +11,7 @@ import com.yahoo.vespa.documentmodel.DocumentSummary; import com.yahoo.vespa.documentmodel.SummaryField; import com.yahoo.vespa.documentmodel.SummaryTransform; +import java.io.IOException; import java.util.Collections; import java.util.Map; import java.util.logging.Level; @@ -119,11 +120,9 @@ public class SummaryClass extends Derived { return classBuilder; } - @Override - public int hashCode() { return id; } + @Override public int hashCode() { return id; } - @Override - protected String getDerivedName() { return "summary"; } + @Override protected String getDerivedName() { return "summary"; } @Override public String toString() { diff --git a/config-model/src/main/java/com/yahoo/schema/derived/VsmFields.java b/config-model/src/main/java/com/yahoo/schema/derived/VsmFields.java index b2b2e9d3a14..6992ac70a1a 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/VsmFields.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/VsmFields.java @@ -25,13 +25,14 @@ import com.yahoo.schema.document.SDField; import com.yahoo.schema.processing.TensorFieldProcessor; import com.yahoo.vespa.config.search.vsm.VsmfieldsConfig; +import java.io.IOException; import java.util.LinkedHashMap; import java.util.Map; /** * Vertical streaming matcher field specification */ -public class VsmFields extends Derived implements VsmfieldsConfig.Producer { +public class VsmFields extends Derived { private final Map<String, StreamingField> fields=new LinkedHashMap<>(); private final Map<String, StreamingDocumentType> doctypes=new LinkedHashMap<>(); @@ -106,13 +107,18 @@ public class VsmFields extends Derived implements VsmfieldsConfig.Producer { return "vsmfields"; } - @Override public void getConfig(VsmfieldsConfig.Builder vsB) { // Replace vsB.fieldspec(fields.values().stream().map(StreamingField::getFieldSpecConfig).toList()); vsB.documenttype(doctypes.values().stream().map(StreamingDocumentType::getDocTypeConfig).toList()); } + public void export(String toDirectory) throws IOException { + var builder = new VsmfieldsConfig.Builder(); + getConfig(builder); + export(toDirectory, builder.build()); + } + private static boolean isAttributeField(ImmutableSDField field, boolean isStructField, boolean ignoreAttributeAspect) { if (field.doesAttributing()) { return true; diff --git a/config-model/src/main/java/com/yahoo/schema/derived/VsmSummary.java b/config-model/src/main/java/com/yahoo/schema/derived/VsmSummary.java index 248cca33bc6..7507ef95482 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/VsmSummary.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/VsmSummary.java @@ -9,14 +9,18 @@ import com.yahoo.vespa.documentmodel.DocumentSummary; import com.yahoo.vespa.documentmodel.SummaryField; import com.yahoo.vespa.config.search.vsm.VsmsummaryConfig; -import java.util.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; /** * Vertical streaming matcher summary specification * * @author bratseth */ -public class VsmSummary extends Derived implements VsmsummaryConfig.Producer { +public class VsmSummary extends Derived { private final Map<SummaryField, List<String>> summaryMap = new java.util.LinkedHashMap<>(1); @@ -89,12 +93,10 @@ public class VsmSummary extends Derived implements VsmsummaryConfig.Producer { return ret; } - @Override - public String getDerivedName() { + @Override public String getDerivedName() { return "vsmsummary"; } - @Override public void getConfig(VsmsummaryConfig.Builder vB) { // Replace vB.fieldmap( @@ -105,5 +107,10 @@ public class VsmSummary extends Derived implements VsmsummaryConfig.Producer { ).toList() ); } - + + public void export(String toDirectory) throws IOException { + var builder = new VsmsummaryConfig.Builder(); + getConfig(builder); + export(toDirectory, builder.build()); + } } diff --git a/config-model/src/main/java/com/yahoo/schema/processing/ImplicitSummaries.java b/config-model/src/main/java/com/yahoo/schema/processing/ImplicitSummaries.java index a05450aa3a0..816e5a074f6 100644 --- a/config-model/src/main/java/com/yahoo/schema/processing/ImplicitSummaries.java +++ b/config-model/src/main/java/com/yahoo/schema/processing/ImplicitSummaries.java @@ -12,7 +12,7 @@ import com.yahoo.vespa.documentmodel.SummaryTransform; import com.yahoo.vespa.model.container.search.QueryProfiles; import java.util.logging.Level; -import static com.yahoo.prelude.fastsearch.VespaBackEndSearcher.SORTABLE_ATTRIBUTES_SUMMARY_CLASS; +import static com.yahoo.prelude.fastsearch.VespaBackend.SORTABLE_ATTRIBUTES_SUMMARY_CLASS; import static com.yahoo.schema.document.ComplexAttributeFieldUtils.isComplexFieldWithOnlyStructFieldAttributes; /** diff --git a/config-model/src/main/java/com/yahoo/schema/processing/PredicateProcessor.java b/config-model/src/main/java/com/yahoo/schema/processing/PredicateProcessor.java index 7e9d79fc858..26107ad2dca 100644 --- a/config-model/src/main/java/com/yahoo/schema/processing/PredicateProcessor.java +++ b/config-model/src/main/java/com/yahoo/schema/processing/PredicateProcessor.java @@ -24,7 +24,7 @@ import com.yahoo.vespa.indexinglanguage.expressions.SetVarExpression; import com.yahoo.vespa.indexinglanguage.expressions.StatementExpression; import com.yahoo.vespa.model.container.search.QueryProfiles; -import static com.yahoo.prelude.fastsearch.VespaBackEndSearcher.SORTABLE_ATTRIBUTES_SUMMARY_CLASS; +import static com.yahoo.prelude.fastsearch.VespaBackend.SORTABLE_ATTRIBUTES_SUMMARY_CLASS; import java.util.ArrayList; import java.util.List; diff --git a/config-model/src/main/java/com/yahoo/schema/processing/ReferenceFieldsProcessor.java b/config-model/src/main/java/com/yahoo/schema/processing/ReferenceFieldsProcessor.java index e425f81c0b4..42457295895 100644 --- a/config-model/src/main/java/com/yahoo/schema/processing/ReferenceFieldsProcessor.java +++ b/config-model/src/main/java/com/yahoo/schema/processing/ReferenceFieldsProcessor.java @@ -10,7 +10,7 @@ import com.yahoo.vespa.documentmodel.DocumentSummary; import com.yahoo.vespa.documentmodel.SummaryTransform; import com.yahoo.vespa.model.container.search.QueryProfiles; -import static com.yahoo.prelude.fastsearch.VespaBackEndSearcher.SORTABLE_ATTRIBUTES_SUMMARY_CLASS; +import static com.yahoo.prelude.fastsearch.VespaBackend.SORTABLE_ATTRIBUTES_SUMMARY_CLASS; /** * Class that processes reference fields and removes attribute aspect of such fields from summary. diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerModelEvaluation.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerModelEvaluation.java index ffd346f704f..62979404025 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerModelEvaluation.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerModelEvaluation.java @@ -55,25 +55,25 @@ public class ContainerModelEvaluation implements @Override public void getConfig(RankProfilesConfig.Builder builder) { - rankProfileList.getConfig(builder); + builder.rankprofile(rankProfileList.getRankProfilesConfig()); } @Override public void getConfig(RankingConstantsConfig.Builder builder) { - rankProfileList.getConfig(builder); + builder.constant(rankProfileList.getConstantsConfig()); } @Override public void getConfig(OnnxModelsConfig.Builder builder) { if (onnxModels != null) { - onnxModels.getConfig(builder); + builder.model(onnxModels.getConfig()); } else { - rankProfileList.getConfig(builder); + builder.model(rankProfileList.getOnnxConfig()); } } public void getConfig(RankingExpressionsConfig.Builder builder) { - rankProfileList.getConfig(builder); + builder.expression(rankProfileList.getExpressionsConfig()); } public static Handler getHandler() { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/PlatformBundles.java b/config-model/src/main/java/com/yahoo/vespa/model/container/PlatformBundles.java index 13e6ee6684d..3252077a79d 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/PlatformBundles.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/PlatformBundles.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.model.container; import com.yahoo.container.bundle.BundleInstantiationSpecification; +import com.yahoo.prelude.fastsearch.IndexedBackend; import com.yahoo.vespa.defaults.Defaults; import java.nio.file.Path; @@ -23,7 +24,7 @@ import static com.yahoo.vespa.model.container.ContainerModelEvaluation.ONNXRUNTI */ public class PlatformBundles { - private enum JarSuffix { + public enum JarSuffix { JAR_WITH_DEPS("-jar-with-dependencies.jar"), DEPLOY("-deploy.jar"); @@ -92,8 +93,8 @@ public class PlatformBundles { com.yahoo.docproc.SimpleDocumentProcessor.class.getName(), com.yahoo.language.simple.SimpleLinguistics.class.getName(), com.yahoo.prelude.cluster.ClusterSearcher.class.getName(), - com.yahoo.prelude.fastsearch.FastSearcher.class.getName(), - com.yahoo.prelude.fastsearch.VespaBackEndSearcher.class.getName(), + IndexedBackend.class.getName(), + com.yahoo.prelude.fastsearch.VespaBackend.class.getName(), com.yahoo.prelude.querytransform.CJKSearcher.class.getName(), com.yahoo.prelude.querytransform.CollapsePhraseSearcher.class.getName(), com.yahoo.prelude.querytransform.LiteralBoostSearcher.class.getName(), @@ -144,7 +145,7 @@ public class PlatformBundles { com.yahoo.search.searchers.CacheControlSearcher.class.getName(), com.yahoo.search.searchers.RateLimitingSearcher.class.getName(), com.yahoo.vespa.streamingvisitors.MetricsSearcher.class.getName(), - com.yahoo.vespa.streamingvisitors.StreamingSearcher.class.getName() + com.yahoo.vespa.streamingvisitors.StreamingBackend.class.getName() ); } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ml/ModelsEvaluatorTester.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ml/ModelsEvaluatorTester.java index 800e766706b..bc936dc7441 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/ml/ModelsEvaluatorTester.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ml/ModelsEvaluatorTester.java @@ -115,27 +115,27 @@ public class ModelsEvaluatorTester { } private static RankProfilesConfig getRankProfilesConfig(RankProfileList rankProfileList) { - RankProfilesConfig.Builder builder = new RankProfilesConfig.Builder(); - rankProfileList.getConfig(builder); - return builder.build(); + return new RankProfilesConfig.Builder() + .rankprofile(rankProfileList.getRankProfilesConfig()) + .build(); } private static RankingConstantsConfig getRankingConstantConfig(RankProfileList rankProfileList) { - RankingConstantsConfig.Builder builder = new RankingConstantsConfig.Builder(); - rankProfileList.getConfig(builder); - return builder.build(); + return new RankingConstantsConfig.Builder() + .constant(rankProfileList.getConstantsConfig()) + .build(); } private static RankingExpressionsConfig getRankingExpressionsConfig(RankProfileList rankProfileList) { - RankingExpressionsConfig.Builder builder = new RankingExpressionsConfig.Builder(); - rankProfileList.getConfig(builder); - return builder.build(); + return new RankingExpressionsConfig.Builder() + .expression(rankProfileList.getExpressionsConfig()) + .build(); } private static OnnxModelsConfig getOnnxModelsConfig(RankProfileList rankProfileList) { - OnnxModelsConfig.Builder builder = new OnnxModelsConfig.Builder(); - rankProfileList.getConfig(builder); - return builder.build(); + return new OnnxModelsConfig.Builder() + .model(rankProfileList.getOnnxConfig()) + .build(); } private static FileAcquirer createFileAcquirer(MockFileRegistry fileRegistry, File appDir) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/search/DocumentDatabase.java b/config-model/src/main/java/com/yahoo/vespa/model/search/DocumentDatabase.java index 334f8d4314a..ed571266f1b 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/search/DocumentDatabase.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/search/DocumentDatabase.java @@ -68,14 +68,20 @@ public class DocumentDatabase extends AnyConfigProducer implements // These methods append as multiple databases join config => TODO will loose information - not good @Override public void getConfig(AttributesConfig.Builder builder) { derivedCfg.getConfig(builder); } - @Override public void getConfig(RankProfilesConfig.Builder builder) { derivedCfg.getRankProfileList().getConfig(builder); } - - // These methods append, TODO unknown usage and consequences - @Override public void getConfig(RankingExpressionsConfig.Builder builder) { derivedCfg.getRankProfileList().getConfig(builder); } - @Override public void getConfig(RankingConstantsConfig.Builder builder) { derivedCfg.getRankProfileList().getConfig(builder); } - @Override public void getConfig(OnnxModelsConfig.Builder builder) { derivedCfg.getRankProfileList().getConfig(builder); } // Below methods will replace config completely + @Override public void getConfig(OnnxModelsConfig.Builder builder) { + builder.model(derivedCfg.getRankProfileList().getOnnxConfig()); + } + @Override public void getConfig(RankingExpressionsConfig.Builder builder) { + builder.expression(derivedCfg.getRankProfileList().getExpressionsConfig()); + } + @Override public void getConfig(RankingConstantsConfig.Builder builder) { + builder.constant(derivedCfg.getRankProfileList().getConstantsConfig()); + } + @Override public void getConfig(RankProfilesConfig.Builder builder) { + builder.rankprofile(derivedCfg.getRankProfileList().getRankProfilesConfig()); + } @Override public void getConfig(IndexschemaConfig.Builder builder) { derivedCfg.getIndexSchema().getConfig(builder); } @Override public void getConfig(JuniperrcConfig.Builder builder) { derivedCfg.getJuniperrc().getConfig(builder); } @Override public void getConfig(SummaryConfig.Builder builder) { derivedCfg.getSummaries().getConfig(builder); } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/search/SearchCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/search/SearchCluster.java index c0aec7ba0b4..f19af8b62ca 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/search/SearchCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/search/SearchCluster.java @@ -113,8 +113,11 @@ public abstract class SearchCluster extends TreeConfigProducer<AnyConfigProducer @Override public void getConfig(DocumentdbInfoConfig.Builder builder) { for (DocumentDatabase db : documentDbs) { - DocumentdbInfoConfig.Documentdb.Builder docDb = new DocumentdbInfoConfig.Documentdb.Builder(); - docDb.name(db.getName()); + var docDb = new DocumentdbInfoConfig.Documentdb.Builder() + .name(db.getName()) + .mode(db.getDerivedConfiguration().isStreaming() + ? DocumentdbInfoConfig.Documentdb.Mode.Enum.STREAMING + : DocumentdbInfoConfig.Documentdb.Mode.Enum.INDEX); builder.documentdb(docDb); } } diff --git a/config-model/src/test/java/com/yahoo/schema/derived/AbstractExportingTestCase.java b/config-model/src/test/java/com/yahoo/schema/derived/AbstractExportingTestCase.java index 7686289f11c..7d7ed2b23eb 100644 --- a/config-model/src/test/java/com/yahoo/schema/derived/AbstractExportingTestCase.java +++ b/config-model/src/test/java/com/yahoo/schema/derived/AbstractExportingTestCase.java @@ -70,6 +70,7 @@ public abstract class AbstractExportingTestCase extends AbstractSchemaTestCase { DerivedConfiguration.exportDocuments(new DocumentTypes().produce(builder.getModel(), new DocumenttypesConfig.Builder()), path); DerivedConfiguration.exportQueryProfiles(builder.getQueryProfileRegistry(), path); config.exportConstants(path); + config.exportOnnxModels(path); return config; } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/search/test/DocumentDatabaseTestCase.java b/config-model/src/test/java/com/yahoo/vespa/model/search/test/DocumentDatabaseTestCase.java index 5b501bad876..eb4ec1af157 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/search/test/DocumentDatabaseTestCase.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/search/test/DocumentDatabaseTestCase.java @@ -289,8 +289,12 @@ public class DocumentDatabaseTestCase { { // documentdb-info config DocumentdbInfoConfig dcfg = model.getConfig(DocumentdbInfoConfig.class, searcherId); assertEquals(2, dcfg.documentdb().size()); - assertEquals("type1", dcfg.documentdb(0).name()); - assertEquals("type2", dcfg.documentdb(1).name()); + var db = dcfg.documentdb(0); + assertEquals("type1", db.name()); + assertEquals(DocumentdbInfoConfig.Documentdb.Mode.INDEX, db.mode()); + db = dcfg.documentdb(1); + assertEquals("type2", db.name()); + assertEquals(DocumentdbInfoConfig.Documentdb.Mode.INDEX, db.mode()); } { // attributes config AttributesConfig acfg = model.getConfig(AttributesConfig.class, searcherId); @@ -312,6 +316,7 @@ public class DocumentDatabaseTestCase { assertEquals(1, dcfg.documentdb().size()); DocumentdbInfoConfig.Documentdb db = dcfg.documentdb(0); assertEquals("type", db.name()); + assertEquals(DocumentdbInfoConfig.Documentdb.Mode.STREAMING, db.mode()); } @Test @@ -319,6 +324,24 @@ public class DocumentDatabaseTestCase { assertDocumentDBConfigAvailableForStreaming("streaming"); } + @Test + void testMixedModeCluster() { + // Will soon change + List<DocType> sds = List.of(DocType.create("a", "index"), DocType.create("b", "streaming")); + var tester = new SchemaTester(); + var model = tester.createModel(sds, ""); + DocumentdbInfoConfig indexed_cfg = model.getConfig(DocumentdbInfoConfig.class, "test/search/cluster.test"); + assertEquals(1, indexed_cfg.documentdb().size()); + var db = indexed_cfg.documentdb(0); + assertEquals("a", db.name()); + assertEquals(DocumentdbInfoConfig.Documentdb.Mode.INDEX, db.mode()); + DocumentdbInfoConfig streaming_cfg = model.getConfig(DocumentdbInfoConfig.class, "test/search/cluster.test.b"); + assertEquals(1, streaming_cfg.documentdb().size()); + db = streaming_cfg.documentdb(0); + assertEquals("b", db.name()); + assertEquals(DocumentdbInfoConfig.Documentdb.Mode.STREAMING, db.mode()); + } + private void assertAttributesConfigIndependentOfMode(String mode, List<String> sds, List<String> documentDBConfigIds, Map<String, List<String>> expectedAttributesMap) diff --git a/config/src/tests/frtconnectionpool/CMakeLists.txt b/config/src/tests/frtconnectionpool/CMakeLists.txt index b39a5bdf6f5..003d3151fc7 100644 --- a/config/src/tests/frtconnectionpool/CMakeLists.txt +++ b/config/src/tests/frtconnectionpool/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(config_frtconnectionpool_test_app TEST frtconnectionpool.cpp DEPENDS config_cloudconfig + GTest::gtest ) vespa_add_test(NAME config_frtconnectionpool_test_app COMMAND config_frtconnectionpool_test_app) diff --git a/config/src/tests/frtconnectionpool/frtconnectionpool.cpp b/config/src/tests/frtconnectionpool/frtconnectionpool.cpp index 9d1501962a1..a27dffa6fc5 100644 --- a/config/src/tests/frtconnectionpool/frtconnectionpool.cpp +++ b/config/src/tests/frtconnectionpool/frtconnectionpool.cpp @@ -1,121 +1,79 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/config/frt/frtconnectionpool.h> #include <vespa/fnet/frt/error.h> #include <vespa/fnet/transport.h> +#include <vespa/vespalib/gtest/gtest.h> #include <sstream> #include <set> #include <unistd.h> using namespace config; -class Test : public vespalib::TestApp { -private: - static ServerSpec::HostSpecList _sources; +class FRTConnectionPoolTest : public testing::Test { +protected: + ServerSpec::HostSpecList _sources; FNET_Transport _transport; void verifyAllSourcesInRotation(FRTConnectionPool& sourcePool); -public: - Test(); - ~Test() override; - int Main() override; - void testBasicRoundRobin(); - void testBasicHashBasedSelection(); - void testSetErrorRoundRobin(); - void testSetErrorAllRoundRobin(); - void testSetErrorHashBased(); - void testSetErrorAllHashBased(); - void testSuspensionTimeout(); - void testManySources(); + FRTConnectionPoolTest(); + ~FRTConnectionPoolTest() override; }; -Test::Test() - : vespalib::TestApp(), +FRTConnectionPoolTest::FRTConnectionPoolTest() + : testing::Test(), + _sources(), _transport() { + _sources.push_back("host0"); + _sources.push_back("host1"); + _sources.push_back("host2"); _transport.Start(); } -Test::~Test() { +FRTConnectionPoolTest::~FRTConnectionPoolTest() { _transport.ShutDown(true); } -TEST_APPHOOK(Test); - -ServerSpec::HostSpecList Test::_sources; TimingValues timingValues; -int Test::Main() { - TEST_INIT("frtconnectionpool_test"); - - _sources.push_back("host0"); - _sources.push_back("host1"); - _sources.push_back("host2"); - - testBasicRoundRobin(); - TEST_FLUSH(); - - testBasicHashBasedSelection(); - TEST_FLUSH(); - - testSetErrorRoundRobin(); - TEST_FLUSH(); - - testSetErrorAllRoundRobin(); - TEST_FLUSH(); - - testSetErrorHashBased(); - TEST_FLUSH(); - - testSetErrorAllHashBased(); - TEST_FLUSH(); - - testSuspensionTimeout(); - TEST_FLUSH(); - - testManySources(); - TEST_FLUSH(); - - TEST_DONE(); - return 0; -} - -void Test::verifyAllSourcesInRotation(FRTConnectionPool& sourcePool) { +void FRTConnectionPoolTest::verifyAllSourcesInRotation(FRTConnectionPool& sourcePool) { std::set<std::string> completeSet(_sources.begin(), _sources.end()); std::set<std::string> foundSet; for (int i = 0; i < (int)_sources.size(); i++) { foundSet.insert(sourcePool.getNextRoundRobin()->getAddress()); } - EXPECT_EQUAL(true, completeSet == foundSet); + EXPECT_EQ(true, completeSet == foundSet); } /** * Tests that basic round robin selection through the list works. */ -void Test::testBasicRoundRobin() { +TEST_F(FRTConnectionPoolTest, test_basic_round_robin) +{ const ServerSpec spec(_sources); FRTConnectionPool sourcePool(_transport, spec, timingValues); for (int i = 0; i < 9; i++) { int j = i % _sources.size(); std::stringstream s; s << "host" << j; - EXPECT_EQUAL(s.str(), sourcePool.getNextRoundRobin()->getAddress()); + EXPECT_EQ(s.str(), sourcePool.getNextRoundRobin()->getAddress()); } } /** * Tests that hash-based selection through the list works. */ -void Test::testBasicHashBasedSelection() { +TEST_F(FRTConnectionPoolTest, test_basic_hash_based_selection) +{ const ServerSpec spec(_sources); FRTConnectionPool sourcePool(_transport, spec, timingValues); sourcePool.setHostname("a.b.com"); for (int i = 0; i < 9; i++) { - EXPECT_EQUAL("host1", sourcePool.getNextHashBased()->getAddress()); + EXPECT_EQ("host1", sourcePool.getNextHashBased()->getAddress()); } sourcePool.setHostname("host98"); for (int i = 0; i < 9; i++) { - EXPECT_EQUAL("host0", sourcePool.getNextHashBased()->getAddress()); + EXPECT_EQ("host0", sourcePool.getNextHashBased()->getAddress()); } ServerSpec::HostSpecList hostnames; @@ -125,24 +83,25 @@ void Test::testBasicHashBasedSelection() { const ServerSpec spec2(hostnames); FRTConnectionPool sourcePool2(_transport, spec2, timingValues); sourcePool2.setHostname("sutter-01.example.yahoo.com"); - EXPECT_EQUAL("stroustrup-02.example.yahoo.com", sourcePool2.getNextHashBased()->getAddress()); + EXPECT_EQ("stroustrup-02.example.yahoo.com", sourcePool2.getNextHashBased()->getAddress()); sourcePool2.setHostname("stroustrup-02.example.yahoo.com"); - EXPECT_EQUAL("sutter-01.example.yahoo.com", sourcePool2.getNextHashBased()->getAddress()); + EXPECT_EQ("sutter-01.example.yahoo.com", sourcePool2.getNextHashBased()->getAddress()); sourcePool2.setHostname("alexandrescu-03.example.yahoo.com"); - EXPECT_EQUAL("alexandrescu-03.example.yahoo.com", sourcePool2.getNextHashBased()->getAddress()); + EXPECT_EQ("alexandrescu-03.example.yahoo.com", sourcePool2.getNextHashBased()->getAddress()); } /** * Tests that a source is taken out of rotation when an error is reported, * and that it is taken back in when a success is reported. */ -void Test::testSetErrorRoundRobin() { +TEST_F(FRTConnectionPoolTest, test_set_error_round_robin) +{ const ServerSpec spec(_sources); FRTConnectionPool sourcePool(_transport, spec, timingValues); FRTConnection* source = sourcePool.getNextRoundRobin(); source->setError(FRTE_RPC_CONNECTION); for (int i = 0; i < 9; i++) { - EXPECT_NOT_EQUAL(source->getAddress(), sourcePool.getCurrent()->getAddress()); + EXPECT_NE(source->getAddress(), sourcePool.getCurrent()->getAddress()); } source->setSuccess(); verifyAllSourcesInRotation(sourcePool); @@ -151,7 +110,8 @@ void Test::testSetErrorRoundRobin() { /** * Tests that all sources are in rotation when all sources have errors set. */ -void Test::testSetErrorAllRoundRobin() { +TEST_F(FRTConnectionPoolTest, test_set_error_all_round_robin) +{ const ServerSpec spec(_sources); FRTConnectionPool sourcePool(_transport, spec, timingValues); for (int i = 0; i < (int)_sources.size(); i++) { @@ -165,22 +125,24 @@ void Test::testSetErrorAllRoundRobin() { * Tests that a source is not used when an error is reported, * and that the same source is used when a success is reported. */ -void Test::testSetErrorHashBased() { +TEST_F(FRTConnectionPoolTest, test_set_error_hash_based) +{ const ServerSpec spec(_sources); FRTConnectionPool sourcePool(_transport, spec, timingValues); FRTConnection* source = sourcePool.getNextHashBased(); source->setError(FRTE_RPC_CONNECTION); for (int i = 0; i < (int)_sources.size(); i++) { - EXPECT_NOT_EQUAL(source->getAddress(), sourcePool.getNextHashBased()->getAddress()); + EXPECT_NE(source->getAddress(), sourcePool.getNextHashBased()->getAddress()); } source->setSuccess(); - EXPECT_EQUAL(source->getAddress(), sourcePool.getNextHashBased()->getAddress()); + EXPECT_EQ(source->getAddress(), sourcePool.getNextHashBased()->getAddress()); } /** * Tests that the same source is used when all sources have errors set. */ -void Test::testSetErrorAllHashBased() { +TEST_F(FRTConnectionPoolTest, test_set_error_all_hash_based) +{ const ServerSpec spec(_sources); FRTConnectionPool sourcePool(_transport, spec, timingValues); FRTConnection* firstSource = sourcePool.getNextHashBased(); @@ -188,11 +150,11 @@ void Test::testSetErrorAllHashBased() { for (int i = 0; i < (int)readySources.size(); i++) { readySources[i]->setError(FRTE_RPC_CONNECTION); } - EXPECT_EQUAL(sourcePool.getReadySources().size(), 0u); - EXPECT_EQUAL(sourcePool.getSuspendedSources().size(), 3u); + EXPECT_EQ(sourcePool.getReadySources().size(), 0u); + EXPECT_EQ(sourcePool.getSuspendedSources().size(), 3u); // should get the same source now, since all are suspended - EXPECT_EQUAL(firstSource->getAddress(), sourcePool.getNextHashBased()->getAddress()); + EXPECT_EQ(firstSource->getAddress(), sourcePool.getNextHashBased()->getAddress()); // set all except firstSource to OK for (int i = 0; i < (int)readySources.size(); i++) { @@ -201,18 +163,19 @@ void Test::testSetErrorAllHashBased() { } } - EXPECT_EQUAL(sourcePool.getReadySources().size(), 2u); - EXPECT_EQUAL(sourcePool.getSuspendedSources().size(), 1u); + EXPECT_EQ(sourcePool.getReadySources().size(), 2u); + EXPECT_EQ(sourcePool.getSuspendedSources().size(), 1u); // should not get the same source now, since original source is // suspended, while the rest are OK - EXPECT_NOT_EQUAL(firstSource->getAddress(), sourcePool.getNextHashBased()->getAddress()); + EXPECT_NE(firstSource->getAddress(), sourcePool.getNextHashBased()->getAddress()); } /** * Tests that the source is put back into rotation when the suspension times out. */ -void Test::testSuspensionTimeout() { +TEST_F(FRTConnectionPoolTest, test_suspension_timeout) +{ const ServerSpec spec(_sources); TimingValues short_transient_delay; short_transient_delay.transientDelay = 1s; @@ -220,7 +183,7 @@ void Test::testSuspensionTimeout() { FRTConnection* source = dynamic_cast<FRTConnection *>(sourcePool.getCurrent()); source->setError(FRTE_RPC_CONNECTION); for (int i = 0; i < 9; i++) { - EXPECT_NOT_EQUAL(source->getAddress(), sourcePool.getCurrent()->getAddress()); + EXPECT_NE(source->getAddress(), sourcePool.getCurrent()->getAddress()); } sleep(2); verifyAllSourcesInRotation(sourcePool); @@ -230,7 +193,8 @@ void Test::testSuspensionTimeout() { * Tests that when there are two sources and several clients * the sources will be chosen with equal probability. */ -void Test::testManySources() { +TEST_F(FRTConnectionPoolTest, test_many_sources) +{ std::vector<std::string> hostnames; for (int i = 0; i < 20; ++i) { hostnames.push_back("host-" + std::to_string(i) + ".example.yahoo.com"); @@ -255,6 +219,8 @@ void Test::testManySources() { timesUsed[address] = 1; } } - EXPECT_EQUAL(timesUsed["host0"], (int)hostnames.size() / 2); - EXPECT_EQUAL(timesUsed["host1"], (int)hostnames.size() / 2); + EXPECT_EQ(timesUsed["host0"], (int)hostnames.size() / 2); + EXPECT_EQ(timesUsed["host1"], (int)hostnames.size() / 2); } + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandlerTest.java index 07b7fa0f244..d4aa0676c4f 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandlerTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandlerTest.java @@ -180,7 +180,7 @@ class ApplicationApiHandlerTest { """ { "error-code": "BAD_REQUEST", - "message": "Unable to decompress application stream: Cannot find zip signature within the file" + "message": "Error preprocessing application package for test.default, session 2: services.xml does not exist in application package" } """); } diff --git a/container-core/src/main/java/com/yahoo/restapi/RestApi.java b/container-core/src/main/java/com/yahoo/restapi/RestApi.java index ee5628988c9..69cbf48cb1b 100644 --- a/container-core/src/main/java/com/yahoo/restapi/RestApi.java +++ b/container-core/src/main/java/com/yahoo/restapi/RestApi.java @@ -15,12 +15,11 @@ import com.yahoo.security.tls.ConnectionAuthContext; import javax.net.ssl.SSLSession; import java.io.InputStream; +import java.math.BigDecimal; import java.net.InetSocketAddress; import java.security.Principal; import java.util.List; import java.util.Optional; -import java.util.OptionalDouble; -import java.util.OptionalLong; /** * Rest API routing and response serialization @@ -149,6 +148,8 @@ public interface RestApi { /** Scheme, domain and port, for the original request. <em>Use this only for generating resources links, not for custom routing!</em> */ // TODO: this needs to include path and query as well, to be useful for generating resource links that need not be rewritten. HttpURL baseRequestURL(); + /** Full URL of the request */ + HttpURL url(); AclMapping.Action aclAction(); Optional<Principal> userPrincipal(); Principal userPrincipalOrThrow(); @@ -161,14 +162,14 @@ public interface RestApi { String getStringOrThrow(String name); default Optional<Boolean> getBoolean(String name) { return getString(name).map(Boolean::valueOf);} default boolean getBooleanOrThrow(String name) { return Boolean.parseBoolean(getStringOrThrow(name)); } - default OptionalLong getLong(String name) { - return getString(name).map(Long::parseLong).map(OptionalLong::of).orElseGet(OptionalLong::empty); - } + default Optional<Long> getLong(String name) { return getString(name).map(Long::parseLong); } default long getLongOrThrow(String name) { return Long.parseLong(getStringOrThrow(name)); } - default OptionalDouble getDouble(String name) { - return getString(name).map(Double::parseDouble).map(OptionalDouble::of).orElseGet(OptionalDouble::empty); - } + default Optional<Double> getDouble(String name) { return getString(name).map(Double::parseDouble); } + default int getIntegerOrThrow(String name) { return Integer.parseInt(getStringOrThrow(name)); } + default Optional<Integer> getInteger(String name) { return getString(name).map(Integer::parseInt); } default double getDoubleOrThrow(String name) { return Double.parseDouble(getStringOrThrow(name)); } + default BigDecimal getBigDecimalOrThrow(String name) { return new BigDecimal(getStringOrThrow(name)); } + default Optional<BigDecimal> getBigDecimal(String name) { return getString(name).map(BigDecimal::new); } } interface PathParameters extends Parameters { diff --git a/container-core/src/main/java/com/yahoo/restapi/RestApiImpl.java b/container-core/src/main/java/com/yahoo/restapi/RestApiImpl.java index a381fd3c9a6..56e7f4e3098 100644 --- a/container-core/src/main/java/com/yahoo/restapi/RestApiImpl.java +++ b/container-core/src/main/java/com/yahoo/restapi/RestApiImpl.java @@ -479,6 +479,7 @@ class RestApiImpl implements RestApi { } return HttpURL.from(URI.create(sb.toString())); } + @Override public HttpURL url() { return HttpURL.from(request.getUri()); } @Override public AclMapping.Action aclAction() { return aclAction; } @Override public Optional<Principal> userPrincipal() { return Optional.ofNullable(request.getJDiscRequest().getUserPrincipal()); diff --git a/container-core/src/main/resources/configdefinitions/container.qr-searchers.def b/container-core/src/main/resources/configdefinitions/container.qr-searchers.def index f8871e9f315..ac0c0dd6ada 100644 --- a/container-core/src/main/resources/configdefinitions/container.qr-searchers.def +++ b/container-core/src/main/resources/configdefinitions/container.qr-searchers.def @@ -25,7 +25,7 @@ com.yahoo.prelude.searcher.XMLStringSearcher.source string default="" ## Default docsum class the QR server should ask the backend to ## use for representing hints as default. -com.yahoo.prelude.fastsearch.FastSearcher.docsum.defaultclass string default="" +com.yahoo.prelude.fastsearch.IndexedBackend.docsum.defaultclass string default="" com.yahoo.prelude.querytransform.PhrasingSearcher.automatonfile string default="" com.yahoo.prelude.querytransform.NonPhrasingSearcher.automatonfile string default="" diff --git a/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java b/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java index f481d58d334..855a524473d 100644 --- a/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java +++ b/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java @@ -1,6 +1,7 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.prelude.cluster; +import com.yahoo.collections.TinyIdentitySet; import com.yahoo.component.annotation.Inject; import com.yahoo.component.ComponentId; import com.yahoo.component.chain.dependencies.After; @@ -10,9 +11,8 @@ import com.yahoo.container.core.documentapi.VespaDocumentAccess; import com.yahoo.container.handler.VipStatus; import com.yahoo.prelude.fastsearch.ClusterParams; import com.yahoo.prelude.fastsearch.DocumentdbInfoConfig; -import com.yahoo.prelude.fastsearch.FastSearcher; -import com.yahoo.prelude.fastsearch.SummaryParameters; -import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; +import com.yahoo.prelude.fastsearch.IndexedBackend; +import com.yahoo.prelude.fastsearch.VespaBackend; import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.Searcher; @@ -24,14 +24,17 @@ import com.yahoo.search.result.ErrorMessage; import com.yahoo.search.schema.Cluster; import com.yahoo.search.schema.SchemaInfo; import com.yahoo.search.searchchain.Execution; -import com.yahoo.vespa.streamingvisitors.StreamingSearcher; +import com.yahoo.vespa.streamingvisitors.StreamingBackend; import com.yahoo.yolean.Exceptions; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ExecutionException; @@ -40,8 +43,6 @@ import java.util.concurrent.FutureTask; import java.util.concurrent.RejectedExecutionException; import java.util.stream.Collectors; -import static com.yahoo.container.QrSearchersConfig.Searchcluster.Indexingmode.STREAMING; - /** * A searcher which forwards to a cluster of monitored native Vespa backends. * @@ -58,13 +59,12 @@ public class ClusterSearcher extends Searcher { private final String searchClusterName; // The set of document types contained in this search cluster - private final Set<String> schemas; + private final Map<String, VespaBackend> schema2Searcher; private final SchemaInfo schemaInfo; private final long maxQueryTimeout; // in milliseconds private final long maxQueryCacheTimeout; // in milliseconds - private final VespaBackEndSearcher server; private final Executor executor; private final GlobalPhaseRanker globalPhaseRanker; @@ -86,26 +86,28 @@ public class ClusterSearcher extends Searcher { searchClusterName = clusterConfig.clusterName(); QrSearchersConfig.Searchcluster searchClusterConfig = getSearchClusterConfigFromClusterName(qrsConfig, searchClusterName); this.globalPhaseRanker = globalPhaseRanker; - schemas = new LinkedHashSet<>(); + schema2Searcher = new LinkedHashMap<>(); maxQueryTimeout = ParameterParser.asMilliSeconds(clusterConfig.maxQueryTimeout(), DEFAULT_MAX_QUERY_TIMEOUT); maxQueryCacheTimeout = ParameterParser.asMilliSeconds(clusterConfig.maxQueryCacheTimeout(), DEFAULT_MAX_QUERY_CACHE_TIMEOUT); - SummaryParameters docSumParams = new SummaryParameters(qrsConfig - .com().yahoo().prelude().fastsearch().FastSearcher().docsum() - .defaultclass()); - - for (DocumentdbInfoConfig.Documentdb docDb : documentDbConfig.documentdb()) - schemas.add(docDb.name()); - - String uniqueServerId = UUID.randomUUID().toString(); - if (searchClusterConfig.indexingmode() == STREAMING) { - server = streamingCluster(uniqueServerId, searchClusterIndex, - searchClusterConfig, docSumParams, documentDbConfig, schemaInfo, access); - vipStatus.addToRotation(server.getName()); - } else { - server = searchDispatch(searchClusterIndex, searchClusterName, uniqueServerId, - docSumParams, documentDbConfig, schemaInfo, dispatchers); + VespaBackend streaming = null, indexed = null; + ClusterParams clusterParams = makeClusterParams(searchClusterIndex, qrsConfig + .com().yahoo().prelude().fastsearch().IndexedBackend().docsum() + .defaultclass(), documentDbConfig, schemaInfo); + for (DocumentdbInfoConfig.Documentdb docDb : documentDbConfig.documentdb()) { + if (docDb.mode() == DocumentdbInfoConfig.Documentdb.Mode.Enum.INDEX) { + if (indexed == null) { + indexed = searchDispatch(clusterParams, searchClusterName, dispatchers); + } + schema2Searcher.put(docDb.name(), indexed); + } else if (docDb.mode() == DocumentdbInfoConfig.Documentdb.Mode.Enum.STREAMING) { + if (streaming == null) { + streaming = streamingCluster(clusterParams, searchClusterConfig, access); + vipStatus.addToRotation(streaming.getName()); + } + schema2Searcher.put(docDb.name(), streaming); + } } } @@ -115,91 +117,88 @@ public class ClusterSearcher extends Searcher { return searchCluster; } } - return null; + throw new IllegalStateException("No configured search cluster '" + name + "' among : " + + config.searchcluster().stream().map(QrSearchersConfig.Searchcluster::name).toList()); } - private static ClusterParams makeClusterParams(int searchclusterIndex) { - return new ClusterParams("sc" + searchclusterIndex + ".num" + 0); + private static ClusterParams makeClusterParams(int searchclusterIndex, String defaultSummary, + DocumentdbInfoConfig documentDbConfig, SchemaInfo schemaInfo) + { + return new ClusterParams("sc" + searchclusterIndex + ".num" + 0, UUID.randomUUID().toString(), + defaultSummary, documentDbConfig, schemaInfo); } - private static FastSearcher searchDispatch(int searchclusterIndex, - String searchClusterName, - String serverId, - SummaryParameters docSumParams, - DocumentdbInfoConfig documentdbInfoConfig, - SchemaInfo schemaInfo, - ComponentRegistry<Dispatcher> dispatchers) { - ClusterParams clusterParams = makeClusterParams(searchclusterIndex); + private static IndexedBackend searchDispatch(ClusterParams clusterParams, + String searchClusterName, + ComponentRegistry<Dispatcher> dispatchers) + { ComponentId dispatcherComponentId = new ComponentId("dispatcher." + searchClusterName); Dispatcher dispatcher = dispatchers.getComponent(dispatcherComponentId); if (dispatcher == null) - throw new IllegalArgumentException("Configuration error: No dispatcher " + dispatcherComponentId + - " is configured"); - return new FastSearcher(serverId, dispatcher, docSumParams, clusterParams, documentdbInfoConfig, schemaInfo); + throw new IllegalArgumentException("Configuration error: No dispatcher " + dispatcherComponentId + " is configured"); + return new IndexedBackend(clusterParams, dispatcher); } - private static StreamingSearcher streamingCluster(String serverId, - int searchclusterIndex, - QrSearchersConfig.Searchcluster searchClusterConfig, - SummaryParameters docSumParams, - DocumentdbInfoConfig documentdbInfoConfig, - SchemaInfo schemaInfo, - VespaDocumentAccess access) { - if (searchClusterConfig.searchdef().size() != 1) - throw new IllegalArgumentException("Streaming search clusters can only contain a single schema but got " + - searchClusterConfig.searchdef()); - ClusterParams clusterParams = makeClusterParams(searchclusterIndex); - StreamingSearcher searcher = new StreamingSearcher(access); - searcher.setSearchClusterName(searchClusterConfig.rankprofiles_configid()); - searcher.setStorageClusterRouteSpec(searchClusterConfig.storagecluster().routespec()); - searcher.init(serverId, docSumParams, clusterParams, documentdbInfoConfig, schemaInfo); - return searcher; + private static StreamingBackend streamingCluster(ClusterParams clusterParams, + QrSearchersConfig.Searchcluster searchClusterConfig, + VespaDocumentAccess access) + { + return new StreamingBackend(clusterParams, searchClusterConfig.rankprofiles_configid(), + access, searchClusterConfig.storagecluster().routespec()); } /** Do not use, for internal testing purposes only. **/ - ClusterSearcher(SchemaInfo schemaInfo, Set<String> schemas, VespaBackEndSearcher searcher, Executor executor) { + ClusterSearcher(SchemaInfo schemaInfo, Map<String, VespaBackend> schema2Searcher, Executor executor) { this.schemaInfo = schemaInfo; searchClusterName = "testScenario"; maxQueryTimeout = DEFAULT_MAX_QUERY_TIMEOUT; maxQueryCacheTimeout = DEFAULT_MAX_QUERY_CACHE_TIMEOUT; - server = searcher; this.executor = executor; this.globalPhaseRanker = null; - this.schemas = schemas; + this.schema2Searcher = schema2Searcher; } /** Do not use, for internal testing purposes only. **/ - ClusterSearcher(SchemaInfo schemaInfo, Set<String> schemas) { - this(schemaInfo, schemas, null, null); + ClusterSearcher(SchemaInfo schemaInfo, Map<String, VespaBackend> schema2Searcher) { + this(schemaInfo, schema2Searcher, null); } @Override public Result search(Query query, Execution execution) { validateQueryTimeout(query); validateQueryCache(query); - Searcher searcher = server; - if (searcher == null) { + if (schema2Searcher.isEmpty()) { return new Result(query, ErrorMessage.createNoBackendsInService("Could not search")); } if (query.getTimeLeft() <= 0) { return new Result(query, ErrorMessage.createTimeout("No time left for searching")); } - return doSearch(searcher, query, execution); + return doSearch(query); } @Override - public void fill(com.yahoo.search.Result result, String summaryClass, Execution execution) { + public void fill(Result result, String summaryClass, Execution execution) { + fill(result, summaryClass); + } + private void fill(Result result, String summaryClass) { Query query = result.getQuery(); - - Searcher searcher = server; - if (searcher != null) { - if (query.getTimeLeft() > 0) { - searcher.fill(result, summaryClass, execution); - } else { - if (result.hits().getErrorHit() == null) { - result.hits().addError(ErrorMessage.createTimeout("No time left to get summaries, query timeout was " + - query.getTimeout() + " ms")); + var restrict = query.getModel().getRestrict(); + Collection<VespaBackend> servers = (restrict != null && ! restrict.isEmpty()) + ? query.getModel().getRestrict().stream() + .map(schema2Searcher::get) + .collect(Collectors.toCollection(TinyIdentitySet::new)) + : schema2Searcher.values().stream().collect(Collectors.toCollection(TinyIdentitySet::new)); + + if ( ! servers.isEmpty() ) { + for (var server : servers) { + if (query.getTimeLeft() > 0) { + server.fill(result, summaryClass); + } else { + if (result.hits().getErrorHit() == null) { + result.hits().addError(ErrorMessage.createTimeout("No time left to get summaries, query timeout was " + + query.getTimeout() + " ms")); + } } } } else { @@ -230,22 +229,21 @@ public class ClusterSearcher extends Searcher { query.getRanking().setQueryCache(false); } - private Result doSearch(Searcher searcher, Query query, Execution execution) { - if (schemas.size() > 1) { - return searchMultipleDocumentTypes(searcher, query, execution); + private Result doSearch(Query query) { + if (schema2Searcher.size() > 1) { + return searchMultipleDocumentTypes(query); } else { - String docType = schemas.iterator().next(); - query.getModel().setRestrict(docType); - return perSchemaSearch(searcher, query, execution); + String schema = schema2Searcher.keySet().iterator().next(); + query.getModel().setRestrict(schema); + return perSchemaSearch(schema, query); } } - private Result perSchemaSearch(Searcher searcher, Query query, Execution execution) { + private Result perSchemaSearch(String schema, Query query) { Set<String> restrict = query.getModel().getRestrict(); if (restrict.size() != 1) { throw new IllegalStateException("perSchemaSearch must always be called with 1 schema, got: " + restrict.size()); } - String schema = restrict.iterator().next(); int rerankCount = globalPhaseRanker != null ? globalPhaseRanker.getRerankCount(query, schema) : 0; boolean useGlobalPhase = rerankCount > 0; final int wantOffset = query.getOffset(); @@ -257,7 +255,7 @@ public class ClusterSearcher extends Searcher { query.setOffset(0); query.setHits(useHits); } - Result result = searcher.search(query, execution); + Result result = schema2Searcher.get(schema).search(schema, query); if (useGlobalPhase) { globalPhaseRanker.rerankHits(query, result, schema); result.hits().trim(wantOffset, wantHits); @@ -284,16 +282,17 @@ public class ClusterSearcher extends Searcher { } } - private Result searchMultipleDocumentTypes(Searcher searcher, Query query, Execution execution) { + private Result searchMultipleDocumentTypes(Query query) { Set<String> schemas = resolveSchemas(query); - List<Query> queries = createQueries(query, schemas); - if (queries.size() == 1) { - return perSchemaSearch(searcher, queries.get(0), execution); + Map<String, Query> schemaQueries = createQueries(query, schemas); + if (schemaQueries.size() == 1) { + var entry = schemaQueries.entrySet().iterator().next(); + return perSchemaSearch(entry.getKey(), entry.getValue()); } else { Result mergedResult = new Result(query); - List<FutureTask<Result>> pending = new ArrayList<>(queries.size()); - for (Query q : queries) { - FutureTask<Result> task = new FutureTask<>(() -> perSchemaSearch(searcher, q, execution)); + List<FutureTask<Result>> pending = new ArrayList<>(schemaQueries.size()); + for (var entry : schemaQueries.entrySet()) { + FutureTask<Result> task = new FutureTask<>(() -> perSchemaSearch(entry.getKey(), entry.getValue())); try { executor.execute(task); pending.add(task); @@ -309,7 +308,7 @@ public class ClusterSearcher extends Searcher { if (query.getOffset() > 0 || query.getHits() < mergedResult.hits().size()) { if (mergedResult.getHitOrderer() != null) { // Make sure we have the necessary data for sorting - searcher.fill(mergedResult, VespaBackEndSearcher.SORTABLE_ATTRIBUTES_SUMMARY_CLASS, execution); + fill(mergedResult, VespaBackend.SORTABLE_ATTRIBUTES_SUMMARY_CLASS); } mergedResult.hits().trim(query.getOffset(), query.getHits()); query.setOffset(0); // Needed when doing a trim @@ -326,7 +325,7 @@ public class ClusterSearcher extends Searcher { candidates.addAll(cluster.schemas()); } return (candidates.isEmpty() ? sources : candidates).stream() - .filter(schemas::contains).collect(Collectors.toUnmodifiableSet()); + .filter(schema2Searcher::containsKey).collect(Collectors.toUnmodifiableSet()); } Set<String> resolveSchemas(Query query) { @@ -334,7 +333,7 @@ public class ClusterSearcher extends Searcher { if (restrict == null || restrict.isEmpty()) { Set<String> sources = query.getModel().getSources(); return (sources == null || sources.isEmpty()) - ? schemas + ? schema2Searcher.keySet() : resolveSourceSubset(sources); } else { return filterValidDocumentTypes(restrict); @@ -344,34 +343,40 @@ public class ClusterSearcher extends Searcher { private Set<String> filterValidDocumentTypes(Collection<String> restrict) { Set<String> retval = new LinkedHashSet<>(); for (String docType : restrict) { - if (docType != null && schemas.contains(docType)) { + if (docType != null && schema2Searcher.containsKey(docType)) { retval.add(docType); } } return retval; } - private List<Query> createQueries(Query query, Set<String> docTypes) { + private Map<String, Query> createQueries(Query query, Set<String> schemas) { query.getModel().getQueryTree(); // performance: parse query before cloning such that it is only done once - List<Query> retval = new ArrayList<>(docTypes.size()); - if (docTypes.size() == 1) { - query.getModel().setRestrict(docTypes.iterator().next()); - retval.add(query); - } else if ( ! docTypes.isEmpty() ) { - for (String docType : docTypes) { + if (schemas.size() == 1) { + String schema = schemas.iterator().next(); + query.getModel().setRestrict(schema); + return Map.of(schema, query); + } else if ( ! schemas.isEmpty() ) { + var schemaQueries = new HashMap<String, Query>(); + for (String schema : schemas) { Query q = query.clone(); q.setOffset(0); q.setHits(query.getOffset() + query.getHits()); - q.getModel().setRestrict(docType); - retval.add(q); + q.getModel().setRestrict(schema); + schemaQueries.put(schema, q); } + return schemaQueries; } - return retval; + return Map.of(); } @Override public void deconstruct() { - if (server != null) { + Map<String, VespaBackend> servers = new HashMap<>(); + for (var server : schema2Searcher.values()) { + servers.put(server.getName(), server); + } + for (var server : servers.values()) { server.shutDown(); } } diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/BoolField.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/BoolField.java index c0f42f6924b..6a980c37f4e 100644 --- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/BoolField.java +++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/BoolField.java @@ -7,7 +7,6 @@ package com.yahoo.prelude.fastsearch; import com.yahoo.data.access.Inspector; -import com.yahoo.search.result.NanNumber; /** * @author bratseth diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/ClusterParams.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/ClusterParams.java index c34187e576b..2987500fdb3 100644 --- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/ClusterParams.java +++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/ClusterParams.java @@ -1,21 +1,40 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.prelude.fastsearch; +import com.yahoo.search.schema.SchemaInfo; + /** * Helper class for carrying around cluster-related - * config parameters to the FastSearcher class. + * config parameters to the VespaBackend class. * * @author arnej27959 */ public class ClusterParams { - public final String searcherName; + private final String searcherName; + private final String serverId; + private final String defaultSummary; + private final DocumentdbInfoConfig documentdbInfoConfig; + private final SchemaInfo schemaInfo; - /** - * Make up full ClusterParams - */ public ClusterParams(String name) { + this(name, "server.0", null, null, null); + } + public ClusterParams(String name, String serverId, String defaultSummary, + DocumentdbInfoConfig documentdbInfoConfig, SchemaInfo schemaInfo) { this.searcherName = name; + this.serverId = serverId; + if (defaultSummary != null && defaultSummary.isEmpty()) + this.defaultSummary = null; + else + this.defaultSummary = defaultSummary; + this.documentdbInfoConfig = documentdbInfoConfig; + this.schemaInfo = schemaInfo; } + public String getServerId() { return serverId; } + public String getSearcherName() { return searcherName; } + public String getDefaultSummary() { return defaultSummary; } + public DocumentdbInfoConfig getDocumentdbInfoConfig() { return documentdbInfoConfig; } + public SchemaInfo getSchemaInfo() { return schemaInfo; } } diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/IndexedBackend.java index ddb36e007d3..9836934acc1 100644 --- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastSearcher.java +++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/IndexedBackend.java @@ -1,8 +1,6 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.prelude.fastsearch; -import com.yahoo.prelude.Ping; -import com.yahoo.prelude.Pong; import com.yahoo.prelude.querytransform.QueryRewrite; import com.yahoo.search.Query; import com.yahoo.search.Result; @@ -15,8 +13,6 @@ import com.yahoo.search.query.Ranking; import com.yahoo.search.result.ErrorMessage; import com.yahoo.search.result.Hit; import com.yahoo.search.result.HitGroup; -import com.yahoo.search.schema.SchemaInfo; -import com.yahoo.search.searchchain.Execution; import java.io.IOException; import java.util.Optional; @@ -33,7 +29,7 @@ import java.util.Optional; // errors on results and returning them. It could be handy to create a QueryHandlingErrorException // or similar which could wrap an error message, and then just always throw that and // catch and unwrap into a results with an error in high level methods. -Jon -public class FastSearcher extends VespaBackEndSearcher { +public class IndexedBackend extends VespaBackend { /** Used to dispatch directly to search nodes over RPC, replacing the old fnet communication path */ private final Dispatcher dispatcher; @@ -41,34 +37,18 @@ public class FastSearcher extends VespaBackEndSearcher { /** * Creates a Fastsearcher. * - * @param serverId the resource pool used to create direct connections to the local search nodes when - * bypassing the dispatch node * @param dispatcher the dispatcher used (when enabled) to send summary requests over the rpc protocol. * Eventually we will move everything to this protocol and never use dispatch nodes. * At that point we won't need a cluster searcher above this to select and pass the right * backend. - * @param docSumParams document summary parameters * @param clusterParams the cluster number, and other cluster backend parameters - * @param documentdbInfoConfig document database parameters */ - public FastSearcher(String serverId, - Dispatcher dispatcher, - SummaryParameters docSumParams, - ClusterParams clusterParams, - DocumentdbInfoConfig documentdbInfoConfig, - SchemaInfo schemaInfo) { - init(serverId, docSumParams, clusterParams, documentdbInfoConfig, schemaInfo); + public IndexedBackend(ClusterParams clusterParams, Dispatcher dispatcher) + { + super(clusterParams); this.dispatcher = dispatcher; } - /** - * Pings the backend. Does not propagate to other searchers. - */ - @Override - public Pong ping(Ping ping, Execution execution) { - throw new IllegalStateException("This ping should not have been called."); - } - @Override protected void transformQuery(Query query) { QueryRewrite.rewriteSddocname(query); @@ -83,11 +63,11 @@ public class FastSearcher extends VespaBackEndSearcher { } @Override - public Result doSearch2(Query query, Execution execution) { + public Result doSearch2(String schema, Query query) { if (dispatcher.allGroupsHaveSize1()) forceSinglePassGrouping(query); try (SearchInvoker invoker = getSearchInvoker(query)) { - Result result = invoker.search(query, execution); + Result result = invoker.search(query); injectSource(result.hits()); if (query.properties().getBoolean(Ranking.RANKFEATURES, false)) { @@ -97,7 +77,7 @@ public class FastSearcher extends VespaBackEndSearcher { // contain the data we need. If we fetch the default // one we end up fetching docsums twice unless the // user also requested the default one. - fill(result, query.getPresentation().getSummary(), execution); // ARGH + fill(result, query.getPresentation().getSummary()); // ARGH } return result; } catch (TimeoutException e) { diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/SummaryParameters.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/SummaryParameters.java deleted file mode 100644 index 8751a730229..00000000000 --- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/SummaryParameters.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.fastsearch; - - -/** - * Wrapper for document summary parameters and configuration. - * - * @author Steinar Knutsen - */ -public class SummaryParameters { - - public final String defaultClass; - - public SummaryParameters(String defaultClass) { - if (defaultClass != null && defaultClass.isEmpty()) - this.defaultClass = null; - else - this.defaultClass = defaultClass; - } - -} diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackend.java index 2e635d21f01..761cb22be57 100644 --- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java +++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackend.java @@ -12,41 +12,37 @@ import com.yahoo.prelude.querytransform.QueryRewrite; import com.yahoo.protect.Validator; import com.yahoo.search.Query; import com.yahoo.search.Result; -import com.yahoo.search.cluster.PingableSearcher; import com.yahoo.search.schema.RankProfile; import com.yahoo.search.grouping.vespa.GroupingExecutor; import com.yahoo.search.result.ErrorMessage; import com.yahoo.search.result.Hit; -import com.yahoo.search.schema.SchemaInfo; -import com.yahoo.search.searchchain.Execution; import com.yahoo.searchlib.aggregation.Grouping; import java.util.ArrayList; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.logging.Logger; +import java.util.stream.Collectors; /** * Superclass for backend searchers. * * @author baldersheim */ -public abstract class VespaBackEndSearcher extends PingableSearcher { +public abstract class VespaBackend { /** for vespa-internal use only; consider renaming the summary class */ public static final String SORTABLE_ATTRIBUTES_SUMMARY_CLASS = "attributeprefetch"; - private String serverId; + private final String serverId; /** The set of all document databases available in the backend handled by this searcher */ - private final Map<String, DocumentDatabase> documentDbs = new LinkedHashMap<>(); - private DocumentDatabase defaultDocumentDb = null; + private final Map<String, DocumentDatabase> documentDbs; + private final DocumentDatabase defaultDocumentDb; /** Default docsum class. null means "unset" and is the default value */ - private String defaultDocsumClass = null; + private final String defaultDocsumClass; /** Returns an iterator which returns all hits below this result **/ private static Iterator<Hit> hitIterator(Result result) { @@ -54,24 +50,36 @@ public abstract class VespaBackEndSearcher extends PingableSearcher { } /** The name of this source */ - private String name; + private final String name; - public final String getName() { return name; } - protected final String getDefaultDocsumClass() { return defaultDocsumClass; } + protected VespaBackend(ClusterParams clusterParams) { + this.serverId = clusterParams.getServerId(); + this.name = clusterParams.getSearcherName(); + this.defaultDocsumClass = clusterParams.getDefaultSummary(); - /** Sets default document summary class. Default is null */ - private void setDefaultDocsumClass(String docsumClass) { defaultDocsumClass = docsumClass; } + Validator.ensureNotNull("Name of Vespa backend integration", name); + + List<DocumentDatabase> dbs = new ArrayList<>(); + if (clusterParams.getDocumentdbInfoConfig() != null) { + for (DocumentdbInfoConfig.Documentdb docDb : clusterParams.getDocumentdbInfoConfig().documentdb()) { + DocumentDatabase db = new DocumentDatabase(clusterParams.getSchemaInfo().schemas().get(docDb.name())); + dbs.add(db); + } + } + this.defaultDocumentDb = dbs.isEmpty() ? null : dbs.get(0); + this.documentDbs = dbs.stream().collect(Collectors.toMap(db -> db.schema().name(), db -> db)); + } - public final Logger getLogger() { return super.getLogger(); } + public final String getName() { return name; } + protected final String getDefaultDocsumClass() { return defaultDocsumClass; } /** * Searches a search cluster * This is an endpoint - searchers will never propagate the search to any nested searcher. * * @param query the query to search - * @param execution the query execution context */ - protected abstract Result doSearch2(Query query, Execution execution); + protected abstract Result doSearch2(String schema, Query query); protected abstract void doPartialFill(Result result, String summaryClass); @@ -133,29 +141,9 @@ public abstract class VespaBackEndSearcher extends PingableSearcher { } } - public final void init(String serverId, SummaryParameters docSumParams, ClusterParams clusterParams, - DocumentdbInfoConfig documentdbInfoConfig, SchemaInfo schemaInfo) { - this.serverId = serverId; - this.name = clusterParams.searcherName; - - Validator.ensureNotNull("Name of Vespa backend integration", getName()); - - setDefaultDocsumClass(docSumParams.defaultClass); - - if (documentdbInfoConfig != null) { - for (DocumentdbInfoConfig.Documentdb docDb : documentdbInfoConfig.documentdb()) { - DocumentDatabase db = new DocumentDatabase(schemaInfo.schemas().get(docDb.name())); - if (documentDbs.isEmpty()) - defaultDocumentDb = db; - documentDbs.put(docDb.name(), db); - } - } - } - protected void transformQuery(Query query) { } - @Override - public Result search(Query query, Execution execution) { + public Result search(String schema, Query query) { // query root should not be null here Item root = query.getModel().getQueryTree().getRoot(); if (root == null || root instanceof NullItem) { @@ -183,7 +171,7 @@ public abstract class VespaBackEndSearcher extends PingableSearcher { if (root == null || root instanceof NullItem) // root can become null after resolving and transformation? return new Result(query); - Result result = doSearch2(query, execution); + Result result = doSearch2(schema, query); if (query.getTrace().getLevel() >= 1) query.trace(getName() + " dispatch response: " + result, false, 1); @@ -191,7 +179,7 @@ public abstract class VespaBackEndSearcher extends PingableSearcher { return result; } - private List<Result> partitionHits(Result result, String summaryClass) { + private static List<Result> partitionHits(Result result, String summaryClass) { List<Result> parts = new ArrayList<>(); TinyIdentitySet<Query> queryMap = new TinyIdentitySet<>(4); @@ -217,8 +205,8 @@ public abstract class VespaBackEndSearcher extends PingableSearcher { return parts; } - @Override - public void fill(Result result, String summaryClass, Execution execution) { + //TODO Add schema here too. + public void fill(Result result, String summaryClass) { if (result.isFilled(summaryClass)) return; // TODO: Checked in the superclass - remove List<Result> parts = partitionHits(result, summaryClass); diff --git a/container-search/src/main/java/com/yahoo/prelude/searcher/BlendingSearcher.java b/container-search/src/main/java/com/yahoo/prelude/searcher/BlendingSearcher.java index 1128ad9570d..634a16d1dee 100644 --- a/container-search/src/main/java/com/yahoo/prelude/searcher/BlendingSearcher.java +++ b/container-search/src/main/java/com/yahoo/prelude/searcher/BlendingSearcher.java @@ -8,7 +8,7 @@ import com.yahoo.component.chain.dependencies.After; import com.yahoo.component.chain.dependencies.Before; import com.yahoo.component.chain.dependencies.Provides; import com.yahoo.container.QrSearchersConfig; -import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; +import com.yahoo.prelude.fastsearch.VespaBackend; import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.Searcher; @@ -115,7 +115,7 @@ public class BlendingSearcher extends Searcher { private Result sortAndTrimResults(Result result, Query q, int offset, int hits, Execution execution) { if (q.getRanking().getSorting() != null) { // TODO: remove or rename this internal summary class for Vespa 9 - execution.fill(result, VespaBackEndSearcher.SORTABLE_ATTRIBUTES_SUMMARY_CLASS); + execution.fill(result, VespaBackend.SORTABLE_ATTRIBUTES_SUMMARY_CLASS); result.hits().sort(); } result.hits().trim(offset, hits); diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java b/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java index 8ec88bd7f45..1689f6d246e 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java @@ -6,7 +6,7 @@ import com.yahoo.component.ComponentId; import com.yahoo.component.annotation.Inject; import com.yahoo.compress.Compressor; import com.yahoo.container.handler.VipStatus; -import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; +import com.yahoo.prelude.fastsearch.VespaBackend; import com.yahoo.processing.request.CompoundName; import com.yahoo.search.Query; import com.yahoo.search.Result; @@ -256,13 +256,13 @@ public class Dispatcher extends AbstractComponent { } } - public FillInvoker getFillInvoker(Result result, VespaBackEndSearcher searcher) { + public FillInvoker getFillInvoker(Result result, VespaBackend searcher) { try (var items = volatileItems()) { // Take a snapshot, and release it when we're done. return items.register(items.get().invokerFactory.createFillInvoker(searcher, result)); } } - public SearchInvoker getSearchInvoker(Query query, VespaBackEndSearcher searcher) { + public SearchInvoker getSearchInvoker(Query query, VespaBackend searcher) { try (var items = volatileItems()) { // Take a snapshot, and release it when we're done. int maxHitsPerNode = dispatchConfig.maxHitsPerNode(); SearchInvoker invoker = getSearchPathInvoker(query, searcher, searchCluster.groupList(), items.get().invokerFactory, maxHitsPerNode) @@ -277,7 +277,7 @@ public class Dispatcher extends AbstractComponent { } /** Builds an invoker based on searchpath */ - private static Optional<SearchInvoker> getSearchPathInvoker(Query query, VespaBackEndSearcher searcher, SearchGroups cluster, + private static Optional<SearchInvoker> getSearchPathInvoker(Query query, VespaBackend searcher, SearchGroups cluster, InvokerFactory invokerFactory, int maxHitsPerNode) { String searchPath = query.getModel().getSearchPath(); if (searchPath == null) return Optional.empty(); @@ -297,7 +297,7 @@ public class Dispatcher extends AbstractComponent { } } - private static SearchInvoker getInternalInvoker(Query query, VespaBackEndSearcher searcher, SearchCluster cluster, + private static SearchInvoker getInternalInvoker(Query query, VespaBackend searcher, SearchCluster cluster, LoadBalancer loadBalancer, InvokerFactory invokerFactory, int maxHitsPerNode) { Optional<Node> directNode = cluster.localCorpusDispatchTarget(); if (directNode.isPresent()) { diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java index be8524bedd2..a246589ec7e 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java @@ -111,9 +111,9 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM } @Override - protected InvokerResult getSearchResult(Execution execution) throws IOException { + protected InvokerResult getSearchResult() throws IOException { InvokerResult result = new InvokerResult(query, query.getHits()); - List<LeanHit> merged = Collections.emptyList(); + List<LeanHit> merged = List.of(); long nextTimeout = query.getTimeLeft(); var groupingResultAggregator = new GroupingResultAggregator(); try { @@ -124,7 +124,7 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM coverageAggregator.getAnsweredNodes() + " responses received"); break; } else { - InvokerResult toMerge = invoker.getSearchResult(execution); + InvokerResult toMerge = invoker.getSearchResult(); merged = mergeResult(result.getResult(), toMerge, merged, groupingResultAggregator); ejectInvoker(invoker); } diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/InvokerFactory.java b/container-search/src/main/java/com/yahoo/search/dispatch/InvokerFactory.java index f1d58122570..d7fad148c8c 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/InvokerFactory.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/InvokerFactory.java @@ -2,7 +2,7 @@ package com.yahoo.search.dispatch; import com.yahoo.concurrent.Timer; -import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; +import com.yahoo.prelude.fastsearch.VespaBackend; import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.dispatch.searchcluster.Group; @@ -34,12 +34,12 @@ public abstract class InvokerFactory { this.hitEstimator = new TopKEstimator(30.0, dispatchConfig.topKProbability(), SKEW_FACTOR); } - protected abstract Optional<SearchInvoker> createNodeSearchInvoker(VespaBackEndSearcher searcher, + protected abstract Optional<SearchInvoker> createNodeSearchInvoker(VespaBackend searcher, Query query, int maxHits, Node node); - public abstract FillInvoker createFillInvoker(VespaBackEndSearcher searcher, Result result); + public abstract FillInvoker createFillInvoker(VespaBackend searcher, Result result); /** * Creates a {@link SearchInvoker} for a list of content nodes. @@ -52,7 +52,7 @@ public abstract class InvokerFactory { * @return the invoker or empty if some node in the * list is invalid and the remaining coverage is not sufficient */ - Optional<SearchInvoker> createSearchInvoker(VespaBackEndSearcher searcher, + Optional<SearchInvoker> createSearchInvoker(VespaBackend searcher, Query query, List<Node> nodes, boolean acceptIncompleteCoverage, diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/SearchErrorInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/SearchErrorInvoker.java index b494b5b3819..74da2388155 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/SearchErrorInvoker.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/SearchErrorInvoker.java @@ -35,7 +35,7 @@ public class SearchErrorInvoker extends SearchInvoker { } @Override - protected Object sendSearchRequest(Query query, Object context) throws IOException { + protected Object sendSearchRequest(Query query, Object context) { this.query = query; if (monitor != null) { monitor.responseAvailable(this); @@ -44,7 +44,7 @@ public class SearchErrorInvoker extends SearchInvoker { } @Override - protected InvokerResult getSearchResult(Execution execution) throws IOException { + protected InvokerResult getSearchResult() { Result res = new Result(query, message); if (coverage != null) { res.setCoverage(coverage); diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/SearchInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/SearchInvoker.java index ad332494179..4ad89674b7b 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/SearchInvoker.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/SearchInvoker.java @@ -31,9 +31,9 @@ public abstract class SearchInvoker extends CloseableInvoker { * nodes, the provided {@link Execution} may be used to retrieve document summaries required * for correct result windowing. */ - public Result search(Query query, Execution execution) throws IOException { + public Result search(Query query) throws IOException { sendSearchRequest(query, null); - InvokerResult result = getSearchResult(execution); + InvokerResult result = getSearchResult(); setFinalStatus(result.getResult().hits().getError() == null); result.complete(); return result.getResult(); @@ -48,7 +48,7 @@ public abstract class SearchInvoker extends CloseableInvoker { */ protected abstract Object sendSearchRequest(Query query, Object context) throws IOException; - protected abstract InvokerResult getSearchResult(Execution execution) throws IOException; + protected abstract InvokerResult getSearchResult() throws IOException; protected void setMonitor(ResponseMonitor<SearchInvoker> monitor) { this.monitor = monitor; diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java index 9da4c91cd16..284b4a4fcbc 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java @@ -14,7 +14,7 @@ import com.yahoo.io.GrowableByteBuffer; import com.yahoo.prelude.fastsearch.DocumentDatabase; import com.yahoo.prelude.fastsearch.FastHit; import com.yahoo.prelude.fastsearch.GroupingListHit; -import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; +import com.yahoo.prelude.fastsearch.VespaBackend; import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.dispatch.InvokerResult; @@ -227,7 +227,7 @@ public class ProtobufSerialization { return convertFromResult(searchResult).toByteArray(); } - static InvokerResult deserializeToSearchResult(byte[] payload, Query query, VespaBackEndSearcher searcher, int partId, int distKey) + static InvokerResult deserializeToSearchResult(byte[] payload, Query query, VespaBackend searcher, int partId, int distKey) throws InvalidProtocolBufferException { var protobuf = SearchProtocol.SearchReply.parseFrom(payload); return convertToResult(query, protobuf, searcher.getDocumentDatabase(query), partId, distKey); diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcInvokerFactory.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcInvokerFactory.java index 8221391afe6..9fd602032e9 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcInvokerFactory.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcInvokerFactory.java @@ -1,7 +1,7 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.search.dispatch.rpc; -import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; +import com.yahoo.prelude.fastsearch.VespaBackend; import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.dispatch.FillInvoker; @@ -37,12 +37,12 @@ public class RpcInvokerFactory extends InvokerFactory { } @Override - protected Optional<SearchInvoker> createNodeSearchInvoker(VespaBackEndSearcher searcher, Query query, int maxHits, Node node) { + protected Optional<SearchInvoker> createNodeSearchInvoker(VespaBackend searcher, Query query, int maxHits, Node node) { return Optional.of(new RpcSearchInvoker(searcher, compressor, node, rpcResourcePool, maxHits)); } @Override - public FillInvoker createFillInvoker(VespaBackEndSearcher searcher, Result result) { + public FillInvoker createFillInvoker(VespaBackend searcher, Result result) { Query query = result.getQuery(); boolean summaryNeedsQuery = searcher.summaryNeedsQuery(query); diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java index e34e5c97bc4..fb028358caf 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java @@ -2,14 +2,13 @@ package com.yahoo.search.dispatch.rpc; import com.yahoo.compress.Compressor; -import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; +import com.yahoo.prelude.fastsearch.VespaBackend; import com.yahoo.search.Query; import com.yahoo.search.dispatch.InvokerResult; import com.yahoo.search.dispatch.SearchInvoker; import com.yahoo.search.dispatch.rpc.Client.ProtobufResponse; import com.yahoo.search.dispatch.searchcluster.Node; import com.yahoo.search.result.ErrorMessage; -import com.yahoo.search.searchchain.Execution; import java.io.IOException; import java.util.Optional; @@ -26,7 +25,7 @@ public class RpcSearchInvoker extends SearchInvoker implements Client.ResponseRe private static final String RPC_METHOD = "vespa.searchprotocol.search"; - private final VespaBackEndSearcher searcher; + private final VespaBackend searcher; private final Node node; private final RpcConnectionPool resourcePool; private final BlockingQueue<Client.ResponseOrError<ProtobufResponse>> responses; @@ -35,7 +34,7 @@ public class RpcSearchInvoker extends SearchInvoker implements Client.ResponseRe private Query query; - RpcSearchInvoker(VespaBackEndSearcher searcher, CompressPayload compressor, Node node, RpcConnectionPool resourcePool, int maxHits) { + RpcSearchInvoker(VespaBackend searcher, CompressPayload compressor, Node node, RpcConnectionPool resourcePool, int maxHits) { super(Optional.of(node)); this.searcher = searcher; this.node = node; @@ -86,7 +85,7 @@ public class RpcSearchInvoker extends SearchInvoker implements Client.ResponseRe } @Override - protected InvokerResult getSearchResult(Execution execution) throws IOException { + protected InvokerResult getSearchResult() throws IOException { long timeLeftMs = query.getTimeLeft(); if (timeLeftMs <= 0) { return errorResult(query, ErrorMessage.createTimeout("Timeout while waiting for " + getName())); diff --git a/container-search/src/main/java/com/yahoo/search/searchchain/Execution.java b/container-search/src/main/java/com/yahoo/search/searchchain/Execution.java index 0b3179f5ad6..6eb69c76afd 100644 --- a/container-search/src/main/java/com/yahoo/search/searchchain/Execution.java +++ b/container-search/src/main/java/com/yahoo/search/searchchain/Execution.java @@ -8,7 +8,7 @@ import com.yahoo.prelude.IndexFacts; import com.yahoo.prelude.Ping; import com.yahoo.prelude.Pong; import com.yahoo.language.process.SpecialTokenRegistry; -import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; +import com.yahoo.prelude.fastsearch.VespaBackend; import com.yahoo.processing.Processor; import com.yahoo.processing.Request; import com.yahoo.processing.Response; @@ -534,7 +534,7 @@ public class Execution extends com.yahoo.processing.execution.Execution { */ @Deprecated // TODO Remove on Vespa 9. public void fillAttributes(Result result) { - fill(result, VespaBackEndSearcher.SORTABLE_ATTRIBUTES_SUMMARY_CLASS); + fill(result, VespaBackend.SORTABLE_ATTRIBUTES_SUMMARY_CLASS); } /** diff --git a/container-search/src/main/java/com/yahoo/search/yql/FieldFiller.java b/container-search/src/main/java/com/yahoo/search/yql/FieldFiller.java index 0685a77d7a9..64a989fd0e7 100644 --- a/container-search/src/main/java/com/yahoo/search/yql/FieldFiller.java +++ b/container-search/src/main/java/com/yahoo/search/yql/FieldFiller.java @@ -5,7 +5,7 @@ import java.util.HashSet; import java.util.Set; import com.yahoo.component.chain.dependencies.After; -import static com.yahoo.prelude.fastsearch.VespaBackEndSearcher.SORTABLE_ATTRIBUTES_SUMMARY_CLASS; +import static com.yahoo.prelude.fastsearch.VespaBackend.SORTABLE_ATTRIBUTES_SUMMARY_CLASS; import com.yahoo.processing.request.CompoundName; import com.yahoo.search.Query; import com.yahoo.search.Result; diff --git a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/MetricsSearcher.java b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/MetricsSearcher.java index 5fef90c2012..e367bb58f80 100644 --- a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/MetricsSearcher.java +++ b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/MetricsSearcher.java @@ -15,7 +15,7 @@ import java.util.Map; import java.util.TreeMap; import java.util.logging.Logger; -import static com.yahoo.vespa.streamingvisitors.StreamingSearcher.STREAMING_STATISTICS; +import static com.yahoo.vespa.streamingvisitors.StreamingBackend.STREAMING_STATISTICS; /** * Generates mail-specific query metrics. diff --git a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/StreamingSearcher.java b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/StreamingBackend.java index 180fdc389d8..6b81ab0fa97 100644 --- a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/StreamingSearcher.java +++ b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/StreamingBackend.java @@ -11,10 +11,11 @@ import com.yahoo.fs4.DocsumPacket; import com.yahoo.messagebus.routing.Route; import com.yahoo.prelude.Ping; import com.yahoo.prelude.Pong; +import com.yahoo.prelude.fastsearch.ClusterParams; import com.yahoo.prelude.fastsearch.FastHit; import com.yahoo.prelude.fastsearch.GroupingListHit; import com.yahoo.prelude.fastsearch.TimeoutException; -import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; +import com.yahoo.prelude.fastsearch.VespaBackend; import com.yahoo.processing.request.CompoundName; import com.yahoo.search.Query; import com.yahoo.search.Result; @@ -44,8 +45,9 @@ import java.util.logging.Logger; * @author baldersheim * @author Ulf Carlin */ -public class StreamingSearcher extends VespaBackEndSearcher { +public class StreamingBackend extends VespaBackend { + private static final Logger log = Logger.getLogger(StreamingBackend.class.getName()); private static final CompoundName streamingUserid = CompoundName.from("streaming.userid"); private static final CompoundName streamingGroupname = CompoundName.from("streaming.groupname"); private static final CompoundName streamingSelection = CompoundName.from("streaming.selection"); @@ -53,41 +55,35 @@ public class StreamingSearcher extends VespaBackEndSearcher { static final String STREAMING_STATISTICS = "streaming.statistics"; private final VisitorFactory visitorFactory; private final TracingOptions tracingOptions; - private static final Logger log = Logger.getLogger(StreamingSearcher.class.getName()); - private Route route; + private final Route route; /** The configId used to access the searchcluster. */ - private String searchClusterName = null; + private final String searchClusterName; /** The route to the storage cluster. */ - private String storageClusterRouteSpec = null; + private final String storageClusterRouteSpec; - StreamingSearcher(VisitorFactory visitorFactory) { - this.visitorFactory = visitorFactory; - tracingOptions = TracingOptions.DEFAULT; + StreamingBackend(ClusterParams clusterParams, String searchClusterName, VisitorFactory visitorFactory, String storageClusterRouteSpec) { + this(clusterParams, searchClusterName, visitorFactory, storageClusterRouteSpec, TracingOptions.DEFAULT); } - StreamingSearcher(VisitorFactory visitorFactory, TracingOptions tracingOptions) { + StreamingBackend(ClusterParams clusterParams, String searchClusterName, VisitorFactory visitorFactory, String storageClusterRouteSpec, TracingOptions tracingOptions) { + super(clusterParams); this.visitorFactory = visitorFactory; this.tracingOptions = tracingOptions; + this.searchClusterName = searchClusterName; + this.storageClusterRouteSpec = storageClusterRouteSpec; + this.route = Route.parse(storageClusterRouteSpec); } - public StreamingSearcher(VespaDocumentAccess access) { - this(new VespaVisitorFactory(access)); + public StreamingBackend(ClusterParams clusterParams, String searchClusterName, VespaDocumentAccess access, String storageClusterRouteSpec) { + this(clusterParams, searchClusterName, new VespaVisitorFactory(access), storageClusterRouteSpec); } private String getSearchClusterName() { return searchClusterName; } - private String getStorageClusterRouteSpec() { return storageClusterRouteSpec; } - public final void setSearchClusterName(String clusterName) { this.searchClusterName = clusterName; } - public final void setStorageClusterRouteSpec(String storageClusterRouteSpec) { - this.storageClusterRouteSpec = storageClusterRouteSpec; - } - - @Override - protected void doPartialFill(Result result, String summaryClass) { - } + @Override protected void doPartialFill(Result result, String summaryClass) { } private double durationInMillisFromNanoTime(long startTimeNanos) { return (tracingOptions.getClock().nanoTimeNow() - startTimeNanos) / (double)TimeUnit.MILLISECONDS.toNanos(1); @@ -126,7 +122,7 @@ public class StreamingSearcher extends VespaBackEndSearcher { } @Override - public Result doSearch2(Query query, Execution execution) { + public Result doSearch2(String schema, Query query) { if (query.getTimeLeft() <= 0) return new Result(query, ErrorMessage.createTimeout(String.format("No time left for searching (timeout=%d)", query.getTimeout()))); @@ -135,8 +131,6 @@ public class StreamingSearcher extends VespaBackEndSearcher { return new Result(query, ErrorMessage.createIllegalQuery("Streaming search requires either " + "streaming.groupname or streaming.selection")); } - // Cluster searcher guarantees that there will be one, and only one schema here - String schema = query.getModel().getRestrict().iterator().next(); if (query.getTrace().isTraceable(4)) query.trace("Routing to search cluster " + getSearchClusterName() + " and document type " + schema, 4); @@ -167,11 +161,7 @@ public class StreamingSearcher extends VespaBackEndSearcher { } private void initializeMissingQueryFields(Query query) { - lazyTrace(query, 7, "Routing to storage cluster ", getStorageClusterRouteSpec()); - - if (route == null) { - route = Route.parse(getStorageClusterRouteSpec()); - } + lazyTrace(query, 7, "Routing to storage cluster ", storageClusterRouteSpec); lazyTrace(query, 8, "Route is ", route); lazyTrace(query, 7, "doSearch2(): query docsum class=", @@ -264,7 +254,7 @@ public class StreamingSearcher extends VespaBackEndSearcher { lazyTrace(query, 8, "Returning result ", result); if (skippedHits > 0) { - getLogger().info("skipping " + skippedHits + " hits for query: " + result.getQuery()); + log.info("skipping " + skippedHits + " hits for query: " + result.getQuery()); result.hits().addError(ErrorMessage.createTimeout("Missing hit summary data for " + skippedHits + " hits")); } @@ -366,8 +356,8 @@ public class StreamingSearcher extends VespaBackEndSearcher { } @Override - public Visitor createVisitor(Query query, String searchCluster, Route route, String documentType, int traceLevelOverride) { - return new StreamingVisitor(query, searchCluster, route, documentType, this, traceLevelOverride); + public Visitor createVisitor(Query query, String searchCluster, Route route, String schema, int traceLevelOverride) { + return new StreamingVisitor(query, searchCluster, route, schema, this, traceLevelOverride); } } diff --git a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/StreamingVisitor.java b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/StreamingVisitor.java index 658eea0b526..bb155e3f934 100644 --- a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/StreamingVisitor.java +++ b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/StreamingVisitor.java @@ -28,6 +28,7 @@ import com.yahoo.vdslib.VisitorStatistics; import com.yahoo.vespa.objects.BufferSerializer; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -76,13 +77,13 @@ class StreamingVisitor extends VisitorDataHandler implements Visitor { } public StreamingVisitor(Query query, String searchCluster, Route route, - String documentType, VisitorSessionFactory visitorSessionFactory, + String schema, VisitorSessionFactory visitorSessionFactory, int traceLevelOverride) { this.query = query; this.visitorSessionFactory = visitorSessionFactory; this.traceLevelOverride = traceLevelOverride; - setVisitorParameters(searchCluster, route, documentType); + setVisitorParameters(searchCluster, route, schema); } private int inferSessionTraceLevel(Query query) { @@ -112,8 +113,8 @@ class StreamingVisitor extends VisitorDataHandler implements Visitor { return query.properties().getString(streamingSelection); } - private void setVisitorParameters(String searchCluster, Route route, String documentType) { - params.setDocumentSelection(createSelectionString(documentType, createQuerySelectionString())); + private void setVisitorParameters(String searchCluster, Route route, String schema) { + params.setDocumentSelection(createSelectionString(schema, createQuerySelectionString())); params.setTimeoutMs(query.getTimeout()); // Per bucket visitor timeout params.setSessionTimeoutMs(query.getTimeout()); params.setVisitorLibrary("searchvisitor"); @@ -146,7 +147,8 @@ class StreamingVisitor extends VisitorDataHandler implements Visitor { encodeQueryData(query, 0, ed); params.setLibraryParameter("query", ed.getEncodedData()); params.setLibraryParameter("querystackcount", String.valueOf(ed.getReturned())); - params.setLibraryParameter("searchcluster", searchCluster.getBytes()); + params.setLibraryParameter("searchcluster", searchCluster.getBytes(StandardCharsets.UTF_8)); + params.setLibraryParameter("schema", schema.getBytes(StandardCharsets.UTF_8)); if (query.getPresentation().getSummary() != null) { params.setLibraryParameter("summaryclass", query.getPresentation().getSummary()); } else { @@ -265,7 +267,7 @@ class StreamingVisitor extends VisitorDataHandler implements Visitor { log.log(Level.FINE, () -> "StreamingVisitor returned from waitUntilDone without being completed for " + query + " with selection " + params.getDocumentSelection()); session.abort(); - throw new TimeoutException("Query timed out in " + StreamingSearcher.class.getName()); + throw new TimeoutException("Query timed out in " + StreamingBackend.class.getName()); } } finally { session.destroy(); diff --git a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VisitorFactory.java b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VisitorFactory.java index 10387065128..e33bbd206be 100644 --- a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VisitorFactory.java +++ b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VisitorFactory.java @@ -11,6 +11,6 @@ import com.yahoo.search.Query; */ interface VisitorFactory { - Visitor createVisitor(Query query, String searchCluster, Route route, String documentType, int traceLevelOverride); + Visitor createVisitor(Query query, String searchCluster, Route route, String schema, int traceLevelOverride); } diff --git a/container-search/src/main/resources/configdefinitions/prelude.fastsearch.documentdb-info.def b/container-search/src/main/resources/configdefinitions/prelude.fastsearch.documentdb-info.def index 3ef3e9ef824..71c88b79ecd 100644 --- a/container-search/src/main/resources/configdefinitions/prelude.fastsearch.documentdb-info.def +++ b/container-search/src/main/resources/configdefinitions/prelude.fastsearch.documentdb-info.def @@ -6,24 +6,4 @@ namespace=prelude.fastsearch ## The name of the schema/document database documentdb[].name string - -## The id of the summary class. Not used TODO: Remove after July 2022 -documentdb[].summaryclass[].id int -## The name of the summary class. Not used TODO: Remove after July 2022 -documentdb[].summaryclass[].name string -## The name of a field in the summary class. Not used TODO: Remove after July 2022 -documentdb[].summaryclass[].fields[].name string -## The type of a field in the summary class. Not used TODO: Remove after July 2022 -documentdb[].summaryclass[].fields[].type string -## Whether this field is a dynamic snippet. Not used TODO: Remove after July 2022 -documentdb[].summaryclass[].fields[].dynamic bool default=false - -## Information about rank profiles. Not used TODO: Remove after July 2022 -documentdb[].rankprofile[].name string -documentdb[].rankprofile[].hasSummaryFeatures bool default=true -documentdb[].rankprofile[].hasRankFeatures bool default=true - -# The name of an input (query rank feature) accepted by this profile. Not used TODO: Remove after July 2022 -documentdb[].rankprofile[].input[].name string -# The tensor type of an input (query rank feature) accepted by this profile. Not used TODO: Remove after July 2022 -documentdb[].rankprofile[].input[].type string +documentdb[].mode enum {INDEX, STREAMING, STORE_ONLY} default=INDEX diff --git a/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java b/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java index 8d4e3364ce4..4adbce3add9 100644 --- a/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java +++ b/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java @@ -7,9 +7,10 @@ import com.yahoo.concurrent.InThreadExecutorService; import com.yahoo.container.QrSearchersConfig; import com.yahoo.container.handler.ClustersStatus; import com.yahoo.container.handler.VipStatus; +import com.yahoo.prelude.fastsearch.ClusterParams; import com.yahoo.prelude.fastsearch.DocumentdbInfoConfig; import com.yahoo.prelude.fastsearch.FastHit; -import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; +import com.yahoo.prelude.fastsearch.VespaBackend; import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.config.ClusterConfig; @@ -28,6 +29,7 @@ import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -38,7 +40,6 @@ import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -51,21 +52,6 @@ public class ClusterSearcherTestCase { private static final double DELTA = 0.0000000000000001; - @Test - void testNoBackends() { - ClusterSearcher cluster = new ClusterSearcher(createSchemaInfo(), Set.of("dummy")); - try { - Execution execution = new Execution(cluster, Execution.Context.createContextStub()); - Query query = new Query("query=hello"); - query.setHits(10); - com.yahoo.search.Result result = execution.search(query); - assertNotNull(result.hits().getError()); - assertEquals("No backends in service. Try later", result.hits().getError().getMessage()); - } finally { - cluster.deconstruct(); - } - } - private static SchemaInfo createSchemaInfo() { var schemas = Stream.of("type1", "type2", "type3", "type4", "type5", "type6") .map(name -> new Schema.Builder(name).build()).toList(); @@ -89,10 +75,11 @@ public class ClusterSearcherTestCase { @Test void testThatDocumentTypesAreResolved() { + var backend = new MyMockBackend(false); SchemaInfo schemaInfo = createSchemaInfo(); - ClusterSearcher cluster1 = new ClusterSearcher(schemaInfo, Set.of("type1", "type2", "type3")); + ClusterSearcher cluster1 = new ClusterSearcher(schemaInfo, Map.of("type1", backend, "type2", backend, "type3", backend)); try { - ClusterSearcher type1 = new ClusterSearcher(schemaInfo, Set.of("type6")); + ClusterSearcher type1 = new ClusterSearcher(schemaInfo, Map.of("type6", backend)); try { assertEquals(Set.of("type1", "type2", "type3"), resolve(cluster1, "")); assertEquals(Set.of("type6"), resolve(type1, "")); @@ -129,10 +116,11 @@ public class ClusterSearcherTestCase { @Test void testThatDocumentTypesAreResolvedTODO_REMOVE() { + var backend = new MyMockBackend(false); SchemaInfo schemaInfo = createSchemaInfo(); - ClusterSearcher cluster1 = new ClusterSearcher(schemaInfo, Set.of("type1", "type2", "type3")); + ClusterSearcher cluster1 = new ClusterSearcher(schemaInfo, Map.of("type1", backend, "type2", backend, "type3", backend)); try { - ClusterSearcher type1 = new ClusterSearcher(schemaInfo, Set.of("type6")); + ClusterSearcher type1 = new ClusterSearcher(schemaInfo, Map.of("type6", backend)); try { assertEquals(Set.of(), resolve(cluster1, "&sources=cluster2")); } finally { @@ -143,13 +131,38 @@ public class ClusterSearcherTestCase { } } - private static class MyMockSearcher extends VespaBackEndSearcher { + @Test + void testThatMultipleBackendsAreUsed() { + var backendA = new MyMockBackend(false); + var backendB = new MyMockBackend(false); + SchemaInfo schemaInfo = createSchemaInfo(); + var cluster1 = new ClusterSearcher(schemaInfo, Map.of("type1", backendA, "type2", backendB, "type3", backendA), + new InThreadExecutorService()); + try { + Execution execution = new Execution(cluster1, Execution.Context.createContextStub()); + execution.search(new Query("?query=hello")); + assertEquals(2, backendA.queries().size()); + assertEquals(1, backendB.queries().size()); + execution.search(new Query("?query=hello&restrict=type1")); + assertEquals(3, backendA.queries().size()); + assertEquals(1, backendB.queries().size()); + execution.search(new Query("?query=hello&restrict=type2,type3")); + assertEquals(4, backendA.queries().size()); + assertEquals(2, backendB.queries().size()); + } finally { + cluster1.deconstruct(); + } + } + + private static class MyMockBackend extends VespaBackend { private final String type1 = "type1"; private final String type2 = "type2"; private final String type3 = "type3"; private final Map<String, List<Hit>> results = new LinkedHashMap<>(); private final boolean expectAttributePrefetch; + + private final List<Query> queries = new ArrayList<>(); static final String ATTRIBUTE_PREFETCH = "attributeprefetch"; private String getId(String type, int i) { @@ -200,18 +213,22 @@ public class ClusterSearcherTestCase { createHit(getId(type3, 2), 5))); } - MyMockSearcher(boolean expectAttributePrefetch) { + MyMockBackend(boolean expectAttributePrefetch) { + super(new ClusterParams("container.0")); this.expectAttributePrefetch = expectAttributePrefetch; init(); } @Override - protected com.yahoo.search.Result doSearch2(Query query, Execution execution) { + protected com.yahoo.search.Result doSearch2(String schema, Query query) { return null; // search() is overriden, this should never be called } + List<Query> queries() { return queries; } + @Override - public com.yahoo.search.Result search(Query query, Execution execution) { + public com.yahoo.search.Result search(String schema, Query query) { + queries.add(query); com.yahoo.search.Result result = new com.yahoo.search.Result(query); List<Hit> hits = getHits(query); if (hits != null) { @@ -267,10 +284,14 @@ public class ClusterSearcherTestCase { } private Execution createExecution(List<String> docTypesList, boolean expectAttributePrefetch) { + var backend = new MyMockBackend(expectAttributePrefetch); + Map<String, VespaBackend> searchers = new HashMap<>(); + for(String schema : docTypesList) { + searchers.put(schema, backend); + } Set<String> documentTypes = new LinkedHashSet<>(docTypesList); ClusterSearcher cluster = new ClusterSearcher(toSchemaInfo(documentTypes, "mycluster"), - documentTypes, - new MyMockSearcher(expectAttributePrefetch), + searchers, new InThreadExecutorService()); try { List<Schema> schemas = new ArrayList<>(); @@ -428,7 +449,7 @@ public class ClusterSearcherTestCase { assertResult(6, List.of(7.0, 9.0), getResult(3, 2, extra, ex)); assertResult(6, List.of(9.0, 10.0), getResult(4, 2, extra, ex)); assertResult(6, List.of(10.0), getResult(5, 2, extra, ex)); - assertResult(6, List.of(), getResult(6, 2, extra, ex)); + assertResult(6, List.of(), getResult(6, 2, extra, ex)); } private static ClusterSearcher createSearcher(String clusterName, Double maxQueryTimeout, Double maxQueryCacheTimeout, @@ -449,7 +470,11 @@ public class ClusterSearcherTestCase { clusterConfig.maxQueryCacheTimeout(maxQueryCacheTimeout); DocumentdbInfoConfig.Builder documentDbConfig = new DocumentdbInfoConfig.Builder(); - documentDbConfig.documentdb(new DocumentdbInfoConfig.Documentdb.Builder().name("type1")); + documentDbConfig.documentdb(new DocumentdbInfoConfig.Documentdb.Builder() + .name("type1") + .mode(streamingMode + ? DocumentdbInfoConfig.Documentdb.Mode.Enum.STREAMING + : DocumentdbInfoConfig.Documentdb.Mode.Enum.INDEX)); var schema = new Schema.Builder("type1"); DispatchConfig dispatchConfig = new DispatchConfig.Builder().build(); diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/DocsumDefinitionTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/DocsumDefinitionTestCase.java index ade094115fe..ba9988b865c 100644 --- a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/DocsumDefinitionTestCase.java +++ b/container-search/src/test/java/com/yahoo/prelude/fastsearch/DocsumDefinitionTestCase.java @@ -1,14 +1,6 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.fastsearch.test; +package com.yahoo.prelude.fastsearch; -import com.yahoo.prelude.fastsearch.ByteField; -import com.yahoo.prelude.fastsearch.DataField; -import com.yahoo.prelude.fastsearch.DocsumDefinition; -import com.yahoo.prelude.fastsearch.DocsumDefinitionSet; -import com.yahoo.prelude.fastsearch.FastHit; -import com.yahoo.prelude.fastsearch.IntegerField; -import com.yahoo.prelude.fastsearch.StringField; -import com.yahoo.document.DocumentId; import com.yahoo.document.GlobalId; import com.yahoo.search.schema.DocumentSummary; import com.yahoo.search.schema.Schema; diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/FastSearcherTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/IndexedBackendTestCase.java index 20d2a304c3c..58427bee30a 100644 --- a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/FastSearcherTestCase.java +++ b/container-search/src/test/java/com/yahoo/prelude/fastsearch/IndexedBackendTestCase.java @@ -1,17 +1,11 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.fastsearch.test; +package com.yahoo.prelude.fastsearch; -import com.yahoo.component.chain.Chain; import com.yahoo.container.QrSearchersConfig; import com.yahoo.container.handler.VipStatus; import com.yahoo.container.protect.Error; -import com.yahoo.prelude.fastsearch.ClusterParams; -import com.yahoo.prelude.fastsearch.DocumentdbInfoConfig; -import com.yahoo.prelude.fastsearch.FastSearcher; -import com.yahoo.prelude.fastsearch.SummaryParameters; import com.yahoo.search.Query; import com.yahoo.search.Result; -import com.yahoo.search.Searcher; import com.yahoo.search.dispatch.MockDispatcher; import com.yahoo.search.dispatch.rpc.RpcResourcePool; import com.yahoo.search.dispatch.searchcluster.Node; @@ -24,10 +18,8 @@ import com.yahoo.search.schema.DocumentSummary; import com.yahoo.search.schema.RankProfile; import com.yahoo.search.schema.Schema; import com.yahoo.search.schema.SchemaInfo; -import com.yahoo.search.searchchain.Execution; import org.junit.jupiter.api.Test; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Level; @@ -41,17 +33,16 @@ import static org.junit.jupiter.api.Assertions.*; * * @author bratseth */ -public class FastSearcherTestCase { +public class IndexedBackendTestCase { + private static final String SCHEMA = "test"; + private static final String CLUSTER = "test"; + private static final ClusterParams CLUSTER_PARAMS = new ClusterParams("testhittype", "container.0", null, + documentdbInfoConfig(SCHEMA), schemaInfo(SCHEMA)); @Test void testNullQuery() { - Logger.getLogger(FastSearcher.class.getName()).setLevel(Level.ALL); - FastSearcher fastSearcher = new FastSearcher("container.0", - MockDispatcher.create(Collections.emptyList()), - new SummaryParameters(null), - new ClusterParams("testhittype"), - documentdbInfoConfig("test"), - schemaInfo("test")); + Logger.getLogger(IndexedBackend.class.getName()).setLevel(Level.ALL); + IndexedBackend fastSearcher = new IndexedBackend(CLUSTER_PARAMS, MockDispatcher.create(List.of())); String query = "?junkparam=ignored"; Result result = doSearch(fastSearcher, new Query(query), 0, 10); @@ -63,30 +54,16 @@ public class FastSearcherTestCase { assertEquals(Error.NULL_QUERY.code, message.getCode()); } - private Chain<Searcher> chainedAsSearchChain(Searcher topOfChain) { - List<Searcher> searchers = new ArrayList<>(); - searchers.add(topOfChain); - return new Chain<>(searchers); - } - - private Result doSearch(Searcher searcher, Query query, int offset, int hits) { + private Result doSearch(VespaBackend searcher, Query query, int offset, int hits) { query.setOffset(offset); query.setHits(hits); - return createExecution(searcher).search(query); - } - - private Execution createExecution(Searcher searcher) { - return new Execution(chainedAsSearchChain(searcher), Execution.Context.createContextStub()); + return searcher.search(SCHEMA, query); } @Test void testSinglePassGroupingIsForcedWithSingleNodeGroups() { - FastSearcher fastSearcher = new FastSearcher("container.0", - MockDispatcher.create(List.of(new Node("test", 0, "host0", 0))), - new SummaryParameters(null), - new ClusterParams("testhittype"), - documentdbInfoConfig("test"), - schemaInfo("test")); + IndexedBackend fastSearcher = new IndexedBackend(CLUSTER_PARAMS, + MockDispatcher.create(List.of(new Node(CLUSTER, 0, "host0", 0)))); Query q = new Query("?query=foo"); GroupingRequest request1 = GroupingRequest.newInstance(q); request1.setRootOperation(new AllOperation()); @@ -98,18 +75,14 @@ public class FastSearcherTestCase { request2.setRootOperation(all); assertForceSinglePassIs(false, q); - fastSearcher.search(q, new Execution(Execution.Context.createContextStub())); + fastSearcher.search(SCHEMA, q); assertForceSinglePassIs(true, q); } @Test void testRankProfileValidation() { - FastSearcher fastSearcher = new FastSearcher("container.0", - MockDispatcher.create(List.of(new Node("test", 0, "host0", 0))), - new SummaryParameters(null), - new ClusterParams("testhittype"), - documentdbInfoConfig("test"), - schemaInfo("test")); + IndexedBackend fastSearcher = new IndexedBackend(CLUSTER_PARAMS, + MockDispatcher.create(List.of(new Node(CLUSTER, 0, "host0", 0)))); assertFalse(searchError("?query=q", fastSearcher).contains("does not contain requested rank profile")); assertFalse(searchError("?query=q&ranking.profile=default", fastSearcher).contains("does not contain requested rank profile")); assertTrue(searchError("?query=q&ranking.profile=nosuch", fastSearcher).contains("does not contain requested rank profile")); @@ -117,18 +90,15 @@ public class FastSearcherTestCase { @Test void testSummaryNeedsQuery() { - var documentDb = new DocumentdbInfoConfig(new DocumentdbInfoConfig.Builder().documentdb(new DocumentdbInfoConfig.Documentdb.Builder().name("test"))); - var schema = new Schema.Builder("test") + var schema = new Schema.Builder(SCHEMA) .add(new DocumentSummary.Builder("default").build()) .add(new RankProfile.Builder("default").setHasRankFeatures(false) .setHasSummaryFeatures(false) .build()); - FastSearcher backend = new FastSearcher("container.0", - MockDispatcher.create(Collections.singletonList(new Node("test", 0, "host0", 0))), - new SummaryParameters(null), - new ClusterParams("testhittype"), - documentDb, - new SchemaInfo(List.of(schema.build()), List.of())); + var backend = new IndexedBackend(new ClusterParams(CLUSTER_PARAMS.getSearcherName(), CLUSTER_PARAMS.getServerId(), + CLUSTER_PARAMS.getDefaultSummary(), CLUSTER_PARAMS.getDocumentdbInfoConfig(), + new SchemaInfo(List.of(schema.build()), List.of())), + MockDispatcher.create(Collections.singletonList(new Node(CLUSTER, 0, "host0", 0)))); Query q = new Query("?query=foo"); Result result = doSearch(backend, q, 0, 10); assertFalse(backend.summaryNeedsQuery(q)); @@ -141,14 +111,9 @@ public class FastSearcherTestCase { @Test void testSinglePassGroupingIsNotForcedWithSingleNodeGroups() { - MockDispatcher dispatcher = MockDispatcher.create(List.of(new Node("test", 0, "host0", 0), new Node("test", 2, "host1", 0))); - - FastSearcher fastSearcher = new FastSearcher("container.0", - dispatcher, - new SummaryParameters(null), - new ClusterParams("testhittype"), - documentdbInfoConfig("test"), - schemaInfo("test")); + MockDispatcher dispatcher = MockDispatcher.create(List.of(new Node(CLUSTER, 0, "host0", 0), new Node(CLUSTER, 2, "host1", 0))); + + IndexedBackend fastSearcher = new IndexedBackend(CLUSTER_PARAMS, dispatcher); Query q = new Query("?query=foo"); GroupingRequest request1 = GroupingRequest.newInstance(q); request1.setRootOperation(new AllOperation()); @@ -160,7 +125,7 @@ public class FastSearcherTestCase { request2.setRootOperation(all); assertForceSinglePassIs(false, q); - fastSearcher.search(q, new Execution(Execution.Context.createContextStub())); + fastSearcher.search(SCHEMA, q); assertForceSinglePassIs(false, q); } @@ -183,7 +148,7 @@ public class FastSearcherTestCase { searchClusterB.name(clusterName); b.searchcluster(searchClusterB); VipStatus vipStatus = new VipStatus(b.build()); - List<Node> nodes_1 = List.of(new Node("test", 0, "host0", 0)); + List<Node> nodes_1 = List.of(new Node(CLUSTER, 0, "host0", 0)); RpcResourcePool rpcPool_1 = new RpcResourcePool(MockDispatcher.toDispatchConfig(), MockDispatcher.toNodesConfig(nodes_1)); MockDispatcher dispatch_1 = MockDispatcher.create(nodes_1, rpcPool_1, vipStatus); dispatch_1.clusterMonitor.shutdown(); @@ -193,20 +158,20 @@ public class FastSearcherTestCase { assertTrue(vipStatus.isInRotation()); //Verify that deconstruct does not touch vipstatus } - private String searchError(String query, Searcher searcher) { + private String searchError(String query, VespaBackend searcher) { return search(query, searcher).hits().getError().getDetailedMessage(); } - private Result search(String query, Searcher searcher) { - return searcher.search(new Query(query), new Execution(Execution.Context.createContextStub())); + private Result search(String query, VespaBackend searcher) { + return searcher.search(SCHEMA, new Query(query)); } - private DocumentdbInfoConfig documentdbInfoConfig(String schemaName) { + private static DocumentdbInfoConfig documentdbInfoConfig(String schemaName) { var db = new DocumentdbInfoConfig.Documentdb.Builder().name(schemaName); return new DocumentdbInfoConfig.Builder().documentdb(db).build(); } - private SchemaInfo schemaInfo(String schemaName) { + private static SchemaInfo schemaInfo(String schemaName) { var schema = new Schema.Builder(schemaName); schema.add(new RankProfile.Builder("default").build()); return new SchemaInfo(List.of(schema.build()), List.of()); diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/PartialFillTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/PartialFillTestCase.java index 27a27e993a8..7e3509cbef9 100644 --- a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/PartialFillTestCase.java +++ b/container-search/src/test/java/com/yahoo/prelude/fastsearch/PartialFillTestCase.java @@ -1,17 +1,10 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.fastsearch.test; +package com.yahoo.prelude.fastsearch; -import com.yahoo.component.chain.Chain; -import com.yahoo.language.simple.SimpleLinguistics; -import com.yahoo.prelude.fastsearch.FastHit; -import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; import com.yahoo.search.Query; import com.yahoo.search.Result; -import com.yahoo.search.Searcher; -import com.yahoo.search.rendering.RendererRegistry; import com.yahoo.search.result.ErrorHit; import com.yahoo.search.result.ErrorMessage; -import com.yahoo.search.searchchain.Execution; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -24,10 +17,14 @@ import static org.junit.jupiter.api.Assertions.*; * @author havardpe */ public class PartialFillTestCase { + private static final ClusterParams CLUSTER_PARAMS = new ClusterParams("container.0"); - public static class FS4 extends VespaBackEndSearcher { + public static class FS4 extends VespaBackend { public List<Result> history = new ArrayList<>(); - protected Result doSearch2(Query query, Execution execution) { + FS4() { + super(CLUSTER_PARAMS); + } + protected Result doSearch2(String schema, Query query) { return new Result(query); } protected void doPartialFill(Result result, String summaryClass) { @@ -35,8 +32,11 @@ public class PartialFillTestCase { } } - public static class BadFS4 extends VespaBackEndSearcher { - protected Result doSearch2(Query query, Execution execution) { + public static class BadFS4 extends VespaBackend { + BadFS4() { + super(CLUSTER_PARAMS); + } + protected Result doSearch2(String schema, Query query) { return new Result(query); } protected void doPartialFill(Result result, String summaryClass) { @@ -130,30 +130,18 @@ public class PartialFillTestCase { com.yahoo.search.result.ErrorMessage error = i.next(); switch (n) { case 0: - assertEquals(exp_sub, error); - break; case 1: assertEquals(exp_sub, error); break; default: - assertTrue(false); + fail(); } n++; } } - private Execution createExecution(Searcher searcher) { - return new Execution(chainedAsSearchChain(searcher), Execution.Context.createContextStub()); - } - - private void doFill(Searcher searcher, Result result, String summaryClass) { - createExecution(searcher).fill(result, summaryClass); - } - - private Chain<Searcher> chainedAsSearchChain(Searcher topOfChain) { - List<Searcher> searchers = new ArrayList<>(); - searchers.add(topOfChain); - return new Chain<>(searchers); + private void doFill(VespaBackend searcher, Result result, String summaryClass) { + searcher.fill(result, summaryClass); } } diff --git a/container-search/src/test/java/com/yahoo/prelude/test/IntegrationTestCase.java b/container-search/src/test/java/com/yahoo/prelude/test/IntegrationTestCase.java deleted file mode 100644 index 0a3e7bda318..00000000000 --- a/container-search/src/test/java/com/yahoo/prelude/test/IntegrationTestCase.java +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.test; - -import com.yahoo.search.result.Hit; -import com.yahoo.search.Result; -import com.yahoo.search.Searcher; -import com.yahoo.search.searchchain.Execution; -import org.junit.jupiter.api.Test; - -/** - * Runs a query thru the configured search chain from a real http channel - * to a mock fdispatch channel. The setup is rather complicated, as the point is - * to span as much of the processing from query to result as possible. - * - * @author bratseth - */ -public class IntegrationTestCase { - - public static class SecondSearcher extends Searcher { - public Result search(com.yahoo.search.Query query, Execution execution) { - Result result = execution.search(query); - result.hits().add(new Hit("searcher:2",1000)); - return result; - } - } - public static class ThirdSearcher extends Searcher { - public Result search(com.yahoo.search.Query query, Execution execution) { - Result result = execution.search(query); - result.hits().add(new Hit("searcher:3",1000)); - return result; - } - } - - @Test - void testQuery() throws java.io.IOException { - /* - TODO: (JSB) This blocks forever on Linux (not Windows) because - the ServerSocketChannel.accept method in Server - seems to starve the test running thread, - causing it to get stuck in waitForServerInitialization. - This must be caused by starvation because - replacing the test with Thread.sleep(n) - gives the same result if n is large enough (2000 - is large enough, 1000 is not. - Resolve this in some way, perhaps by switching to - non-blocking io (and then remember to remove the next line). - */ - } - - /* - if (1==1) return; - ServerThread serverThread=new ServerThread(); - try { - serverThread.start(); - waitForServerInitialization(); - insertMockFs4Channel(); - ByteBuffer buffer=ByteBuffer.allocate(4096); - buffer.put(getBytes("GET /?query=hans HTTP/1.1\n\n")); - SocketChannel socket= - SocketChannel.open(new InetSocketAddress(Server.get().getHost(), - Server.get().getPort())); - buffer.flip(); - socket.write(buffer); - - buffer.clear(); - socket.read(buffer); - // TODO: Validate return too - - } - finally { - serverThread.interrupt(); - } - } - - private static void assertCorrectQueryData(QueryPacket packet) { - assertEquals("Query x packet " + - "[query: query 'RANK hans bcatpat.bidxpatlvl1:hans' [path='/']]", - packet.toString()); - } - - private void insertMockFs4Channel() { - Searcher current=SearchChain.get(); - while (current.getChained().getChained()!=null) - current=current.getChained(); - assertTrue(current.getChained() instanceof FastSearcher); - FastSearcher mockFastSearcher= - new FastSearcher(new MockFSChannel(), - "file:etc/qr-summary.cf", - "testhittype"); - current.setChained(mockFastSearcher); - } - - private void waitForServerInitialization() { - int sleptMs=0; - while (Server.get().getHost()==null) { - try { Thread.sleep(10); } catch (Exception e) {} - sleptMs+=10; - } - } - - private class ServerThread extends Thread { - - public void run() { - try { - Server.get().start(8081,new SearchRequestHandler()); - } - catch (java.io.IOException e) { - throw new RuntimeException("Failed",e); - } - } - } - - private byte[] getBytes(String string) { - try { - return string.getBytes("utf-8"); - } - catch (java.io.UnsupportedEncodingException e) { - throw new RuntimeException("Won't happen",e); - } - } - */ - /** A channel which returns hardcoded packets of the same type as fdispatch */ - /* - private static class MockFSChannel extends Channel { - - public MockFSChannel() {} - - public void sendPacket(Packet packet) { - if (packet instanceof QueryPacket) { - assertCorrectQueryData((QueryPacket)packet); - } - else { - throw new RuntimeException("Mock channel don't know what to reply to " + - packet); - } - } - - public Packet[] receivePackets() { - List packets=new java.util.ArrayList(); - QueryResultPacket result=QueryResultPacket.create(); - result.addDocument(new DocumentInfo(123,2003,234,1000,1)); - result.addDocument(new DocumentInfo(456,1855,234,1001,1)); - packets.add(result); - addDocsums(packets); - return (Packet[])packets.toArray(new Packet[packets.size()]); - } - - private void addDocsums(List packets) { - ByteBuffer buffer=createDocsumPacketData(DocsumDefinitionTestCase.docsum4); - buffer.position(0); - packets.add(PacketDecoder.decode(buffer)); - - buffer=createDocsumPacketData(DocsumDefinitionTestCase.docsum4); - buffer.position(0); - packets.add(PacketDecoder.decode(buffer)); - - packets.add(EolPacket.create()); - } - - private ByteBuffer createDocsumPacketData(byte[] docsumData) { - ByteBuffer buffer=ByteBuffer.allocate(docsumData.length+12+4); - buffer.limit(buffer.capacity()); - buffer.position(0); - buffer.putInt(docsumData.length+8+4); - buffer.putInt(205); // Docsum packet code - buffer.putInt(0); - buffer.putInt(0); - buffer.put(docsumData); - return buffer; - } - - } - */ -} diff --git a/container-search/src/test/java/com/yahoo/search/dispatch/DispatcherTest.java b/container-search/src/test/java/com/yahoo/search/dispatch/DispatcherTest.java index 8dc74110291..c966fbc200d 100644 --- a/container-search/src/test/java/com/yahoo/search/dispatch/DispatcherTest.java +++ b/container-search/src/test/java/com/yahoo/search/dispatch/DispatcherTest.java @@ -3,7 +3,7 @@ package com.yahoo.search.dispatch; import com.yahoo.compress.CompressionType; import com.yahoo.prelude.Pong; -import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; +import com.yahoo.prelude.fastsearch.VespaBackend; import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.cluster.ClusterMonitor; @@ -18,7 +18,6 @@ import com.yahoo.search.dispatch.searchcluster.Pinger; import com.yahoo.search.dispatch.searchcluster.PongHandler; import com.yahoo.search.dispatch.searchcluster.SearchCluster; import com.yahoo.search.dispatch.searchcluster.SearchGroups; -import com.yahoo.search.searchchain.Execution; import com.yahoo.vespa.config.search.DispatchConfig; import com.yahoo.vespa.config.search.DispatchNodesConfig; import com.yahoo.yolean.UncheckedInterruptedException; @@ -237,19 +236,19 @@ public class DispatcherTest { // This factory just forwards search to the dummy RPC layer above, nothing more. InvokerFactoryFactory invokerFactories = (rpcConnectionPool, searchGroups, dispatchConfig) -> new InvokerFactory(searchGroups, dispatchConfig) { - @Override protected Optional<SearchInvoker> createNodeSearchInvoker(VespaBackEndSearcher searcher, Query query, int maxHits, Node node) { + @Override protected Optional<SearchInvoker> createNodeSearchInvoker(VespaBackend searcher, Query query, int maxHits, Node node) { return Optional.of(new SearchInvoker(Optional.of(node)) { @Override protected Object sendSearchRequest(Query query, Object context) { rpcPool.getConnection(node.key()).request(null, null, 0, null, null, 0); return null; }; - @Override protected InvokerResult getSearchResult(Execution execution) { + @Override protected InvokerResult getSearchResult() { return new InvokerResult(new Result(new Query())); } @Override protected void release() { } }); }; - @Override public FillInvoker createFillInvoker(VespaBackEndSearcher searcher, Result result) { + @Override public FillInvoker createFillInvoker(VespaBackend searcher, Result result) { return new FillInvoker() { @Override protected void getFillResults(Result result, String summaryClass) { fail(); } @Override protected void sendFillRequest(Result result, String summaryClass) { fail(); } @@ -288,11 +287,11 @@ public class DispatcherTest { // Start some searches, one against each group, since we have a round-robin policy. SearchInvoker search0 = dispatcher.getSearchInvoker(new Query(), null); - search0.search(new Query(), null); + search0.search(new Query()); // Unknown whether the first or second search hits node0, so we must track that. int offset = nodeIdOfSearcher0.get(); SearchInvoker search1 = dispatcher.getSearchInvoker(new Query(), null); - search1.search(new Query(), null); + search1.search(new Query()); // Wait for the current cluster monitor to be mid-ping-round. doPing.set(true); @@ -330,7 +329,7 @@ public class DispatcherTest { // Next search should hit group0 again, this time on node2. SearchInvoker search2 = dispatcher.getSearchInvoker(new Query(), null); - search2.search(new Query(), null); + search2.search(new Query()); // Searches against nodes 1 and 2 complete. (offset == 0 ? search0 : search1).close(); @@ -370,7 +369,7 @@ public class DispatcherTest { } @Override - public Optional<SearchInvoker> createSearchInvoker(VespaBackEndSearcher searcher, + public Optional<SearchInvoker> createSearchInvoker(VespaBackend searcher, Query query, List<Node> nodes, boolean acceptIncompleteCoverage, @@ -392,7 +391,7 @@ public class DispatcherTest { } @Override - protected Optional<SearchInvoker> createNodeSearchInvoker(VespaBackEndSearcher searcher, + protected Optional<SearchInvoker> createNodeSearchInvoker(VespaBackend searcher, Query query, int maxHitsPerNode, Node node) { @@ -401,7 +400,7 @@ public class DispatcherTest { } @Override - public FillInvoker createFillInvoker(VespaBackEndSearcher searcher, Result result) { + public FillInvoker createFillInvoker(VespaBackend searcher, Result result) { fail("Unexpected call to createFillInvoker"); return null; } diff --git a/container-search/src/test/java/com/yahoo/search/dispatch/InterleavedSearchInvokerTest.java b/container-search/src/test/java/com/yahoo/search/dispatch/InterleavedSearchInvokerTest.java index fac75b1dd68..8ced7d3895e 100644 --- a/container-search/src/test/java/com/yahoo/search/dispatch/InterleavedSearchInvokerTest.java +++ b/container-search/src/test/java/com/yahoo/search/dispatch/InterleavedSearchInvokerTest.java @@ -61,7 +61,7 @@ public class InterleavedSearchInvokerTest { expectedEvents.add(new Event(4900, 100, 1)); expectedEvents.add(new Event(4800, 100, 2)); - invoker.search(query, null); + invoker.search(query); assertTrue(expectedEvents.isEmpty(), "All test scenario events processed"); } @@ -75,7 +75,7 @@ public class InterleavedSearchInvokerTest { expectedEvents.add(new Event(4700, 300, 1)); expectedEvents.add(null); - Result result = invoker.search(query, null); + Result result = invoker.search(query); assertTrue(expectedEvents.isEmpty(), "All test scenario events processed"); assertNull(result.hits().getErrorHit(), "Result is not marked as an error"); @@ -94,7 +94,7 @@ public class InterleavedSearchInvokerTest { expectedEvents.add(new Event(2400, 100, 2)); expectedEvents.add(new Event(0, 0, null)); - Result result = invoker.search(query, null); + Result result = invoker.search(query); assertTrue(expectedEvents.isEmpty(), "All test scenario events processed"); assertNull(result.hits().getErrorHit(), "Result is not marked as an error"); @@ -113,7 +113,7 @@ public class InterleavedSearchInvokerTest { expectedEvents.add(new Event(null, 100, 0)); expectedEvents.add(new Event(null, 200, 1)); - Result result = invoker.search(query, null); + Result result = invoker.search(query); Coverage cov = result.getCoverage(true); assertEquals(100000L, cov.getDocs()); @@ -134,7 +134,7 @@ public class InterleavedSearchInvokerTest { expectedEvents.add(new Event(null, 100, 0)); expectedEvents.add(new Event(null, 200, 1)); - Result result = invoker.search(query, null); + Result result = invoker.search(query); Coverage cov = result.getCoverage(true); assertEquals(23420L, cov.getDocs()); @@ -156,7 +156,7 @@ public class InterleavedSearchInvokerTest { expectedEvents.add(new Event(null, 100, 0)); expectedEvents.add(new Event(null, 200, 1)); - Result result = invoker.search(query, null); + Result result = invoker.search(query); Coverage cov = result.getCoverage(true); assertEquals(9900L, cov.getDocs()); @@ -178,7 +178,7 @@ public class InterleavedSearchInvokerTest { expectedEvents.add(new Event(null, 100, 0)); expectedEvents.add(null); - Result result = invoker.search(query, null); + Result result = invoker.search(query); Coverage cov = result.getCoverage(true); assertEquals(50155L, cov.getDocs()); @@ -213,7 +213,7 @@ public class InterleavedSearchInvokerTest { query.setHits(8); query.properties().set(Dispatcher.topKProbability, topKProbability); SearchInvoker[] invokers = invoker.invokers().toArray(new SearchInvoker[0]); - Result result = invoker.search(query, null); + Result result = invoker.search(query); assertEquals(2, invokers.length); assertEquals(expectedK, ((MockInvoker) invokers[0]).hitsRequested); assertEquals(8, result.hits().size()); @@ -264,7 +264,7 @@ public class InterleavedSearchInvokerTest { void requireThatMergeOfConcreteHitsObeySorting() throws IOException { try (InterleavedSearchInvoker invoker = createInterLeavedTestInvoker(A5, B5, new Group(0, List.of()))) { query.setHits(12); - Result result = invoker.search(query, null); + Result result = invoker.search(query); assertEquals(10, result.hits().size()); assertEquals(11.0, result.hits().get(0).getRelevance().getScore(), DELTA); assertEquals(1.0, result.hits().get(9).getRelevance().getScore(), DELTA); @@ -273,7 +273,7 @@ public class InterleavedSearchInvokerTest { } try ( InterleavedSearchInvoker invoker = createInterLeavedTestInvoker(B5, A5, new Group(0, List.of()))) { - Result result = invoker.search(query, null); + Result result = invoker.search(query); assertEquals(10, result.hits().size()); assertEquals(11.0, result.hits().get(0).getRelevance().getScore(), DELTA); assertEquals(1.0, result.hits().get(9).getRelevance().getScore(), DELTA); @@ -287,7 +287,7 @@ public class InterleavedSearchInvokerTest { try (InterleavedSearchInvoker invoker = createInterLeavedTestInvoker(A5, B5, new Group(0, List.of()))) { query.setHits(3); query.setOffset(5); - Result result = invoker.search(query, null); + Result result = invoker.search(query); assertEquals(3, result.hits().size()); assertEquals(7.0, result.hits().get(0).getRelevance().getScore(), DELTA); assertEquals(3.0, result.hits().get(2).getRelevance().getScore(), DELTA); @@ -297,7 +297,7 @@ public class InterleavedSearchInvokerTest { try (InterleavedSearchInvoker invoker = createInterLeavedTestInvoker(B5, A5, new Group(0, List.of()))) { query.setOffset(5); - Result result = invoker.search(query, null); + Result result = invoker.search(query); assertEquals(3, result.hits().size()); assertEquals(7.0, result.hits().get(0).getRelevance().getScore(), DELTA); assertEquals(3.0, result.hits().get(2).getRelevance().getScore(), DELTA); @@ -311,7 +311,7 @@ public class InterleavedSearchInvokerTest { try (InterleavedSearchInvoker invoker = createInterLeavedTestInvoker(A5Aux, B5Aux, new Group(0, List.of()))) { query.setHits(3); query.setOffset(5); - Result result = invoker.search(query, null); + Result result = invoker.search(query); assertEquals(7, result.hits().size()); assertEquals(7.0, result.hits().get(0).getRelevance().getScore(), DELTA); assertEquals(3.0, result.hits().get(2).getRelevance().getScore(), DELTA); @@ -322,7 +322,7 @@ public class InterleavedSearchInvokerTest { try (InterleavedSearchInvoker invoker = createInterLeavedTestInvoker(B5Aux, A5Aux, new Group(0, List.of()))) { query.setOffset(5); - Result result = invoker.search(query, null); + Result result = invoker.search(query); assertEquals(7, result.hits().size()); assertEquals(7.0, result.hits().get(0).getRelevance().getScore(), DELTA); assertEquals(3.0, result.hits().get(2).getRelevance().getScore(), DELTA); @@ -359,7 +359,7 @@ public class InterleavedSearchInvokerTest { try (InterleavedSearchInvoker invoker = new InterleavedSearchInvoker(Timer.monotonic, invokers, hitEstimator, dispatchConfig, new Group(0, List.of()), Collections.emptySet())) { invoker.responseAvailable(invokers.get(0)); invoker.responseAvailable(invokers.get(1)); - Result result = invoker.search(query, null); + Result result = invoker.search(query); assertEquals(1, ((GroupingListHit) result.hits().get(0)).getGroupingList().size()); } for (SearchInvoker invoker : invokers) { @@ -404,7 +404,7 @@ public class InterleavedSearchInvokerTest { expectedEvents.add(new Event(null, 1, 1)); expectedEvents.add(new Event(null, 100, 0)); - Result result = invoker.search(query, null); + Result result = invoker.search(query); Coverage cov = result.getCoverage(true); assertEquals(50155L, cov.getDocs()); diff --git a/container-search/src/test/java/com/yahoo/search/dispatch/MockInvoker.java b/container-search/src/test/java/com/yahoo/search/dispatch/MockInvoker.java index a1521a88fb7..e43f3b0bd9a 100644 --- a/container-search/src/test/java/com/yahoo/search/dispatch/MockInvoker.java +++ b/container-search/src/test/java/com/yahoo/search/dispatch/MockInvoker.java @@ -40,7 +40,7 @@ class MockInvoker extends SearchInvoker { } @Override - protected InvokerResult getSearchResult(Execution execution) { + protected InvokerResult getSearchResult() { InvokerResult ret = new InvokerResult(query, 10); if (coverage != null) { ret.getResult().setCoverage(coverage); diff --git a/container-search/src/test/java/com/yahoo/search/dispatch/rpc/RpcSearchInvokerTest.java b/container-search/src/test/java/com/yahoo/search/dispatch/rpc/RpcSearchInvokerTest.java index 3f527f34f31..b6fa385cfae 100644 --- a/container-search/src/test/java/com/yahoo/search/dispatch/rpc/RpcSearchInvokerTest.java +++ b/container-search/src/test/java/com/yahoo/search/dispatch/rpc/RpcSearchInvokerTest.java @@ -5,11 +5,11 @@ package com.yahoo.search.dispatch.rpc; import ai.vespa.searchlib.searchprotocol.protobuf.SearchProtocol; import com.google.common.collect.ImmutableMap; import com.yahoo.compress.CompressionType; -import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; +import com.yahoo.prelude.fastsearch.ClusterParams; +import com.yahoo.prelude.fastsearch.VespaBackend; import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.dispatch.searchcluster.Node; -import com.yahoo.search.searchchain.Execution; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -45,7 +45,7 @@ public class RpcSearchInvokerTest { assertEquals(10, request.getHits()); assertEquals(3, request.getOffset()); - assertTrue(request.getQueryTreeBlob().size() > 0); + assertFalse(request.getQueryTreeBlob().isEmpty()); var invoker2 = new RpcSearchInvoker(mockSearcher(), compressor, new Node("test", 8, "eight", 1), mockPool, 1000); RpcSearchInvoker.RpcContext context2 = (RpcSearchInvoker.RpcContext) invoker2.sendSearchRequest(q, context); @@ -118,10 +118,10 @@ public class RpcSearchInvokerTest { }; } - private VespaBackEndSearcher mockSearcher() { - return new VespaBackEndSearcher() { + private VespaBackend mockSearcher() { + return new VespaBackend(new ClusterParams("container.0")) { @Override - protected Result doSearch2(Query query, Execution execution) { + protected Result doSearch2(String schema, Query query) { fail("Unexpected call"); return null; } diff --git a/container-search/src/test/java/com/yahoo/search/yql/YqlFieldAndSourceTestCase.java b/container-search/src/test/java/com/yahoo/search/yql/YqlFieldAndSourceTestCase.java index 4455c8a04a5..87d18c18db5 100644 --- a/container-search/src/test/java/com/yahoo/search/yql/YqlFieldAndSourceTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/yql/YqlFieldAndSourceTestCase.java @@ -5,7 +5,6 @@ import static org.junit.jupiter.api.Assertions.*; import java.util.Arrays; import java.util.List; -import java.util.Map; import com.yahoo.search.schema.DocumentSummary; import com.yahoo.search.schema.Schema; @@ -21,7 +20,7 @@ import com.yahoo.search.result.Hit; import com.yahoo.search.searchchain.Execution; import com.yahoo.search.searchchain.testutil.DocumentSourceSearcher; import static com.yahoo.search.searchchain.testutil.DocumentSourceSearcher.DEFAULT_SUMMARY_CLASS; -import static com.yahoo.prelude.fastsearch.VespaBackEndSearcher.SORTABLE_ATTRIBUTES_SUMMARY_CLASS; +import static com.yahoo.prelude.fastsearch.VespaBackend.SORTABLE_ATTRIBUTES_SUMMARY_CLASS; /** diff --git a/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/MetricsSearcherTestCase.java b/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/MetricsSearcherTestCase.java index 831261bb91a..5cc0e6b060b 100644 --- a/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/MetricsSearcherTestCase.java +++ b/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/MetricsSearcherTestCase.java @@ -134,9 +134,9 @@ public class MetricsSearcherTestCase { private void assignContextProperties(Query query, String loadType) { if (loadType != null && loadType.equals(LOADTYPE1)) { - query.getContext(true).setProperty(StreamingSearcher.STREAMING_STATISTICS, visitorStats); + query.getContext(true).setProperty(StreamingBackend.STREAMING_STATISTICS, visitorStats); } else { - query.getContext(true).setProperty(StreamingSearcher.STREAMING_STATISTICS, null); + query.getContext(true).setProperty(StreamingBackend.STREAMING_STATISTICS, null); } } } diff --git a/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/StreamingSearcherTestCase.java b/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/StreamingSearcherTestCase.java index 3d9a958c757..8d264f9860b 100644 --- a/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/StreamingSearcherTestCase.java +++ b/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/StreamingSearcherTestCase.java @@ -9,14 +9,12 @@ import com.yahoo.messagebus.routing.Route; import com.yahoo.prelude.fastsearch.ClusterParams; import com.yahoo.prelude.fastsearch.DocumentdbInfoConfig; import com.yahoo.document.select.parser.ParseException; -import com.yahoo.prelude.fastsearch.SummaryParameters; import com.yahoo.prelude.fastsearch.TimeoutException; import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.result.Hit; import com.yahoo.search.schema.Schema; import com.yahoo.search.schema.SchemaInfo; -import com.yahoo.search.searchchain.Execution; import com.yahoo.searchlib.aggregation.Grouping; import com.yahoo.vdslib.DocumentSummary; import com.yahoo.vdslib.SearchResult; @@ -47,6 +45,7 @@ public class StreamingSearcherTestCase { public static final String USERDOC_ID_PREFIX = "id:namespace:mytype:n=1:userspecific"; public static final String GROUPDOC_ID_PREFIX = "id:namespace:mytype:g=group1:userspecific"; + private static final ClusterParams CLUSTER_PARAMS = new ClusterParams("clusterName"); private static class MockVisitor implements Visitor { private final Query query; @@ -160,10 +159,8 @@ public class StreamingSearcherTestCase { } } - private static Result executeQuery(StreamingSearcher searcher, Query query) { - Execution execution = new Execution(Execution.Context.createContextStub()); - query.getModel().setRestrict("test"); - return searcher.doSearch2(query, execution); + private static Result executeQuery(StreamingBackend searcher, Query query) { + return searcher.doSearch2("test", query); } private static Query[] generateTestQueries(String queryString) { @@ -184,7 +181,7 @@ public class StreamingSearcherTestCase { return queries; } - private static void checkError(StreamingSearcher searcher, String queryString, String message, String detailedMessage) { + private static void checkError(StreamingBackend searcher, String queryString, String message, String detailedMessage) { for (Query query : generateTestQueries(queryString)) { Result result = executeQuery(searcher, query); assertNotNull(result.hits().getError()); @@ -197,7 +194,7 @@ public class StreamingSearcherTestCase { } } - private static void checkSearch(StreamingSearcher searcher, String queryString, int hitCount, String idPrefix) { + private static void checkSearch(StreamingBackend searcher, String queryString, int hitCount, String idPrefix) { for (Query query : generateTestQueries(queryString)) { Result result = executeQuery(searcher, query); assertNull(result.hits().getError()); @@ -215,11 +212,11 @@ public class StreamingSearcherTestCase { } } - private static void checkGrouping(StreamingSearcher searcher, String queryString, int hitCount) { + private static void checkGrouping(StreamingBackend searcher, String queryString, int hitCount) { checkSearch(searcher, queryString, hitCount, null); } - private static void checkMatchFeatures(StreamingSearcher searcher) { + private static void checkMatchFeatures(StreamingBackend searcher) { String queryString = "/?streaming.selection=true&query=match_features"; Result result = executeQuery(searcher, new Query(queryString)); assertNull(result.hits().getError()); @@ -232,15 +229,12 @@ public class StreamingSearcherTestCase { @Test void testBasics() { MockVisitorFactory factory = new MockVisitorFactory(); - StreamingSearcher searcher = new StreamingSearcher(factory); - var schema = new Schema.Builder("test"); schema.add(new com.yahoo.search.schema.DocumentSummary.Builder("default").build()); - searcher.init("container.0", - new SummaryParameters("default"), - new ClusterParams("clusterName"), + ClusterParams clusterParams = new ClusterParams("clusterName", "server.0", "default", new DocumentdbInfoConfig.Builder().documentdb(new DocumentdbInfoConfig.Documentdb.Builder().name("test")).build(), new SchemaInfo(List.of(schema.build()), List.of())); + StreamingBackend searcher = new StreamingBackend(clusterParams, "search-cluster-A", factory, "content-cluster-A"); // Magic query values are used to trigger specific behaviors from mock visitor. checkError(searcher, "/?query=noselection", @@ -279,25 +273,25 @@ public class StreamingSearcherTestCase { String groupId2 = "id:namespace:mytype:g=group2:userspecific"; String badId = "unknowscheme:namespace:something"; - assertTrue(StreamingSearcher.verifyDocId(userId1, generalQuery, true)); - - assertTrue(StreamingSearcher.verifyDocId(userId1, generalQuery, false)); - assertTrue(StreamingSearcher.verifyDocId(userId2, generalQuery, false)); - assertTrue(StreamingSearcher.verifyDocId(groupId1, generalQuery, false)); - assertTrue(StreamingSearcher.verifyDocId(groupId2, generalQuery, false)); - assertFalse(StreamingSearcher.verifyDocId(badId, generalQuery, false)); - - assertTrue(StreamingSearcher.verifyDocId(userId1, user1Query, false)); - assertFalse(StreamingSearcher.verifyDocId(userId2, user1Query, false)); - assertFalse(StreamingSearcher.verifyDocId(groupId1, user1Query, false)); - assertFalse(StreamingSearcher.verifyDocId(groupId2, user1Query, false)); - assertFalse(StreamingSearcher.verifyDocId(badId, user1Query, false)); - - assertFalse(StreamingSearcher.verifyDocId(userId1, group1Query, false)); - assertFalse(StreamingSearcher.verifyDocId(userId2, group1Query, false)); - assertTrue(StreamingSearcher.verifyDocId(groupId1, group1Query, false)); - assertFalse(StreamingSearcher.verifyDocId(groupId2, group1Query, false)); - assertFalse(StreamingSearcher.verifyDocId(badId, group1Query, false)); + assertTrue(StreamingBackend.verifyDocId(userId1, generalQuery, true)); + + assertTrue(StreamingBackend.verifyDocId(userId1, generalQuery, false)); + assertTrue(StreamingBackend.verifyDocId(userId2, generalQuery, false)); + assertTrue(StreamingBackend.verifyDocId(groupId1, generalQuery, false)); + assertTrue(StreamingBackend.verifyDocId(groupId2, generalQuery, false)); + assertFalse(StreamingBackend.verifyDocId(badId, generalQuery, false)); + + assertTrue(StreamingBackend.verifyDocId(userId1, user1Query, false)); + assertFalse(StreamingBackend.verifyDocId(userId2, user1Query, false)); + assertFalse(StreamingBackend.verifyDocId(groupId1, user1Query, false)); + assertFalse(StreamingBackend.verifyDocId(groupId2, user1Query, false)); + assertFalse(StreamingBackend.verifyDocId(badId, user1Query, false)); + + assertFalse(StreamingBackend.verifyDocId(userId1, group1Query, false)); + assertFalse(StreamingBackend.verifyDocId(userId2, group1Query, false)); + assertTrue(StreamingBackend.verifyDocId(groupId1, group1Query, false)); + assertFalse(StreamingBackend.verifyDocId(groupId2, group1Query, false)); + assertFalse(StreamingBackend.verifyDocId(badId, group1Query, false)); } private static class TraceFixture { @@ -307,13 +301,13 @@ public class StreamingSearcherTestCase { TracingOptions options; MockVisitorFactory factory; - StreamingSearcher searcher; + StreamingBackend searcher; private TraceFixture(Long firstTimestamp, Long... additionalTimestamps) { clock = MockUtils.mockedClockReturning(firstTimestamp, additionalTimestamps); options = new TracingOptions(sampler, exporter, clock, 8, 2.0); factory = new MockVisitorFactory(); - searcher = new StreamingSearcher(factory, options); + searcher = new StreamingBackend(CLUSTER_PARAMS, "search-cluster-A", factory, "content-cluster-A", options); } private TraceFixture() { diff --git a/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/StreamingVisitorTest.java b/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/StreamingVisitorTest.java index 8be60b7c3b0..30fb33ee8c8 100644 --- a/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/StreamingVisitorTest.java +++ b/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/StreamingVisitorTest.java @@ -23,6 +23,7 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import static org.junit.jupiter.api.Assertions.*; @@ -76,7 +77,7 @@ public class StreamingVisitorTest { }; } - private class QueryArguments { + private static class QueryArguments { // General query parameters String query = "test"; double timeout = 0.5; @@ -188,25 +189,21 @@ public class StreamingVisitorTest { return query; } - private void verifyVisitorParameters(VisitorParameters params, QueryArguments qa, String searchCluster, String docType, Route route) { + private void verifyVisitorParameters(VisitorParameters params, QueryArguments qa, String searchCluster, String schema, Route route) { //System.out.println("params="+params); // Verify parameters based on properties if (qa.userId != null) { - assertEquals(docType + " and ( id.user=="+qa.userId + " )", params.getDocumentSelection()); + assertEquals(schema + " and ( id.user=="+qa.userId + " )", params.getDocumentSelection()); } else if (qa.groupName != null) { - assertEquals(docType + " and ( id.group==\""+qa.groupName+"\" )", params.getDocumentSelection()); + assertEquals(schema + " and ( id.group==\""+qa.groupName+"\" )", params.getDocumentSelection()); } else if ((qa.selection == null) || qa.selection.isEmpty()) { - assertEquals(docType, params.getDocumentSelection()); + assertEquals(schema, params.getDocumentSelection()); } else { - assertEquals(docType + " and ( " + qa.selection + " )", params.getDocumentSelection()); + assertEquals(schema + " and ( " + qa.selection + " )", params.getDocumentSelection()); } assertEquals(qa.from, params.getFromTimestamp()); assertEquals(qa.to, params.getToTimestamp()); - if (qa.priority != null) { - assertEquals(qa.priority, params.getPriority()); - } else { - assertEquals(DocumentProtocol.Priority.VERY_HIGH, params.getPriority()); - } + assertEquals(Objects.requireNonNullElse(qa.priority, DocumentProtocol.Priority.VERY_HIGH), params.getPriority()); if (qa.maxBucketsPerVisitor != 0) { assertEquals(qa.maxBucketsPerVisitor, params.getMaxBucketsPerVisitor()); } else { @@ -227,17 +224,10 @@ public class StreamingVisitorTest { //System.err.println("query="+new String(params.getLibraryParameters().get("querystackcount"))); assertNotNull(params.getLibraryParameters().get("querystackcount")); // TODO: Check contents assertEquals(searchCluster, new String(params.getLibraryParameters().get("searchcluster"))); - if (qa.summary != null) { - assertEquals(qa.summary, new String(params.getLibraryParameters().get("summaryclass"))); - } else { - assertEquals("default", new String(params.getLibraryParameters().get("summaryclass"))); - } + assertEquals(schema, new String(params.getLibraryParameters().get("schema"))); + assertEquals(Objects.requireNonNullElse(qa.summary, "default"), new String(params.getLibraryParameters().get("summaryclass"))); assertEquals(Integer.toString(qa.offset+qa.hits), new String(params.getLibraryParameters().get("summarycount"))); - if (qa.profile != null) { - assertEquals(qa.profile, new String(params.getLibraryParameters().get("rankprofile"))); - } else { - assertEquals("default", new String(params.getLibraryParameters().get("rankprofile"))); - } + assertEquals(Objects.requireNonNullElse(qa.profile, "default"), new String(params.getLibraryParameters().get("rankprofile"))); //System.err.println("queryflags="+new String(params.getLibraryParameters().get("queryflags"))); assertNotNull(params.getLibraryParameters().get("queryflags")); // TODO: Check contents if (qa.location != null) { diff --git a/dependency-versions/pom.xml b/dependency-versions/pom.xml index f6f6646eb76..77292dcea8c 100644 --- a/dependency-versions/pom.xml +++ b/dependency-versions/pom.xml @@ -33,10 +33,10 @@ <!-- DO NOT UPGRADE THESE TO A NEW MAJOR VERSION WITHOUT CHECKING FOR BINARY COMPATIBILITY --> <aopalliance.vespa.version>1.0</aopalliance.vespa.version> - <error-prone-annotations.vespa.version>2.25.0</error-prone-annotations.vespa.version> + <error-prone-annotations.vespa.version>2.26.1</error-prone-annotations.vespa.version> <guava.vespa.version>33.0.0-jre</guava.vespa.version> <guice.vespa.version>6.0.0</guice.vespa.version> - <jackson2.vespa.version>2.16.1</jackson2.vespa.version> + <jackson2.vespa.version>2.16.2</jackson2.vespa.version> <jackson-databind.vespa.version>${jackson2.vespa.version}</jackson-databind.vespa.version> <jakarta.inject.vespa.version>2.0.1</jakarta.inject.vespa.version> <javax.inject.vespa.version>1</javax.inject.vespa.version> @@ -65,7 +65,7 @@ <assertj.vespa.version>3.25.3</assertj.vespa.version> <!-- Athenz dependencies. Make sure these dependencies match those in Vespa's internal repositories --> - <aws-sdk.vespa.version>1.12.674</aws-sdk.vespa.version> + <aws-sdk.vespa.version>1.12.678</aws-sdk.vespa.version> <athenz.vespa.version>1.11.53</athenz.vespa.version> <!-- Athenz END --> @@ -87,7 +87,7 @@ <commons-lang3.vespa.version>3.14.0</commons-lang3.vespa.version> <commons-logging.vespa.version>1.3.0</commons-logging.vespa.version> <!-- Bindings exported by jdisc through jcl-over-slf4j. --> <commons.math3.vespa.version>3.6.1</commons.math3.vespa.version> - <commons-compress.vespa.version>1.26.0</commons-compress.vespa.version> + <commons-compress.vespa.version>1.26.1</commons-compress.vespa.version> <commons-cli.vespa.version>1.6.0</commons-cli.vespa.version> <curator.vespa.version>5.6.0</curator.vespa.version> <dropwizard.metrics.vespa.version>4.2.25</dropwizard.metrics.vespa.version> <!-- ZK 3.9.1 requires this --> @@ -122,7 +122,7 @@ <mockito.vespa.version>5.11.0</mockito.vespa.version> <mojo-executor.vespa.version>2.4.0</mojo-executor.vespa.version> <netty.vespa.version>4.1.107.Final</netty.vespa.version> - <netty-tcnative.vespa.version>2.0.63.Final</netty-tcnative.vespa.version> + <netty-tcnative.vespa.version>2.0.65.Final</netty-tcnative.vespa.version> <onnxruntime.vespa.version>1.17.1</onnxruntime.vespa.version> <opennlp.vespa.version>2.3.2</opennlp.vespa.version> <opentest4j.vespa.version>1.3.0</opentest4j.vespa.version> @@ -158,7 +158,7 @@ <!-- Maven plugins --> <clover-maven-plugin.vespa.version>4.5.2</clover-maven-plugin.vespa.version> <maven-antrun-plugin.vespa.version>3.1.0</maven-antrun-plugin.vespa.version> - <maven-assembly-plugin.vespa.version>3.6.0</maven-assembly-plugin.vespa.version> + <maven-assembly-plugin.vespa.version>3.7.0</maven-assembly-plugin.vespa.version> <maven-bundle-plugin.vespa.version>5.1.9</maven-bundle-plugin.vespa.version> <maven-compiler-plugin.vespa.version>3.12.1</maven-compiler-plugin.vespa.version> <maven-core.vespa.version>3.9.6</maven-core.vespa.version> @@ -166,7 +166,7 @@ <maven-deploy-plugin.vespa.version>3.1.1</maven-deploy-plugin.vespa.version> <maven-enforcer-plugin.vespa.version>3.4.1</maven-enforcer-plugin.vespa.version> <maven-failsafe-plugin.vespa.version>3.2.5</maven-failsafe-plugin.vespa.version> - <maven-gpg-plugin.vespa.version>3.1.0</maven-gpg-plugin.vespa.version> + <maven-gpg-plugin.vespa.version>3.2.0</maven-gpg-plugin.vespa.version> <maven-install-plugin.vespa.version>3.1.1</maven-install-plugin.vespa.version> <maven-jar-plugin.vespa.version>3.3.0</maven-jar-plugin.vespa.version> <maven-javadoc-plugin.vespa.version>3.6.3</maven-javadoc-plugin.vespa.version> diff --git a/dist/vespa.spec b/dist/vespa.spec index 14e1869b6a5..53e82e372af 100644 --- a/dist/vespa.spec +++ b/dist/vespa.spec @@ -32,6 +32,7 @@ %define _create_vespa_service 1 %define _defattr_is_vespa_vespa 0 %define _command_cmake cmake3 +%global _vespa_build_depencencies_version 1.2.7 Name: vespa Version: _VESPA_VERSION_ @@ -42,7 +43,7 @@ License: Commercial URL: http://vespa.ai Source0: vespa-%{version}.tar.gz -BuildRequires: vespa-build-dependencies = 1.2.7 +BuildRequires: vespa-build-dependencies = %{_vespa_build_depencencies_version} Requires: %{name}-base = %{version}-%{release} Requires: %{name}-base-libs = %{version}-%{release} @@ -262,6 +263,7 @@ Vespa - The open big data serving engine - tools for system tests Summary: Vespa - The open big data serving engine - devel package +Requires: vespa-build-dependencies = %{_vespa_build_depencencies_version} Requires: %{name} = %{version}-%{release} Requires: %{name}-base-libs = %{version}-%{release} diff --git a/docproc/src/main/java/com/yahoo/docproc/jdisc/messagebus/MbusRequestContext.java b/docproc/src/main/java/com/yahoo/docproc/jdisc/messagebus/MbusRequestContext.java index 180173789ae..1836f25f8d2 100644 --- a/docproc/src/main/java/com/yahoo/docproc/jdisc/messagebus/MbusRequestContext.java +++ b/docproc/src/main/java/com/yahoo/docproc/jdisc/messagebus/MbusRequestContext.java @@ -40,6 +40,7 @@ public class MbusRequestContext implements RequestContext, ResponseHandler { private final static Logger log = Logger.getLogger(MbusRequestContext.class.getName()); private final static CopyOnWriteHashMap<String, URI> uriCache = new CopyOnWriteHashMap<>(); + private final AtomicBoolean deserialized = new AtomicBoolean(false); private final AtomicBoolean responded = new AtomicBoolean(false); private final ProcessingFactory processingFactory; diff --git a/docproc/src/main/java/com/yahoo/docproc/jdisc/messagebus/ProcessingFactory.java b/docproc/src/main/java/com/yahoo/docproc/jdisc/messagebus/ProcessingFactory.java index 030f95e380b..41d7f7920ca 100644 --- a/docproc/src/main/java/com/yahoo/docproc/jdisc/messagebus/ProcessingFactory.java +++ b/docproc/src/main/java/com/yahoo/docproc/jdisc/messagebus/ProcessingFactory.java @@ -81,7 +81,12 @@ class ProcessingFactory { log.fine(() -> "Unable to get document factory component '" + componentId + "' from document factory registry."); return document; } - return cdf.getDocumentCopy(document.getDataType().getName(), document, document.getId()); + try { + return cdf.getDocumentCopy(document.getDataType().getName(), document, document.getId()); + } + catch (RuntimeException e) { + throw new IllegalArgumentException("error in document with id '" + document.getId() + "'", e); + } } private ContainerDocumentConfig.Doctype getDocumentConfig(String name) { diff --git a/document/abi-spec.json b/document/abi-spec.json index ca06e2547d7..5096039a941 100644 --- a/document/abi-spec.json +++ b/document/abi-spec.json @@ -2862,7 +2862,9 @@ "methods" : [ "public abstract void write(com.yahoo.document.Document)", "public abstract void write(com.yahoo.document.DocumentId)", - "public abstract void write(com.yahoo.document.DocumentType)" + "public abstract void write(com.yahoo.document.DocumentType)", + "public abstract void write(com.yahoo.document.DocumentRemove)", + "public abstract void write(com.yahoo.document.DocumentUpdate)" ], "fields" : [ ] }, @@ -3104,6 +3106,7 @@ "public void write(com.yahoo.vespa.objects.FieldBase, com.yahoo.document.annotation.AnnotationReference)", "public void write(com.yahoo.document.DocumentId)", "public void write(com.yahoo.document.DocumentType)", + "public void write(com.yahoo.document.DocumentRemove)", "public void write(com.yahoo.document.annotation.Annotation)", "public void write(com.yahoo.document.annotation.SpanTree)", "public void write(com.yahoo.document.annotation.SpanNode)", diff --git a/document/src/main/java/com/yahoo/document/DocumentUpdate.java b/document/src/main/java/com/yahoo/document/DocumentUpdate.java index d3063b76feb..20d9b352d2d 100644 --- a/document/src/main/java/com/yahoo/document/DocumentUpdate.java +++ b/document/src/main/java/com/yahoo/document/DocumentUpdate.java @@ -147,7 +147,7 @@ public class DocumentUpdate extends DocumentOperation implements Iterable<FieldP Map.Entry<Integer, FieldUpdate> entry = iter.next(); FieldUpdate update = entry.getValue(); if (!update.isEmpty()) { - ValueUpdate last = update.getValueUpdate(update.size() - 1); + ValueUpdate<?> last = update.getValueUpdate(update.size() - 1); if (last instanceof AssignValueUpdate) { FieldValue currentValue = doc.getFieldValue(update.getField()); if ((currentValue != null) && currentValue.equals(last.getValue())) { @@ -190,7 +190,7 @@ public class DocumentUpdate extends DocumentOperation implements Iterable<FieldP /** Returns the type of the document this updates * - * @return The documentype of the document + * @return The document type of the document */ public DocumentType getDocumentType() { return documentType; @@ -357,9 +357,7 @@ public class DocumentUpdate extends DocumentOperation implements Iterable<FieldP @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof DocumentUpdate)) return false; - - DocumentUpdate that = (DocumentUpdate) o; + if (!(o instanceof DocumentUpdate that)) return false; if (docId != null ? !docId.equals(that.docId) : that.docId != null) return false; if (documentType != null ? !documentType.equals(that.documentType) : that.documentType != null) return false; @@ -413,7 +411,7 @@ public class DocumentUpdate extends DocumentOperation implements Iterable<FieldP } /** - * Returns whether or not this field update contains any field- or field path updates. + * Returns whether this field update contains any field- or field path updates. * * @return True if this update is empty. */ diff --git a/document/src/main/java/com/yahoo/document/datatypes/StringFieldValue.java b/document/src/main/java/com/yahoo/document/datatypes/StringFieldValue.java index 8b4b94f6bbf..d09967f973f 100644 --- a/document/src/main/java/com/yahoo/document/datatypes/StringFieldValue.java +++ b/document/src/main/java/com/yahoo/document/datatypes/StringFieldValue.java @@ -29,6 +29,9 @@ import java.util.Objects; */ public class StringFieldValue extends FieldValue { + // TODO: remove this, it's a temporary workaround for invalid data stored before unicode validation was fixed + private static final boolean replaceInvalidUnicode = System.getProperty("vespa.replace_invalid_unicode", "false").equals("true"); + private static class Factory extends PrimitiveDataType.Factory { @Override public FieldValue create() { return new StringFieldValue(); } @Override public FieldValue create(String value) { return new StringFieldValue(value); } @@ -56,16 +59,17 @@ public class StringFieldValue extends FieldValue { setValue(value); } - private static void validateTextString(String value) { + private static String validateTextString(String value) { if ( ! Text.isValidTextString(value)) { - throw new IllegalArgumentException("The string field value contains illegal code point 0x" + - Integer.toHexString(Text.validateTextString(value).getAsInt()).toUpperCase()); + if (replaceInvalidUnicode) return Text.stripInvalidCharacters(value); + else throw new IllegalArgumentException("The string field value contains illegal code point 0x" + + Integer.toHexString(Text.validateTextString(value).getAsInt()).toUpperCase()); } + return value; } private void setValue(String value) { - validateTextString(value); - this.value = value; + this.value = validateTextString(value); } /** diff --git a/document/src/main/java/com/yahoo/document/json/JsonSerializationHelper.java b/document/src/main/java/com/yahoo/document/json/JsonSerializationHelper.java index 7b1042903ec..ed6bdc721a0 100644 --- a/document/src/main/java/com/yahoo/document/json/JsonSerializationHelper.java +++ b/document/src/main/java/com/yahoo/document/json/JsonSerializationHelper.java @@ -347,4 +347,5 @@ public class JsonSerializationHelper { wrapIOException(() -> generator.writeFieldName(field.getName())); } } + } diff --git a/document/src/main/java/com/yahoo/document/json/JsonWriter.java b/document/src/main/java/com/yahoo/document/json/JsonWriter.java index 7e82e830064..2b0ba138466 100644 --- a/document/src/main/java/com/yahoo/document/json/JsonWriter.java +++ b/document/src/main/java/com/yahoo/document/json/JsonWriter.java @@ -7,7 +7,9 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.StreamReadConstraints; import com.yahoo.document.Document; import com.yahoo.document.DocumentId; +import com.yahoo.document.DocumentRemove; import com.yahoo.document.DocumentType; +import com.yahoo.document.DocumentUpdate; import com.yahoo.document.Field; import com.yahoo.document.annotation.AnnotationReference; import com.yahoo.document.datatypes.Array; @@ -263,6 +265,26 @@ public class JsonWriter implements DocumentWriter { // NOP, fetched from Document } + @Override + public void write(DocumentRemove documentRemove) { + try { + generator.writeStartObject(); + + serializeStringField(generator, new FieldBase("remove"), new StringFieldValue(documentRemove.getId().toString())); + + generator.writeEndObject(); + generator.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void write(DocumentUpdate documentUpdate) { + var serializer = new DocumentUpdateJsonSerializer(generator); + serializer.serialize(documentUpdate); + } + /** * Utility method to easily serialize a single document. * diff --git a/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateWriter.java b/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateWriter.java index 0202ec8bf23..b9cc439ad54 100644 --- a/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateWriter.java +++ b/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateWriter.java @@ -17,8 +17,7 @@ import com.yahoo.document.update.TensorRemoveUpdate; /** * Interface for writing document updates in custom serializers. * - * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a> - * @since 5.1.27 + * @author Einar M R Rosenvinge */ public interface DocumentUpdateWriter { void write(DocumentUpdate update); diff --git a/document/src/main/java/com/yahoo/document/serialization/DocumentWriter.java b/document/src/main/java/com/yahoo/document/serialization/DocumentWriter.java index c84140c9ea0..16125926fe6 100644 --- a/document/src/main/java/com/yahoo/document/serialization/DocumentWriter.java +++ b/document/src/main/java/com/yahoo/document/serialization/DocumentWriter.java @@ -3,7 +3,9 @@ package com.yahoo.document.serialization; import com.yahoo.document.Document; import com.yahoo.document.DocumentId; +import com.yahoo.document.DocumentRemove; import com.yahoo.document.DocumentType; +import com.yahoo.document.DocumentUpdate; /** * @author ravishar @@ -17,4 +19,8 @@ public interface DocumentWriter extends FieldWriter { void write(DocumentType type); + void write(DocumentRemove documentRemove); + + void write(DocumentUpdate documentUpdate); + } diff --git a/document/src/main/java/com/yahoo/document/serialization/VespaDocumentSerializer6.java b/document/src/main/java/com/yahoo/document/serialization/VespaDocumentSerializer6.java index 17ab3890bcf..4cb836860be 100644 --- a/document/src/main/java/com/yahoo/document/serialization/VespaDocumentSerializer6.java +++ b/document/src/main/java/com/yahoo/document/serialization/VespaDocumentSerializer6.java @@ -8,6 +8,7 @@ import com.yahoo.document.CollectionDataType; import com.yahoo.document.DataType; import com.yahoo.document.Document; import com.yahoo.document.DocumentId; +import com.yahoo.document.DocumentRemove; import com.yahoo.document.DocumentType; import com.yahoo.document.DocumentUpdate; import com.yahoo.document.Field; @@ -426,6 +427,10 @@ public class VespaDocumentSerializer6 extends BufferSerializer implements Docume putShort(null, (short) 0); // Used to hold the version. Is now always 0. } + public void write(DocumentRemove documentRemove) { + throw new UnsupportedOperationException("serializing remove not implemented"); + } + public void write(Annotation annotation) { buf.putInt(annotation.getType().getId()); //name hash diff --git a/document/src/tests/serialization/CMakeLists.txt b/document/src/tests/serialization/CMakeLists.txt index e5bf91f401d..8a997299e38 100644 --- a/document/src/tests/serialization/CMakeLists.txt +++ b/document/src/tests/serialization/CMakeLists.txt @@ -11,5 +11,6 @@ vespa_add_executable(document_annotationserializer_test_app TEST annotationserializer_test.cpp DEPENDS document + GTest::gtest ) vespa_add_test(NAME document_annotationserializer_test_app COMMAND document_annotationserializer_test_app) diff --git a/document/src/tests/serialization/annotationserializer_test.cpp b/document/src/tests/serialization/annotationserializer_test.cpp index 14edd38d0b0..3499f9d8012 100644 --- a/document/src/tests/serialization/annotationserializer_test.cpp +++ b/document/src/tests/serialization/annotationserializer_test.cpp @@ -11,11 +11,13 @@ #include <vespa/document/serialization/vespadocumentdeserializer.h> #include <vespa/document/serialization/vespadocumentserializer.h> #include <vespa/document/repo/documenttyperepo.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/objects/nbostream.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/testkit/test_path.h> #include <vespa/fastos/file.h> -#include <fstream> #include <algorithm> +#include <fstream> +#include <optional> using std::fstream; @@ -27,35 +29,11 @@ using namespace document; namespace { -class Test : public vespalib::TestApp { - StringFieldValue::SpanTrees readSpanTree(const string &file_name, const FixedTypeRepo &repo); - - void requireThatSimpleSpanTreeIsDeserialized(); - void requireThatAdvancedSpanTreeIsDeserialized(); - void requireThatSpanTreeCanBeSerialized(); - void requireThatUnknownAnnotationIsSkipped(); - -public: - int Main() override; -}; - -int -Test::Main() -{ - if (getenv("TEST_SUBSET") != 0) { return 0; } - TEST_INIT("annotationserializer_test"); - TEST_DO(requireThatSimpleSpanTreeIsDeserialized()); - TEST_DO(requireThatAdvancedSpanTreeIsDeserialized()); - TEST_DO(requireThatSpanTreeCanBeSerialized()); - TEST_DO(requireThatUnknownAnnotationIsSkipped()); - - TEST_DONE(); -} - template <typename T, int N> int arraysize(const T (&)[N]) { return N; } -StringFieldValue::SpanTrees -Test::readSpanTree(const string &file_name, const FixedTypeRepo &repo) { +void +read_span_trees(const string &file_name, const FixedTypeRepo &repo, std::optional<StringFieldValue::SpanTrees>& span_trees) +{ FastOS_File file(file_name.c_str()); ASSERT_TRUE(file.OpenReadOnlyExisting()); char buffer[1024]; @@ -67,26 +45,31 @@ Test::readSpanTree(const string &file_name, const FixedTypeRepo &repo) { StringFieldValue value; deserializer.read(value); - EXPECT_EQUAL(0u, stream.size()); + EXPECT_EQ(0u, stream.size()); ASSERT_TRUE(value.hasSpanTrees()); - return value.getSpanTrees(); + span_trees = value.getSpanTrees(); } -void Test::requireThatSimpleSpanTreeIsDeserialized() { +} + +TEST(AnnotationSerializerTest, require_that_simple_span_tree_is_deserialized) +{ DocumentTypeRepo type_repo(readDocumenttypesConfig(TEST_PATH("annotation.serialize.test.repo.cfg"))); FixedTypeRepo repo(type_repo); - SpanTree::UP span_tree = std::move(readSpanTree(TEST_PATH("test_data_serialized_simple"), repo).front()); + std::optional<StringFieldValue::SpanTrees> span_trees; + ASSERT_NO_FATAL_FAILURE(read_span_trees(TEST_PATH("test_data_serialized_simple"), repo, span_trees)); + auto span_tree = std::move(span_trees.value().front()); - EXPECT_EQUAL("html", span_tree->getName()); + EXPECT_EQ("html", span_tree->getName()); const SimpleSpanList *root = dynamic_cast<const SimpleSpanList *>(&span_tree->getRoot()); ASSERT_TRUE(root); - EXPECT_EQUAL(5u, root->size()); + EXPECT_EQ(5u, root->size()); SimpleSpanList::const_iterator it = root->begin(); - EXPECT_EQUAL(Span(0, 19), (*it++)); - EXPECT_EQUAL(Span(19, 5), (*it++)); - EXPECT_EQUAL(Span(24, 21), (*it++)); - EXPECT_EQUAL(Span(45, 23), (*it++)); - EXPECT_EQUAL(Span(68, 14), (*it++)); + EXPECT_EQ(Span(0, 19), (*it++)); + EXPECT_EQ(Span(19, 5), (*it++)); + EXPECT_EQ(Span(24, 21), (*it++)); + EXPECT_EQ(Span(45, 23), (*it++)); + EXPECT_EQ(Span(68, 14), (*it++)); EXPECT_TRUE(it == root->end()); } @@ -107,49 +90,51 @@ struct AnnotationComparator { void compare() { std::sort(expect.begin(), expect.end()); std::sort(actual.begin(), actual.end()); - EXPECT_EQUAL(expect.size(), actual.size()); + EXPECT_EQ(expect.size(), actual.size()); for (size_t i = 0; i < expect.size() && i < actual.size(); ++i) { - EXPECT_EQUAL(expect[i].size(), actual[i].size()); - EXPECT_EQUAL(expect[i], actual[i]); + EXPECT_EQ(expect[i].size(), actual[i].size()); + EXPECT_EQ(expect[i], actual[i]); } } }; -void Test::requireThatAdvancedSpanTreeIsDeserialized() { +TEST(AnnotationSerializerTest, require_that_advanced_span_tree_is_deserialized) +{ DocumentTypeRepo type_repo(readDocumenttypesConfig(TEST_PATH("annotation.serialize.test.repo.cfg"))); FixedTypeRepo repo(type_repo, "my_document"); - SpanTree::UP span_tree = std::move(readSpanTree(TEST_PATH("test_data_serialized_advanced"), - repo).front()); + std::optional<StringFieldValue::SpanTrees> span_trees; + ASSERT_NO_FATAL_FAILURE(read_span_trees(TEST_PATH("test_data_serialized_advanced"), repo, span_trees)); + auto span_tree = std::move(span_trees.value().front()); - EXPECT_EQUAL("html", span_tree->getName()); + EXPECT_EQ("html", span_tree->getName()); const SpanList *root = dynamic_cast<const SpanList *>(&span_tree->getRoot()); ASSERT_TRUE(root); - EXPECT_EQUAL(4u, root->size()); + EXPECT_EQ(4u, root->size()); SpanList::const_iterator it = root->begin(); - EXPECT_EQUAL(Span(0, 6), *(static_cast<Span *>(*it++))); + EXPECT_EQ(Span(0, 6), *(static_cast<Span *>(*it++))); AlternateSpanList *alt_list = dynamic_cast<AlternateSpanList *>(*it++); - EXPECT_EQUAL(Span(27, 9), *(static_cast<Span *>(*it++))); - EXPECT_EQUAL(Span(36, 8), *(static_cast<Span *>(*it++))); + EXPECT_EQ(Span(27, 9), *(static_cast<Span *>(*it++))); + EXPECT_EQ(Span(36, 8), *(static_cast<Span *>(*it++))); EXPECT_TRUE(it == root->end()); ASSERT_TRUE(alt_list); - EXPECT_EQUAL(2u, alt_list->getNumSubtrees()); - EXPECT_EQUAL(0.9, alt_list->getProbability(0)); - EXPECT_EQUAL(0.1, alt_list->getProbability(1)); - EXPECT_EQUAL(4u, alt_list->getSubtree(0).size()); + EXPECT_EQ(2u, alt_list->getNumSubtrees()); + EXPECT_EQ(0.9, alt_list->getProbability(0)); + EXPECT_EQ(0.1, alt_list->getProbability(1)); + EXPECT_EQ(4u, alt_list->getSubtree(0).size()); it = alt_list->getSubtree(0).begin(); - EXPECT_EQUAL(Span(6, 3), *(static_cast<Span *>(*it++))); - EXPECT_EQUAL(Span(9, 10), *(static_cast<Span *>(*it++))); - EXPECT_EQUAL(Span(19, 4), *(static_cast<Span *>(*it++))); - EXPECT_EQUAL(Span(23, 4), *(static_cast<Span *>(*it++))); + EXPECT_EQ(Span(6, 3), *(static_cast<Span *>(*it++))); + EXPECT_EQ(Span(9, 10), *(static_cast<Span *>(*it++))); + EXPECT_EQ(Span(19, 4), *(static_cast<Span *>(*it++))); + EXPECT_EQ(Span(23, 4), *(static_cast<Span *>(*it++))); EXPECT_TRUE(it == alt_list->getSubtree(0).end()); - EXPECT_EQUAL(2u, alt_list->getSubtree(1).size()); + EXPECT_EQ(2u, alt_list->getSubtree(1).size()); it = alt_list->getSubtree(1).begin(); - EXPECT_EQUAL(Span(6, 13), *(static_cast<Span *>(*it++))); - EXPECT_EQUAL(Span(19, 8), *(static_cast<Span *>(*it++))); + EXPECT_EQ(Span(6, 13), *(static_cast<Span *>(*it++))); + EXPECT_EQ(Span(19, 8), *(static_cast<Span *>(*it++))); EXPECT_TRUE(it == alt_list->getSubtree(1).end()); - EXPECT_EQUAL(12u, span_tree->numAnnotations()); + EXPECT_EQ(12u, span_tree->numAnnotations()); AnnotationComparator comparator; comparator.addActual(span_tree->begin(), span_tree->end()) @@ -213,10 +198,11 @@ void Test::requireThatAdvancedSpanTreeIsDeserialized() { " AnnotationReferenceFieldValue(n)\n" " )\n" "))"); - TEST_DO(comparator.compare()); + comparator.compare(); } -void Test::requireThatSpanTreeCanBeSerialized() { +TEST(AnnotationSerializerTest, require_that_span_tree_can_be_serialized) +{ DocumentTypeRepo type_repo( readDocumenttypesConfig(TEST_PATH("annotation.serialize.test.repo.cfg"))); FixedTypeRepo repo(type_repo, "my_document"); @@ -233,25 +219,26 @@ void Test::requireThatSpanTreeCanBeSerialized() { StringFieldValue value; deserializer.read(value); - SpanTree::UP span_tree = std::move(value.getSpanTrees().front()); - EXPECT_EQUAL("html", span_tree->getName()); - EXPECT_EQUAL(0u, stream.size()); + auto span_tree = std::move(value.getSpanTrees().front()); + EXPECT_EQ("html", span_tree->getName()); + EXPECT_EQ(0u, stream.size()); stream.clear(); VespaDocumentSerializer serializer(stream); serializer.write(value); - EXPECT_EQUAL(size, static_cast<ssize_t>(stream.size())); + EXPECT_EQ(size, static_cast<ssize_t>(stream.size())); int diff_count = 0; for (size_t i = 0; i < stream.size(); ++i) { if (buffer[i] != stream.peek()[i]) { ++diff_count; } - EXPECT_EQUAL((int) buffer[i], (int) stream.peek()[i]); + EXPECT_EQ((int) buffer[i], (int) stream.peek()[i]); } - EXPECT_EQUAL(0, diff_count); + EXPECT_EQ(0, diff_count); } -void Test::requireThatUnknownAnnotationIsSkipped() { +TEST(AnnotationSerializerTest, require_that_unknown_annotation_is_skipped) +{ AnnotationType type(42, "my type"); Annotation annotation(type, FieldValue::UP(new StringFieldValue("foo"))); nbostream stream; @@ -264,9 +251,7 @@ void Test::requireThatUnknownAnnotationIsSkipped() { Annotation a; deserializer.readAnnotation(a); EXPECT_FALSE(a.valid()); - EXPECT_EQUAL(0u, stream.size()); + EXPECT_EQ(0u, stream.size()); } -} // namespace - -TEST_APPHOOK(Test); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/document/src/tests/struct_anno/CMakeLists.txt b/document/src/tests/struct_anno/CMakeLists.txt index 855cba606a3..2d688454058 100644 --- a/document/src/tests/struct_anno/CMakeLists.txt +++ b/document/src/tests/struct_anno/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(document_struct_anno_test_app TEST struct_anno_test.cpp DEPENDS document + GTest::gtest ) vespa_add_test(NAME document_struct_anno_test_app COMMAND document_struct_anno_test_app) diff --git a/document/src/tests/struct_anno/struct_anno_test.cpp b/document/src/tests/struct_anno/struct_anno_test.cpp index 31d3900c6bc..8ab883c6de1 100644 --- a/document/src/tests/struct_anno/struct_anno_test.cpp +++ b/document/src/tests/struct_anno/struct_anno_test.cpp @@ -11,8 +11,9 @@ #include <vespa/document/serialization/vespadocumentdeserializer.h> #include <vespa/document/serialization/vespadocumentserializer.h> #include <vespa/document/repo/documenttyperepo.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/objects/nbostream.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/testkit/test_path.h> #include <vespa/fastos/file.h> using std::ostringstream; @@ -23,23 +24,12 @@ using namespace document; namespace { -class Test : public vespalib::TestApp { - void requireThatStructFieldsCanContainAnnotations(); - -public: - int Main() override; -}; +template <typename T, int N> int arraysize(const T (&)[N]) { return N; } -int Test::Main() { - if (getenv("TEST_SUBSET") != 0) { return 0; } - TEST_INIT("struct_anno_test"); - TEST_DO(requireThatStructFieldsCanContainAnnotations()); - TEST_DONE(); } -template <typename T, int N> int arraysize(const T (&)[N]) { return N; } - -void Test::requireThatStructFieldsCanContainAnnotations() { +TEST(StructAnnoTest, require_that_struct_fields_can_contain_annotations) +{ DocumentTypeRepo repo(readDocumenttypesConfig(TEST_PATH("documenttypes.cfg"))); FastOS_File file(TEST_PATH("document.dat").c_str()); @@ -62,19 +52,17 @@ void Test::requireThatStructFieldsCanContainAnnotations() { const StringFieldValue *str = dynamic_cast<const StringFieldValue*>(strRef.get()); ASSERT_TRUE(str != NULL); - SpanTree::UP tree = std::move(str->getSpanTrees().front()); + auto tree = std::move(str->getSpanTrees().front()); - EXPECT_EQUAL("my_tree", tree->getName()); + EXPECT_EQ("my_tree", tree->getName()); const SimpleSpanList *root = dynamic_cast<const SimpleSpanList*>(&tree->getRoot()); ASSERT_TRUE(root != NULL); - EXPECT_EQUAL(1u, root->size()); + EXPECT_EQ(1u, root->size()); SimpleSpanList::const_iterator it = root->begin(); - EXPECT_EQUAL(Span(0, 6), (*it++)); + EXPECT_EQ(Span(0, 6), (*it++)); EXPECT_TRUE(it == root->end()); - EXPECT_EQUAL(1u, tree->numAnnotations()); + EXPECT_EQ(1u, tree->numAnnotations()); } -} // namespace - -TEST_APPHOOK(Test); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/document/src/vespa/document/select/branch.cpp b/document/src/vespa/document/select/branch.cpp index 02f767c96b5..6035b5fe9a0 100644 --- a/document/src/vespa/document/select/branch.cpp +++ b/document/src/vespa/document/select/branch.cpp @@ -39,6 +39,10 @@ namespace { ResultList traceAndValue(const T& value, std::ostream& out, const Node& leftNode, const Node& rightNode) { + out << "And (lhs):\n"; + (void)leftNode.trace(value, out); + out << "And (rhs):\n"; + (void)rightNode.trace(value, out); out << "And - Left branch returned " << leftNode.contains(value) << ".\n"; out << "And - Right branch returned " << rightNode.contains(value) << ".\n"; return leftNode.contains(value) && rightNode.contains(value); @@ -83,6 +87,10 @@ namespace { ResultList traceOrValue(const T& value, std::ostream& out, const Node& leftNode, const Node& rightNode) { + out << "Or (lhs):\n"; + (void)leftNode.trace(value, out); + out << "Or (rhs):\n"; + (void)rightNode.trace(value, out); out << "Or - Left branch returned " << leftNode.contains(value) << ".\n"; out << "Or - Right branch returned " << rightNode.contains(value) << ".\n"; return leftNode.contains(value) || rightNode.contains(value); @@ -122,6 +130,8 @@ namespace { template<typename T> ResultList traceNotValue(const T& value, std::ostream& out, const Node& node) { + out << "Not:\n"; + (void)node.trace(value, out); out << "Not - Child returned " << node.contains(value) << ". Returning opposite.\n"; return !node.contains(value); diff --git a/documentapi/src/tests/messagebus/CMakeLists.txt b/documentapi/src/tests/messagebus/CMakeLists.txt index 22e213f29d8..ef597fbee10 100644 --- a/documentapi/src/tests/messagebus/CMakeLists.txt +++ b/documentapi/src/tests/messagebus/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(documentapi_messagebus_test_app TEST messagebus_test.cpp DEPENDS documentapi + GTest::gtest ) vespa_add_test(NAME documentapi_messagebus_test_app COMMAND documentapi_messagebus_test_app) diff --git a/documentapi/src/tests/messagebus/messagebus_test.cpp b/documentapi/src/tests/messagebus/messagebus_test.cpp index 6ce76fc753f..39f9cedb38f 100644 --- a/documentapi/src/tests/messagebus/messagebus_test.cpp +++ b/documentapi/src/tests/messagebus/messagebus_test.cpp @@ -6,7 +6,8 @@ #include <vespa/document/repo/documenttyperepo.h> #include <vespa/document/update/documentupdate.h> #include <vespa/documentapi/documentapi.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> +#include <vespa/vespalib/testkit/test_path.h> using document::DocumentTypeRepo; using document::readDocumenttypesConfig; @@ -15,44 +16,35 @@ using mbus::Blob; using mbus::Routable; using mbus::IRoutingPolicy; -class Test : public vespalib::TestApp { - std::shared_ptr<const DocumentTypeRepo> _repo; - -public: - Test(); - ~Test(); - int Main() override; - -private: - void testMessage(); - void testProtocol(); - void get_document_message_is_not_sequenced(); - void stat_bucket_message_is_not_sequenced(); - void get_bucket_list_message_is_not_sequenced(); +class MessageBusTest : public testing::Test { +protected: + static std::shared_ptr<const DocumentTypeRepo> _repo; + MessageBusTest(); + ~MessageBusTest() override; + static void SetUpTestSuite(); + static void TearDownTestSuite(); }; -TEST_APPHOOK(Test); - -int -Test::Main() -{ - TEST_INIT(_argv[0]); - _repo.reset(new DocumentTypeRepo(readDocumenttypesConfig( - TEST_PATH("../../../test/cfg/testdoctypes.cfg")))); +MessageBusTest::MessageBusTest() = default; +MessageBusTest::~MessageBusTest() = default; - testMessage(); TEST_FLUSH(); - testProtocol(); TEST_FLUSH(); - get_document_message_is_not_sequenced(); TEST_FLUSH(); - stat_bucket_message_is_not_sequenced(); TEST_FLUSH(); - get_bucket_list_message_is_not_sequenced(); TEST_FLUSH(); +std::shared_ptr<const DocumentTypeRepo> MessageBusTest::_repo; - TEST_DONE(); +void +MessageBusTest::SetUpTestSuite() +{ + auto path = TEST_PATH("../../../test/cfg/testdoctypes.cfg"); + _repo = std::make_shared<const DocumentTypeRepo>(readDocumenttypesConfig(path)); } -Test::Test() = default; -Test::~Test() = default; +void +MessageBusTest::TearDownTestSuite() +{ + _repo.reset(); +} -void Test::testMessage() { +TEST_F(MessageBusTest, test_message) +{ const document::DataType *testdoc_type = _repo->getDocumentType("testdoc"); // Test one update. @@ -85,7 +77,8 @@ void Test::testMessage() { EXPECT_TRUE(msg2.getType() == DocumentProtocol::MESSAGE_UPDATEDOCUMENT); } -void Test::testProtocol() { +TEST_F(MessageBusTest, test_protocol) +{ DocumentProtocol protocol(_repo); EXPECT_TRUE(protocol.getName() == "document"); @@ -99,17 +92,22 @@ void Test::testProtocol() { EXPECT_TRUE(policy.get() == NULL); } -void Test::get_document_message_is_not_sequenced() { +TEST_F(MessageBusTest, get_document_message_is_not_sequenced) +{ GetDocumentMessage message(document::DocumentId("id:foo:bar::baz")); EXPECT_FALSE(message.hasSequenceId()); } -void Test::stat_bucket_message_is_not_sequenced() { +TEST_F(MessageBusTest, stat_bucket_message_is_not_sequenced) +{ StatBucketMessage message(document::BucketId(16, 1), ""); EXPECT_FALSE(message.hasSequenceId()); } -void Test::get_bucket_list_message_is_not_sequenced() { +TEST_F(MessageBusTest, get_bucket_list_message_is_not_sequenced) +{ GetBucketListMessage message(document::BucketId(16, 1)); EXPECT_FALSE(message.hasSequenceId()); } + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/documentapi/src/tests/policies/CMakeLists.txt b/documentapi/src/tests/policies/CMakeLists.txt index 2482342a08f..9c537c33db8 100644 --- a/documentapi/src/tests/policies/CMakeLists.txt +++ b/documentapi/src/tests/policies/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(documentapi_policies_test_app TEST policies_test.cpp DEPENDS documentapi + GTest::gtest ) vespa_add_test(NAME documentapi_policies_test_app COMMAND documentapi_policies_test_app) diff --git a/documentapi/src/tests/policies/policies_test.cpp b/documentapi/src/tests/policies/policies_test.cpp index 7091b63b6b3..c289bae0bcd 100644 --- a/documentapi/src/tests/policies/policies_test.cpp +++ b/documentapi/src/tests/policies/policies_test.cpp @@ -23,8 +23,11 @@ #include <vespa/document/repo/documenttyperepo.h> #include <vespa/document/update/documentupdate.h> #include <vespa/document/fieldvalue/document.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> +#include <vespa/vespalib/testkit/test_path.h> #include <vespa/vespalib/util/stringfmt.h> +#include <functional> +#include <optional> #include <thread> #include <vespa/log/log.h> @@ -44,16 +47,21 @@ using std::make_shared; using namespace std::chrono_literals; -class Test : public vespalib::TestApp { -private: - std::shared_ptr<const DocumentTypeRepo> _repo; - const DataType *_docType; +class PoliciesTest : public testing::Test { +protected: + static std::shared_ptr<const DocumentTypeRepo> _repo; + static const DataType* _docType; + PoliciesTest(); + ~PoliciesTest() override; + static void SetUpTestSuite(); + static void TearDownTestSuite(); + + using WrappedPolicy = std::optional<std::reference_wrapper<ContentPolicy>>; -private: static bool trySelect(TestFrame &frame, uint32_t numSelects, const std::vector<string> &expected); static void setupExternPolicy(TestFrame &frame, mbus::Slobrok &slobrok, const string &pattern, int32_t numEntries = -1); - static ContentPolicy &setupContentPolicy(TestFrame &frame, const string ¶m, - const string &pattern = "", int32_t numEntries = -1); + static void setupContentPolicy(TestFrame &frame, const string ¶m, + const string &pattern, int32_t numEntries, WrappedPolicy& wrapped_policy); bool isErrorPolicy(const string &name, const string ¶m); static void assertMirrorReady(const IMirrorAPI &mirror); static void assertMirrorContains(const IMirrorAPI &mirror, const string &pattern, uint32_t numEntries); @@ -61,86 +69,32 @@ private: std::shared_ptr<Document> make_doc(DocumentId docid) { return std::make_shared<Document>(*_repo, *_docType, docid); } - -public: - Test(); - ~Test() override; - int Main() override; - void testAND(); - void testDocumentRouteSelector(); - void testDocumentRouteSelectorIgnore(); - void remove_document_messages_are_sent_to_the_route_handling_the_given_document_type(); - void get_document_messages_are_sent_to_the_route_handling_the_given_document_type(); - void testExternSend(); - void testExternMultipleSlobroks(); - static void testLoadBalancer(); - void testLocalService(); - void testLocalServiceCache(); - void testProtocol(); - void testRoundRobin(); - void testRoundRobinCache(); - void multipleGetRepliesAreMergedToFoundDocument(); - void testSubsetService(); - void testSubsetServiceCache(); - - void requireThatExternPolicyWithIllegalParamIsAnErrorPolicy(); - void requireThatExternPolicyWithUnknownPatternSelectsNone(); - void requireThatExternPolicySelectsFromExternSlobrok(); - void requireThatExternPolicyMergesOneReplyAsProtocol(); - void requireThatContentPolicyWithIllegalParamIsAnErrorPolicy(); - void requireThatContentPolicyIsRandomWithoutState(); - void requireThatContentPolicyIsTargetedWithState(); - void requireThatContentPolicyCombinesSystemAndSlobrokState(); }; -TEST_APPHOOK(Test); - -Test::Test() = default; -Test::~Test() = default; - -const vespalib::duration TIMEOUT = 600s; +PoliciesTest::PoliciesTest() = default; +PoliciesTest::~PoliciesTest() = default; -int -Test::Main() { - TEST_INIT(_argv[0]); +std::shared_ptr<const DocumentTypeRepo> PoliciesTest::_repo; +const DataType* PoliciesTest::_docType = nullptr; - _repo = std::make_shared<DocumentTypeRepo>(readDocumenttypesConfig(TEST_PATH("../../../test/cfg/testdoctypes.cfg"))); +void +PoliciesTest::SetUpTestSuite() +{ + auto path = TEST_PATH("../../../test/cfg/testdoctypes.cfg"); + _repo = std::make_shared<DocumentTypeRepo>(readDocumenttypesConfig(path)); _docType = _repo->getDocumentType("testdoc"); - - testProtocol(); TEST_FLUSH(); - - testAND(); TEST_FLUSH(); - testDocumentRouteSelector(); TEST_FLUSH(); - testDocumentRouteSelectorIgnore(); TEST_FLUSH(); - remove_document_messages_are_sent_to_the_route_handling_the_given_document_type(); TEST_FLUSH(); - get_document_messages_are_sent_to_the_route_handling_the_given_document_type(); TEST_FLUSH(); - testExternSend(); TEST_FLUSH(); - testExternMultipleSlobroks(); TEST_FLUSH(); - testLoadBalancer(); TEST_FLUSH(); - testLocalService(); TEST_FLUSH(); - testLocalServiceCache(); TEST_FLUSH(); - testRoundRobin(); TEST_FLUSH(); - testRoundRobinCache(); TEST_FLUSH(); - testSubsetService(); TEST_FLUSH(); - testSubsetServiceCache(); TEST_FLUSH(); - - multipleGetRepliesAreMergedToFoundDocument(); TEST_FLUSH(); - - requireThatExternPolicyWithIllegalParamIsAnErrorPolicy(); TEST_FLUSH(); - requireThatExternPolicyWithUnknownPatternSelectsNone(); TEST_FLUSH(); - requireThatExternPolicySelectsFromExternSlobrok(); TEST_FLUSH(); - requireThatExternPolicyMergesOneReplyAsProtocol(); TEST_FLUSH(); - - requireThatContentPolicyWithIllegalParamIsAnErrorPolicy(); TEST_FLUSH(); - requireThatContentPolicyIsRandomWithoutState(); TEST_FLUSH(); - requireThatContentPolicyIsTargetedWithState(); TEST_FLUSH(); - requireThatContentPolicyCombinesSystemAndSlobrokState(); TEST_FLUSH(); - - TEST_DONE(); } void -Test::testProtocol() +PoliciesTest::TearDownTestSuite() +{ + _repo.reset(); + _docType = nullptr; +} + +const vespalib::duration TIMEOUT = 600s; + +TEST_F(PoliciesTest, test_protocol) { auto protocol = std::make_shared<DocumentProtocol>(_repo); @@ -168,8 +122,7 @@ Test::testProtocol() ASSERT_TRUE(dynamic_cast<SubsetServicePolicy*>(policy.get()) != nullptr); } -void -Test::testAND() +TEST_F(PoliciesTest, test_and) { TestFrame frame(_repo); frame.setMessage(make_unique<PutDocumentMessage>(make_doc(DocumentId("id:ns:testdoc::")))); @@ -189,8 +142,7 @@ Test::testAND() EXPECT_TRUE(frame.testMergeTwoReplies("foo", "bar")); } -void -Test::requireThatExternPolicyWithIllegalParamIsAnErrorPolicy() +TEST_F(PoliciesTest, require_that_extern_policy_with_illegal_param_is_an_error_policy) { mbus::Slobrok slobrok; string spec = vespalib::make_string("tcp/localhost:%d", slobrok.port()); @@ -201,19 +153,17 @@ Test::requireThatExternPolicyWithIllegalParamIsAnErrorPolicy() EXPECT_TRUE(isErrorPolicy("Extern", spec + ";bar")); } -void -Test::requireThatExternPolicyWithUnknownPatternSelectsNone() +TEST_F(PoliciesTest, require_that_extern_policy_with_unknown_pattern_selects_none) { TestFrame frame(_repo); frame.setMessage(newPutDocumentMessage("id:ns:testdoc::")); mbus::Slobrok slobrok; - setupExternPolicy(frame, slobrok, "foo/bar"); + ASSERT_NO_FATAL_FAILURE(setupExternPolicy(frame, slobrok, "foo/bar")); EXPECT_TRUE(frame.testSelect(StringList())); } -void -Test::requireThatExternPolicySelectsFromExternSlobrok() +TEST_F(PoliciesTest, require_that_extern_policy_selects_from_extern_slobrok) { TestFrame frame(_repo); frame.setMessage(newPutDocumentMessage("id:ns:testdoc::")); @@ -226,7 +176,7 @@ Test::requireThatExternPolicySelectsFromExternSlobrok() servers.push_back(server); server->net.registerSession("chain.default"); } - setupExternPolicy(frame, slobrok, "docproc/cluster.default/*/chain.default", 10); + ASSERT_NO_FATAL_FAILURE(setupExternPolicy(frame, slobrok, "docproc/cluster.default/*/chain.default", 10)); std::set<string> lst; for (uint32_t i = 0; i < servers.size(); ++i) { std::vector<mbus::RoutingNode*> leaf; @@ -236,14 +186,13 @@ Test::requireThatExternPolicySelectsFromExternSlobrok() leaf[0]->handleReply(std::make_unique<mbus::EmptyReply>()); ASSERT_TRUE(frame.getReceptor().getReply(TIMEOUT)); } - EXPECT_EQUAL(servers.size(), lst.size()); + EXPECT_EQ(servers.size(), lst.size()); for (auto & server : servers) { delete server; } } -void -Test::requireThatExternPolicyMergesOneReplyAsProtocol() +TEST_F(PoliciesTest, require_that_extern_policy_merges_one_reply_as_protocol) { TestFrame frame(_repo); frame.setMessage(newPutDocumentMessage("id:ns:testdoc::")); @@ -251,18 +200,18 @@ Test::requireThatExternPolicyMergesOneReplyAsProtocol() mbus::TestServer server(mbus::Identity("docproc/cluster.default/0"), mbus::RoutingSpec(), slobrok, std::make_shared<DocumentProtocol>(_repo)); server.net.registerSession("chain.default"); - setupExternPolicy(frame, slobrok, "docproc/cluster.default/0/chain.default", 1); + ASSERT_NO_FATAL_FAILURE(setupExternPolicy(frame, slobrok, "docproc/cluster.default/0/chain.default", 1)); EXPECT_TRUE(frame.testMergeOneReply(server.net.getConnectionSpec() + "/chain.default")); } mbus::Message::UP -Test::newPutDocumentMessage(const string &documentId) +PoliciesTest::newPutDocumentMessage(const string &documentId) { return make_unique<PutDocumentMessage>(make_doc(DocumentId(documentId))); } void -Test::setupExternPolicy(TestFrame &frame, mbus::Slobrok &slobrok, const string &pattern, int32_t numEntries) +PoliciesTest::setupExternPolicy(TestFrame &frame, mbus::Slobrok &slobrok, const string &pattern, int32_t numEntries) { string param = vespalib::make_string("tcp/localhost:%d;%s", slobrok.port(), pattern.c_str()); frame.setHop(mbus::HopSpec("test", vespalib::make_string("[Extern:%s]", param.c_str()))); @@ -270,14 +219,14 @@ Test::setupExternPolicy(TestFrame &frame, mbus::Slobrok &slobrok, const string & const mbus::HopBlueprint *hop = mbus.getRoutingTable(DocumentProtocol::NAME)->getHop("test"); const mbus::PolicyDirective &dir = dynamic_cast<const mbus::PolicyDirective&>(*hop->getDirective(0)); ExternPolicy &policy = dynamic_cast<ExternPolicy&>(*mbus.getRoutingPolicy(DocumentProtocol::NAME, dir.getName(), dir.getParam())); - assertMirrorReady(*policy.getMirror()); + ASSERT_NO_FATAL_FAILURE(assertMirrorReady(*policy.getMirror())); if (numEntries >= 0) { - assertMirrorContains(*policy.getMirror(), pattern, numEntries); + ASSERT_NO_FATAL_FAILURE(assertMirrorContains(*policy.getMirror(), pattern, numEntries)); } } void -Test::assertMirrorReady(const slobrok::api::IMirrorAPI &mirror) +PoliciesTest::assertMirrorReady(const slobrok::api::IMirrorAPI &mirror) { for (uint32_t i = 0; i < 6000; ++i) { if (mirror.ready()) { @@ -285,11 +234,11 @@ Test::assertMirrorReady(const slobrok::api::IMirrorAPI &mirror) } std::this_thread::sleep_for(10ms); } - ASSERT_TRUE(false); + FAIL() << "Mirror not ready"; } void -Test::assertMirrorContains(const slobrok::api::IMirrorAPI &mirror, const string &pattern, uint32_t numEntries) +PoliciesTest::assertMirrorContains(const slobrok::api::IMirrorAPI &mirror, const string &pattern, uint32_t numEntries) { for (uint32_t i = 0; i < 6000; ++i) { if (mirror.lookup(pattern).size() == numEntries) { @@ -297,11 +246,10 @@ Test::assertMirrorContains(const slobrok::api::IMirrorAPI &mirror, const string } std::this_thread::sleep_for(10ms); } - ASSERT_TRUE(false); + FAIL() << "Mirror does not contain pattern '" << pattern << "'"; } -void -Test::testExternSend() +TEST_F(PoliciesTest, test_extern_send) { // Setup local source node. mbus::Slobrok local; @@ -342,8 +290,7 @@ Test::testExternSend() fprintf(stderr, "%s", reply->getTrace().toString().c_str()); } -void -Test::testExternMultipleSlobroks() +TEST_F(PoliciesTest, test_extern_multiple_slobroks) { mbus::Slobrok local; mbus::TestServer src(mbus::Identity("src"), mbus::RoutingSpec(), local, @@ -387,8 +334,7 @@ Test::testExternMultipleSlobroks() } } -void -Test::testLocalService() +TEST_F(PoliciesTest, test_local_service) { // Prepare message. TestFrame frame(_repo, "docproc/cluster.default"); @@ -410,7 +356,7 @@ Test::testLocalService() leaf[0]->handleReply(std::make_unique<mbus::EmptyReply>()); ASSERT_TRUE(frame.getReceptor().getReply(TIMEOUT)); } - EXPECT_EQUAL(10u, lst.size()); + EXPECT_EQ(10u, lst.size()); // Test select with broken address. lst.clear(); @@ -423,16 +369,15 @@ Test::testLocalService() leaf[0]->handleReply(std::make_unique<mbus::EmptyReply>()); ASSERT_TRUE(frame.getReceptor().getReply(TIMEOUT)); } - EXPECT_EQUAL(1u, lst.size()); - EXPECT_EQUAL("docproc/cluster.default/*/chain.default", *lst.begin()); + EXPECT_EQ(1u, lst.size()); + EXPECT_EQ("docproc/cluster.default/*/chain.default", *lst.begin()); // Test merge behavior. frame.setHop(mbus::HopSpec("test", "[LocalService]")); EXPECT_TRUE(frame.testMergeOneReply("*")); } -void -Test::testLocalServiceCache() +TEST_F(PoliciesTest, test_local_service_cache) { TestFrame fooFrame(_repo, "docproc/cluster.default"); mbus::HopSpec fooHop("foo", "docproc/cluster.default/[LocalService]/chain.foo"); @@ -455,11 +400,11 @@ Test::testLocalServiceCache() std::vector<mbus::RoutingNode*> fooSelected; ASSERT_TRUE(fooFrame.select(fooSelected, 1)); - EXPECT_EQUAL("docproc/cluster.default/0/chain.foo", fooSelected[0]->getRoute().getHop(0).toString()); + EXPECT_EQ("docproc/cluster.default/0/chain.foo", fooSelected[0]->getRoute().getHop(0).toString()); std::vector<mbus::RoutingNode*> barSelected; ASSERT_TRUE(barFrame.select(barSelected, 1)); - EXPECT_EQUAL("docproc/cluster.default/0/chain.bar", barSelected[0]->getRoute().getHop(0).toString()); + EXPECT_EQ("docproc/cluster.default/0/chain.bar", barSelected[0]->getRoute().getHop(0).toString()); barSelected[0]->handleReply(std::make_unique<mbus::EmptyReply>()); fooSelected[0]->handleReply(std::make_unique<mbus::EmptyReply>()); @@ -468,8 +413,7 @@ Test::testLocalServiceCache() ASSERT_TRUE(fooFrame.getReceptor().getReply(TIMEOUT)); } -void -Test::testRoundRobin() +TEST_F(PoliciesTest, test_round_robin) { // Prepare message. TestFrame frame(_repo, "docproc/cluster.default"); @@ -506,8 +450,7 @@ Test::testRoundRobin() EXPECT_TRUE(frame.testMergeOneReply("docproc/cluster.default/0/chain.default")); } -void -Test::testRoundRobinCache() +TEST_F(PoliciesTest, test_round_robin_cache) { TestFrame fooFrame(_repo, "docproc/cluster.default"); mbus::HopSpec fooHop("foo", "[RoundRobin]"); @@ -532,11 +475,11 @@ Test::testRoundRobinCache() std::vector<mbus::RoutingNode*> fooSelected; ASSERT_TRUE(fooFrame.select(fooSelected, 1)); - EXPECT_EQUAL("docproc/cluster.default/0/chain.foo", fooSelected[0]->getRoute().getHop(0).toString()); + EXPECT_EQ("docproc/cluster.default/0/chain.foo", fooSelected[0]->getRoute().getHop(0).toString()); std::vector<mbus::RoutingNode*> barSelected; ASSERT_TRUE(barFrame.select(barSelected, 1)); - EXPECT_EQUAL("docproc/cluster.default/0/chain.bar", barSelected[0]->getRoute().getHop(0).toString()); + EXPECT_EQ("docproc/cluster.default/0/chain.bar", barSelected[0]->getRoute().getHop(0).toString()); barSelected[0]->handleReply(std::make_unique<mbus::EmptyReply>()); fooSelected[0]->handleReply(std::make_unique<mbus::EmptyReply>()); @@ -545,8 +488,7 @@ Test::testRoundRobinCache() ASSERT_TRUE(fooFrame.getReceptor().getReply(TIMEOUT)); } -void -Test::multipleGetRepliesAreMergedToFoundDocument() +TEST_F(PoliciesTest, multiple_get_replies_are_merged_to_found_document) { TestFrame frame(_repo); frame.setHop(mbus::HopSpec("test", "[DocumentRouteSelector:raw:" @@ -573,12 +515,11 @@ Test::multipleGetRepliesAreMergedToFoundDocument() } mbus::Reply::UP reply = frame.getReceptor().getReply(TIMEOUT); EXPECT_TRUE(reply); - EXPECT_EQUAL(static_cast<uint32_t>(DocumentProtocol::REPLY_GETDOCUMENT), reply->getType()); - EXPECT_EQUAL(123456ULL, dynamic_cast<GetDocumentReply&>(*reply).getLastModified()); + EXPECT_EQ(static_cast<uint32_t>(DocumentProtocol::REPLY_GETDOCUMENT), reply->getType()); + EXPECT_EQ(123456ULL, dynamic_cast<GetDocumentReply&>(*reply).getLastModified()); } -void -Test::testDocumentRouteSelector() +TEST_F(PoliciesTest, test_document_route_selector) { // Test policy with usage safeguard. string okConfig = "raw:route[0]\n"; @@ -630,8 +571,7 @@ Test::testDocumentRouteSelector() EXPECT_TRUE(frame.testMergeOneReply("foo")); } -void -Test::testDocumentRouteSelectorIgnore() +TEST_F(PoliciesTest, test_document_route_selector_ignore) { TestFrame frame(_repo); frame.setHop(mbus::HopSpec("test", "[DocumentRouteSelector:raw:" @@ -647,8 +587,8 @@ Test::testDocumentRouteSelectorIgnore() ASSERT_TRUE(frame.select(leaf, 0)); mbus::Reply::UP reply = frame.getReceptor().getReply(TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(uint32_t(DocumentProtocol::REPLY_DOCUMENTIGNORED), reply->getType()); - EXPECT_EQUAL(0u, reply->getNumErrors()); + EXPECT_EQ(uint32_t(DocumentProtocol::REPLY_DOCUMENTIGNORED), reply->getType()); + EXPECT_EQ(0u, reply->getNumErrors()); frame.setMessage(make_unique<UpdateDocumentMessage>( make_shared<DocumentUpdate>(*_repo, *_docType, DocumentId("id:ns:testdoc::")))); @@ -693,8 +633,7 @@ makeGet(vespalib::stringref docId) } -void -Test::remove_document_messages_are_sent_to_the_route_handling_the_given_document_type() +TEST_F(PoliciesTest, remove_document_messages_are_sent_to_the_route_handling_the_given_document_type) { auto frame = createFrameWithTwoRoutes(_repo); @@ -705,8 +644,7 @@ Test::remove_document_messages_are_sent_to_the_route_handling_the_given_document EXPECT_TRUE(frame->testSelect({"other-route"})); } -void -Test::get_document_messages_are_sent_to_the_route_handling_the_given_document_type() +TEST_F(PoliciesTest, get_document_messages_are_sent_to_the_route_handling_the_given_document_type) { auto frame = createFrameWithTwoRoutes(_repo); @@ -735,7 +673,8 @@ namespace { } } -void Test::testLoadBalancer() { +TEST_F(PoliciesTest, test_load_balancer) +{ LoadBalancer lb("foo", ""); IMirrorAPI::SpecList entries; @@ -745,7 +684,7 @@ void Test::testLoadBalancer() { for (int i = 0; i < 99; i++) { std::pair<string, int> recipient = lb.getRecipient(entries); - EXPECT_EQUAL((i % 3), recipient.second); + EXPECT_EQ((i % 3), recipient.second); } // Simulate that one node is overloaded. It returns busy twice as often as the others. @@ -761,31 +700,29 @@ void Test::testLoadBalancer() { lb.received(1, false); } - EXPECT_EQUAL(421, (int)(100 * lb.getWeight(0) / lb.getWeight(1))); - EXPECT_EQUAL(421, (int)(100 * lb.getWeight(2) / lb.getWeight(1))); - - EXPECT_EQUAL(0 , lb.getRecipient(entries).second); - EXPECT_EQUAL(0 , lb.getRecipient(entries).second); - EXPECT_EQUAL(1 , lb.getRecipient(entries).second); - EXPECT_EQUAL(2 , lb.getRecipient(entries).second); - EXPECT_EQUAL(2 , lb.getRecipient(entries).second); - EXPECT_EQUAL(2 , lb.getRecipient(entries).second); - EXPECT_EQUAL(2 , lb.getRecipient(entries).second); - EXPECT_EQUAL(0 , lb.getRecipient(entries).second); - EXPECT_EQUAL(0 , lb.getRecipient(entries).second); - EXPECT_EQUAL(0 , lb.getRecipient(entries).second); + EXPECT_EQ(421, (int)(100 * lb.getWeight(0) / lb.getWeight(1))); + EXPECT_EQ(421, (int)(100 * lb.getWeight(2) / lb.getWeight(1))); + + EXPECT_EQ(0 , lb.getRecipient(entries).second); + EXPECT_EQ(0 , lb.getRecipient(entries).second); + EXPECT_EQ(1 , lb.getRecipient(entries).second); + EXPECT_EQ(2 , lb.getRecipient(entries).second); + EXPECT_EQ(2 , lb.getRecipient(entries).second); + EXPECT_EQ(2 , lb.getRecipient(entries).second); + EXPECT_EQ(2 , lb.getRecipient(entries).second); + EXPECT_EQ(0 , lb.getRecipient(entries).second); + EXPECT_EQ(0 , lb.getRecipient(entries).second); + EXPECT_EQ(0 , lb.getRecipient(entries).second); } -void -Test::requireThatContentPolicyWithIllegalParamIsAnErrorPolicy() +TEST_F(PoliciesTest, require_that_content_policy_with_illegal_param_is_an_error_policy) { EXPECT_TRUE(isErrorPolicy("Content", "")); EXPECT_TRUE(isErrorPolicy("Content", "config=foo;slobroks=foo")); EXPECT_TRUE(isErrorPolicy("Content", "slobroks=foo")); } -void -Test::requireThatContentPolicyIsRandomWithoutState() +TEST_F(PoliciesTest, require_that_content_policy_is_random_without_state) { TestFrame frame(_repo); frame.setMessage(newPutDocumentMessage("id:ns:testdoc::")); @@ -803,9 +740,11 @@ Test::requireThatContentPolicyIsRandomWithoutState() string param = vespalib::make_string( "cluster=mycluster;slobroks=tcp/localhost:%d;clusterconfigid=%s;syncinit", slobrok.port(), getDefaultDistributionConfig(2, 5).c_str()); - ContentPolicy &policy = setupContentPolicy( + WrappedPolicy wrapped_policy; + ASSERT_NO_FATAL_FAILURE(setupContentPolicy( frame, param, - "storage/cluster.mycluster/distributor/*/default", 5); + "storage/cluster.mycluster/distributor/*/default", 5, wrapped_policy)); + auto& policy = wrapped_policy.value().get(); ASSERT_FALSE(policy.getSystemState()); std::set<string> lst; @@ -815,15 +754,16 @@ Test::requireThatContentPolicyIsRandomWithoutState() lst.insert(leaf[0]->getRoute().toString()); leaf[0]->handleReply(std::make_unique<mbus::EmptyReply>()); } - EXPECT_EQUAL(servers.size(), lst.size()); + EXPECT_EQ(servers.size(), lst.size()); for (auto & server : servers) { delete server; } } -ContentPolicy & -Test::setupContentPolicy(TestFrame &frame, const string ¶m, - const string &pattern, int32_t numEntries) +void +PoliciesTest::setupContentPolicy(TestFrame &frame, const string ¶m, + const string &pattern, int32_t numEntries, + WrappedPolicy& wrapped_policy) { frame.setHop(mbus::HopSpec("test", vespalib::make_string("[Content:%s]", param.c_str()))); mbus::MessageBus &mbus = frame.getMessageBus(); @@ -831,15 +771,14 @@ Test::setupContentPolicy(TestFrame &frame, const string ¶m, const mbus::PolicyDirective & dir = dynamic_cast<const mbus::PolicyDirective&>(*hop->getDirective(0)); ContentPolicy &policy = dynamic_cast<ContentPolicy&>(*mbus.getRoutingPolicy(DocumentProtocol::NAME, dir.getName(), dir.getParam())); policy.initSynchronous(); - assertMirrorReady(*policy.getMirror()); + ASSERT_NO_FATAL_FAILURE(assertMirrorReady(*policy.getMirror())); if (numEntries >= 0) { - assertMirrorContains(*policy.getMirror(), pattern, numEntries); + ASSERT_NO_FATAL_FAILURE(assertMirrorContains(*policy.getMirror(), pattern, numEntries)); } - return policy; + wrapped_policy = std::ref(policy); } -void -Test::requireThatContentPolicyIsTargetedWithState() +TEST_F(PoliciesTest, require_that_content_policy_is_targeted_with_state) { TestFrame frame(_repo); frame.setMessage(newPutDocumentMessage("id:ns:testdoc::")); @@ -857,14 +796,16 @@ Test::requireThatContentPolicyIsTargetedWithState() string param = vespalib::make_string( "cluster=mycluster;slobroks=tcp/localhost:%d;clusterconfigid=%s;syncinit", slobrok.port(), getDefaultDistributionConfig(2, 5).c_str()); - ContentPolicy &policy = setupContentPolicy(frame, param, "storage/cluster.mycluster/distributor/*/default", 5); + WrappedPolicy wrapped_policy; + ASSERT_NO_FATAL_FAILURE(setupContentPolicy(frame, param, "storage/cluster.mycluster/distributor/*/default", 5, wrapped_policy)); + auto& policy = wrapped_policy.value().get(); ASSERT_FALSE(policy.getSystemState()); { std::vector<mbus::RoutingNode*> leaf; ASSERT_TRUE(frame.select(leaf, 1)); leaf[0]->handleReply(std::make_unique<WrongDistributionReply>("distributor:5 storage:5")); ASSERT_TRUE(policy.getSystemState()); - EXPECT_EQUAL(policy.getSystemState()->toString(), "distributor:5 storage:5"); + EXPECT_EQ(policy.getSystemState()->toString(), "distributor:5 storage:5"); } std::set<string> lst; for (int i = 0; i < 666; i++) { @@ -873,14 +814,13 @@ Test::requireThatContentPolicyIsTargetedWithState() lst.insert(leaf[0]->getRoute().toString()); leaf[0]->handleReply(std::make_unique<mbus::EmptyReply>()); } - EXPECT_EQUAL(1u, lst.size()); + EXPECT_EQ(1u, lst.size()); for (auto & server : servers) { delete server; } } -void -Test::requireThatContentPolicyCombinesSystemAndSlobrokState() +TEST_F(PoliciesTest, require_that_content_policy_combines_system_and_slobrok_state) { TestFrame frame(_repo); frame.setMessage(newPutDocumentMessage("id:ns:testdoc::")); @@ -894,24 +834,25 @@ Test::requireThatContentPolicyCombinesSystemAndSlobrokState() string param = vespalib::make_string( "cluster=mycluster;slobroks=tcp/localhost:%d;clusterconfigid=%s;syncinit", slobrok.port(), getDefaultDistributionConfig(2, 5).c_str()); - ContentPolicy &policy = setupContentPolicy( + WrappedPolicy wrapped_policy; + ASSERT_NO_FATAL_FAILURE(setupContentPolicy( frame, param, - "storage/cluster.mycluster/distributor/*/default", 1); + "storage/cluster.mycluster/distributor/*/default", 1, wrapped_policy)); + auto& policy = wrapped_policy.value().get(); ASSERT_FALSE(policy.getSystemState()); { std::vector<mbus::RoutingNode*> leaf; ASSERT_TRUE(frame.select(leaf, 1)); leaf[0]->handleReply(std::make_unique<WrongDistributionReply>("distributor:99 storage:99")); ASSERT_TRUE(policy.getSystemState()); - EXPECT_EQUAL(policy.getSystemState()->toString(), "distributor:99 storage:99"); + EXPECT_EQ(policy.getSystemState()->toString(), "distributor:99 storage:99"); } for (int i = 0; i < 666; i++) { ASSERT_TRUE(frame.testSelect(StringList().add(server.net.getConnectionSpec() + "/default"))); } } -void -Test::testSubsetService() +TEST_F(PoliciesTest, test_subset_service) { // Prepare message. TestFrame frame(_repo, "docproc/cluster.default"); @@ -966,15 +907,14 @@ Test::testSubsetService() leaf[0]->handleReply(std::move(reply)); ASSERT_TRUE(frame.getReceptor().getReply(TIMEOUT)); } - EXPECT_EQUAL(10u, lst.size()); + EXPECT_EQ(10u, lst.size()); // Test merge behavior. frame.setHop(mbus::HopSpec("test", "[SubsetService]")); EXPECT_TRUE(frame.testMergeOneReply("*")); } -void -Test::testSubsetServiceCache() +TEST_F(PoliciesTest, test_subset_service_cache) { TestFrame fooFrame(_repo, "docproc/cluster.default"); mbus::HopSpec fooHop("foo", "docproc/cluster.default/[SubsetService:2]/chain.foo"); @@ -997,11 +937,11 @@ Test::testSubsetServiceCache() std::vector<mbus::RoutingNode*> fooSelected; ASSERT_TRUE(fooFrame.select(fooSelected, 1)); - EXPECT_EQUAL("docproc/cluster.default/0/chain.foo", fooSelected[0]->getRoute().getHop(0).toString()); + EXPECT_EQ("docproc/cluster.default/0/chain.foo", fooSelected[0]->getRoute().getHop(0).toString()); std::vector<mbus::RoutingNode*> barSelected; ASSERT_TRUE(barFrame.select(barSelected, 1)); - EXPECT_EQUAL("docproc/cluster.default/0/chain.bar", barSelected[0]->getRoute().getHop(0).toString()); + EXPECT_EQ("docproc/cluster.default/0/chain.bar", barSelected[0]->getRoute().getHop(0).toString()); barSelected[0]->handleReply(std::make_unique<mbus::EmptyReply>()); fooSelected[0]->handleReply(std::make_unique<mbus::EmptyReply>()); @@ -1011,7 +951,7 @@ Test::testSubsetServiceCache() } bool -Test::trySelect(TestFrame &frame, uint32_t numSelects, const std::vector<string> &expected) { +PoliciesTest::trySelect(TestFrame &frame, uint32_t numSelects, const std::vector<string> &expected) { std::set<string> lst; for (uint32_t i = 0; i < numSelects; ++i) { std::vector<mbus::RoutingNode*> leaf; @@ -1042,7 +982,7 @@ Test::trySelect(TestFrame &frame, uint32_t numSelects, const std::vector<string> } bool -Test::isErrorPolicy(const string &name, const string ¶m) +PoliciesTest::isErrorPolicy(const string &name, const string ¶m) { DocumentProtocol protocol(_repo); mbus::IRoutingPolicy::UP policy = protocol.createPolicy(name, param); @@ -1050,3 +990,4 @@ Test::isErrorPolicy(const string &name, const string ¶m) return policy && dynamic_cast<ErrorPolicy*>(policy.get()) != nullptr; } +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/documentapi/src/tests/replymerger/CMakeLists.txt b/documentapi/src/tests/replymerger/CMakeLists.txt index c0aa754d2d6..41eaae643c4 100644 --- a/documentapi/src/tests/replymerger/CMakeLists.txt +++ b/documentapi/src/tests/replymerger/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(documentapi_replymerger_test_app TEST replymerger_test.cpp DEPENDS documentapi + GTest::gtest ) vespa_add_test(NAME documentapi_replymerger_test_app COMMAND documentapi_replymerger_test_app) diff --git a/documentapi/src/tests/replymerger/replymerger_test.cpp b/documentapi/src/tests/replymerger/replymerger_test.cpp index bfcc4612ce1..bdc41b9f44d 100644 --- a/documentapi/src/tests/replymerger/replymerger_test.cpp +++ b/documentapi/src/tests/replymerger/replymerger_test.cpp @@ -1,7 +1,6 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <iostream> -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/documentapi/messagebus/replymerger.h> #include <vespa/documentapi/messagebus/documentprotocol.h> #include <vespa/documentapi/messagebus/messages/removedocumentreply.h> @@ -9,34 +8,26 @@ #include <vespa/documentapi/messagebus/messages/getdocumentreply.h> #include <vespa/messagebus/emptyreply.h> #include <vespa/messagebus/error.h> +#include <vespa/vespalib/gtest/gtest.h> using namespace documentapi; -class Test : public vespalib::TestApp -{ - static void assertReplyErrorsMatch(const mbus::Reply& r, - const std::vector<mbus::Error>& errors); -public: - int Main() override; +namespace { - void mergingGenericRepliesWithNoErrorsPicksFirstReply(); - void mergingSingleReplyWithOneErrorReturnsEmptyReplyWithError(); - void mergingSingleReplyWithMultipleErrorsReturnsEmptyReplyWithAllErrors(); - void mergingMultipleRepliesWithMultipleErrorsReturnsEmptyReplyWithAllErrors(); - void returnIgnoredReplyWhenAllRepliesHaveOnlyIgnoredErrors(); - void successfulReplyTakesPrecedenceOverIgnoredReplyWhenNoErrors(); - void nonIgnoredErrorTakesPrecedence(); - void returnRemoveDocumentReplyWhereDocWasFound(); - void returnFirstRemoveDocumentReplyIfNoDocsWereFound(); - void returnUpdateDocumentReplyWhereDocWasFound(); - void returnGetDocumentReplyWhereDocWasFound(); - void mergingZeroRepliesReturnsDefaultEmptyReply(); -}; +void +assertReplyErrorsMatch(const mbus::Reply& r, + const std::vector<mbus::Error>& errors) +{ + ASSERT_EQ(r.getNumErrors(), errors.size()); + for (size_t i = 0; i < errors.size(); ++i) { + ASSERT_EQ(errors[i].getCode(), r.getError(i).getCode()); + ASSERT_EQ(errors[i].getMessage(), r.getError(i).getMessage()); + } +} -TEST_APPHOOK(Test); +} -void -Test::mergingGenericRepliesWithNoErrorsPicksFirstReply() +TEST(ReplyMergerTest, merging_generic_replies_with_no_errors_picks_first_reply) { mbus::EmptyReply r1; mbus::EmptyReply r2; @@ -48,11 +39,10 @@ Test::mergingGenericRepliesWithNoErrorsPicksFirstReply() ReplyMerger::Result ret(merger.mergedReply()); ASSERT_TRUE(ret.isSuccessful()); ASSERT_FALSE(ret.hasGeneratedReply()); - EXPECT_EQUAL(0u, ret.getSuccessfulReplyIndex()); + EXPECT_EQ(0u, ret.getSuccessfulReplyIndex()); } -void -Test::mergingSingleReplyWithOneErrorReturnsEmptyReplyWithError() +TEST(ReplyMergerTest, merging_single_reply_with_one_error_returns_empty_reply_with_error) { mbus::EmptyReply r1; std::vector<mbus::Error> errors = { mbus::Error(1234, "oh no!") }; @@ -66,8 +56,7 @@ Test::mergingSingleReplyWithOneErrorReturnsEmptyReplyWithError() assertReplyErrorsMatch(*gen, errors); } -void -Test::mergingSingleReplyWithMultipleErrorsReturnsEmptyReplyWithAllErrors() +TEST(ReplyMergerTest, merging_single_reply_with_multiple_errors_returns_empty_reply_with_all_errors) { mbus::EmptyReply r1; std::vector<mbus::Error> errors = { @@ -85,8 +74,7 @@ Test::mergingSingleReplyWithMultipleErrorsReturnsEmptyReplyWithAllErrors() assertReplyErrorsMatch(*gen, errors); } -void -Test::mergingMultipleRepliesWithMultipleErrorsReturnsEmptyReplyWithAllErrors() +TEST(ReplyMergerTest, merging_multiple_replies_with_multiple_errors_returns_empty_reply_with_all_errors) { mbus::EmptyReply r1; mbus::EmptyReply r2; @@ -108,8 +96,7 @@ Test::mergingMultipleRepliesWithMultipleErrorsReturnsEmptyReplyWithAllErrors() assertReplyErrorsMatch(*gen, errors); } -void -Test::returnIgnoredReplyWhenAllRepliesHaveOnlyIgnoredErrors() +TEST(ReplyMergerTest, return_ignored_reply_when_all_replies_have_only_ignored_errors) { mbus::EmptyReply r1; mbus::EmptyReply r2; @@ -132,8 +119,7 @@ Test::returnIgnoredReplyWhenAllRepliesHaveOnlyIgnoredErrors() assertReplyErrorsMatch(*gen, { errors[0], errors[2] }); } -void -Test::successfulReplyTakesPrecedenceOverIgnoredReplyWhenNoErrors() +TEST(ReplyMergerTest, successful_reply_takes_precedence_over_ignored_reply_when_no_errors) { mbus::EmptyReply r1; mbus::EmptyReply r2; @@ -147,11 +133,10 @@ Test::successfulReplyTakesPrecedenceOverIgnoredReplyWhenNoErrors() ReplyMerger::Result ret(merger.mergedReply()); ASSERT_TRUE(ret.isSuccessful()); ASSERT_FALSE(ret.hasGeneratedReply()); - EXPECT_EQUAL(1u, ret.getSuccessfulReplyIndex()); + EXPECT_EQ(1u, ret.getSuccessfulReplyIndex()); } -void -Test::nonIgnoredErrorTakesPrecedence() +TEST(ReplyMergerTest, non_ignored_error_takes_precedence) { mbus::EmptyReply r1; mbus::EmptyReply r2; @@ -175,8 +160,7 @@ Test::nonIgnoredErrorTakesPrecedence() assertReplyErrorsMatch(*gen, { errors[0], errors[1] }); } -void -Test::returnRemoveDocumentReplyWhereDocWasFound() +TEST(ReplyMergerTest, return_remove_document_reply_where_doc_was_found) { RemoveDocumentReply r1; RemoveDocumentReply r2; @@ -192,11 +176,10 @@ Test::returnRemoveDocumentReplyWhereDocWasFound() ReplyMerger::Result ret(merger.mergedReply()); ASSERT_TRUE(ret.isSuccessful()); ASSERT_FALSE(ret.hasGeneratedReply()); - ASSERT_EQUAL(1u, ret.getSuccessfulReplyIndex()); + ASSERT_EQ(1u, ret.getSuccessfulReplyIndex()); } -void -Test::returnFirstRemoveDocumentReplyIfNoDocsWereFound() +TEST(ReplyMergerTest, return_first_remove_document_reply_if_no_docs_were_found) { RemoveDocumentReply r1; RemoveDocumentReply r2; @@ -209,11 +192,10 @@ Test::returnFirstRemoveDocumentReplyIfNoDocsWereFound() ReplyMerger::Result ret(merger.mergedReply()); ASSERT_TRUE(ret.isSuccessful()); ASSERT_FALSE(ret.hasGeneratedReply()); - ASSERT_EQUAL(0u, ret.getSuccessfulReplyIndex()); + ASSERT_EQ(0u, ret.getSuccessfulReplyIndex()); } -void -Test::returnUpdateDocumentReplyWhereDocWasFound() +TEST(ReplyMergerTest, return_update_document_reply_where_doc_was_found) { UpdateDocumentReply r1; UpdateDocumentReply r2; @@ -229,11 +211,10 @@ Test::returnUpdateDocumentReplyWhereDocWasFound() ReplyMerger::Result ret(merger.mergedReply()); ASSERT_TRUE(ret.isSuccessful()); ASSERT_FALSE(ret.hasGeneratedReply()); - ASSERT_EQUAL(1u, ret.getSuccessfulReplyIndex()); + ASSERT_EQ(1u, ret.getSuccessfulReplyIndex()); } -void -Test::returnGetDocumentReplyWhereDocWasFound() +TEST(ReplyMergerTest, return_get_document_reply_where_doc_was_found) { GetDocumentReply r1; GetDocumentReply r2; @@ -247,22 +228,10 @@ Test::returnGetDocumentReplyWhereDocWasFound() ReplyMerger::Result ret(merger.mergedReply()); ASSERT_TRUE(ret.isSuccessful()); ASSERT_FALSE(ret.hasGeneratedReply()); - ASSERT_EQUAL(1u, ret.getSuccessfulReplyIndex()); + ASSERT_EQ(1u, ret.getSuccessfulReplyIndex()); } -void -Test::assertReplyErrorsMatch(const mbus::Reply& r, - const std::vector<mbus::Error>& errors) -{ - ASSERT_EQUAL(r.getNumErrors(), errors.size()); - for (size_t i = 0; i < errors.size(); ++i) { - ASSERT_EQUAL(errors[i].getCode(), r.getError(i).getCode()); - ASSERT_EQUAL(errors[i].getMessage(), r.getError(i).getMessage()); - } -} - -void -Test::mergingZeroRepliesReturnsDefaultEmptyReply() +TEST(ReplyMergerTest, merging_zero_replies_returns_default_empty_reply) { ReplyMerger merger; ReplyMerger::Result ret(merger.mergedReply()); @@ -273,30 +242,4 @@ Test::mergingZeroRepliesReturnsDefaultEmptyReply() assertReplyErrorsMatch(*gen, {}); } -#ifdef RUN_TEST -# error Someone defined RUN_TEST already! Oh no! -#endif -#define RUN_TEST(f) \ - std::cerr << "running test case '" #f "'\n"; \ - f(); TEST_FLUSH(); - -int -Test::Main() -{ - TEST_INIT("replymerger_test"); - - RUN_TEST(mergingGenericRepliesWithNoErrorsPicksFirstReply); - RUN_TEST(mergingSingleReplyWithOneErrorReturnsEmptyReplyWithError); - RUN_TEST(mergingSingleReplyWithMultipleErrorsReturnsEmptyReplyWithAllErrors); - RUN_TEST(mergingMultipleRepliesWithMultipleErrorsReturnsEmptyReplyWithAllErrors); - RUN_TEST(returnIgnoredReplyWhenAllRepliesHaveOnlyIgnoredErrors); - RUN_TEST(successfulReplyTakesPrecedenceOverIgnoredReplyWhenNoErrors); - RUN_TEST(nonIgnoredErrorTakesPrecedence); - RUN_TEST(returnRemoveDocumentReplyWhereDocWasFound); - RUN_TEST(returnFirstRemoveDocumentReplyIfNoDocsWereFound); - RUN_TEST(returnUpdateDocumentReplyWhereDocWasFound); - RUN_TEST(returnGetDocumentReplyWhereDocWasFound); - RUN_TEST(mergingZeroRepliesReturnsDefaultEmptyReply); - - TEST_DONE(); -} +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/handler/UnsafeContentInputStream.java b/jdisc_core/src/main/java/com/yahoo/jdisc/handler/UnsafeContentInputStream.java index 45971784aa3..86cd685f869 100644 --- a/jdisc_core/src/main/java/com/yahoo/jdisc/handler/UnsafeContentInputStream.java +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/handler/UnsafeContentInputStream.java @@ -109,9 +109,10 @@ public class UnsafeContentInputStream extends InputStream { if (marked == null) { throw new IOException("mark has not been called, or too much has been read since marked."); } - ByteBuffer newBuf = ByteBuffer.allocate(readSinceMarked + currBuf.remaining()); + var remainingInCurrent = currBuf == null ? 0 : currBuf.remaining(); + ByteBuffer newBuf = ByteBuffer.allocate(readSinceMarked + remainingInCurrent); newBuf.put(marked, 0, readSinceMarked); - newBuf.put(currBuf); + if (remainingInCurrent > 0) newBuf.put(currBuf); newBuf.flip(); currBuf = newBuf; marked = null; diff --git a/messagebus/src/tests/advancedrouting/CMakeLists.txt b/messagebus/src/tests/advancedrouting/CMakeLists.txt index dc4013b833f..ca2d3e4bba0 100644 --- a/messagebus/src/tests/advancedrouting/CMakeLists.txt +++ b/messagebus/src/tests/advancedrouting/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_advancedrouting_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_advancedrouting_test_app COMMAND messagebus_advancedrouting_test_app) diff --git a/messagebus/src/tests/advancedrouting/advancedrouting.cpp b/messagebus/src/tests/advancedrouting/advancedrouting.cpp index ce4a13d435a..4415674986e 100644 --- a/messagebus/src/tests/advancedrouting/advancedrouting.cpp +++ b/messagebus/src/tests/advancedrouting/advancedrouting.cpp @@ -5,14 +5,16 @@ #include <vespa/messagebus/testlib/simplemessage.h> #include <vespa/messagebus/testlib/slobrok.h> #include <vespa/messagebus/testlib/testserver.h> -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/vespalib/util/stringfmt.h> #include <vespa/messagebus/emptyreply.h> #include <vespa/messagebus/errorcode.h> #include <vespa/messagebus/routing/retrytransienterrorspolicy.h> +#include <vespa/vespalib/gtest/gtest.h> using namespace mbus; +namespace { + class TestData { public: Slobrok _slobrok; @@ -34,38 +36,27 @@ public: bool start(); }; -class Test : public vespalib::TestApp { -private: - Message::UP createMessage(const string &msg); - bool testTrace(const std::vector<string> &expected, const Trace &trace); - -public: - int Main() override; - void testAdvanced(TestData &data); -}; - -TEST_APPHOOK(Test); - -TestData::~TestData() = default; -TestData::TestData() : - _slobrok(), - _retryPolicy(std::make_shared<RetryTransientErrorsPolicy>()), - _srcServer(MessageBusParams().setRetryPolicy(_retryPolicy).addProtocol(std::make_shared<SimpleProtocol>()), - RPCNetworkParams(_slobrok.config())), - _srcSession(), - _srcHandler(), - _dstServer(MessageBusParams().addProtocol(std::make_shared<SimpleProtocol>()), - RPCNetworkParams(_slobrok.config()).setIdentity(Identity("dst"))), - _fooSession(), - _fooHandler(), - _barSession(), - _barHandler(), - _bazSession(), - _bazHandler() +TestData::TestData() + : _slobrok(), + _retryPolicy(std::make_shared<RetryTransientErrorsPolicy>()), + _srcServer(MessageBusParams().setRetryPolicy(_retryPolicy).addProtocol(std::make_shared<SimpleProtocol>()), + RPCNetworkParams(_slobrok.config())), + _srcSession(), + _srcHandler(), + _dstServer(MessageBusParams().addProtocol(std::make_shared<SimpleProtocol>()), + RPCNetworkParams(_slobrok.config()).setIdentity(Identity("dst"))), + _fooSession(), + _fooHandler(), + _barSession(), + _barHandler(), + _bazSession(), + _bazHandler() { _retryPolicy->setBaseDelay(0); } +TestData::~TestData() = default; + bool TestData::start() { @@ -91,30 +82,21 @@ TestData::start() return true; } -Message::UP -Test::createMessage(const string &msg) +std::unique_ptr<Message> +createMessage(const string &msg) { auto ret = std::make_unique<SimpleMessage>(msg); ret->getTrace().setLevel(9); return ret; } -int -Test::Main() -{ - TEST_INIT("routing_test"); +} +TEST(AdvancedRoutingTest, test_advanced) +{ TestData data; ASSERT_TRUE(data.start()); - testAdvanced(data); TEST_FLUSH(); - - TEST_DONE(); -} - -void -Test::testAdvanced(TestData &data) -{ const duration TIMEOUT = 60s; IProtocol::SP protocol(new SimpleProtocol()); auto &simple = dynamic_cast<SimpleProtocol&>(*protocol); @@ -174,7 +156,9 @@ Test::testAdvanced(TestData &data) reply = data._srcHandler.getReply(); ASSERT_TRUE(reply); printf("%s", reply->getTrace().toString().c_str()); - EXPECT_EQUAL(2u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::FATAL_ERROR, reply->getError(0).getCode()); - EXPECT_EQUAL((uint32_t)ErrorCode::NO_ADDRESS_FOR_SERVICE, reply->getError(1).getCode()); + EXPECT_EQ(2u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::FATAL_ERROR, reply->getError(0).getCode()); + EXPECT_EQ((uint32_t)ErrorCode::NO_ADDRESS_FOR_SERVICE, reply->getError(1).getCode()); } + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/messagebus/src/tests/choke/CMakeLists.txt b/messagebus/src/tests/choke/CMakeLists.txt index b4db862f717..c87c51f8c82 100644 --- a/messagebus/src/tests/choke/CMakeLists.txt +++ b/messagebus/src/tests/choke/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_choke_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_choke_test_app NO_VALGRIND COMMAND messagebus_choke_test_app) diff --git a/messagebus/src/tests/choke/choke.cpp b/messagebus/src/tests/choke/choke.cpp index 313aace8fd4..9c25fc64cd1 100644 --- a/messagebus/src/tests/choke/choke.cpp +++ b/messagebus/src/tests/choke/choke.cpp @@ -7,7 +7,7 @@ #include <vespa/messagebus/testlib/simpleprotocol.h> #include <vespa/messagebus/testlib/slobrok.h> #include <vespa/messagebus/testlib/testserver.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> using namespace mbus; @@ -17,6 +17,8 @@ using namespace mbus; // //////////////////////////////////////////////////////////////////////////////// +namespace { + class TestData { public: Slobrok _slobrok; @@ -33,32 +35,20 @@ public: bool start(); }; -class Test : public vespalib::TestApp { -private: - Message::UP createMessage(const string &msg); - -public: - int Main() override; - void testMaxCount(TestData &data); - void testMaxSize(TestData &data); -}; - -TEST_APPHOOK(Test); - -TestData::TestData() : - _slobrok(), - _srcServer(MessageBusParams() - .setRetryPolicy(IRetryPolicy::SP()) - .addProtocol(std::make_shared<SimpleProtocol>()), - RPCNetworkParams(_slobrok.config())), - _srcSession(), - _srcHandler(), - _dstServer(MessageBusParams() - .addProtocol(std::make_shared<SimpleProtocol>()), - RPCNetworkParams(_slobrok.config()) - .setIdentity(Identity("dst"))), - _dstSession(), - _dstHandler() +TestData::TestData() + : _slobrok(), + _srcServer(MessageBusParams() + .setRetryPolicy(IRetryPolicy::SP()) + .addProtocol(std::make_shared<SimpleProtocol>()), + RPCNetworkParams(_slobrok.config())), + _srcSession(), + _srcHandler(), + _dstServer(MessageBusParams() + .addProtocol(std::make_shared<SimpleProtocol>()), + RPCNetworkParams(_slobrok.config()) + .setIdentity(Identity("dst"))), + _dstSession(), + _dstHandler() { // empty } @@ -86,26 +76,41 @@ TestData::start() return true; } -Message::UP -Test::createMessage(const string &msg) +std::unique_ptr<Message> +createMessage(const string &msg) { Message::UP ret(new SimpleMessage(msg)); ret->getTrace().setLevel(9); return ret; } -int -Test::Main() -{ - TEST_INIT("choke_test"); +} + +class ChokeTest : public testing::Test { +protected: + static std::shared_ptr<TestData> _data; + ChokeTest(); + ~ChokeTest() override; + static void SetUpTestSuite(); + static void TearDownTestSuite(); +}; - TestData data; - ASSERT_TRUE(data.start()); +std::shared_ptr<TestData> ChokeTest::_data; - testMaxCount(data); TEST_FLUSH(); - testMaxSize(data); TEST_FLUSH(); +ChokeTest::ChokeTest() = default; +ChokeTest::~ChokeTest() = default; - TEST_DONE(); +void +ChokeTest::SetUpTestSuite() +{ + _data = std::make_shared<TestData>(); + ASSERT_TRUE(_data->start()); +} + +void +ChokeTest::TearDownTestSuite() +{ + _data.reset(); } static const duration TIMEOUT = 120s; @@ -116,17 +121,17 @@ static const duration TIMEOUT = 120s; // //////////////////////////////////////////////////////////////////////////////// -void -Test::testMaxCount(TestData &data) +TEST_F(ChokeTest, test_max_count) { + auto& data = *_data; uint32_t max = 10; data._dstServer.mb.setMaxPendingCount(max); std::vector<Message*> lst; for (uint32_t i = 0; i < max * 2; ++i) { if (i < max) { - EXPECT_EQUAL(i, data._dstServer.mb.getPendingCount()); + EXPECT_EQ(i, data._dstServer.mb.getPendingCount()); } else { - EXPECT_EQUAL(max, data._dstServer.mb.getPendingCount()); + EXPECT_EQ(max, data._dstServer.mb.getPendingCount()); } EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst/session")).isAccepted()); if (i < max) { @@ -136,8 +141,8 @@ Test::testMaxCount(TestData &data) } else { Reply::UP reply = data._srcHandler.getReply(); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::SESSION_BUSY, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::SESSION_BUSY, reply->getError(0).getCode()); } } for (uint32_t i = 0; i < 5; ++i) { @@ -157,7 +162,7 @@ Test::testMaxCount(TestData &data) lst.push_back(msg.release()); } while (!lst.empty()) { - EXPECT_EQUAL(lst.size(), data._dstServer.mb.getPendingCount()); + EXPECT_EQ(lst.size(), data._dstServer.mb.getPendingCount()); Message::UP msg(lst[0]); lst.erase(lst.begin()); data._dstSession->acknowledge(std::move(msg)); @@ -166,21 +171,21 @@ Test::testMaxCount(TestData &data) ASSERT_TRUE(reply); EXPECT_TRUE(!reply->hasErrors()); } - EXPECT_EQUAL(0u, data._dstServer.mb.getPendingCount()); + EXPECT_EQ(0u, data._dstServer.mb.getPendingCount()); } -void -Test::testMaxSize(TestData &data) +TEST_F(ChokeTest, test_max_size) { + auto& data = *_data; uint32_t size = createMessage("msg")->getApproxSize(); uint32_t max = size * 10; data._dstServer.mb.setMaxPendingSize(max); std::vector<Message*> lst; for (uint32_t i = 0; i < max * 2; i += size) { if (i < max) { - EXPECT_EQUAL(i, data._dstServer.mb.getPendingSize()); + EXPECT_EQ(i, data._dstServer.mb.getPendingSize()); } else { - EXPECT_EQUAL(max, data._dstServer.mb.getPendingSize()); + EXPECT_EQ(max, data._dstServer.mb.getPendingSize()); } EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst/session")).isAccepted()); if (i < max) { @@ -190,8 +195,8 @@ Test::testMaxSize(TestData &data) } else { Reply::UP reply = data._srcHandler.getReply(); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::SESSION_BUSY, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::SESSION_BUSY, reply->getError(0).getCode()); } } for (uint32_t i = 0; i < 5; ++i) { @@ -211,7 +216,7 @@ Test::testMaxSize(TestData &data) lst.push_back(msg.release()); } while (!lst.empty()) { - EXPECT_EQUAL(size * lst.size(), data._dstServer.mb.getPendingSize()); + EXPECT_EQ(size * lst.size(), data._dstServer.mb.getPendingSize()); Message::UP msg(lst[0]); lst.erase(lst.begin()); data._dstSession->acknowledge(std::move(msg)); @@ -220,5 +225,7 @@ Test::testMaxSize(TestData &data) ASSERT_TRUE(reply); EXPECT_TRUE(!reply->hasErrors()); } - EXPECT_EQUAL(0u, data._dstServer.mb.getPendingSize()); + EXPECT_EQ(0u, data._dstServer.mb.getPendingSize()); } + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/messagebus/src/tests/configagent/CMakeLists.txt b/messagebus/src/tests/configagent/CMakeLists.txt index 9cc9eacbe1c..9b07222fc74 100644 --- a/messagebus/src/tests/configagent/CMakeLists.txt +++ b/messagebus/src/tests/configagent/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_configagent_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_configagent_test_app COMMAND messagebus_configagent_test_app) diff --git a/messagebus/src/tests/configagent/configagent.cpp b/messagebus/src/tests/configagent/configagent.cpp index f93bfd6c841..e8cab1e679a 100644 --- a/messagebus/src/tests/configagent/configagent.cpp +++ b/messagebus/src/tests/configagent/configagent.cpp @@ -1,109 +1,113 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/messagebus/configagent.h> #include <vespa/messagebus/iconfighandler.h> #include <vespa/messagebus/routing/routingspec.h> #include <vespa/messagebus/config-messagebus.h> #include <vespa/config/print/fileconfigreader.hpp> +#include <vespa/vespalib/gtest/gtest.h> +#include <vespa/vespalib/testkit/test_path.h> using namespace mbus; using namespace messagebus; using namespace config; -class Test : public vespalib::TestApp, public IConfigHandler { -private: +class ConfigAgentTest : public testing::Test, public IConfigHandler { +protected: RoutingSpec _spec; + ConfigAgentTest(); + ~ConfigAgentTest() override; bool checkHalf(); bool checkFull(); - bool checkTables(uint32_t numTables); - -public: - ~Test() override; - int Main() override; + void checkTables(uint32_t numTables, bool& success); bool setupRouting(RoutingSpec spec) override; }; -Test::~Test() = default; +ConfigAgentTest::ConfigAgentTest() + : testing::Test(), + IConfigHandler(), + _spec() +{ +} -TEST_APPHOOK(Test); +ConfigAgentTest::~ConfigAgentTest() = default; bool -Test::setupRouting(RoutingSpec spec) +ConfigAgentTest::setupRouting(RoutingSpec spec) { _spec = std::move(spec); return true; } -bool -Test::checkTables(uint32_t numTables) +void +ConfigAgentTest::checkTables(uint32_t numTables, bool& success) { - if (!EXPECT_EQUAL(numTables, _spec.getNumTables())) return false; + ASSERT_EQ(numTables, _spec.getNumTables()); if (numTables > 0) { - if (!EXPECT_EQUAL("foo", _spec.getTable(0).getProtocol())) return false; - if (!EXPECT_EQUAL(2u, _spec.getTable(0).getNumHops())) return false; - if (!EXPECT_EQUAL("foo-h1", _spec.getTable(0).getHop(0).getName())) return false; - if (!EXPECT_EQUAL("foo-h1-sel", _spec.getTable(0).getHop(0).getSelector())) return false; - if (!EXPECT_EQUAL(2u, _spec.getTable(0).getHop(0).getNumRecipients())) return false; - if (!EXPECT_EQUAL("foo-h1-r1", _spec.getTable(0).getHop(0).getRecipient(0))) return false; - if (!EXPECT_EQUAL("foo-h1-r2", _spec.getTable(0).getHop(0).getRecipient(1))) return false; - if (!EXPECT_EQUAL(true, _spec.getTable(0).getHop(0).getIgnoreResult())) return false; - if (!EXPECT_EQUAL("foo-h2", _spec.getTable(0).getHop(1).getName())) return false; - if (!EXPECT_EQUAL("foo-h2-sel", _spec.getTable(0).getHop(1).getSelector())) return false; - if (!EXPECT_EQUAL(2u, _spec.getTable(0).getHop(1).getNumRecipients())) return false; - if (!EXPECT_EQUAL("foo-h2-r1", _spec.getTable(0).getHop(1).getRecipient(0))) return false; - if (!EXPECT_EQUAL("foo-h2-r2", _spec.getTable(0).getHop(1).getRecipient(1))) return false; - if (!EXPECT_EQUAL(2u, _spec.getTable(0).getNumRoutes())) return false; - if (!EXPECT_EQUAL("foo-r1", _spec.getTable(0).getRoute(0).getName())) return false; - if (!EXPECT_EQUAL(2u, _spec.getTable(0).getRoute(0).getNumHops())) return false; - if (!EXPECT_EQUAL("foo-h1", _spec.getTable(0).getRoute(0).getHop(0))) return false; - if (!EXPECT_EQUAL("foo-h2", _spec.getTable(0).getRoute(0).getHop(1))) return false; - if (!EXPECT_EQUAL("foo-r2", _spec.getTable(0).getRoute(1).getName())) return false; - if (!EXPECT_EQUAL(2u, _spec.getTable(0).getRoute(1).getNumHops())) return false; - if (!EXPECT_EQUAL("foo-h2", _spec.getTable(0).getRoute(1).getHop(0))) return false; - if (!EXPECT_EQUAL("foo-h1", _spec.getTable(0).getRoute(1).getHop(1))) return false; + ASSERT_EQ("foo", _spec.getTable(0).getProtocol()); + ASSERT_EQ(2u, _spec.getTable(0).getNumHops()); + ASSERT_EQ("foo-h1", _spec.getTable(0).getHop(0).getName()); + ASSERT_EQ("foo-h1-sel", _spec.getTable(0).getHop(0).getSelector()); + ASSERT_EQ(2u, _spec.getTable(0).getHop(0).getNumRecipients()); + ASSERT_EQ("foo-h1-r1", _spec.getTable(0).getHop(0).getRecipient(0)); + ASSERT_EQ("foo-h1-r2", _spec.getTable(0).getHop(0).getRecipient(1)); + ASSERT_EQ(true, _spec.getTable(0).getHop(0).getIgnoreResult()); + ASSERT_EQ("foo-h2", _spec.getTable(0).getHop(1).getName()); + ASSERT_EQ("foo-h2-sel", _spec.getTable(0).getHop(1).getSelector()); + ASSERT_EQ(2u, _spec.getTable(0).getHop(1).getNumRecipients()); + ASSERT_EQ("foo-h2-r1", _spec.getTable(0).getHop(1).getRecipient(0)); + ASSERT_EQ("foo-h2-r2", _spec.getTable(0).getHop(1).getRecipient(1)); + ASSERT_EQ(2u, _spec.getTable(0).getNumRoutes()); + ASSERT_EQ("foo-r1", _spec.getTable(0).getRoute(0).getName()); + ASSERT_EQ(2u, _spec.getTable(0).getRoute(0).getNumHops()); + ASSERT_EQ("foo-h1", _spec.getTable(0).getRoute(0).getHop(0)); + ASSERT_EQ("foo-h2", _spec.getTable(0).getRoute(0).getHop(1)); + ASSERT_EQ("foo-r2", _spec.getTable(0).getRoute(1).getName()); + ASSERT_EQ(2u, _spec.getTable(0).getRoute(1).getNumHops()); + ASSERT_EQ("foo-h2", _spec.getTable(0).getRoute(1).getHop(0)); + ASSERT_EQ("foo-h1", _spec.getTable(0).getRoute(1).getHop(1)); } if (numTables > 1) { - if (!EXPECT_EQUAL("bar", _spec.getTable(1).getProtocol())) return false; - if (!EXPECT_EQUAL(2u, _spec.getTable(1).getNumHops())) return false; - if (!EXPECT_EQUAL("bar-h1", _spec.getTable(1).getHop(0).getName())) return false; - if (!EXPECT_EQUAL("bar-h1-sel", _spec.getTable(1).getHop(0).getSelector())) return false; - if (!EXPECT_EQUAL(2u, _spec.getTable(1).getHop(0).getNumRecipients())) return false; - if (!EXPECT_EQUAL("bar-h1-r1", _spec.getTable(1).getHop(0).getRecipient(0))) return false; - if (!EXPECT_EQUAL("bar-h1-r2", _spec.getTable(1).getHop(0).getRecipient(1))) return false; - if (!EXPECT_EQUAL("bar-h2", _spec.getTable(1).getHop(1).getName())) return false; - if (!EXPECT_EQUAL("bar-h2-sel", _spec.getTable(1).getHop(1).getSelector())) return false; - if (!EXPECT_EQUAL(2u, _spec.getTable(1).getHop(1).getNumRecipients())) return false; - if (!EXPECT_EQUAL("bar-h2-r1", _spec.getTable(1).getHop(1).getRecipient(0))) return false; - if (!EXPECT_EQUAL("bar-h2-r2", _spec.getTable(1).getHop(1).getRecipient(1))) return false; - if (!EXPECT_EQUAL(2u, _spec.getTable(1).getNumRoutes())) return false; - if (!EXPECT_EQUAL("bar-r1", _spec.getTable(1).getRoute(0).getName())) return false; - if (!EXPECT_EQUAL(2u, _spec.getTable(1).getRoute(0).getNumHops())) return false; - if (!EXPECT_EQUAL("bar-h1", _spec.getTable(1).getRoute(0).getHop(0))) return false; - if (!EXPECT_EQUAL("bar-h2", _spec.getTable(1).getRoute(0).getHop(1))) return false; - if (!EXPECT_EQUAL("bar-r2", _spec.getTable(1).getRoute(1).getName())) return false; - if (!EXPECT_EQUAL(2u, _spec.getTable(1).getRoute(1).getNumHops())) return false; - if (!EXPECT_EQUAL("bar-h2", _spec.getTable(1).getRoute(1).getHop(0))) return false; - if (!EXPECT_EQUAL("bar-h1", _spec.getTable(1).getRoute(1).getHop(1))) return false; + ASSERT_EQ("bar", _spec.getTable(1).getProtocol()); + ASSERT_EQ(2u, _spec.getTable(1).getNumHops()); + ASSERT_EQ("bar-h1", _spec.getTable(1).getHop(0).getName()); + ASSERT_EQ("bar-h1-sel", _spec.getTable(1).getHop(0).getSelector()); + ASSERT_EQ(2u, _spec.getTable(1).getHop(0).getNumRecipients()); + ASSERT_EQ("bar-h1-r1", _spec.getTable(1).getHop(0).getRecipient(0)); + ASSERT_EQ("bar-h1-r2", _spec.getTable(1).getHop(0).getRecipient(1)); + ASSERT_EQ("bar-h2", _spec.getTable(1).getHop(1).getName()); + ASSERT_EQ("bar-h2-sel", _spec.getTable(1).getHop(1).getSelector()); + ASSERT_EQ(2u, _spec.getTable(1).getHop(1).getNumRecipients()); + ASSERT_EQ("bar-h2-r1", _spec.getTable(1).getHop(1).getRecipient(0)); + ASSERT_EQ("bar-h2-r2", _spec.getTable(1).getHop(1).getRecipient(1)); + ASSERT_EQ(2u, _spec.getTable(1).getNumRoutes()); + ASSERT_EQ("bar-r1", _spec.getTable(1).getRoute(0).getName()); + ASSERT_EQ(2u, _spec.getTable(1).getRoute(0).getNumHops()); + ASSERT_EQ("bar-h1", _spec.getTable(1).getRoute(0).getHop(0)); + ASSERT_EQ("bar-h2", _spec.getTable(1).getRoute(0).getHop(1)); + ASSERT_EQ("bar-r2", _spec.getTable(1).getRoute(1).getName()); + ASSERT_EQ(2u, _spec.getTable(1).getRoute(1).getNumHops()); + ASSERT_EQ("bar-h2", _spec.getTable(1).getRoute(1).getHop(0)); + ASSERT_EQ("bar-h1", _spec.getTable(1).getRoute(1).getHop(1)); } - return true; + success = true; } bool -Test::checkHalf() +ConfigAgentTest::checkHalf() { - return _spec.getNumTables() == 1 && EXPECT_TRUE(checkTables(1)); + bool success = false; + return _spec.getNumTables() == 1 && (checkTables(1, success), success); } bool -Test::checkFull() +ConfigAgentTest::checkFull() { - return _spec.getNumTables() == 2 && EXPECT_TRUE(checkTables(2)); + bool success = false; + return _spec.getNumTables() == 2 && (checkTables(2, success), success); } -int -Test::Main() +TEST_F(ConfigAgentTest, test_config_agent) { - TEST_INIT("configagent_test"); EXPECT_TRUE(!checkHalf()); EXPECT_TRUE(!checkFull()); ConfigAgent agent(*this); @@ -118,5 +122,6 @@ Test::Main() agent.configure(FileConfigReader<MessagebusConfig>(TEST_PATH("full.cfg")).read()); EXPECT_TRUE(checkFull()); EXPECT_TRUE(!checkHalf()); - TEST_DONE(); } + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/messagebus/src/tests/messagebus/CMakeLists.txt b/messagebus/src/tests/messagebus/CMakeLists.txt index 3f79e2ed851..f05141ca28f 100644 --- a/messagebus/src/tests/messagebus/CMakeLists.txt +++ b/messagebus/src/tests/messagebus/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_messagebus_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_messagebus_test_app COMMAND messagebus_messagebus_test_app) diff --git a/messagebus/src/tests/messagebus/messagebus.cpp b/messagebus/src/tests/messagebus/messagebus.cpp index 5c1bdc54f00..e4d90a3c198 100644 --- a/messagebus/src/tests/messagebus/messagebus.cpp +++ b/messagebus/src/tests/messagebus/messagebus.cpp @@ -11,8 +11,8 @@ #include <vespa/messagebus/testlib/simpleprotocol.h> #include <vespa/messagebus/testlib/slobrok.h> #include <vespa/messagebus/testlib/testserver.h> -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/vespalib/util/stringfmt.h> +#include <vespa/vespalib/gtest/gtest.h> #include <thread> using namespace mbus; @@ -98,8 +98,8 @@ struct Search : public Server { //----------------------------------------------------------------------------- -class Test : public vespalib::TestApp { -private: +class MessageBusTest : public testing::Test { +protected: Slobrok::UP slobrok; Client::UP client; DocProc::UP dp0; @@ -112,44 +112,21 @@ private: std::vector<DocProc*> dpVec; std::vector<Search*> searchVec; -public: - Test(); - ~Test(); - int Main() override; - void testSendToCol(); - void testDirectHop(); - void testDirectRoute(); - void testRoutingPolicyCache(); - -private: - void setup(); - void teardown(); + MessageBusTest(); + ~MessageBusTest(); + void SetUp() override; + void TearDown() override; void assertSrc(Client& src); void assertItr(DocProc& itr); void assertDst(Search& dst); }; -TEST_APPHOOK(Test); - -Test::Test() = default; -Test::~Test() = default; - -int -Test::Main() -{ - TEST_INIT("messagebus_test"); - - testSendToCol(); TEST_FLUSH(); - testDirectHop(); TEST_FLUSH(); - testDirectRoute(); TEST_FLUSH(); - testRoutingPolicyCache(); TEST_FLUSH(); - - TEST_DONE(); -} +MessageBusTest::MessageBusTest() = default; +MessageBusTest::~MessageBusTest() = default; void -Test::setup() +MessageBusTest::SetUp() { slobrok.reset(new Slobrok()); client.reset(new Client(*slobrok)); @@ -188,7 +165,8 @@ Test::setup() ASSERT_TRUE(dp2->server.waitSlobrok("search/r.1/c.1/session")); } -void Test::teardown() +void +MessageBusTest::TearDown() { dpVec.clear(); searchVec.clear(); @@ -203,10 +181,8 @@ void Test::teardown() slobrok.reset(); } -void -Test::testSendToCol() +TEST_F(MessageBusTest, test_send_to_col) { - setup(); ASSERT_TRUE(SimpleMessage("msg").getHash() % 2 == 0); for (uint32_t i = 0; i < 150; ++i) { Message::UP msg(new SimpleMessage("msg")); @@ -244,13 +220,10 @@ Test::testSendToCol() ASSERT_TRUE(reply->isReply()); EXPECT_TRUE(static_cast<Reply&>(*reply).getNumErrors() == 0); } - teardown(); } -void -Test::testDirectHop() +TEST_F(MessageBusTest, test_direct_hop) { - setup(); for (int row = 0; row < 2; row++) { for (int col = 0; col < 2; col++) { Search* dst = searchVec[row * 2 + col]; @@ -260,25 +233,22 @@ Test::testDirectHop() Message::UP(new SimpleMessage("empty")), Route().addHop(vespalib::make_string("search/r.%d/c.%d/session", row, col))) .isAccepted()); - assertDst(*dst); - assertSrc(*client); + ASSERT_NO_FATAL_FAILURE(assertDst(*dst)); + ASSERT_NO_FATAL_FAILURE(assertSrc(*client)); // Send using address. ASSERT_TRUE(client->session->send( Message::UP(new SimpleMessage("empty")), Route().addHop(Hop(dst->session->getConnectionSpec().c_str()))) .isAccepted()); - assertDst(*dst); - assertSrc(*client); + ASSERT_NO_FATAL_FAILURE(assertDst(*dst)); + ASSERT_NO_FATAL_FAILURE(assertSrc(*client)); } } - teardown(); } -void -Test::testDirectRoute() +TEST_F(MessageBusTest, test_direct_route) { - setup(); ASSERT_TRUE(client->session->send( Message::UP(new SimpleMessage("empty")), Route() @@ -290,26 +260,24 @@ Test::testDirectRoute() .addHop(Hop(dp2->session->getConnectionSpec())) .addHop(Hop("search/r.0/c.0/session"))) .isAccepted()); - assertItr(*dp0); - assertItr(*dp0); - assertItr(*dp1); - assertItr(*dp1); - assertItr(*dp2); - assertItr(*dp2); - assertDst(*search00); - assertItr(*dp2); - assertItr(*dp2); - assertItr(*dp1); - assertItr(*dp1); - assertItr(*dp0); - assertItr(*dp0); - assertSrc(*client); - - teardown(); + ASSERT_NO_FATAL_FAILURE(assertItr(*dp0)); + ASSERT_NO_FATAL_FAILURE(assertItr(*dp0)); + ASSERT_NO_FATAL_FAILURE(assertItr(*dp1)); + ASSERT_NO_FATAL_FAILURE(assertItr(*dp1)); + ASSERT_NO_FATAL_FAILURE(assertItr(*dp2)); + ASSERT_NO_FATAL_FAILURE(assertItr(*dp2)); + ASSERT_NO_FATAL_FAILURE(assertDst(*search00)); + ASSERT_NO_FATAL_FAILURE(assertItr(*dp2)); + ASSERT_NO_FATAL_FAILURE(assertItr(*dp2)); + ASSERT_NO_FATAL_FAILURE(assertItr(*dp1)); + ASSERT_NO_FATAL_FAILURE(assertItr(*dp1)); + ASSERT_NO_FATAL_FAILURE(assertItr(*dp0)); + ASSERT_NO_FATAL_FAILURE(assertItr(*dp0)); + ASSERT_NO_FATAL_FAILURE(assertSrc(*client)); } void -Test::assertDst(Search& dst) +MessageBusTest::assertDst(Search& dst) { ASSERT_TRUE(dst.waitQueueSize(1)); Routable::UP msg = dst.queue.dequeue(); @@ -318,7 +286,7 @@ Test::assertDst(Search& dst) } void -Test::assertItr(DocProc& itr) +MessageBusTest::assertItr(DocProc& itr) { ASSERT_TRUE(itr.waitQueueSize(1)); Routable::UP msg = itr.queue.dequeue(); @@ -327,17 +295,15 @@ Test::assertItr(DocProc& itr) } void -Test::assertSrc(Client& src) +MessageBusTest::assertSrc(Client& src) { ASSERT_TRUE(src.waitQueueSize(1)); Routable::UP msg = src.queue.dequeue(); ASSERT_TRUE(msg); } -void -Test::testRoutingPolicyCache() +TEST_F(MessageBusTest, test_routing_policy_cache) { - setup(); MessageBus &bus = client->server.mb; IRoutingPolicy::SP all = bus.getRoutingPolicy(SimpleProtocol::NAME, "All", ""); @@ -354,6 +320,6 @@ Test::testRoutingPolicyCache() IRoutingPolicy::SP refArg = bus.getRoutingPolicy(SimpleProtocol::NAME, "All", "Arg"); ASSERT_TRUE(refArg.get() != NULL); ASSERT_TRUE(allArg.get() == refArg.get()); - - teardown(); } + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/messagebus/src/tests/resender/CMakeLists.txt b/messagebus/src/tests/resender/CMakeLists.txt index 2d0e5dbbb61..c364806b2dd 100644 --- a/messagebus/src/tests/resender/CMakeLists.txt +++ b/messagebus/src/tests/resender/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_resender_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_resender_test_app COMMAND messagebus_resender_test_app) diff --git a/messagebus/src/tests/resender/resender.cpp b/messagebus/src/tests/resender/resender.cpp index b9c75c36dd0..e61d3704909 100644 --- a/messagebus/src/tests/resender/resender.cpp +++ b/messagebus/src/tests/resender/resender.cpp @@ -9,26 +9,11 @@ #include <vespa/messagebus/testlib/simpleprotocol.h> #include <vespa/messagebus/testlib/slobrok.h> #include <vespa/messagebus/testlib/testserver.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> using namespace mbus; -//////////////////////////////////////////////////////////////////////////////// -// -// Utilities -// -//////////////////////////////////////////////////////////////////////////////// - -class StringList : public std::vector<string> { -public: - StringList &add(const string &str); -}; - -StringList & -StringList::add(const string &str) -{ - std::vector<string>::push_back(str); return *this; -} +namespace { static const duration GET_MESSAGE_TIMEOUT = 60s; @@ -55,35 +40,17 @@ public: bool start(); }; -class Test : public vespalib::TestApp { -private: - Message::UP createMessage(const string &msg); - void replyFromDestination(TestData &data, Message::UP msg, uint32_t errorCode, double retryDelay); - -public: - int Main() override; - void testRetryTag(TestData &data); - void testRetryEnabledTag(TestData &data); - void testTransientError(TestData &data); - void testFatalError(TestData &data); - void testDisableRetry(TestData &data); - void testRetryDelay(TestData &data); - void testRequestRetryDelay(TestData &data); -}; - -TEST_APPHOOK(Test); - -TestData::TestData() : - _slobrok(), - _retryPolicy(new RetryTransientErrorsPolicy()), - _srcServer(MessageBusParams().setRetryPolicy(_retryPolicy).addProtocol(std::make_shared<SimpleProtocol>()), - RPCNetworkParams(_slobrok.config())), - _srcSession(), - _srcHandler(), - _dstServer(MessageBusParams().addProtocol(std::make_shared<SimpleProtocol>()), - RPCNetworkParams(_slobrok.config()).setIdentity(Identity("dst"))), - _dstSession(), - _dstHandler() +TestData::TestData() + : _slobrok(), + _retryPolicy(new RetryTransientErrorsPolicy()), + _srcServer(MessageBusParams().setRetryPolicy(_retryPolicy).addProtocol(std::make_shared<SimpleProtocol>()), + RPCNetworkParams(_slobrok.config())), + _srcSession(), + _srcHandler(), + _dstServer(MessageBusParams().addProtocol(std::make_shared<SimpleProtocol>()), + RPCNetworkParams(_slobrok.config()).setIdentity(Identity("dst"))), + _dstSession(), + _dstHandler() { } TestData::~TestData() = default; @@ -105,35 +72,16 @@ TestData::start() return true; } -Message::UP -Test::createMessage(const string &msg) +std::unique_ptr<Message> +createMessage(const string &msg) { Message::UP ret(new SimpleMessage(msg)); ret->getTrace().setLevel(9); return ret; } -int -Test::Main() -{ - TEST_INIT("resender_test"); - - TestData data; - ASSERT_TRUE(data.start()); - - testRetryTag(data); TEST_FLUSH(); - testRetryEnabledTag(data); TEST_FLUSH(); - testTransientError(data); TEST_FLUSH(); - testFatalError(data); TEST_FLUSH(); - testDisableRetry(data); TEST_FLUSH(); - testRetryDelay(data); TEST_FLUSH(); - testRequestRetryDelay(data); TEST_FLUSH(); - - TEST_DONE(); -} - void -Test::replyFromDestination(TestData &data, Message::UP msg, uint32_t errorCode, double retryDelay) +replyFromDestination(TestData &data, Message::UP msg, uint32_t errorCode, double retryDelay) { Reply::UP reply(new EmptyReply()); reply->swapState(*msg); @@ -144,22 +92,51 @@ Test::replyFromDestination(TestData &data, Message::UP msg, uint32_t errorCode, data._dstSession->reply(std::move(reply)); } +} + +class ResenderTest : public testing::Test { +protected: + static std::shared_ptr<TestData> _data; + ResenderTest(); + ~ResenderTest() override; + static void SetUpTestSuite(); + static void TearDownTestSuite(); +}; + +std::shared_ptr<TestData> ResenderTest::_data; + +ResenderTest::ResenderTest() = default; +ResenderTest::~ResenderTest() = default; + +void +ResenderTest::SetUpTestSuite() +{ + _data = std::make_shared<TestData>(); + ASSERT_TRUE(_data->start()); +} + +void +ResenderTest::TearDownTestSuite() +{ + _data.reset(); +} + //////////////////////////////////////////////////////////////////////////////// // // Tests // //////////////////////////////////////////////////////////////////////////////// -void -Test::testRetryTag(TestData &data) +TEST_F(ResenderTest, test_retry_tag) { + auto& data = *_data; data._retryPolicy->setEnabled(true); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst/session")).isAccepted()); Message::UP msg = data._dstHandler.getMessage(GET_MESSAGE_TIMEOUT); ASSERT_TRUE(msg); for (uint32_t i = 0; i < 5; ++i) { - EXPECT_EQUAL(i, msg->getRetry()); - EXPECT_EQUAL(true, msg->getRetryEnabled()); + EXPECT_EQ(i, msg->getRetry()); + EXPECT_EQ(true, msg->getRetryEnabled()); replyFromDestination(data, std::move(msg), ErrorCode::APP_TRANSIENT_ERROR, 0); msg = data._dstHandler.getMessage(GET_MESSAGE_TIMEOUT); ASSERT_TRUE(msg); @@ -173,16 +150,16 @@ Test::testRetryTag(TestData &data) printf("%s", reply->getTrace().toString().c_str()); } -void -Test::testRetryEnabledTag(TestData &data) +TEST_F(ResenderTest, test_retry_enabled_tag) { + auto& data = *_data; data._retryPolicy->setEnabled(true); Message::UP msg = createMessage("msg"); msg->setRetryEnabled(false); EXPECT_TRUE(data._srcSession->send(std::move(msg), Route::parse("dst/session")).isAccepted()); msg = data._dstHandler.getMessage(GET_MESSAGE_TIMEOUT); ASSERT_TRUE(msg); - EXPECT_EQUAL(false, msg->getRetryEnabled()); + EXPECT_EQ(false, msg->getRetryEnabled()); replyFromDestination(data, std::move(msg), ErrorCode::APP_TRANSIENT_ERROR, 0); Reply::UP reply = data._srcHandler.getReply(); ASSERT_TRUE(reply); @@ -192,9 +169,9 @@ Test::testRetryEnabledTag(TestData &data) printf("%s", reply->getTrace().toString().c_str()); } -void -Test::testTransientError(TestData &data) +TEST_F(ResenderTest, test_transient_error) { + auto& data = *_data; data._retryPolicy->setEnabled(true); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst/session")).isAccepted()); Message::UP msg = data._dstHandler.getMessage(GET_MESSAGE_TIMEOUT); @@ -211,9 +188,9 @@ Test::testTransientError(TestData &data) printf("%s", reply->getTrace().toString().c_str()); } -void -Test::testFatalError(TestData &data) +TEST_F(ResenderTest, test_fatal_error) { + auto& data = *_data; data._retryPolicy->setEnabled(true); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst/session")).isAccepted()); Message::UP msg = data._dstHandler.getMessage(GET_MESSAGE_TIMEOUT); @@ -227,9 +204,9 @@ Test::testFatalError(TestData &data) printf("%s", reply->getTrace().toString().c_str()); } -void -Test::testDisableRetry(TestData &data) +TEST_F(ResenderTest, test_disable_retry) { + auto& data = *_data; data._retryPolicy->setEnabled(false); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst/session")).isAccepted()); Message::UP msg = data._dstHandler.getMessage(GET_MESSAGE_TIMEOUT); @@ -244,16 +221,16 @@ Test::testDisableRetry(TestData &data) printf("%s", reply->getTrace().toString().c_str()); } -void -Test::testRetryDelay(TestData &data) +TEST_F(ResenderTest, test_retry_delay) { + auto& data = *_data; data._retryPolicy->setEnabled(true); data._retryPolicy->setBaseDelay(0.01); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst/session")).isAccepted()); Message::UP msg = data._dstHandler.getMessage(GET_MESSAGE_TIMEOUT); ASSERT_TRUE(msg); for (uint32_t i = 0; i < 5; ++i) { - EXPECT_EQUAL(i, msg->getRetry()); + EXPECT_EQ(i, msg->getRetry()); replyFromDestination(data, std::move(msg), ErrorCode::APP_TRANSIENT_ERROR, -1); msg = data._dstHandler.getMessage(GET_MESSAGE_TIMEOUT); ASSERT_TRUE(msg); @@ -273,16 +250,16 @@ Test::testRetryDelay(TestData &data) EXPECT_TRUE(trace.find("retry 5 in 0.160") != string::npos); } -void -Test::testRequestRetryDelay(TestData &data) +TEST_F(ResenderTest, test_request_retry_delay) { + auto& data = *_data; data._retryPolicy->setEnabled(true); data._retryPolicy->setBaseDelay(1); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst/session")).isAccepted()); Message::UP msg = data._dstHandler.getMessage(GET_MESSAGE_TIMEOUT); ASSERT_TRUE(msg); for (uint32_t i = 0; i < 5; ++i) { - EXPECT_EQUAL(i, msg->getRetry()); + EXPECT_EQ(i, msg->getRetry()); replyFromDestination(data, std::move(msg), ErrorCode::APP_TRANSIENT_ERROR, i / 50.0); msg = data._dstHandler.getMessage(GET_MESSAGE_TIMEOUT); ASSERT_TRUE(msg); @@ -302,3 +279,4 @@ Test::testRequestRetryDelay(TestData &data) EXPECT_TRUE(trace.find("retry 5 in 0.080") != string::npos); } +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/messagebus/src/tests/result/CMakeLists.txt b/messagebus/src/tests/result/CMakeLists.txt index 6aba63fdc41..d4360f3826b 100644 --- a/messagebus/src/tests/result/CMakeLists.txt +++ b/messagebus/src/tests/result/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_result_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_result_test_app COMMAND messagebus_result_test_app) diff --git a/messagebus/src/tests/result/result.cpp b/messagebus/src/tests/result/result.cpp index 4140e26db95..ce6e19b7dcb 100644 --- a/messagebus/src/tests/result/result.cpp +++ b/messagebus/src/tests/result/result.cpp @@ -1,13 +1,15 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/messagebus/result.h> #include <vespa/messagebus/error.h> #include <vespa/messagebus/errorcode.h> #include <vespa/messagebus/testlib/simplemessage.h> +#include <vespa/vespalib/gtest/gtest.h> using namespace mbus; +namespace { + struct MyMessage : public SimpleMessage { static int ctorCnt; @@ -22,28 +24,23 @@ struct MyMessage : public SimpleMessage int MyMessage::ctorCnt = 0; int MyMessage::dtorCnt = 0; -struct Test : public vespalib::TestApp -{ - Result sendOk(Message::UP msg); - Result sendFail(Message::UP msg); - int Main() override; -}; - Result -Test::sendOk(Message::UP msg) { +sendOk(Message::UP msg) +{ (void) msg; return Result(); } Result -Test::sendFail(Message::UP msg) { +sendFail(Message::UP msg) +{ return Result(Error(ErrorCode::FATAL_ERROR, "error"), std::move(msg)); } -int -Test::Main() +} + +TEST(ResultTest, test_result) { - TEST_INIT("result_test"); { // test accepted Message::UP msg(new MyMessage("test")); Result res = sendOk(std::move(msg)); @@ -68,7 +65,6 @@ Test::Main() } EXPECT_TRUE(MyMessage::ctorCnt == 2); EXPECT_TRUE(MyMessage::dtorCnt == 2); - TEST_DONE(); } -TEST_APPHOOK(Test); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/messagebus/src/tests/routeparser/CMakeLists.txt b/messagebus/src/tests/routeparser/CMakeLists.txt index 917c6983d9f..6c715d49f73 100644 --- a/messagebus/src/tests/routeparser/CMakeLists.txt +++ b/messagebus/src/tests/routeparser/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_routeparser_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_routeparser_test_app COMMAND messagebus_routeparser_test_app) diff --git a/messagebus/src/tests/routeparser/routeparser.cpp b/messagebus/src/tests/routeparser/routeparser.cpp index 0983b6734c6..f01ad44fdba 100644 --- a/messagebus/src/tests/routeparser/routeparser.cpp +++ b/messagebus/src/tests/routeparser/routeparser.cpp @@ -11,63 +11,34 @@ #include <vespa/messagebus/testlib/simplemessage.h> #include <vespa/messagebus/testlib/slobrok.h> #include <vespa/messagebus/testlib/testserver.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/log/log.h> LOG_SETUP("routeparser_test"); using namespace mbus; -class Test : public vespalib::TestApp { -public: - int Main() override; - void testHopParser(); - void testHopParserErrors(); - void testRouteParser(); - void testRouteParserErrors(); - -private: - bool testError(const Route &route, const string &msg); - bool testError(const Hop &hop, const string &msg); - bool testErrorDirective(const IHopDirective & dir, const string &msg); - bool testPolicyDirective(const IHopDirective & dir, const string &name, const string ¶m); - bool testRouteDirective(const IHopDirective & dir, const string &name); - bool testTcpDirective(const IHopDirective & dir, const string &host, uint32_t port, const string &session); - bool testVerbatimDirective(const IHopDirective & dir, const string &image); -}; - -TEST_APPHOOK(Test); - -int -Test::Main() -{ - TEST_INIT("routeparser_test"); - - testHopParser(); TEST_FLUSH(); - testHopParserErrors(); TEST_FLUSH(); - testRouteParser(); TEST_FLUSH(); - testRouteParserErrors(); TEST_FLUSH(); - - TEST_DONE(); -} +namespace { bool -Test::testError(const Route &route, const string &msg) +testErrorDirective(const IHopDirective & dir, const string &msg) { - if (!EXPECT_EQUAL(1u, route.getNumHops())) { + bool failed = false; + EXPECT_EQ(IHopDirective::TYPE_ERROR, dir.getType()) << (failed = true, ""); + if (failed) { return false; } - if (!testError(route.getHop(0), msg)) { - return false; - } - return true; + EXPECT_EQ(msg, static_cast<const ErrorDirective&>(dir).getMessage()) << (failed = true, ""); + return !failed; } bool -Test::testError(const Hop &hop, const string &msg) +testError(const Hop &hop, const string &msg) { LOG(info, "%s", hop.toDebugString().c_str()); - if (!EXPECT_EQUAL(1u, hop.getNumDirectives())) { + bool failed = false; + EXPECT_EQ(1u, hop.getNumDirectives()) << (failed = true, ""); + if (failed) { return false; } if (!testErrorDirective(hop.getDirective(0), msg)) { @@ -77,106 +48,121 @@ Test::testError(const Hop &hop, const string &msg) } bool -Test::testErrorDirective(const IHopDirective & dir, const string &msg) +testError(const Route &route, const string &msg) { - if (!EXPECT_EQUAL(IHopDirective::TYPE_ERROR, dir.getType())) { + bool failed = false; + EXPECT_EQ(1u, route.getNumHops()) << (failed = true, ""); + if (failed) { return false; } - if (!EXPECT_EQUAL(msg, static_cast<const ErrorDirective&>(dir).getMessage())) { + if (!testError(route.getHop(0), msg)) { return false; } return true; } bool -Test::testPolicyDirective(const IHopDirective & dir, const string &name, const string ¶m) +testPolicyDirective(const IHopDirective & dir, const string &name, const string ¶m) { - if (!EXPECT_EQUAL(IHopDirective::TYPE_POLICY, dir.getType())) { - return false; - } - if (!EXPECT_EQUAL(name, static_cast<const PolicyDirective&>(dir).getName())) { + bool failed = false; + EXPECT_EQ(IHopDirective::TYPE_POLICY, dir.getType()) << (failed = true, ""); + if (failed) { return false; } - if (!EXPECT_EQUAL(param, static_cast<const PolicyDirective&>(dir).getParam())) { + EXPECT_EQ(name, static_cast<const PolicyDirective&>(dir).getName()) << (failed = true, ""); + if (failed) { return false; } - return true; + EXPECT_EQ(param, static_cast<const PolicyDirective&>(dir).getParam()) << (failed = true, ""); + return !failed; } bool -Test::testRouteDirective(const IHopDirective & dir, const string &name) +testRouteDirective(const IHopDirective & dir, const string &name) { - if (!EXPECT_EQUAL(IHopDirective::TYPE_ROUTE, dir.getType())) { + bool failed = false; + EXPECT_EQ(IHopDirective::TYPE_ROUTE, dir.getType()) << (failed = true, ""); + if (failed) { return false; } - if (!EXPECT_EQUAL(name, static_cast<const RouteDirective&>(dir).getName())) { - return false; - } - return true; + EXPECT_EQ(name, static_cast<const RouteDirective&>(dir).getName()) << (failed = true, ""); + return !failed; } bool -Test::testTcpDirective(const IHopDirective & dir, const string &host, uint32_t port, const string &session) +testTcpDirective(const IHopDirective & dir, const string &host, uint32_t port, const string &session) { - if (!EXPECT_EQUAL(IHopDirective::TYPE_TCP, dir.getType())) { - return false; - } - if (!EXPECT_EQUAL(host, static_cast<const TcpDirective&>(dir).getHost())) { + bool failed = false; + EXPECT_EQ(IHopDirective::TYPE_TCP, dir.getType()) << (failed = true, ""); + if (failed) { return false; } - if (!EXPECT_EQUAL(port, static_cast<const TcpDirective&>(dir).getPort())) { + EXPECT_EQ(host, static_cast<const TcpDirective&>(dir).getHost()) << (failed = true, ""); + if (failed) { return false; } - if (!EXPECT_EQUAL(session, static_cast<const TcpDirective&>(dir).getSession())) { + EXPECT_EQ(port, static_cast<const TcpDirective&>(dir).getPort()) << (failed = true, ""); + if (failed) { return false; } - return true; + EXPECT_EQ(session, static_cast<const TcpDirective&>(dir).getSession()) << (failed = true, ""); + return !failed; } bool -Test::testVerbatimDirective(const IHopDirective & dir, const string &image) +testVerbatimDirective(const IHopDirective & dir, const string &image) { - if (!EXPECT_EQUAL(IHopDirective::TYPE_VERBATIM, dir.getType())) { - return false; - } - if (!EXPECT_EQUAL(image, static_cast<const VerbatimDirective&>(dir).getImage())) { + bool failed = false; + EXPECT_EQ(IHopDirective::TYPE_VERBATIM, dir.getType()) << (failed = true, ""); + if (failed) { return false; } - return true; + EXPECT_EQ(image, static_cast<const VerbatimDirective&>(dir).getImage()) << (failed = true, ""); + return !failed; +} + } -void -Test::testHopParser() +class RouteParserTest : public testing::Test { +protected: + RouteParserTest(); + ~RouteParserTest() override; +}; + +RouteParserTest::RouteParserTest() = default; +RouteParserTest::~RouteParserTest() = default; + +TEST_F(RouteParserTest, test_hop_parser) { { Hop hop = Hop::parse("foo"); - EXPECT_EQUAL(1u, hop.getNumDirectives()); + EXPECT_EQ(1u, hop.getNumDirectives()); EXPECT_TRUE(testVerbatimDirective(hop.getDirective(0), "foo")); } { Hop hop = Hop::parse("foo/bar"); - EXPECT_EQUAL(2u, hop.getNumDirectives()); + EXPECT_EQ(2u, hop.getNumDirectives()); EXPECT_TRUE(testVerbatimDirective(hop.getDirective(0), "foo")); EXPECT_TRUE(testVerbatimDirective(hop.getDirective(1), "bar")); } { Hop hop = Hop::parse("tcp/foo:666/bar"); - EXPECT_EQUAL(1u, hop.getNumDirectives()); + EXPECT_EQ(1u, hop.getNumDirectives()); EXPECT_TRUE(testTcpDirective(hop.getDirective(0), "foo", 666, "bar")); } { Hop hop = Hop::parse("route:foo"); - EXPECT_EQUAL(1u, hop.getNumDirectives()); + EXPECT_EQ(1u, hop.getNumDirectives()); EXPECT_TRUE(testRouteDirective(hop.getDirective(0), "foo")); } { Hop hop = Hop::parse("[Extern:tcp/localhost:3619;foo/bar]"); - EXPECT_EQUAL(1u, hop.getNumDirectives()); + EXPECT_EQ(1u, hop.getNumDirectives()); EXPECT_TRUE(testPolicyDirective(hop.getDirective(0), "Extern", "tcp/localhost:3619;foo/bar")); } { Hop hop = Hop::parse("[AND:foo bar]"); - EXPECT_EQUAL(1u, hop.getNumDirectives()); + EXPECT_EQ(1u, hop.getNumDirectives()); EXPECT_TRUE(testPolicyDirective(hop.getDirective(0), "AND", "foo bar")); } { @@ -188,7 +174,7 @@ Test::testHopParser() "route[1].selector \"other\"\n" "route[1].feed \"myfeed\"\n" "]"); - EXPECT_EQUAL(1u, hop.getNumDirectives()); + EXPECT_EQ(1u, hop.getNumDirectives()); EXPECT_TRUE(testPolicyDirective(hop.getDirective(0), "DocumentRouteSelector", "raw:route[2]\n" "route[0].name \"foo\"\n" @@ -204,7 +190,7 @@ Test::testHopParser() "route[0].selector \"testdoc\"\n" "route[0].feed \"myfeed\"\n" "]"); - EXPECT_EQUAL(1u, hop.getNumDirectives()); + EXPECT_EQ(1u, hop.getNumDirectives()); EXPECT_TRUE(testPolicyDirective(hop.getDirective(0), "DocumentRouteSelector", "raw:route[1]\n" "route[0].name \"docproc/cluster.foo\"\n" @@ -213,8 +199,7 @@ Test::testHopParser() } } -void -Test::testHopParserErrors() +TEST_F(RouteParserTest, test_hop_parser_errors) { EXPECT_TRUE(testError(Hop::parse(""), "Failed to parse empty string.")); EXPECT_TRUE(testError(Hop::parse("[foo"), "Unexpected token '': syntax error")); @@ -222,44 +207,44 @@ Test::testHopParserErrors() EXPECT_TRUE(testError(Hop::parse("foo bar"), "Failed to completely parse 'foo bar'.")); } -void -Test::testRouteParser() +TEST_F(RouteParserTest, test_route_parser) { { Route route = Route::parse("foo bar/baz"); - EXPECT_EQUAL(2u, route.getNumHops()); + EXPECT_EQ(2u, route.getNumHops()); { const Hop &hop = route.getHop(0); - EXPECT_EQUAL(1u, hop.getNumDirectives()); + EXPECT_EQ(1u, hop.getNumDirectives()); EXPECT_TRUE(testVerbatimDirective(hop.getDirective(0), "foo")); } { const Hop &hop = route.getHop(1); - EXPECT_EQUAL(2u, hop.getNumDirectives()); + EXPECT_EQ(2u, hop.getNumDirectives()); EXPECT_TRUE(testVerbatimDirective(hop.getDirective(0), "bar")); EXPECT_TRUE(testVerbatimDirective(hop.getDirective(1), "baz")); } } { Route route = Route::parse("[Extern:tcp/localhost:3633;itr/session] default"); - EXPECT_EQUAL(2u, route.getNumHops()); + EXPECT_EQ(2u, route.getNumHops()); { const Hop &hop = route.getHop(0); - EXPECT_EQUAL(1u, hop.getNumDirectives()); + EXPECT_EQ(1u, hop.getNumDirectives()); EXPECT_TRUE(testPolicyDirective(hop.getDirective(0), "Extern", "tcp/localhost:3633;itr/session")); } { const Hop &hop = route.getHop(1); - EXPECT_EQUAL(1u, hop.getNumDirectives()); + EXPECT_EQ(1u, hop.getNumDirectives()); EXPECT_TRUE(testVerbatimDirective(hop.getDirective(0), "default")); } } } -void -Test::testRouteParserErrors() +TEST_F(RouteParserTest, test_route_parser_errors) { EXPECT_TRUE(testError(Route::parse(""), "Failed to parse empty string.")); EXPECT_TRUE(testError(Route::parse("foo [bar"), "Unexpected token '': syntax error")); EXPECT_TRUE(testError(Route::parse("foo bar/[baz]]"), "Unexpected token ']': syntax error")); } + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/messagebus/src/tests/routing/CMakeLists.txt b/messagebus/src/tests/routing/CMakeLists.txt index 68e466ceff6..6b013f7b9cc 100644 --- a/messagebus/src/tests/routing/CMakeLists.txt +++ b/messagebus/src/tests/routing/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_routing_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_routing_test_app COMMAND messagebus_routing_test_app) diff --git a/messagebus/src/tests/routing/routing.cpp b/messagebus/src/tests/routing/routing.cpp index b459f093e4c..f37032e18e7 100644 --- a/messagebus/src/tests/routing/routing.cpp +++ b/messagebus/src/tests/routing/routing.cpp @@ -11,7 +11,7 @@ #include <vespa/messagebus/testlib/slobrok.h> #include <vespa/messagebus/testlib/testserver.h> #include <vespa/vespalib/component/vtag.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/log/log.h> @@ -330,59 +330,59 @@ public: mergeFromChild, mergeError, mergeException); } - static MyPolicyFactory::SP - newSelectAndMerge(const string &select) + static MyPolicyFactory::SP + newSelectAndMerge(const string &select) { return newInstance(select, ErrorCode::NONE, false, true, ErrorCode::NONE, false); } - static MyPolicyFactory::SP - newEmptySelection() + static MyPolicyFactory::SP + newEmptySelection() { return newInstance("", ErrorCode::NONE, false, false, ErrorCode::NONE, false); } - static MyPolicyFactory::SP + static MyPolicyFactory::SP newSelectError(uint32_t errCode) { return newInstance("", errCode, false, false, ErrorCode::NONE, false); } - static MyPolicyFactory::SP - newSelectException() + static MyPolicyFactory::SP + newSelectException() { return newInstance("", ErrorCode::NONE, true, false, ErrorCode::NONE, false); } - static MyPolicyFactory::SP - newSelectAndThrow(const string &select) + static MyPolicyFactory::SP + newSelectAndThrow(const string &select) { return newInstance(select, ErrorCode::NONE, true, false, ErrorCode::NONE, false); } - static MyPolicyFactory::SP - newEmptyMerge(const string &select) + static MyPolicyFactory::SP + newEmptyMerge(const string &select) { return newInstance(select, ErrorCode::NONE, false, false, ErrorCode::NONE, false); } - static MyPolicyFactory::SP - newMergeError(const string &select, int errCode) + static MyPolicyFactory::SP + newMergeError(const string &select, int errCode) { return newInstance(select, ErrorCode::NONE, false, false, errCode, false); } - static MyPolicyFactory::SP - newMergeException(const string &select) + static MyPolicyFactory::SP + newMergeException(const string &select) { return newInstance(select, ErrorCode::NONE, false, false, ErrorCode::NONE, true); } - static MyPolicyFactory::SP + static MyPolicyFactory::SP newMergeAndThrow(const string &select) { return newInstance(select, ErrorCode::NONE, false, true, ErrorCode::NONE, true); - } + } }; MyPolicyFactory::MyPolicyFactory(const string &selectRoute, uint32_t &selectError, bool selectException, @@ -400,7 +400,7 @@ MyPolicyFactory::~MyPolicyFactory() = default; class MyPolicy : public IRoutingPolicy { private: const MyPolicyFactory &_parent; - + public: explicit MyPolicy(const MyPolicyFactory &parent) : _parent(parent) @@ -465,76 +465,6 @@ public: bool start(); }; -class Test : public vespalib::TestApp { -private: - Message::UP createMessage(const string &msg, uint32_t level = 9); - void setupRouting(TestData &data, RoutingTableSpec && spec); - void setupPolicy(TestData &data, const string &policyName, - SimpleProtocol::IPolicyFactory::SP policy); - static bool testAcknowledge(TestData &data); - bool testSend(TestData &data, const string &route, uint32_t level = 9); - bool testTrace(TestData &data, const std::vector<string> &expected); - bool testTrace(const std::vector<string> &expected, const Trace &trace); - - static const duration RECEPTOR_TIMEOUT; - -public: - int Main() override; - void testNoRoutingTable(TestData &data); - void testUnknownRoute(TestData &data); - void testNoRoute(TestData &data); - void testRecognizeHopName(TestData &data); - void testRecognizeRouteDirective(TestData &data); - void testRecognizeRouteName(TestData &data); - void testHopResolutionOverflow(TestData &data); - void testRouteResolutionOverflow(TestData &data); - void testInsertRoute(TestData &data); - void testErrorDirective(TestData &data); - void testSelectError(TestData &data); - void testSelectNone(TestData &data); - void testSelectOne(TestData &data); - void testResend1(TestData &data); - void testResend2(TestData &data); - void testNoResend(TestData &data); - void testSelectOnResend(TestData &data); - void testNoSelectOnResend(TestData &data); - void testCanConsumeError(TestData &data); - void testCantConsumeError(TestData &data); - void testNestedPolicies(TestData &data); - void testRemoveReply(TestData &data); - void testSetReply(TestData &data); - void testResendSetAndReuseReply(TestData &data); - void testResendSetAndRemoveReply(TestData &data); - void testHopIgnoresReply(TestData &data); - void testHopBlueprintIgnoresReply(TestData &data); - void testAcceptEmptyRoute(TestData &data); - void testAbortOnlyActiveNodes(TestData &data); - void testTimeout(TestData &data); - void testUnknownPolicy(TestData &data); - void testSelectException(TestData &data); - void testMergeException(TestData &data); - - void requireThatIgnoreFlagPersistsThroughHopLookup(TestData &data); - void requireThatIgnoreFlagPersistsThroughRouteLookup(TestData &data); - void requireThatIgnoreFlagPersistsThroughPolicySelect(TestData &data); - void requireThatIgnoreFlagIsSerializedWithMessage(TestData &data); - void requireThatIgnoreFlagDoesNotInterfere(TestData &data); - void requireThatEmptySelectionCanBeIgnored(TestData &data); - void requireThatSelectErrorCanBeIgnored(TestData &data); - void requireThatSelectExceptionCanBeIgnored(TestData &data); - void requireThatSelectAndThrowCanBeIgnored(TestData &data); - void requireThatEmptyMergeCanBeIgnored(TestData &data); - void requireThatMergeErrorCanBeIgnored(TestData &data); - void requireThatMergeExceptionCanBeIgnored(TestData &data); - void requireThatMergeAndThrowCanBeIgnored(TestData &data); - void requireThatAllocServiceCanBeIgnored(TestData &data); - void requireThatDepthLimitCanBeIgnored(TestData &data); -}; - -const duration Test::RECEPTOR_TIMEOUT = 120s; - -TEST_APPHOOK(Test); - TestData::TestData() : _slobrok(), _retryPolicy(std::make_shared<RetryTransientErrorsPolicy>()), @@ -577,22 +507,81 @@ TestData::start() return true; } +class RoutingTest : public testing::Test { +protected: + static const duration RECEPTOR_TIMEOUT; + static std::shared_ptr<TestData> _data; + static bool _force_teardown; + RoutingTest(); + ~RoutingTest() override; + static void SetUpTestSuite(); + static void TearDownTestSuite(); + void SetUp() override; + void TearDown() override; + static Message::UP createMessage(const string &msg, uint32_t level = 9); + static void setupRouting(TestData &data, RoutingTableSpec && spec); + static void setupPolicy(TestData &data, const string &policyName, + SimpleProtocol::IPolicyFactory::SP policy); + static bool testAcknowledge(TestData &data); + static bool testSend(TestData &data, const string &route, uint32_t level = 9); + static bool testTrace(TestData &data, const std::vector<string> &expected); + static bool testTrace(const std::vector<string> &expected, const Trace &trace); +}; + +const duration RoutingTest::RECEPTOR_TIMEOUT = 120s; +std::shared_ptr<TestData> RoutingTest::_data; +bool RoutingTest::_force_teardown = false; + +RoutingTest::RoutingTest() = default; +RoutingTest::~RoutingTest() = default; + +void +RoutingTest::SetUpTestSuite() +{ + _data = std::make_shared<TestData>(); + ASSERT_TRUE(_data->start()); +} + +void +RoutingTest::TearDownTestSuite() +{ + _data.reset(); +} + +void +RoutingTest::SetUp() +{ + if (!_data) { + _data = std::make_shared<TestData>(); + ASSERT_TRUE(_data->start()); + } +} + +void +RoutingTest::TearDown() +{ + if (_force_teardown) { + _force_teardown = false; + _data.reset(); + } +} + Message::UP -Test::createMessage(const string &msg, uint32_t level) +RoutingTest::createMessage(const string &msg, uint32_t level) { auto ret = std::make_unique<SimpleMessage>(msg); ret->getTrace().setLevel(level); return ret; } -void -Test::setupRouting(TestData &data, RoutingTableSpec && spec) +void +RoutingTest::setupRouting(TestData &data, RoutingTableSpec && spec) { data._srcServer.mb.setupRouting(RoutingSpec().addTable(std::move(spec))); } -void -Test::setupPolicy(TestData &data, const string &policyName, +void +RoutingTest::setupPolicy(TestData &data, const string &policyName, SimpleProtocol::IPolicyFactory::SP policy) { auto protocol = std::make_shared<SimpleProtocol>(); @@ -600,40 +589,45 @@ Test::setupPolicy(TestData &data, const string &policyName, data._srcServer.mb.putProtocol(protocol); } -bool -Test::testAcknowledge(TestData &data) +bool +RoutingTest::testAcknowledge(TestData &data) { Message::UP msg = data._dstHandler.getMessage(RECEPTOR_TIMEOUT); - if (!EXPECT_TRUE(msg)) { + bool failed = false; + EXPECT_TRUE(msg) << (failed = true, ""); + if (failed) { return false; } data._dstSession->acknowledge(std::move(msg)); return true; } - -bool -Test::testSend(TestData &data, const string &route, uint32_t level) + +bool +RoutingTest::testSend(TestData &data, const string &route, uint32_t level) { Message::UP msg = createMessage("msg", level); msg->setRoute(Route::parse(route)); return data._srcSession->send(std::move(msg)).isAccepted(); } -bool -Test::testTrace(TestData &data, const std::vector<string> &expected) +bool +RoutingTest::testTrace(TestData &data, const std::vector<string> &expected) { Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); - if (!EXPECT_TRUE(reply)) { + bool failed = false; + EXPECT_TRUE(reply) << (failed = true, ""); + if (failed) { return false; } - if (!EXPECT_FALSE(reply->hasErrors())) { + EXPECT_FALSE(reply->hasErrors()) << (failed = true, ""); + if (failed) { return false; } return testTrace(expected, reply->getTrace()); } bool -Test::testTrace(const std::vector<string> &expected, const Trace &trace) +RoutingTest::testTrace(const std::vector<string> &expected, const Trace &trace) { const string& version = vespalib::Vtag::currentVersion.toString(); string actual = trace.toString(); @@ -646,13 +640,17 @@ Test::testTrace(const std::vector<string> &expected, const Trace &trace) } if (line[0] == '-') { string str = line.substr(1); - if (!EXPECT_TRUE(actual.find(str, pos) == string::npos)) { + bool failed = false; + EXPECT_TRUE(actual.find(str, pos) == string::npos) << (failed = true, ""); + if (failed) { LOG(error, "Line %d '%s' not expected.", i, str.c_str()); return false; } } else { pos = actual.find(line, pos); - if (!EXPECT_TRUE(pos != string::npos)) { + bool failed = false; + EXPECT_TRUE(pos != string::npos) << (failed = true, ""); + if (failed) { LOG(error, "Line %d '%s' missing.", i, line.c_str()); return false; } @@ -662,110 +660,47 @@ Test::testTrace(const std::vector<string> &expected, const Trace &trace) return true; } -int -Test::Main() -{ - TEST_INIT("routing_test"); - - TestData data; - ASSERT_TRUE(data.start()); - - testNoRoutingTable(data); TEST_FLUSH(); - testUnknownRoute(data); TEST_FLUSH(); - testNoRoute(data); TEST_FLUSH(); - testRecognizeHopName(data); TEST_FLUSH(); - testRecognizeRouteDirective(data); TEST_FLUSH(); - testRecognizeRouteName(data); TEST_FLUSH(); - testHopResolutionOverflow(data); TEST_FLUSH(); - testRouteResolutionOverflow(data); TEST_FLUSH(); - testInsertRoute(data); TEST_FLUSH(); - testErrorDirective(data); TEST_FLUSH(); - testSelectError(data); TEST_FLUSH(); - testSelectNone(data); TEST_FLUSH(); - testSelectOne(data); TEST_FLUSH(); - testResend1(data); TEST_FLUSH(); - testResend2(data); TEST_FLUSH(); - testNoResend(data); TEST_FLUSH(); - testSelectOnResend(data); TEST_FLUSH(); - testNoSelectOnResend(data); TEST_FLUSH(); - testCanConsumeError(data); TEST_FLUSH(); - testCantConsumeError(data); TEST_FLUSH(); - testNestedPolicies(data); TEST_FLUSH(); - testRemoveReply(data); TEST_FLUSH(); - testSetReply(data); TEST_FLUSH(); - testResendSetAndReuseReply(data); TEST_FLUSH(); - testResendSetAndRemoveReply(data); TEST_FLUSH(); - testHopIgnoresReply(data); TEST_FLUSH(); - testHopBlueprintIgnoresReply(data); TEST_FLUSH(); - testAcceptEmptyRoute(data); TEST_FLUSH(); - testAbortOnlyActiveNodes(data); TEST_FLUSH(); - testUnknownPolicy(data); TEST_FLUSH(); - testSelectException(data); TEST_FLUSH(); - testMergeException(data); TEST_FLUSH(); - - requireThatIgnoreFlagPersistsThroughHopLookup(data); TEST_FLUSH(); - requireThatIgnoreFlagPersistsThroughRouteLookup(data); TEST_FLUSH(); - requireThatIgnoreFlagPersistsThroughPolicySelect(data); TEST_FLUSH(); - requireThatIgnoreFlagIsSerializedWithMessage(data); TEST_FLUSH(); - requireThatIgnoreFlagDoesNotInterfere(data); TEST_FLUSH(); - requireThatEmptySelectionCanBeIgnored(data); TEST_FLUSH(); - requireThatSelectErrorCanBeIgnored(data); TEST_FLUSH(); - requireThatSelectExceptionCanBeIgnored(data); TEST_FLUSH(); - requireThatSelectAndThrowCanBeIgnored(data); TEST_FLUSH(); - requireThatEmptyMergeCanBeIgnored(data); TEST_FLUSH(); - requireThatMergeErrorCanBeIgnored(data); TEST_FLUSH(); - requireThatMergeExceptionCanBeIgnored(data); TEST_FLUSH(); - requireThatMergeAndThrowCanBeIgnored(data); TEST_FLUSH(); - requireThatAllocServiceCanBeIgnored(data); TEST_FLUSH(); - requireThatDepthLimitCanBeIgnored(data); TEST_FLUSH(); - - // This needs to be last because it changes timeouts: - testTimeout(data); TEST_FLUSH(); - - TEST_DONE(); -} - //////////////////////////////////////////////////////////////////////////////// // // Tests // //////////////////////////////////////////////////////////////////////////////// -void -Test::testNoRoutingTable(TestData &data) +TEST_F(RoutingTest, test_no_routing_table) { + auto& data = *_data; Result res = data._srcSession->send(createMessage("msg"), "foo"); EXPECT_FALSE(res.isAccepted()); - EXPECT_EQUAL((uint32_t)ErrorCode::ILLEGAL_ROUTE, res.getError().getCode()); + EXPECT_EQ((uint32_t)ErrorCode::ILLEGAL_ROUTE, res.getError().getCode()); Message::UP msg = res.getMessage(); EXPECT_TRUE(msg); } -void -Test::testUnknownRoute(TestData &data) +TEST_F(RoutingTest, test_unknown_route) { + auto& data = *_data; data._srcServer.mb.setupRouting(RoutingSpec().addTable(RoutingTableSpec(SimpleProtocol::NAME) .addHop(HopSpec("foo", "bar")))); Result res = data._srcSession->send(createMessage("msg"), "baz"); EXPECT_FALSE(res.isAccepted()); - EXPECT_EQUAL((uint32_t)ErrorCode::ILLEGAL_ROUTE, res.getError().getCode()); + EXPECT_EQ((uint32_t)ErrorCode::ILLEGAL_ROUTE, res.getError().getCode()); Message::UP msg = res.getMessage(); EXPECT_TRUE(msg); } -void -Test::testNoRoute(TestData &data) +TEST_F(RoutingTest, test_no_route) { + auto& data = *_data; EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route()).isAccepted()); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::ILLEGAL_ROUTE, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::ILLEGAL_ROUTE, reply->getError(0).getCode()); } -void -Test::testRecognizeHopName(TestData &data) +TEST_F(RoutingTest, test_recognize_hop_name) { + auto& data = *_data; data._srcServer.mb.setupRouting(RoutingSpec().addTable(RoutingTableSpec(SimpleProtocol::NAME) .addHop(HopSpec("dst", "dst/session")))); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst")).isAccepted()); @@ -777,9 +712,9 @@ Test::testRecognizeHopName(TestData &data) EXPECT_FALSE(reply->hasErrors()); } -void -Test::testRecognizeRouteDirective(TestData &data) +TEST_F(RoutingTest, test_recognize_route_directive) { + auto& data = *_data; data._srcServer.mb.setupRouting(RoutingSpec().addTable(RoutingTableSpec(SimpleProtocol::NAME) .addRoute(RouteSpec("dst").addHop("dst/session")) .addHop(HopSpec("dir", "route:dst")))); @@ -792,9 +727,9 @@ Test::testRecognizeRouteDirective(TestData &data) EXPECT_FALSE(reply->hasErrors()); } -void -Test::testRecognizeRouteName(TestData &data) +TEST_F(RoutingTest, test_recognize_route_name) { + auto& data = *_data; data._srcServer.mb.setupRouting(RoutingSpec().addTable(RoutingTableSpec(SimpleProtocol::NAME) .addRoute(RouteSpec("dst").addHop("dst/session")))); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst")).isAccepted()); @@ -806,64 +741,64 @@ Test::testRecognizeRouteName(TestData &data) EXPECT_FALSE(reply->hasErrors()); } -void -Test::testHopResolutionOverflow(TestData &data) +TEST_F(RoutingTest, test_hop_resolution_overflow) { + auto& data = *_data; data._srcServer.mb.setupRouting(RoutingSpec().addTable(RoutingTableSpec(SimpleProtocol::NAME) .addHop(HopSpec("foo", "bar")) .addHop(HopSpec("bar", "foo")))); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("foo")).isAccepted()); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::ILLEGAL_ROUTE, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::ILLEGAL_ROUTE, reply->getError(0).getCode()); } -void -Test::testRouteResolutionOverflow(TestData &data) +TEST_F(RoutingTest, test_route_resolution_overflow) { + auto& data = *_data; data._srcServer.mb.setupRouting(RoutingSpec().addTable(RoutingTableSpec(SimpleProtocol::NAME) .addRoute(RouteSpec("foo").addHop("route:foo")))); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), "foo").isAccepted()); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::ILLEGAL_ROUTE, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::ILLEGAL_ROUTE, reply->getError(0).getCode()); } -void -Test::testInsertRoute(TestData &data) +TEST_F(RoutingTest, test_insert_route) { + auto& data = *_data; data._srcServer.mb.setupRouting(RoutingSpec().addTable(RoutingTableSpec(SimpleProtocol::NAME) .addRoute(RouteSpec("foo").addHop("dst/session").addHop("bar")))); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("route:foo baz")).isAccepted()); Message::UP msg = data._dstHandler.getMessage(RECEPTOR_TIMEOUT); ASSERT_TRUE(msg); - EXPECT_EQUAL(2u, msg->getRoute().getNumHops()); - EXPECT_EQUAL("bar", msg->getRoute().getHop(0).toString()); - EXPECT_EQUAL("baz", msg->getRoute().getHop(1).toString()); + EXPECT_EQ(2u, msg->getRoute().getNumHops()); + EXPECT_EQ("bar", msg->getRoute().getHop(0).toString()); + EXPECT_EQ("baz", msg->getRoute().getHop(1).toString()); data._dstSession->acknowledge(std::move(msg)); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); EXPECT_FALSE(reply->hasErrors()); } -void -Test::testErrorDirective(TestData &data) +TEST_F(RoutingTest, test_error_directive) { + auto& data = *_data; Route route = Route::parse("foo/bar/baz"); route.getHop(0).setDirective(1, std::make_shared<ErrorDirective>("err")); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), route).isAccepted()); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::ILLEGAL_ROUTE, reply->getError(0).getCode()); - EXPECT_EQUAL("err", reply->getError(0).getMessage()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::ILLEGAL_ROUTE, reply->getError(0).getCode()); + EXPECT_EQ("err", reply->getError(0).getMessage()); } -void -Test::testSelectError(TestData &data) +TEST_F(RoutingTest, test_select_error) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("Custom", std::make_shared<CustomPolicyFactory>()); data._srcServer.mb.putProtocol(protocol); @@ -872,26 +807,26 @@ Test::testSelectError(TestData &data) ASSERT_TRUE(reply); LOG(info, "testSelectError trace=%s", reply->getTrace().toString().c_str()); LOG(info, "testSelectError error=%s", reply->getError(0).toString().c_str()); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::ILLEGAL_ROUTE, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::ILLEGAL_ROUTE, reply->getError(0).getCode()); } -void -Test::testSelectNone(TestData &data) +TEST_F(RoutingTest, test_select_none) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("Custom", std::make_shared<CustomPolicyFactory>()); data._srcServer.mb.putProtocol(protocol); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("[Custom]")).isAccepted()); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::NO_SERVICES_FOR_ROUTE, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::NO_SERVICES_FOR_ROUTE, reply->getError(0).getCode()); } -void -Test::testSelectOne(TestData &data) +TEST_F(RoutingTest, test_select_one) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("Custom", std::make_shared<CustomPolicyFactory>()); data._srcServer.mb.putProtocol(protocol); @@ -904,9 +839,9 @@ Test::testSelectOne(TestData &data) EXPECT_FALSE(reply->hasErrors()); } -void -Test::testResend1(TestData &data) +TEST_F(RoutingTest, test_resend_1) { + auto& data = *_data; data._retryPolicy->setEnabled(true); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst/session")).isAccepted()); Message::UP msg = data._dstHandler.getMessage(RECEPTOR_TIMEOUT); @@ -935,9 +870,9 @@ Test::testResend1(TestData &data) reply->getTrace())); } -void -Test::testResend2(TestData &data) +TEST_F(RoutingTest, test_resend_2) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("Custom", std::make_shared<CustomPolicyFactory>()); data._srcServer.mb.putProtocol(protocol); @@ -1003,9 +938,9 @@ Test::testResend2(TestData &data) reply->getTrace())); } -void -Test::testNoResend(TestData &data) +TEST_F(RoutingTest, test_no_resend) { + auto& data = *_data; data._retryPolicy->setEnabled(false); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst/session")).isAccepted()); Message::UP msg = data._dstHandler.getMessage(RECEPTOR_TIMEOUT); @@ -1016,13 +951,13 @@ Test::testNoResend(TestData &data) data._dstSession->reply(std::move(reply)); reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::APP_TRANSIENT_ERROR, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::APP_TRANSIENT_ERROR, reply->getError(0).getCode()); } -void -Test::testSelectOnResend(TestData &data) +TEST_F(RoutingTest, test_select_on_resend) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("Custom", std::make_shared<CustomPolicyFactory>()); data._srcServer.mb.putProtocol(protocol); @@ -1051,9 +986,9 @@ Test::testSelectOnResend(TestData &data) reply->getTrace())); } -void -Test::testNoSelectOnResend(TestData &data) +TEST_F(RoutingTest, test_no_select_on_resend) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("Custom", std::make_shared<CustomPolicyFactory>(false)); data._srcServer.mb.putProtocol(protocol); @@ -1082,9 +1017,9 @@ Test::testNoSelectOnResend(TestData &data) reply->getTrace())); } -void -Test::testCanConsumeError(TestData &data) +TEST_F(RoutingTest, test_can_consume_error) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("Custom", std::make_shared<CustomPolicyFactory>(true, ErrorCode::NO_ADDRESS_FOR_SERVICE)); data._srcServer.mb.putProtocol(protocol); @@ -1095,8 +1030,8 @@ Test::testCanConsumeError(TestData &data) data._dstSession->acknowledge(std::move(msg)); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::NO_ADDRESS_FOR_SERVICE, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::NO_ADDRESS_FOR_SERVICE, reply->getError(0).getCode()); EXPECT_TRUE(testTrace(StringList() .add("Selecting { 'dst/session', 'dst/unknown' }.") .add("[NO_ADDRESS_FOR_SERVICE @ localhost]") @@ -1105,9 +1040,9 @@ Test::testCanConsumeError(TestData &data) reply->getTrace())); } -void -Test::testCantConsumeError(TestData &data) +TEST_F(RoutingTest, test_cant_consume_error) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("Custom", std::make_shared<CustomPolicyFactory>()); data._srcServer.mb.putProtocol(protocol); @@ -1116,8 +1051,8 @@ Test::testCantConsumeError(TestData &data) Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); printf("%s", reply->getTrace().toString().c_str()); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::NO_ADDRESS_FOR_SERVICE, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::NO_ADDRESS_FOR_SERVICE, reply->getError(0).getCode()); EXPECT_TRUE(testTrace(StringList() .add("Selecting { 'dst/unknown' }.") .add("[NO_ADDRESS_FOR_SERVICE @ localhost]") @@ -1125,9 +1060,9 @@ Test::testCantConsumeError(TestData &data) reply->getTrace())); } -void -Test::testNestedPolicies(TestData &data) +TEST_F(RoutingTest, test_nested_policies) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("Custom", std::make_shared<CustomPolicyFactory>(true, ErrorCode::NO_ADDRESS_FOR_SERVICE)); data._srcServer.mb.putProtocol(protocol); @@ -1138,13 +1073,13 @@ Test::testNestedPolicies(TestData &data) data._dstSession->acknowledge(std::move(msg)); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::NO_ADDRESS_FOR_SERVICE, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::NO_ADDRESS_FOR_SERVICE, reply->getError(0).getCode()); } -void -Test::testRemoveReply(TestData &data) +TEST_F(RoutingTest, test_remove_reply) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("Custom", std::make_shared<RemoveReplyPolicyFactory>(true, UIntList().add(ErrorCode::NO_ADDRESS_FOR_SERVICE), 0)); data._srcServer.mb.putProtocol(protocol); @@ -1164,9 +1099,9 @@ Test::testRemoveReply(TestData &data) reply->getTrace())); } -void -Test::testSetReply(TestData &data) +TEST_F(RoutingTest, test_set_reply) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("Select", std::make_shared<CustomPolicyFactory>(true, ErrorCode::APP_FATAL_ERROR)); protocol->addPolicyFactory("SetReply", std::make_shared<SetReplyPolicyFactory>(true, UIntList().add(ErrorCode::APP_FATAL_ERROR))); @@ -1178,14 +1113,14 @@ Test::testSetReply(TestData &data) data._dstSession->acknowledge(std::move(msg)); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::APP_FATAL_ERROR, reply->getError(0).getCode()); - EXPECT_EQUAL("foo", reply->getError(0).getMessage()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::APP_FATAL_ERROR, reply->getError(0).getCode()); + EXPECT_EQ("foo", reply->getError(0).getMessage()); } -void -Test::testResendSetAndReuseReply(TestData &data) +TEST_F(RoutingTest, test_resend_set_and_reuse_reply) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("ReuseReply", std::make_shared<ReuseReplyPolicyFactory>(false, UIntList().add(ErrorCode::APP_FATAL_ERROR))); protocol->addPolicyFactory("SetReply", std::make_shared<SetReplyPolicyFactory>(false, UIntList().add(ErrorCode::APP_FATAL_ERROR))); @@ -1206,9 +1141,9 @@ Test::testResendSetAndReuseReply(TestData &data) EXPECT_FALSE(reply->hasErrors()); } -void -Test::testResendSetAndRemoveReply(TestData &data) +TEST_F(RoutingTest, test_resend_set_and_remove_reply) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("RemoveReply", std::make_shared<RemoveReplyPolicyFactory>(false, UIntList().add(ErrorCode::APP_TRANSIENT_ERROR), 0)); protocol->addPolicyFactory("SetReply", std::make_shared<SetReplyPolicyFactory>(false, UIntList().add(ErrorCode::APP_TRANSIENT_ERROR).add(ErrorCode::APP_FATAL_ERROR))); @@ -1220,9 +1155,9 @@ Test::testResendSetAndRemoveReply(TestData &data) data._dstSession->acknowledge(std::move(msg)); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::APP_FATAL_ERROR, reply->getError(0).getCode()); - EXPECT_EQUAL("foo", reply->getError(0).getMessage()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::APP_FATAL_ERROR, reply->getError(0).getCode()); + EXPECT_EQ("foo", reply->getError(0).getMessage()); EXPECT_TRUE(testTrace(StringList() .add("Resolving '[SetReply:foo]'.") .add("Resolving 'dst/session'.") @@ -1232,9 +1167,9 @@ Test::testResendSetAndRemoveReply(TestData &data) reply->getTrace())); } -void -Test::testHopIgnoresReply(TestData &data) +TEST_F(RoutingTest, test_hop_ignores_reply) { + auto& data = *_data; EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("?dst/session")).isAccepted()); Message::UP msg = data._dstHandler.getMessage(RECEPTOR_TIMEOUT); ASSERT_TRUE(msg); @@ -1250,9 +1185,9 @@ Test::testHopIgnoresReply(TestData &data) reply->getTrace())); } -void -Test::testHopBlueprintIgnoresReply(TestData &data) +TEST_F(RoutingTest, test_hop_blueprint_ignores_reply) { + auto& data = *_data; data._srcServer.mb.setupRouting(RoutingSpec().addTable(RoutingTableSpec(SimpleProtocol::NAME) .addHop(std::move(HopSpec("foo", "dst/session").setIgnoreResult(true))))); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("foo")).isAccepted()); @@ -1270,22 +1205,22 @@ Test::testHopBlueprintIgnoresReply(TestData &data) reply->getTrace())); } -void -Test::testAcceptEmptyRoute(TestData &data) +TEST_F(RoutingTest, test_accept_empty_route) { + auto& data = *_data; EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst/session")).isAccepted()); Message::UP msg = data._dstHandler.getMessage(RECEPTOR_TIMEOUT); ASSERT_TRUE(msg); const Route &route = msg->getRoute(); - EXPECT_EQUAL(0u, route.getNumHops()); + EXPECT_EQ(0u, route.getNumHops()); data._dstSession->acknowledge(std::move(msg)); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); } -void -Test::testAbortOnlyActiveNodes(TestData &data) +TEST_F(RoutingTest, test_abort_only_active_nodes) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("Custom", std::make_shared<CustomPolicyFactory>(false)); protocol->addPolicyFactory("SetReply", std::make_shared<SetReplyPolicyFactory>(false, @@ -1297,39 +1232,39 @@ Test::testAbortOnlyActiveNodes(TestData &data) EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("[Custom:[SetReply:foo],?bar,dst/session]")).isAccepted()); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(2u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::APP_FATAL_ERROR, reply->getError(0).getCode()); - EXPECT_EQUAL((uint32_t)ErrorCode::SEND_ABORTED, reply->getError(1).getCode()); + EXPECT_EQ(2u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::APP_FATAL_ERROR, reply->getError(0).getCode()); + EXPECT_EQ((uint32_t)ErrorCode::SEND_ABORTED, reply->getError(1).getCode()); } -void -Test::testUnknownPolicy(TestData &data) +TEST_F(RoutingTest, test_unknown_policy) { + auto& data = *_data; EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("[Unknown]")).isAccepted()); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::UNKNOWN_POLICY, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::UNKNOWN_POLICY, reply->getError(0).getCode()); } -void -Test::testSelectException(TestData &data) +TEST_F(RoutingTest, test_select_exception) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("SelectException", std::make_shared<SelectExceptionPolicyFactory>()); data._srcServer.mb.putProtocol(protocol); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("[SelectException]")).isAccepted()); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::POLICY_ERROR, reply->getError(0).getCode()); - EXPECT_EQUAL("Policy 'SelectException' threw an exception; {test exception}", - reply->getError(0).getMessage()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::POLICY_ERROR, reply->getError(0).getCode()); + EXPECT_EQ("Policy 'SelectException' threw an exception; {test exception}", + reply->getError(0).getMessage()); } -void -Test::testMergeException(TestData &data) +TEST_F(RoutingTest, test_merge_exception) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); protocol->addPolicyFactory("MergeException", std::make_shared<MergeExceptionPolicyFactory>()); data._srcServer.mb.putProtocol(protocol); @@ -1340,157 +1275,161 @@ Test::testMergeException(TestData &data) data._dstSession->acknowledge(std::move(msg)); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::POLICY_ERROR, + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::POLICY_ERROR, reply->getError(0).getCode()); - EXPECT_EQUAL("Policy 'MergeException' threw an exception; {test exception}", - reply->getError(0).getMessage()); + EXPECT_EQ("Policy 'MergeException' threw an exception; {test exception}", + reply->getError(0).getMessage()); } -void -Test::requireThatIgnoreFlagPersistsThroughHopLookup(TestData &data) +TEST_F(RoutingTest, require_that_ignore_flag_persists_through_hop_lookup) { + auto& data = *_data; setupRouting(data, RoutingTableSpec(SimpleProtocol::NAME).addHop(HopSpec("foo", "dst/unknown"))); ASSERT_TRUE(testSend(data, "?foo")); ASSERT_TRUE(testTrace(data, StringList().add("Ignoring errors in reply."))); } -void -Test::requireThatIgnoreFlagPersistsThroughRouteLookup(TestData &data) +TEST_F(RoutingTest, require_that_ignore_flag_persists_through_route_lookup) { + auto& data = *_data; setupRouting(data, RoutingTableSpec(SimpleProtocol::NAME).addRoute(RouteSpec("foo").addHop("dst/unknown"))); ASSERT_TRUE(testSend(data, "?foo")); ASSERT_TRUE(testTrace(data, StringList().add("Ignoring errors in reply."))); } -void -Test::requireThatIgnoreFlagPersistsThroughPolicySelect(TestData &data) +TEST_F(RoutingTest, require_that_ignore_flag_persists_through_policy_select) { + auto& data = *_data; setupPolicy(data, "Custom", MyPolicyFactory::newSelectAndMerge("dst/unknown")); ASSERT_TRUE(testSend(data, "?[Custom]")); ASSERT_TRUE(testTrace(data, StringList().add("Ignoring errors in reply."))); } -void -Test::requireThatIgnoreFlagIsSerializedWithMessage(TestData &data) +TEST_F(RoutingTest, require_that_ignore_flag_is_serialized_with_message) { + auto& data = *_data; ASSERT_TRUE(testSend(data, "dst/session foo ?bar")); Message::UP msg = data._dstHandler.getMessage(RECEPTOR_TIMEOUT); ASSERT_TRUE(msg); Route route = msg->getRoute(); - EXPECT_EQUAL(2u, route.getNumHops()); + EXPECT_EQ(2u, route.getNumHops()); Hop hop = route.getHop(0); - EXPECT_EQUAL("foo", hop.toString()); + EXPECT_EQ("foo", hop.toString()); EXPECT_FALSE(hop.getIgnoreResult()); hop = route.getHop(1); - EXPECT_EQUAL("?bar", hop.toString()); + EXPECT_EQ("?bar", hop.toString()); EXPECT_TRUE(hop.getIgnoreResult()); data._dstSession->acknowledge(std::move(msg)); ASSERT_TRUE(testTrace(data, StringList().add("-Ignoring errors in reply."))); } -void -Test::requireThatIgnoreFlagDoesNotInterfere(TestData &data) +TEST_F(RoutingTest, require_that_ignore_flag_does_not_interfere) { + auto& data = *_data; setupPolicy(data, "Custom", MyPolicyFactory::newSelectAndMerge("dst/session")); ASSERT_TRUE(testSend(data, "?[Custom]")); ASSERT_TRUE(testTrace(data, StringList().add("-Ignoring errors in reply."))); ASSERT_TRUE(testAcknowledge(data)); } - -void -Test::requireThatEmptySelectionCanBeIgnored(TestData &data) + +TEST_F(RoutingTest, require_that_empty_selection_can_be_ignored) { + auto& data = *_data; setupPolicy(data, "Custom", MyPolicyFactory::newEmptySelection()); ASSERT_TRUE(testSend(data, "?[Custom]")); ASSERT_TRUE(testTrace(data, StringList().add("Ignoring errors in reply."))); } -void -Test::requireThatSelectErrorCanBeIgnored(TestData &data) +TEST_F(RoutingTest, require_that_select_error_can_be_ignored) { + auto& data = *_data; setupPolicy(data, "Custom", MyPolicyFactory::newSelectError(ErrorCode::APP_FATAL_ERROR)); ASSERT_TRUE(testSend(data, "?[Custom]")); ASSERT_TRUE(testTrace(data, StringList().add("Ignoring errors in reply."))); } -void -Test::requireThatSelectExceptionCanBeIgnored(TestData &data) +TEST_F(RoutingTest, require_that_select_exception_can_be_ignored) { + auto& data = *_data; setupPolicy(data, "Custom", MyPolicyFactory::newSelectException()); ASSERT_TRUE(testSend(data, "?[Custom]")); ASSERT_TRUE(testTrace(data, StringList().add("Ignoring errors in reply."))); } -void -Test::requireThatSelectAndThrowCanBeIgnored(TestData &data) +TEST_F(RoutingTest, require_that_select_and_throw_can_be_ignored) { + auto& data = *_data; setupPolicy(data, "Custom", MyPolicyFactory::newSelectAndThrow("dst/session")); ASSERT_TRUE(testSend(data, "?[Custom]")); ASSERT_TRUE(testTrace(data, StringList().add("Ignoring errors in reply."))); } -void -Test::requireThatEmptyMergeCanBeIgnored(TestData &data) +TEST_F(RoutingTest, require_that_empty_merge_can_be_ignored) { + auto& data = *_data; setupPolicy(data, "Custom", MyPolicyFactory::newEmptyMerge("dst/session")); ASSERT_TRUE(testSend(data, "?[Custom]")); ASSERT_TRUE(testAcknowledge(data)); ASSERT_TRUE(testTrace(data, StringList().add("Ignoring errors in reply."))); } -void -Test::requireThatMergeErrorCanBeIgnored(TestData &data) +TEST_F(RoutingTest, require_that_merge_error_can_be_ignored) { + auto& data = *_data; setupPolicy(data, "Custom", MyPolicyFactory::newMergeError("dst/session", ErrorCode::APP_FATAL_ERROR)); ASSERT_TRUE(testSend(data, "?[Custom]")); ASSERT_TRUE(testAcknowledge(data)); ASSERT_TRUE(testTrace(data, StringList().add("Ignoring errors in reply."))); } -void -Test::requireThatMergeExceptionCanBeIgnored(TestData &data) +TEST_F(RoutingTest, require_that_merge_exception_can_be_ignored) { + auto& data = *_data; setupPolicy(data, "Custom", MyPolicyFactory::newMergeException("dst/session")); ASSERT_TRUE(testSend(data, "?[Custom]")); ASSERT_TRUE(testAcknowledge(data)); ASSERT_TRUE(testTrace(data, StringList().add("Ignoring errors in reply."))); } - -void -Test::requireThatMergeAndThrowCanBeIgnored(TestData &data) + +TEST_F(RoutingTest, require_that_merge_and_throw_can_be_ignored) { + auto& data = *_data; setupPolicy(data, "Custom", MyPolicyFactory::newMergeAndThrow("dst/session")); ASSERT_TRUE(testSend(data, "?[Custom]")); ASSERT_TRUE(testAcknowledge(data)); ASSERT_TRUE(testTrace(data, StringList().add("Ignoring errors in reply."))); } -void -Test::requireThatAllocServiceCanBeIgnored(TestData &data) +TEST_F(RoutingTest, require_that_alloc_service_can_be_ignored) { + auto& data = *_data; ASSERT_TRUE(testSend(data, "?dst/unknown")); ASSERT_TRUE(testTrace(data, StringList().add("Ignoring errors in reply."))); } -void -Test::requireThatDepthLimitCanBeIgnored(TestData &data) +TEST_F(RoutingTest, require_that_depth_limit_can_be_ignored) { + auto& data = *_data; setupPolicy(data, "Custom", MyPolicyFactory::newSelectAndMerge("[Custom]")); ASSERT_TRUE(testSend(data, "?[Custom]", 0)); ASSERT_TRUE(testTrace(data, StringList())); } -void -Test::testTimeout(TestData &data) +TEST_F(RoutingTest, test_timeout) { + auto& data = *_data; + // Force teardown after this test case since timeouts have been changed. + _force_teardown = true; data._retryPolicy->setEnabled(true); data._retryPolicy->setBaseDelay(0.01); data._srcSession->setTimeout(500ms); EXPECT_TRUE(data._srcSession->send(createMessage("msg"), Route::parse("dst/unknown")).isAccepted()); Reply::UP reply = data._srcHandler.getReply(RECEPTOR_TIMEOUT); ASSERT_TRUE(reply); - EXPECT_EQUAL(2u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::NO_ADDRESS_FOR_SERVICE, reply->getError(0).getCode()); - EXPECT_EQUAL((uint32_t)ErrorCode::TIMEOUT, reply->getError(1).getCode()); + EXPECT_EQ(2u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::NO_ADDRESS_FOR_SERVICE, reply->getError(0).getCode()); + EXPECT_EQ((uint32_t)ErrorCode::TIMEOUT, reply->getError(1).getCode()); } + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/messagebus/src/tests/routingcontext/CMakeLists.txt b/messagebus/src/tests/routingcontext/CMakeLists.txt index 96bf6dbe35e..932d0020a3e 100644 --- a/messagebus/src/tests/routingcontext/CMakeLists.txt +++ b/messagebus/src/tests/routingcontext/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_routingcontext_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_routingcontext_test_app COMMAND messagebus_routingcontext_test_app) diff --git a/messagebus/src/tests/routingcontext/routingcontext.cpp b/messagebus/src/tests/routingcontext/routingcontext.cpp index d81bada2bc6..c8bbc53a0df 100644 --- a/messagebus/src/tests/routingcontext/routingcontext.cpp +++ b/messagebus/src/tests/routingcontext/routingcontext.cpp @@ -9,7 +9,7 @@ #include <vespa/messagebus/testlib/simpleprotocol.h> #include <vespa/messagebus/testlib/slobrok.h> #include <vespa/messagebus/testlib/testserver.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/util/stringfmt.h> @@ -17,6 +17,8 @@ using namespace mbus; using vespalib::make_string; +namespace { + static const duration TIMEOUT = 120s; class StringList : public std::vector<string> { @@ -192,20 +194,6 @@ public: bool start(); }; -class Test : public vespalib::TestApp { -private: - static Message::UP createMessage(const string &msg); - -public: - int Main() override; - void testSingleDirective(TestData &data); - void testMoreDirectives(TestData &data); - void testRecipientsRemain(TestData &data); - void testConstRoute(TestData &data); -}; - -TEST_APPHOOK(Test); - TestData::TestData() : _slobrok(), _retryPolicy(std::make_shared<RetryTransientErrorsPolicy>()), @@ -240,28 +228,33 @@ TestData::start() return true; } -Message::UP -Test::createMessage(const string &msg) -{ - auto ret = std::make_unique<SimpleMessage>(msg); - ret->getTrace().setLevel(9); - return ret; } -int -Test::Main() -{ - TEST_INIT("routingcontext_test"); +class RoutingContextTest : public testing::Test { +protected: + static std::shared_ptr<TestData> _data; + RoutingContextTest(); + ~RoutingContextTest() override; + static void SetUpTestSuite(); + static void TearDownTestSuite(); +}; - TestData data; - ASSERT_TRUE(data.start()); +std::shared_ptr<TestData> RoutingContextTest::_data; - testSingleDirective(data); TEST_FLUSH(); - testMoreDirectives(data); TEST_FLUSH(); - testRecipientsRemain(data); TEST_FLUSH(); - testConstRoute(data); TEST_FLUSH(); +RoutingContextTest::RoutingContextTest() = default; +RoutingContextTest::~RoutingContextTest() = default; - TEST_DONE(); +void +RoutingContextTest::SetUpTestSuite() +{ + _data = std::make_shared<TestData>(); + ASSERT_TRUE(_data->start()); +} + +void +RoutingContextTest::TearDownTestSuite() +{ + _data.reset(); } //////////////////////////////////////////////////////////////////////////////// @@ -270,9 +263,9 @@ Test::Main() // //////////////////////////////////////////////////////////////////////////////// -void -Test::testSingleDirective(TestData &data) +TEST_F(RoutingContextTest, test_single_directive) { + auto& data = *_data; IProtocol::SP protocol(new SimpleProtocol()); auto &simple = dynamic_cast<SimpleProtocol&>(*protocol); simple.addPolicyFactory("Custom", SimpleProtocol::IPolicyFactory::SP(new CustomPolicyFactory( @@ -295,9 +288,9 @@ Test::testSingleDirective(TestData &data) } } -void -Test::testMoreDirectives(TestData &data) +TEST_F(RoutingContextTest, test_more_directives) { + auto& data = *_data; IProtocol::SP protocol(new SimpleProtocol()); auto &simple = dynamic_cast<SimpleProtocol&>(*protocol); simple.addPolicyFactory("Custom", SimpleProtocol::IPolicyFactory::SP(new CustomPolicyFactory( @@ -322,9 +315,9 @@ Test::testMoreDirectives(TestData &data) } } -void -Test::testRecipientsRemain(TestData &data) +TEST_F(RoutingContextTest, test_recipients_remain) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); auto &simple = dynamic_cast<SimpleProtocol&>(*protocol); simple.addPolicyFactory("First", std::make_shared<CustomPolicyFactory>(true, @@ -347,9 +340,9 @@ Test::testRecipientsRemain(TestData &data) } } -void -Test::testConstRoute(TestData &data) +TEST_F(RoutingContextTest, test_const_route) { + auto& data = *_data; auto protocol = std::make_shared<SimpleProtocol>(); auto &simple = dynamic_cast<SimpleProtocol&>(*protocol); simple.addPolicyFactory("DocumentRouteSelector", @@ -371,3 +364,4 @@ Test::testConstRoute(TestData &data) } } +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/messagebus/src/tests/routingspec/CMakeLists.txt b/messagebus/src/tests/routingspec/CMakeLists.txt index 7a2ba9d8fe4..c7115c16fd9 100644 --- a/messagebus/src/tests/routingspec/CMakeLists.txt +++ b/messagebus/src/tests/routingspec/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_routingspec_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_routingspec_test_app COMMAND messagebus_routingspec_test_app) diff --git a/messagebus/src/tests/routingspec/routingspec.cpp b/messagebus/src/tests/routingspec/routingspec.cpp index 40f3f293de3..eec19982b8e 100644 --- a/messagebus/src/tests/routingspec/routingspec.cpp +++ b/messagebus/src/tests/routingspec/routingspec.cpp @@ -3,9 +3,9 @@ #include <vespa/messagebus/configagent.h> #include <vespa/messagebus/iconfighandler.h> #include <vespa/messagebus/routing/routingspec.h> -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/messagebus/config-messagebus.h> #include <vespa/config/helper/configgetter.hpp> +#include <vespa/vespalib/gtest/gtest.h> using namespace mbus; @@ -31,32 +31,19 @@ public: } }; -class Test : public vespalib::TestApp { -private: - bool testRouting(const RoutingSpec &spec); - bool testConfig(const RoutingSpec &spec); - -public: - void testConstructors(); - void testConfigGeneration(); - int Main() override; +class RoutingSpecTest : public testing::Test { +protected: + RoutingSpecTest(); + ~RoutingSpecTest() override; + static void test_routing_helper(const RoutingSpec &spec, bool& success); + static bool testRouting(const RoutingSpec &spec); + static bool testConfig(const RoutingSpec &spec); }; -TEST_APPHOOK(Test); - -int -Test::Main() -{ - TEST_INIT("routingspec_test"); - - testConstructors(); TEST_FLUSH(); - testConfigGeneration(); TEST_FLUSH(); - - TEST_DONE(); -} +RoutingSpecTest::RoutingSpecTest() = default; +RoutingSpecTest::~RoutingSpecTest() = default; -void -Test::testConstructors() +TEST_F(RoutingSpecTest, test_constructors) { { RoutingSpec spec; @@ -126,57 +113,64 @@ Test::testConstructors() } } +void +RoutingSpecTest::test_routing_helper(const RoutingSpec &spec, bool& success) +{ + ASSERT_TRUE(spec.getNumTables() == 2); + ASSERT_TRUE(spec.getTable(0).getProtocol() == "foo"); + ASSERT_TRUE(spec.getTable(0).getNumHops() == 2); + ASSERT_TRUE(spec.getTable(0).getHop(0).getName() == "foo-h1"); + ASSERT_TRUE(spec.getTable(0).getHop(0).getSelector() == "foo-h1-sel"); + ASSERT_TRUE(spec.getTable(0).getHop(0).getNumRecipients() == 2); + ASSERT_TRUE(spec.getTable(0).getHop(0).getRecipient(0) == "foo-h1-r1"); + ASSERT_TRUE(spec.getTable(0).getHop(0).getRecipient(1) == "foo-h1-r2"); + ASSERT_TRUE(spec.getTable(0).getHop(1).getName() == "foo-h2"); + ASSERT_TRUE(spec.getTable(0).getHop(1).getSelector() == "foo-h2-sel"); + ASSERT_TRUE(spec.getTable(0).getHop(1).getNumRecipients() == 2); + ASSERT_TRUE(spec.getTable(0).getHop(1).getRecipient(0) == "foo-h2-r1"); + ASSERT_TRUE(spec.getTable(0).getHop(1).getRecipient(1) == "foo-h2-r2"); + ASSERT_TRUE(spec.getTable(0).getNumRoutes() == 2); + ASSERT_TRUE(spec.getTable(0).getRoute(0).getName() == "foo-r1"); + ASSERT_TRUE(spec.getTable(0).getRoute(0).getNumHops() == 2); + ASSERT_TRUE(spec.getTable(0).getRoute(0).getHop(0) == "foo-h1"); + ASSERT_TRUE(spec.getTable(0).getRoute(0).getHop(1) == "foo-h2"); + ASSERT_TRUE(spec.getTable(0).getRoute(1).getName() == "foo-r2"); + ASSERT_TRUE(spec.getTable(0).getRoute(1).getNumHops() == 2); + ASSERT_TRUE(spec.getTable(0).getRoute(1).getHop(0) == "foo-h2"); + ASSERT_TRUE(spec.getTable(0).getRoute(1).getHop(1) == "foo-h1"); + ASSERT_TRUE(spec.getTable(1).getProtocol() == "bar"); + ASSERT_TRUE(spec.getTable(1).getNumHops() == 2); + ASSERT_TRUE(spec.getTable(1).getHop(0).getName() == "bar-h1"); + ASSERT_TRUE(spec.getTable(1).getHop(0).getSelector() == "bar-h1-sel"); + ASSERT_TRUE(spec.getTable(1).getHop(0).getNumRecipients() == 2); + ASSERT_TRUE(spec.getTable(1).getHop(0).getRecipient(0) == "bar-h1-r1"); + ASSERT_TRUE(spec.getTable(1).getHop(0).getRecipient(1) == "bar-h1-r2"); + ASSERT_TRUE(spec.getTable(1).getHop(1).getName() == "bar-h2"); + ASSERT_TRUE(spec.getTable(1).getHop(1).getSelector() == "bar-h2-sel"); + ASSERT_TRUE(spec.getTable(1).getHop(1).getNumRecipients() == 2); + ASSERT_TRUE(spec.getTable(1).getHop(1).getRecipient(0) == "bar-h2-r1"); + ASSERT_TRUE(spec.getTable(1).getHop(1).getRecipient(1) == "bar-h2-r2"); + ASSERT_TRUE(spec.getTable(1).getNumRoutes() == 2); + ASSERT_TRUE(spec.getTable(1).getRoute(0).getName() == "bar-r1"); + ASSERT_TRUE(spec.getTable(1).getRoute(0).getNumHops() == 2); + ASSERT_TRUE(spec.getTable(1).getRoute(0).getHop(0) == "bar-h1"); + ASSERT_TRUE(spec.getTable(1).getRoute(0).getHop(1) == "bar-h2"); + ASSERT_TRUE(spec.getTable(1).getRoute(1).getName() == "bar-r2"); + ASSERT_TRUE(spec.getTable(1).getRoute(1).getNumHops() == 2); + ASSERT_TRUE(spec.getTable(1).getRoute(1).getHop(0) == "bar-h2"); + ASSERT_TRUE(spec.getTable(1).getRoute(1).getHop(1) == "bar-h1"); + success = true; +} + bool -Test::testRouting(const RoutingSpec &spec) +RoutingSpecTest::testRouting(const RoutingSpec &spec) { - if (!ASSERT_TRUE(spec.getNumTables() == 2)) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getProtocol() == "foo")) { return false; } - if (!ASSERT_TRUE(spec.getTable(0).getNumHops() == 2)) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getHop(0).getName() == "foo-h1")) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getHop(0).getSelector() == "foo-h1-sel")) { return false; } - if (!ASSERT_TRUE(spec.getTable(0).getHop(0).getNumRecipients() == 2)) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getHop(0).getRecipient(0) == "foo-h1-r1")) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getHop(0).getRecipient(1) == "foo-h1-r2")) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getHop(1).getName() == "foo-h2")) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getHop(1).getSelector() == "foo-h2-sel")) { return false; } - if (!ASSERT_TRUE(spec.getTable(0).getHop(1).getNumRecipients() == 2)) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getHop(1).getRecipient(0) == "foo-h2-r1")) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getHop(1).getRecipient(1) == "foo-h2-r2")) { return false; } - if (!ASSERT_TRUE(spec.getTable(0).getNumRoutes() == 2)) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getRoute(0).getName() == "foo-r1")) { return false; } - if (!ASSERT_TRUE(spec.getTable(0).getRoute(0).getNumHops() == 2)) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getRoute(0).getHop(0) == "foo-h1")) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getRoute(0).getHop(1) == "foo-h2")) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getRoute(1).getName() == "foo-r2")) { return false; } - if (!ASSERT_TRUE(spec.getTable(0).getRoute(1).getNumHops() == 2)) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getRoute(1).getHop(0) == "foo-h2")) { return false; } - if (!EXPECT_TRUE(spec.getTable(0).getRoute(1).getHop(1) == "foo-h1")) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getProtocol() == "bar")) { return false; } - if (!ASSERT_TRUE(spec.getTable(1).getNumHops() == 2)) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getHop(0).getName() == "bar-h1")) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getHop(0).getSelector() == "bar-h1-sel")) { return false; } - if (!ASSERT_TRUE(spec.getTable(1).getHop(0).getNumRecipients() == 2)) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getHop(0).getRecipient(0) == "bar-h1-r1")) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getHop(0).getRecipient(1) == "bar-h1-r2")) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getHop(1).getName() == "bar-h2")) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getHop(1).getSelector() == "bar-h2-sel")) { return false; } - if (!ASSERT_TRUE(spec.getTable(1).getHop(1).getNumRecipients() == 2)) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getHop(1).getRecipient(0) == "bar-h2-r1")) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getHop(1).getRecipient(1) == "bar-h2-r2")) { return false; } - if (!ASSERT_TRUE(spec.getTable(1).getNumRoutes() == 2)) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getRoute(0).getName() == "bar-r1")) { return false; } - if (!ASSERT_TRUE(spec.getTable(1).getRoute(0).getNumHops() == 2)) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getRoute(0).getHop(0) == "bar-h1")) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getRoute(0).getHop(1) == "bar-h2")) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getRoute(1).getName() == "bar-r2")) { return false; } - if (!ASSERT_TRUE(spec.getTable(1).getRoute(1).getNumHops() == 2)) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getRoute(1).getHop(0) == "bar-h2")) { return false; } - if (!EXPECT_TRUE(spec.getTable(1).getRoute(1).getHop(1) == "bar-h1")) { return false; } - return true; + bool success = false; + test_routing_helper(spec, success); + return success; } -void -Test::testConfigGeneration() +TEST_F(RoutingSpecTest, test_config_generation) { EXPECT_TRUE(testConfig(RoutingSpec())); EXPECT_TRUE(testConfig(RoutingSpec().addTable(RoutingTableSpec("mytable1")))); @@ -200,50 +194,52 @@ Test::testConfigGeneration() .addRoute(RouteSpec("myroute12").addHop("myhop1").addHop("myhop2"))) .addTable(RoutingTableSpec("mytable2")))); - EXPECT_EQUAL("routingtable[2]\n" - "routingtable[0].protocol \"mytable1\"\n" - "routingtable[1].protocol \"mytable2\"\n" - "routingtable[1].hop[3]\n" - "routingtable[1].hop[0].name \"myhop1\"\n" - "routingtable[1].hop[0].selector \"myselector1\"\n" - "routingtable[1].hop[1].name \"myhop2\"\n" - "routingtable[1].hop[1].selector \"myselector2\"\n" - "routingtable[1].hop[1].ignoreresult true\n" - "routingtable[1].hop[2].name \"myhop1\"\n" - "routingtable[1].hop[2].selector \"myselector3\"\n" - "routingtable[1].hop[2].recipient[2]\n" - "routingtable[1].hop[2].recipient[0] \"myrecipient1\"\n" - "routingtable[1].hop[2].recipient[1] \"myrecipient2\"\n" - "routingtable[1].route[1]\n" - "routingtable[1].route[0].name \"myroute1\"\n" - "routingtable[1].route[0].hop[1]\n" - "routingtable[1].route[0].hop[0] \"myhop1\"\n", - RoutingSpec() - .addTable(RoutingTableSpec("mytable1")) - .addTable(RoutingTableSpec("mytable2") - .addHop(HopSpec("myhop1", "myselector1")) - .addHop(std::move(HopSpec("myhop2", "myselector2").setIgnoreResult(true))) - .addHop(HopSpec("myhop1", "myselector3") - .addRecipient("myrecipient1") - .addRecipient("myrecipient2")) - .addRoute(RouteSpec("myroute1").addHop("myhop1"))).toString()); + EXPECT_EQ("routingtable[2]\n" + "routingtable[0].protocol \"mytable1\"\n" + "routingtable[1].protocol \"mytable2\"\n" + "routingtable[1].hop[3]\n" + "routingtable[1].hop[0].name \"myhop1\"\n" + "routingtable[1].hop[0].selector \"myselector1\"\n" + "routingtable[1].hop[1].name \"myhop2\"\n" + "routingtable[1].hop[1].selector \"myselector2\"\n" + "routingtable[1].hop[1].ignoreresult true\n" + "routingtable[1].hop[2].name \"myhop1\"\n" + "routingtable[1].hop[2].selector \"myselector3\"\n" + "routingtable[1].hop[2].recipient[2]\n" + "routingtable[1].hop[2].recipient[0] \"myrecipient1\"\n" + "routingtable[1].hop[2].recipient[1] \"myrecipient2\"\n" + "routingtable[1].route[1]\n" + "routingtable[1].route[0].name \"myroute1\"\n" + "routingtable[1].route[0].hop[1]\n" + "routingtable[1].route[0].hop[0] \"myhop1\"\n", + RoutingSpec() + .addTable(RoutingTableSpec("mytable1")) + .addTable(RoutingTableSpec("mytable2") + .addHop(HopSpec("myhop1", "myselector1")) + .addHop(std::move(HopSpec("myhop2", "myselector2").setIgnoreResult(true))) + .addHop(HopSpec("myhop1", "myselector3") + .addRecipient("myrecipient1") + .addRecipient("myrecipient2")) + .addRoute(RouteSpec("myroute1").addHop("myhop1"))).toString()); } bool -Test::testConfig(const RoutingSpec &spec) +RoutingSpecTest::testConfig(const RoutingSpec &spec) { - if (!EXPECT_TRUE(spec == spec)) { + bool failure = false; + EXPECT_TRUE(spec == spec) << (failure = true, ""); + if (failure) { return false; } - if (!EXPECT_TRUE(spec == RoutingSpec(spec))) { + EXPECT_TRUE(spec == RoutingSpec(spec)) << (failure = true, ""); + if (failure) { return false; } ConfigStore store; ConfigAgent agent(store); agent.configure(ConfigGetter<MessagebusConfig>().getConfig("", RawSpec(spec.toString()))); - if (!EXPECT_TRUE(store.getRoutingSpec() == spec)) { - return false; - } - return true; + EXPECT_TRUE(store.getRoutingSpec() == spec) << (failure = true, ""); + return !failure; } +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/messagebus/src/tests/sequencer/CMakeLists.txt b/messagebus/src/tests/sequencer/CMakeLists.txt index bdcd4d1b2da..0c00209f3c7 100644 --- a/messagebus/src/tests/sequencer/CMakeLists.txt +++ b/messagebus/src/tests/sequencer/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_sequencer_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_sequencer_test_app COMMAND messagebus_sequencer_test_app) diff --git a/messagebus/src/tests/sequencer/sequencer.cpp b/messagebus/src/tests/sequencer/sequencer.cpp index 3fb905bce7a..8814ff45f1d 100644 --- a/messagebus/src/tests/sequencer/sequencer.cpp +++ b/messagebus/src/tests/sequencer/sequencer.cpp @@ -4,7 +4,7 @@ #include <vespa/messagebus/sequencer.h> #include <vespa/messagebus/routablequeue.h> #include <vespa/messagebus/emptyreply.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <cinttypes> #include <vespa/log/log.h> @@ -82,32 +82,13 @@ struct MyQueue : public RoutableQueue { } }; -class Test : public vespalib::TestApp { -private: - void testSyncNone(); - void testSyncId(); - -public: - int Main() override { - TEST_INIT("sequencer_test"); - - testSyncNone(); TEST_FLUSH(); - testSyncId(); TEST_FLUSH(); - - TEST_DONE(); - } -}; - -TEST_APPHOOK(Test); - // -------------------------------------------------------------------------------- // // Tests. // // -------------------------------------------------------------------------------- -void -Test::testSyncNone() +TEST(SequencerTest, test_sync_none) { MyQueue src; MyQueue dst; @@ -118,28 +99,27 @@ Test::testSyncNone() seq.handleMessage(src.createMessage(false, 0)); seq.handleMessage(src.createMessage(false, 0)); seq.handleMessage(src.createMessage(false, 0)); - EXPECT_EQUAL(0u, src.size()); - EXPECT_EQUAL(5u, dst.size()); + EXPECT_EQ(0u, src.size()); + EXPECT_EQ(5u, dst.size()); dst.replyNext(); dst.replyNext(); dst.replyNext(); dst.replyNext(); dst.replyNext(); - EXPECT_EQUAL(5u, src.size()); - EXPECT_EQUAL(0u, dst.size()); + EXPECT_EQ(5u, src.size()); + EXPECT_EQ(0u, dst.size()); EXPECT_TRUE(src.checkReply(false, 0)); EXPECT_TRUE(src.checkReply(false, 0)); EXPECT_TRUE(src.checkReply(false, 0)); EXPECT_TRUE(src.checkReply(false, 0)); EXPECT_TRUE(src.checkReply(false, 0)); - EXPECT_EQUAL(0u, src.size()); - EXPECT_EQUAL(0u, dst.size()); + EXPECT_EQ(0u, src.size()); + EXPECT_EQ(0u, dst.size()); } -void -Test::testSyncId() +TEST(SequencerTest, test_sync_id) { MyQueue src; MyQueue dst; @@ -150,8 +130,8 @@ Test::testSyncId() seq.handleMessage(src.createMessage(true, 3)); seq.handleMessage(src.createMessage(true, 4)); seq.handleMessage(src.createMessage(true, 5)); - EXPECT_EQUAL(0u, src.size()); - EXPECT_EQUAL(5u, dst.size()); + EXPECT_EQ(0u, src.size()); + EXPECT_EQ(5u, dst.size()); seq.handleMessage(src.createMessage(true, 1)); seq.handleMessage(src.createMessage(true, 5)); @@ -159,16 +139,16 @@ Test::testSyncId() seq.handleMessage(src.createMessage(true, 10)); seq.handleMessage(src.createMessage(true, 4)); seq.handleMessage(src.createMessage(true, 3)); - EXPECT_EQUAL(0u, src.size()); - EXPECT_EQUAL(6u, dst.size()); + EXPECT_EQ(0u, src.size()); + EXPECT_EQ(6u, dst.size()); dst.replyNext(); dst.replyNext(); dst.replyNext(); dst.replyNext(); dst.replyNext(); - EXPECT_EQUAL(5u, src.size()); - EXPECT_EQUAL(6u, dst.size()); + EXPECT_EQ(5u, src.size()); + EXPECT_EQ(6u, dst.size()); dst.replyNext(); dst.replyNext(); @@ -176,8 +156,8 @@ Test::testSyncId() dst.replyNext(); dst.replyNext(); dst.replyNext(); - EXPECT_EQUAL(11u, src.size()); - EXPECT_EQUAL(0u, dst.size()); + EXPECT_EQ(11u, src.size()); + EXPECT_EQ(0u, dst.size()); EXPECT_TRUE(src.checkReply(true, 1)); EXPECT_TRUE(src.checkReply(true, 2)); @@ -190,6 +170,8 @@ Test::testSyncId() EXPECT_TRUE(src.checkReply(true, 3)); EXPECT_TRUE(src.checkReply(true, 4)); EXPECT_TRUE(src.checkReply(true, 5)); - EXPECT_EQUAL(0u, src.size()); - EXPECT_EQUAL(0u, dst.size()); + EXPECT_EQ(0u, src.size()); + EXPECT_EQ(0u, dst.size()); } + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/messagebus/src/tests/sourcesession/CMakeLists.txt b/messagebus/src/tests/sourcesession/CMakeLists.txt index 067b281939a..6f8b14667ee 100644 --- a/messagebus/src/tests/sourcesession/CMakeLists.txt +++ b/messagebus/src/tests/sourcesession/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_sourcesession_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_sourcesession_test_app COMMAND messagebus_sourcesession_test_app) diff --git a/messagebus/src/tests/sourcesession/sourcesession.cpp b/messagebus/src/tests/sourcesession/sourcesession.cpp index 5d1a8e8ad24..d642209d816 100644 --- a/messagebus/src/tests/sourcesession/sourcesession.cpp +++ b/messagebus/src/tests/sourcesession/sourcesession.cpp @@ -15,7 +15,7 @@ #include <vespa/messagebus/testlib/simpleprotocol.h> #include <vespa/messagebus/testlib/slobrok.h> #include <vespa/messagebus/testlib/testserver.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <thread> using namespace mbus; @@ -64,21 +64,7 @@ bool waitQueueSize(RoutableQueue &queue, uint32_t size) { return false; } -class Test : public vespalib::TestApp -{ -public: - void testSequencing(); - void testResendError(); - void testResendConnDown(); - void testIllegalRoute(); - void testNoServices(); - void testBlockingClose(); - void testNonBlockingClose(); - int Main() override; -}; - -void -Test::testSequencing() +TEST(SourceSessionTest, test_sequencing) { Slobrok slobrok; TestServer src(Identity(""), getRouting(), slobrok); @@ -111,8 +97,7 @@ Test::testSequencing() ASSERT_TRUE(waitQueueSize(dstQ, 0)); } -void -Test::testResendError() +TEST(SourceSessionTest, test_resend_error) { Slobrok slobrok; auto retryPolicy = std::make_shared<RetryTransientErrorsPolicy>(); @@ -172,8 +157,7 @@ Test::testResendError() } } -void -Test::testResendConnDown() +TEST(SourceSessionTest, test_resend_conn_down) { Slobrok slobrok; auto retryPolicy = std::make_shared<RetryTransientErrorsPolicy>(); @@ -218,8 +202,7 @@ Test::testResendConnDown() fprintf(stderr, "\nTRACE DUMP:\n%s\n\n", trace.c_str()); } -void -Test::testIllegalRoute() +TEST(SourceSessionTest, test_illegal_route) { Slobrok slobrok; TestServer src(MessageBusParams() @@ -243,16 +226,15 @@ Test::testIllegalRoute() Routable::UP routable = srcQ.dequeue(); ASSERT_TRUE(routable->isReply()); Reply::UP r(dynamic_cast<Reply*>(routable.release())); - EXPECT_EQUAL(1u, r->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::NO_ADDRESS_FOR_SERVICE, r->getError(0).getCode()); + EXPECT_EQ(1u, r->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::NO_ADDRESS_FOR_SERVICE, r->getError(0).getCode()); string trace = r->getTrace().toString(); fprintf(stderr, "\nTRACE DUMP:\n%s\n\n", trace.c_str()); } } } -void -Test::testNoServices() +TEST(SourceSessionTest, test_no_services) { Slobrok slobrok; TestServer src(MessageBusParams() @@ -283,8 +265,7 @@ Test::testNoServices() } } -void -Test::testBlockingClose() +TEST(SourceSessionTest, test_blocking_close) { Slobrok slobrok; TestServer src(Identity(""), getRouting(), slobrok); @@ -304,8 +285,7 @@ Test::testBlockingClose() EXPECT_TRUE(routable->isReply()); } -void -Test::testNonBlockingClose() +TEST(SourceSessionTest, test_non_blocking_close) { Slobrok slobrok; TestServer src(Identity(""), getRouting(), slobrok); @@ -317,18 +297,4 @@ Test::testNonBlockingClose() ss->close(); // this should not hang } -int -Test::Main() -{ - TEST_INIT("sourcesession_test"); - testSequencing(); TEST_FLUSH(); - testResendError(); TEST_FLUSH(); - testResendConnDown(); TEST_FLUSH(); - testIllegalRoute(); TEST_FLUSH(); - testNoServices(); TEST_FLUSH(); - testBlockingClose(); TEST_FLUSH(); - testNonBlockingClose(); TEST_FLUSH(); - TEST_DONE(); -} - -TEST_APPHOOK(Test); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/messagebus/src/tests/throttling/CMakeLists.txt b/messagebus/src/tests/throttling/CMakeLists.txt index 95df4c6d873..3ad0662d13b 100644 --- a/messagebus/src/tests/throttling/CMakeLists.txt +++ b/messagebus/src/tests/throttling/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_throttling_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_throttling_test_app COMMAND messagebus_throttling_test_app) diff --git a/messagebus/src/tests/throttling/throttling.cpp b/messagebus/src/tests/throttling/throttling.cpp index 73f4366e5d7..5b372334dcf 100644 --- a/messagebus/src/tests/throttling/throttling.cpp +++ b/messagebus/src/tests/throttling/throttling.cpp @@ -1,6 +1,5 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/messagebus/destinationsession.h> #include <vespa/messagebus/dynamicthrottlepolicy.h> #include <vespa/messagebus/routablequeue.h> @@ -12,6 +11,7 @@ #include <vespa/messagebus/testlib/simplemessage.h> #include <vespa/messagebus/testlib/simplereply.h> #include <vespa/messagebus/testlib/testserver.h> +#include <vespa/vespalib/gtest/gtest.h> #include <thread> using namespace mbus; @@ -65,46 +65,31 @@ bool waitPending(SourceSession& session, uint32_t size) return false; } -//////////////////////////////////////////////////////////////////////////////// -// -// Setup -// -//////////////////////////////////////////////////////////////////////////////// - -class Test : public vespalib::TestApp { -private: - uint32_t getWindowSize(DynamicThrottlePolicy &policy, DynamicTimer &timer, uint32_t maxPending); - -protected: - void testMaxPendingCount(); - void testMaxPendingSize(); - void testMinOne(); - void testDynamicWindowSize(); - void testIdleTimePeriod(); - void testMinWindowSize(); - void testMaxWindowSize(); - -public: - int Main() override; -}; - -int -Test::Main() +uint32_t +getWindowSize(DynamicThrottlePolicy &policy, DynamicTimer &timer, uint32_t maxPending) { - TEST_INIT("throttling_test"); + SimpleMessage msg("foo"); + SimpleReply reply("bar"); + reply.setContext(mbus::Context(uint64_t(1))); // To offset pending size bump in static policy - testMaxPendingCount(); TEST_FLUSH(); - testMaxPendingSize(); TEST_FLUSH(); - testMinOne(); TEST_FLUSH(); - testDynamicWindowSize(); TEST_FLUSH(); - testIdleTimePeriod(); TEST_FLUSH(); - testMinWindowSize(); TEST_FLUSH(); - testMaxWindowSize(); TEST_FLUSH(); + for (uint32_t i = 0; i < 999; ++i) { + uint32_t numPending = 0; + while (policy.canSend(msg, numPending)) { + policy.processMessage(msg); + ++numPending; + } - TEST_DONE(); -} + uint64_t tripTime = (numPending < maxPending) ? 1000 : 1000 + (numPending - maxPending) * 1000; + timer._millis += tripTime; -TEST_APPHOOK(Test); + for( ; numPending > 0 ; --numPending) { + policy.processReply(reply); + } + } + uint32_t ret = policy.getMaxPendingCount(); + fprintf(stderr, "getWindowSize() = %u\n", ret); + return ret; +} //////////////////////////////////////////////////////////////////////////////// // @@ -112,8 +97,7 @@ TEST_APPHOOK(Test); // //////////////////////////////////////////////////////////////////////////////// -void -Test::testMaxPendingCount() +TEST(ThrottlingTest, test_max_pending_count) { Slobrok slobrok; TestServer src(Identity(""), getRouting(), slobrok); @@ -165,8 +149,7 @@ Test::testMaxPendingCount() ASSERT_TRUE(waitQueueSize(dstQ, 0)); } -void -Test::testMaxPendingSize() +TEST(ThrottlingTest, test_max_pending_size) { ASSERT_TRUE(SimpleMessage("1234567890").getApproxSize() == 10); ASSERT_TRUE(SimpleMessage("123456").getApproxSize() == 6); @@ -191,8 +174,8 @@ Test::testMaxPendingSize() DestinationSession::UP ds = dst.mb.createDestinationSession("session", true, dstQ); ASSERT_TRUE(src.waitSlobrok("dst/session")); - EXPECT_EQUAL(1u, SimpleMessage("1").getApproxSize()); - EXPECT_EQUAL(2u, SimpleMessage("12").getApproxSize()); + EXPECT_EQ(1u, SimpleMessage("1").getApproxSize()); + EXPECT_EQ(2u, SimpleMessage("12").getApproxSize()); EXPECT_TRUE(ss->send(Message::UP(new SimpleMessage("1")), "dst").isAccepted()); EXPECT_TRUE(waitQueueSize(dstQ, 1)); @@ -214,8 +197,7 @@ Test::testMaxPendingSize() ASSERT_TRUE(waitQueueSize(srcQ, 3)); } -void -Test::testMinOne() +TEST(ThrottlingTest, test_min_one) { ASSERT_TRUE(SimpleMessage("1234567890").getApproxSize() == 10); ASSERT_TRUE(SimpleMessage("").getApproxSize() == 0); @@ -248,8 +230,7 @@ Test::testMinOne() } -void -Test::testDynamicWindowSize() +TEST(ThrottlingTest, test_dynamic_window_size) { auto ptr = std::make_unique<DynamicTimer>(); auto* timer = ptr.get(); @@ -274,8 +255,7 @@ Test::testDynamicWindowSize() ASSERT_TRUE(windowSize >= 90 && windowSize <= 115); } -void -Test::testIdleTimePeriod() +TEST(ThrottlingTest, test_idle_time_period) { auto ptr = std::make_unique<DynamicTimer>(); auto* timer = ptr.get(); @@ -295,15 +275,14 @@ Test::testIdleTimePeriod() timer->_millis += 60001; ASSERT_TRUE(policy.canSend(msg, 50)); - EXPECT_EQUAL(55u, policy.getMaxPendingCount()); + EXPECT_EQ(55u, policy.getMaxPendingCount()); timer->_millis += 60001; ASSERT_TRUE(policy.canSend(msg, 0)); - EXPECT_EQUAL(5u, policy.getMaxPendingCount()); + EXPECT_EQ(5u, policy.getMaxPendingCount()); } -void -Test::testMinWindowSize() +TEST(ThrottlingTest, test_min_window_size) { auto ptr = std::make_unique<DynamicTimer>(); auto* timer = ptr.get(); @@ -317,8 +296,7 @@ Test::testMinWindowSize() ASSERT_TRUE(windowSize >= 150 && windowSize <= 210); } -void -Test::testMaxWindowSize() +TEST(ThrottlingTest, test_max_window_size) { auto ptr = std::make_unique<DynamicTimer>(); auto* timer = ptr.get(); @@ -337,28 +315,4 @@ Test::testMaxWindowSize() } -uint32_t -Test::getWindowSize(DynamicThrottlePolicy &policy, DynamicTimer &timer, uint32_t maxPending) -{ - SimpleMessage msg("foo"); - SimpleReply reply("bar"); - reply.setContext(mbus::Context(uint64_t(1))); // To offset pending size bump in static policy - - for (uint32_t i = 0; i < 999; ++i) { - uint32_t numPending = 0; - while (policy.canSend(msg, numPending)) { - policy.processMessage(msg); - ++numPending; - } - - uint64_t tripTime = (numPending < maxPending) ? 1000 : 1000 + (numPending - maxPending) * 1000; - timer._millis += tripTime; - - for( ; numPending > 0 ; --numPending) { - policy.processReply(reply); - } - } - uint32_t ret = policy.getMaxPendingCount(); - fprintf(stderr, "getWindowSize() = %u\n", ret); - return ret; -} +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/messagebus/src/tests/timeout/CMakeLists.txt b/messagebus/src/tests/timeout/CMakeLists.txt index 2292b6d649f..4aa3458cb14 100644 --- a/messagebus/src/tests/timeout/CMakeLists.txt +++ b/messagebus/src/tests/timeout/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_timeout_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_timeout_test_app COMMAND messagebus_timeout_test_app) diff --git a/messagebus/src/tests/timeout/timeout.cpp b/messagebus/src/tests/timeout/timeout.cpp index 2ffdab11c40..497af9c5c0e 100644 --- a/messagebus/src/tests/timeout/timeout.cpp +++ b/messagebus/src/tests/timeout/timeout.cpp @@ -1,6 +1,5 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/messagebus/errorcode.h> #include <vespa/messagebus/emptyreply.h> #include <vespa/messagebus/sourcesession.h> @@ -11,33 +10,13 @@ #include <vespa/messagebus/testlib/simplemessage.h> #include <vespa/messagebus/testlib/slobrok.h> #include <vespa/messagebus/testlib/testserver.h> +#include <vespa/vespalib/gtest/gtest.h> using namespace mbus; using namespace std::chrono_literals; -class Test : public vespalib::TestApp { -public: - int Main() override; - void testZeroTimeout(); - void testMessageExpires(); -}; - -TEST_APPHOOK(Test); - -int -Test::Main() -{ - TEST_INIT("timeout_test"); - - testZeroTimeout(); TEST_FLUSH(); - testMessageExpires(); TEST_FLUSH(); - - TEST_DONE(); -} - -void -Test::testZeroTimeout() +TEST(TimeoutTest, test_zero_timeout) { Slobrok slobrok; TestServer srcServer(Identity("src"), RoutingSpec(), slobrok); @@ -53,12 +32,11 @@ Test::testZeroTimeout() Reply::UP reply = srcHandler.getReply(); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::TIMEOUT, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::TIMEOUT, reply->getError(0).getCode()); } -void -Test::testMessageExpires() +TEST(TimeoutTest, test_message_expires) { Slobrok slobrok; TestServer srcServer(Identity("src"), RoutingSpec(), slobrok); @@ -73,11 +51,13 @@ Test::testMessageExpires() Reply::UP reply = srcHandler.getReply(); ASSERT_TRUE(reply); - EXPECT_EQUAL(1u, reply->getNumErrors()); - EXPECT_EQUAL((uint32_t)ErrorCode::TIMEOUT, reply->getError(0).getCode()); + EXPECT_EQ(1u, reply->getNumErrors()); + EXPECT_EQ((uint32_t)ErrorCode::TIMEOUT, reply->getError(0).getCode()); Message::UP msg = dstHandler.getMessage(1s); if (msg) { msg->discard(); } } + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/metrics/src/main/java/ai/vespa/metrics/set/InfrastructureMetricSet.java b/metrics/src/main/java/ai/vespa/metrics/set/InfrastructureMetricSet.java index 61ab8cea941..38a1b252df9 100644 --- a/metrics/src/main/java/ai/vespa/metrics/set/InfrastructureMetricSet.java +++ b/metrics/src/main/java/ai/vespa/metrics/set/InfrastructureMetricSet.java @@ -68,11 +68,11 @@ public class InfrastructureMetricSet { addMetric(metrics, ConfigServerMetrics.CLUSTER_LOAD_IDEAL_MEMORY.max()); addMetric(metrics, ConfigServerMetrics.CLUSTER_LOAD_IDEAL_DISK.max()); addMetric(metrics, ConfigServerMetrics.NODES_EMPTY_EXCLUSIVE.max()); - addMetric(metrics, ConfigServerMetrics.NODES_EXPIRED_DEPROVISIONED.sum()); - addMetric(metrics, ConfigServerMetrics.NODES_EXPIRED_DIRTY.sum()); - addMetric(metrics, ConfigServerMetrics.NODES_EXPIRED_INACTIVE.sum()); - addMetric(metrics, ConfigServerMetrics.NODES_EXPIRED_PROVISIONED.sum()); - addMetric(metrics, ConfigServerMetrics.NODES_EXPIRED_RESERVED.sum()); + addMetric(metrics, ConfigServerMetrics.NODES_EXPIRED_DEPROVISIONED.count()); + addMetric(metrics, ConfigServerMetrics.NODES_EXPIRED_DIRTY.count()); + addMetric(metrics, ConfigServerMetrics.NODES_EXPIRED_INACTIVE.count()); + addMetric(metrics, ConfigServerMetrics.NODES_EXPIRED_PROVISIONED.count()); + addMetric(metrics, ConfigServerMetrics.NODES_EXPIRED_RESERVED.count()); addMetric(metrics, ConfigServerMetrics.WANT_TO_REBOOT.max()); addMetric(metrics, ConfigServerMetrics.WANT_TO_RESTART.max()); addMetric(metrics, ConfigServerMetrics.WANT_TO_RETIRE.max()); diff --git a/parent/pom.xml b/parent/pom.xml index 780d05241be..0511b227211 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -317,7 +317,7 @@ --> <groupId>org.openrewrite.maven</groupId> <artifactId>rewrite-maven-plugin</artifactId> - <version>5.23.3</version> + <version>5.25.0</version> <configuration> <activeRecipes> <recipe>org.openrewrite.java.testing.junit5.JUnit5BestPractices</recipe> @@ -327,7 +327,7 @@ <dependency> <groupId>org.openrewrite.recipe</groupId> <artifactId>rewrite-testing-frameworks</artifactId> - <version>2.4.1</version> + <version>2.5.0</version> </dependency> </dependencies> </plugin> @@ -1187,7 +1187,7 @@ See pluginManagement of rewrite-maven-plugin for more details --> <groupId>org.openrewrite.recipe</groupId> <artifactId>rewrite-recipe-bom</artifactId> - <version>2.7.1</version> + <version>2.8.0</version> <type>pom</type> <scope>import</scope> </dependency> diff --git a/searchcore/src/tests/proton/attribute/CMakeLists.txt b/searchcore/src/tests/proton/attribute/CMakeLists.txt index 911268bd92a..88b30df608f 100644 --- a/searchcore/src/tests/proton/attribute/CMakeLists.txt +++ b/searchcore/src/tests/proton/attribute/CMakeLists.txt @@ -21,6 +21,7 @@ vespa_add_executable(searchcore_attributeflush_test_app TEST searchcore_attribute searchcore_flushengine searchcore_pcommon + GTest::gtest ) vespa_add_test(NAME searchcore_attributeflush_test_app COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/attributeflush_test.sh DEPENDS searchcore_attributeflush_test_app) diff --git a/searchcore/src/tests/proton/attribute/attributeflush_test.cpp b/searchcore/src/tests/proton/attribute/attributeflush_test.cpp index a621451bf3b..6969032535c 100644 --- a/searchcore/src/tests/proton/attribute/attributeflush_test.cpp +++ b/searchcore/src/tests/proton/attribute/attributeflush_test.cpp @@ -14,7 +14,7 @@ #include <vespa/searchlib/index/dummyfileheadercontext.h> #include <vespa/searchlib/test/directory_handler.h> #include <vespa/searchcommon/attribute/config.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/util/foreground_thread_executor.h> #include <vespa/vespalib/util/foregroundtaskexecutor.h> #include <vespa/vespalib/util/idestructorcallback.h> @@ -209,46 +209,6 @@ AVConfig getInt32ArrayConfig() return AVConfig(AVBasicType::INT32, AVCollectionType::ARRAY); } -class Test : public vespalib::TestApp -{ -private: - void - requireThatUpdaterAndFlusherCanRunConcurrently(); - - void - requireThatFlushableAttributeReportsMemoryUsage(); - - void - requireThatFlushableAttributeManagesSyncTokenInfo(); - - void - requireThatFlushTargetsCanBeRetrieved(); - - void - requireThatCleanUpIsPerformedAfterFlush(); - - void - requireThatFlushStatsAreUpdated(); - - void - requireThatOnlyOneFlusherCanRunAtTheSameTime(); - - void - requireThatLastFlushTimeIsReported(); - - void - requireThatShrinkWorks(); - - void requireThatFlushedAttributeCanBeLoaded(const HwInfo &hwInfo); - void requireThatFlushedAttributeCanBeLoaded(); - - void requireThatFlushFailurePreventsSyncTokenUpdate(); -public: - int - Main() override; -}; - - const string test_dir = "flush"; struct BaseFixture @@ -325,9 +285,7 @@ struct Fixture : public BaseFixture, public AttributeManagerFixture Fixture::~Fixture() = default; - -void -Test::requireThatUpdaterAndFlusherCanRunConcurrently() +TEST(AttributeFlushTest, require_that_updater_and_flusher_can_run_concurrently) { Fixture f; AttributeManager &am = f._m; @@ -352,14 +310,12 @@ Test::requireThatUpdaterAndFlusherCanRunConcurrently() AttributeFactory::createAttribute(baseFileName, getInt32Config()); EXPECT_TRUE(attr->load()); - EXPECT_EQUAL((uint32_t)snap.syncToken + 1, attr->getNumDocs()); + EXPECT_EQ((uint32_t)snap.syncToken + 1, attr->getNumDocs()); } } } - -void -Test::requireThatFlushableAttributeReportsMemoryUsage() +TEST(AttributeFlushTest, require_that_flushable_attribute_reports_memory_usage) { Fixture f; AttributeManager &am = f._m; @@ -368,16 +324,14 @@ Test::requireThatFlushableAttributeReportsMemoryUsage() av->commit(); IFlushTarget::SP fa = am.getFlushable("a2"); EXPECT_TRUE(av->getStatus().getAllocated() >= 100u * sizeof(int32_t)); - EXPECT_EQUAL(av->getStatus().getUsed(), - fa->getApproxMemoryGain().getBefore()+0lu); + EXPECT_EQ(av->getStatus().getUsed(), + fa->getApproxMemoryGain().getBefore()+0lu); // attributes stay in memory - EXPECT_EQUAL(fa->getApproxMemoryGain().getBefore(), - fa->getApproxMemoryGain().getAfter()); + EXPECT_EQ(fa->getApproxMemoryGain().getBefore(), + fa->getApproxMemoryGain().getAfter()); } - -void -Test::requireThatFlushableAttributeManagesSyncTokenInfo() +TEST(AttributeFlushTest, require_that_flushable_attribute_manages_sync_token_info) { Fixture f; AttributeManager &am = f._m; @@ -386,49 +340,45 @@ Test::requireThatFlushableAttributeManagesSyncTokenInfo() IFlushTarget::SP fa = am.getFlushable("a3"); IndexMetaInfo info("flush/a3"); - EXPECT_EQUAL(0u, fa->getFlushedSerialNum()); + EXPECT_EQ(0u, fa->getFlushedSerialNum()); EXPECT_TRUE(fa->initFlush(0, std::make_shared<search::FlushToken>()).get() == NULL); EXPECT_TRUE(!info.load()); av->commit(CommitParam(10)); // last sync token = 10 - EXPECT_EQUAL(0u, fa->getFlushedSerialNum()); + EXPECT_EQ(0u, fa->getFlushedSerialNum()); EXPECT_TRUE(fa->initFlush(10, std::make_shared<search::FlushToken>()).get() != NULL); fa->initFlush(10, std::make_shared<search::FlushToken>())->run(); - EXPECT_EQUAL(10u, fa->getFlushedSerialNum()); + EXPECT_EQ(10u, fa->getFlushedSerialNum()); EXPECT_TRUE(info.load()); - EXPECT_EQUAL(1u, info.snapshots().size()); + EXPECT_EQ(1u, info.snapshots().size()); EXPECT_TRUE(info.snapshots()[0].valid); - EXPECT_EQUAL(10u, info.snapshots()[0].syncToken); + EXPECT_EQ(10u, info.snapshots()[0].syncToken); av->commit(CommitParam(20)); // last sync token = 20 - EXPECT_EQUAL(10u, fa->getFlushedSerialNum()); + EXPECT_EQ(10u, fa->getFlushedSerialNum()); fa->initFlush(20, std::make_shared<search::FlushToken>())->run(); - EXPECT_EQUAL(20u, fa->getFlushedSerialNum()); + EXPECT_EQ(20u, fa->getFlushedSerialNum()); EXPECT_TRUE(info.load()); - EXPECT_EQUAL(1u, info.snapshots().size()); // snapshot 10 removed + EXPECT_EQ(1u, info.snapshots().size()); // snapshot 10 removed EXPECT_TRUE(info.snapshots()[0].valid); - EXPECT_EQUAL(20u, info.snapshots()[0].syncToken); + EXPECT_EQ(20u, info.snapshots()[0].syncToken); } - -void -Test::requireThatFlushTargetsCanBeRetrieved() +TEST(AttributeFlushTest, require_that_flush_targets_can_be_retrieved) { Fixture f; AttributeManager &am = f._m; f.addAttribute("a4"); f.addAttribute("a5"); std::vector<IFlushTarget::SP> ftl = am.getFlushTargets(); - EXPECT_EQUAL(4u, ftl.size()); - EXPECT_EQUAL(am.getFlushable("a4").get(), ftl[0].get()); - EXPECT_EQUAL(am.getShrinker("a4").get(), ftl[1].get()); - EXPECT_EQUAL(am.getFlushable("a5").get(), ftl[2].get()); - EXPECT_EQUAL(am.getShrinker("a5").get(), ftl[3].get()); + EXPECT_EQ(4u, ftl.size()); + EXPECT_EQ(am.getFlushable("a4").get(), ftl[0].get()); + EXPECT_EQ(am.getShrinker("a4").get(), ftl[1].get()); + EXPECT_EQ(am.getFlushable("a5").get(), ftl[2].get()); + EXPECT_EQ(am.getShrinker("a5").get(), ftl[3].get()); } - -void -Test::requireThatCleanUpIsPerformedAfterFlush() +TEST(AttributeFlushTest, require_that_cleanup_is_performed_after_flush) { Fixture f; AttributeVector::SP av = f.addAttribute("a6"); @@ -454,16 +404,14 @@ Test::requireThatCleanUpIsPerformedAfterFlush() fa.initFlush(30, std::make_shared<search::FlushToken>())->run(); EXPECT_TRUE(info.load()); - EXPECT_EQUAL(1u, info.snapshots().size()); // snapshots 10 & 20 removed + EXPECT_EQ(1u, info.snapshots().size()); // snapshots 10 & 20 removed EXPECT_TRUE(info.snapshots()[0].valid); - EXPECT_EQUAL(30u, info.snapshots()[0].syncToken); + EXPECT_EQ(30u, info.snapshots()[0].syncToken); EXPECT_FALSE(fs::exists(fs::path(snap10))); EXPECT_FALSE(fs::exists(fs::path(snap20))); } - -void -Test::requireThatFlushStatsAreUpdated() +TEST(AttributeFlushTest, require_that_flush_stats_are_updated) { Fixture f; AttributeManager &am = f._m; @@ -473,13 +421,11 @@ Test::requireThatFlushStatsAreUpdated() IFlushTarget::SP ft = am.getFlushable("a7"); ft->initFlush(101, std::make_shared<search::FlushToken>())->run(); FlushStats stats = ft->getLastFlushStats(); - EXPECT_EQUAL("flush/a7/snapshot-101", stats.getPath()); - EXPECT_EQUAL(8u, stats.getPathElementsToLog()); + EXPECT_EQ("flush/a7/snapshot-101", stats.getPath()); + EXPECT_EQ(8u, stats.getPathElementsToLog()); } - -void -Test::requireThatOnlyOneFlusherCanRunAtTheSameTime() +TEST(AttributeFlushTest, require_that_only_one_flusher_can_run_at_the_same_time) { Fixture f; AttributeManager &am = f._m; @@ -504,15 +450,13 @@ Test::requireThatOnlyOneFlusherCanRunAtTheSameTime() ASSERT_TRUE(info.load()); LOG(info, "Found %zu snapshots", info.snapshots().size()); for (size_t i = 0; i < info.snapshots().size(); ++i) { - EXPECT_EQUAL(true, info.snapshots()[i].valid); + EXPECT_EQ(true, info.snapshots()[i].valid); } IndexMetaInfo::Snapshot best = info.getBestSnapshot(); - EXPECT_EQUAL(true, best.valid); + EXPECT_EQ(true, best.valid); } - -void -Test::requireThatLastFlushTimeIsReported() +TEST(AttributeFlushTest, require_that_last_flush_time_is_reported) { using seconds = std::chrono::seconds; BaseFixture f; @@ -521,38 +465,36 @@ Test::requireThatLastFlushTimeIsReported() AttributeManagerFixture amf(f); AttributeManager &am = amf._m; AttributeVector::SP av = amf.addAttribute("a9"); - EXPECT_EQUAL(vespalib::system_time(), am.getFlushable("a9")->getLastFlushTime()); + EXPECT_EQ(vespalib::system_time(), am.getFlushable("a9")->getLastFlushTime()); } { // no snapshot flushed yet AttributeManagerFixture amf(f); AttributeManager &am = amf._m; AttributeVector::SP av = amf.addAttribute("a9"); IFlushTarget::SP ft = am.getFlushable("a9"); - EXPECT_EQUAL(vespalib::system_time(), ft->getLastFlushTime()); + EXPECT_EQ(vespalib::system_time(), ft->getLastFlushTime()); ft->initFlush(200, std::make_shared<search::FlushToken>())->run(); EXPECT_TRUE(FastOS_File::Stat("flush/a9/snapshot-200", &stat)); - EXPECT_EQUAL(stat._modifiedTime, ft->getLastFlushTime()); + EXPECT_EQ(stat._modifiedTime, ft->getLastFlushTime()); } { // snapshot flushed AttributeManagerFixture amf(f); AttributeManager &am = amf._m; amf.addAttribute("a9"); IFlushTarget::SP ft = am.getFlushable("a9"); - EXPECT_EQUAL(stat._modifiedTime, ft->getLastFlushTime()); + EXPECT_EQ(stat._modifiedTime, ft->getLastFlushTime()); { // updated flush time after nothing to flush std::this_thread::sleep_for(1100ms); std::chrono::seconds now = duration_cast<seconds>(vespalib::system_clock::now().time_since_epoch()); Executor::Task::UP task = ft->initFlush(200, std::make_shared<search::FlushToken>()); EXPECT_FALSE(task); - EXPECT_LESS(stat._modifiedTime, ft->getLastFlushTime()); - EXPECT_APPROX(now.count(), duration_cast<seconds>(ft->getLastFlushTime().time_since_epoch()).count(), 3); + EXPECT_LT(stat._modifiedTime, ft->getLastFlushTime()); + EXPECT_NEAR(now.count(), duration_cast<seconds>(ft->getLastFlushTime().time_since_epoch()).count(), 3); } } } - -void -Test::requireThatShrinkWorks() +TEST(AttributeFlushTest, require_that_shrink_works) { Fixture f; AttributeManager &am = f._m; @@ -562,32 +504,32 @@ Test::requireThatShrinkWorks() av->addDocs(1000 - av->getNumDocs()); av->commit(CommitParam(50)); IFlushTarget::SP ft = am.getShrinker("a10"); - EXPECT_EQUAL(ft->getApproxMemoryGain().getBefore(), - ft->getApproxMemoryGain().getAfter()); + EXPECT_EQ(ft->getApproxMemoryGain().getBefore(), + ft->getApproxMemoryGain().getAfter()); AttributeGuard::UP g = am.getAttribute("a10"); EXPECT_FALSE(av->wantShrinkLidSpace()); EXPECT_FALSE(av->canShrinkLidSpace()); - EXPECT_EQUAL(1000u, av->getNumDocs()); - EXPECT_EQUAL(1000u, av->getCommittedDocIdLimit()); + EXPECT_EQ(1000u, av->getNumDocs()); + EXPECT_EQ(1000u, av->getCommittedDocIdLimit()); av->compactLidSpace(100); EXPECT_TRUE(av->wantShrinkLidSpace()); EXPECT_FALSE(av->canShrinkLidSpace()); - EXPECT_EQUAL(1000u, av->getNumDocs()); - EXPECT_EQUAL(100u, av->getCommittedDocIdLimit()); + EXPECT_EQ(1000u, av->getNumDocs()); + EXPECT_EQ(100u, av->getCommittedDocIdLimit()); aw.heartBeat(51, IDestructorCallback::SP()); EXPECT_TRUE(av->wantShrinkLidSpace()); EXPECT_FALSE(av->canShrinkLidSpace()); - EXPECT_EQUAL(ft->getApproxMemoryGain().getBefore(), - ft->getApproxMemoryGain().getAfter()); + EXPECT_EQ(ft->getApproxMemoryGain().getBefore(), + ft->getApproxMemoryGain().getAfter()); g.reset(); aw.heartBeat(52, IDestructorCallback::SP()); EXPECT_TRUE(av->wantShrinkLidSpace()); EXPECT_TRUE(av->canShrinkLidSpace()); EXPECT_TRUE(ft->getApproxMemoryGain().getBefore() > ft->getApproxMemoryGain().getAfter()); - EXPECT_EQUAL(1000u, av->getNumDocs()); - EXPECT_EQUAL(100u, av->getCommittedDocIdLimit()); - EXPECT_EQUAL(createSerialNum - 1, ft->getFlushedSerialNum()); + EXPECT_EQ(1000u, av->getNumDocs()); + EXPECT_EQ(100u, av->getCommittedDocIdLimit()); + EXPECT_EQ(createSerialNum - 1, ft->getFlushedSerialNum()); vespalib::ThreadStackExecutor exec(1); vespalib::Executor::Task::UP task = ft->initFlush(53, std::make_shared<search::FlushToken>()); exec.execute(std::move(task)); @@ -595,15 +537,16 @@ Test::requireThatShrinkWorks() exec.shutdown(); EXPECT_FALSE(av->wantShrinkLidSpace()); EXPECT_FALSE(av->canShrinkLidSpace()); - EXPECT_EQUAL(ft->getApproxMemoryGain().getBefore(), - ft->getApproxMemoryGain().getAfter()); - EXPECT_EQUAL(100u, av->getNumDocs()); - EXPECT_EQUAL(100u, av->getCommittedDocIdLimit()); + EXPECT_EQ(ft->getApproxMemoryGain().getBefore(), + ft->getApproxMemoryGain().getAfter()); + EXPECT_EQ(100u, av->getNumDocs()); + EXPECT_EQ(100u, av->getCommittedDocIdLimit()); } void -Test::requireThatFlushedAttributeCanBeLoaded(const HwInfo &hwInfo) +require_that_flushed_attribute_can_be_loaded(const HwInfo &hwInfo, const vespalib::string& label) { + SCOPED_TRACE(label); constexpr uint32_t numDocs = 100; BaseFixture f(hwInfo); vespalib::string attrName(hwInfo.disk().slow() ? "a11slow" : "a11fast"); @@ -612,9 +555,9 @@ Test::requireThatFlushedAttributeCanBeLoaded(const HwInfo &hwInfo) AttributeManager &am = amf._m; AttributeVector::SP av = amf.addPostingAttribute(attrName); IntegerAttribute & ia = static_cast<IntegerAttribute &>(*av); - EXPECT_EQUAL(1u, av->getNumDocs()); + EXPECT_EQ(1u, av->getNumDocs()); av->addDocs(numDocs); - EXPECT_EQUAL(numDocs + 1, av->getNumDocs()); + EXPECT_EQ(numDocs + 1, av->getNumDocs()); for (uint32_t i = 0; i < numDocs; ++i) { ia.update(i + 1, i + 43); } @@ -625,61 +568,44 @@ Test::requireThatFlushedAttributeCanBeLoaded(const HwInfo &hwInfo) { AttributeManagerFixture amf(f); AttributeVector::SP av = amf.addPostingAttribute(attrName); - EXPECT_EQUAL(numDocs + 1, av->getNumDocs()); + EXPECT_EQ(numDocs + 1, av->getNumDocs()); for (uint32_t i = 0; i < numDocs; ++i) { - EXPECT_EQUAL(i + 43, av->getInt(i + 1)); + EXPECT_EQ(i + 43, av->getInt(i + 1)); } } } -void -Test::requireThatFlushedAttributeCanBeLoaded() +TEST(AttributeFlushTest, require_that_flushed_attribute_can_be_loaded) { - TEST_DO(requireThatFlushedAttributeCanBeLoaded(HwInfo(HwInfo::Disk(0, false, false), HwInfo::Memory(0), HwInfo::Cpu(0)))); - TEST_DO(requireThatFlushedAttributeCanBeLoaded(HwInfo(HwInfo::Disk(0, true, false), HwInfo::Memory(0), HwInfo::Cpu(0)))); + require_that_flushed_attribute_can_be_loaded(HwInfo(HwInfo::Disk(0, false, false), HwInfo::Memory(0), HwInfo::Cpu(0)), "fast-disk"); + require_that_flushed_attribute_can_be_loaded(HwInfo(HwInfo::Disk(0, true, false), HwInfo::Memory(0), HwInfo::Cpu(0)), "slow-disk"); } -void -Test::requireThatFlushFailurePreventsSyncTokenUpdate() +TEST(AttributeFlushTest, require_that_flush_failure_prevents_sync_token_update) { BaseFixture f; AttributeManagerFixture amf(f); auto &am = amf._m; auto av = amf.addIntArrayPostingAttribute("a12"); - EXPECT_EQUAL(1u, av->getNumDocs()); + EXPECT_EQ(1u, av->getNumDocs()); auto flush_target = am.getFlushable("a12"); - EXPECT_EQUAL(0u, flush_target->getFlushedSerialNum()); + EXPECT_EQ(0u, flush_target->getFlushedSerialNum()); auto flush_task = flush_target->initFlush(200, std::make_shared<search::FlushToken>()); // Trigger flush failure av->getEnumStoreBase()->inc_compaction_count(); flush_task->run(); - EXPECT_EQUAL(0u, flush_target->getFlushedSerialNum()); + EXPECT_EQ(0u, flush_target->getFlushedSerialNum()); +} + } int -Test::Main() +main(int argc, char* argv[]) { - TEST_INIT("attributeflush_test"); - - if (_argc > 0) { - DummyFileHeaderContext::setCreator(_argv[0]); + ::testing::InitGoogleTest(&argc, argv); + if (argc > 0) { + DummyFileHeaderContext::setCreator(argv[0]); } - fs::remove_all(fs::path(test_dir)); - TEST_DO(requireThatUpdaterAndFlusherCanRunConcurrently()); - TEST_DO(requireThatFlushableAttributeReportsMemoryUsage()); - TEST_DO(requireThatFlushableAttributeManagesSyncTokenInfo()); - TEST_DO(requireThatFlushTargetsCanBeRetrieved()); - TEST_DO(requireThatCleanUpIsPerformedAfterFlush()); - TEST_DO(requireThatFlushStatsAreUpdated()); - TEST_DO(requireThatOnlyOneFlusherCanRunAtTheSameTime()); - TEST_DO(requireThatLastFlushTimeIsReported()); - TEST_DO(requireThatShrinkWorks()); - TEST_DO(requireThatFlushedAttributeCanBeLoaded()); - TEST_DO(requireThatFlushFailurePreventsSyncTokenUpdate()); - - TEST_DONE(); + fs::remove_all(fs::path(proton::test_dir)); + return RUN_ALL_TESTS(); } - -} - -TEST_APPHOOK(proton::Test); diff --git a/searchcore/src/tests/proton/common/cachedselect_test.cpp b/searchcore/src/tests/proton/common/cachedselect_test.cpp index 8c2913a3d1b..a0c8fef3b83 100644 --- a/searchcore/src/tests/proton/common/cachedselect_test.cpp +++ b/searchcore/src/tests/proton/common/cachedselect_test.cpp @@ -102,7 +102,8 @@ makeDocTypeRepo() addField("aa", DataType::T_INT). addField("aaa", Array(DataType::T_INT)). addField("aaw", Wset(DataType::T_INT)). - addField("ab", DataType::T_INT)); + addField("ab", DataType::T_INT)). + imported_field("my_imported_field"); builder.document(doc_type_id + 1, type_name_2, Struct(header_name_2), Struct(body_name_2). addField("ic", DataType::T_STRING). @@ -152,12 +153,17 @@ checkSelect(const NodeUP &sel, void checkSelect(const CachedSelect::SP &cs, + uint32_t docId, const Document &doc, const Result &exp) { + SelectContext ctx(*cs); + ctx._docId = docId; + ctx._doc = &doc; + ctx.getAttributeGuards(); bool expSessionContains = (cs->preDocOnlySelect() || (exp == Result::True)); - EXPECT_TRUE(checkSelect(cs->docSelect(), Context(doc), exp)); - EXPECT_EQUAL(expSessionContains, cs->createSession()->contains(doc)); + EXPECT_TRUE(checkSelect(cs->docSelect(), ctx, exp)); + EXPECT_EQUAL(expSessionContains, cs->createSession()->contains_doc(ctx)); } void @@ -170,7 +176,7 @@ checkSelect(const CachedSelect::SP &cs, ctx._docId = docId; ctx.getAttributeGuards(); EXPECT_TRUE(checkSelect((cs->preDocOnlySelect() ? cs->preDocOnlySelect() : cs->preDocSelect()), ctx, exp)); - EXPECT_EQUAL(expSessionContains, cs->createSession()->contains(ctx)); + EXPECT_EQUAL(expSessionContains, cs->createSession()->contains_pre_doc(ctx)); } void @@ -271,18 +277,22 @@ MyDB::addDoc(uint32_t lid, Document::UP doc(makeDoc(_repo, docId, ia, ib, aa, ab)); _docIdToLid[docId] = lid; - _lidToDocSP[lid] = Document::SP(doc.release()); - AttributeGuard::UP guard = _amgr.getAttribute("aa"); - AttributeVector &av = *guard->get(); - if (lid >= av.getNumDocs()) { - AttributeVector::DocId checkDocId(0u); - ASSERT_TRUE(av.addDoc(checkDocId)); - ASSERT_EQUAL(lid, checkDocId); - } - IntegerAttribute &iav(static_cast<IntegerAttribute &>(av)); - AttributeVector::largeint_t laa(aa); - EXPECT_TRUE(iav.update(lid, laa)); - av.commit(); + _lidToDocSP[lid] = std::move(doc); + auto add_attr_value = [lid, aa](auto guard) { + AttributeVector &av = *guard->get(); + if (lid >= av.getNumDocs()) { + AttributeVector::DocId checkDocId(0u); + ASSERT_TRUE(av.addDoc(checkDocId)); + ASSERT_EQUAL(lid, checkDocId); + } + auto &iav(dynamic_cast<IntegerAttribute &>(av)); + AttributeVector::largeint_t laa(aa); + EXPECT_TRUE(iav.update(lid, laa)); + av.commit(); + }; + + add_attr_value(_amgr.getAttribute("aa")); + add_attr_value(_amgr.getAttribute("my_imported_field")); } @@ -327,15 +337,14 @@ TestFixture::TestFixture() _amgr.addAttribute("aa"); _amgr.addAttribute("aaa", AttributeFactory::createAttribute("aaa", {BasicType::INT32, CollectionType::ARRAY})); _amgr.addAttribute("aaw", AttributeFactory::createAttribute("aaw", {BasicType::INT32, CollectionType::WSET})); + // "Faked" imported attribute, as in `selectpruner_test.cpp` + _amgr.addAttribute("my_imported_field", AttributeFactory::createAttribute("my_imported_field", { BasicType::INT32 })); - _db.reset(new MyDB(*_repoUP, _amgr)); + _db = std::make_unique<MyDB>(*_repoUP, _amgr); } -TestFixture::~TestFixture() -{ -} - +TestFixture::~TestFixture() = default; CachedSelect::SP TestFixture::testParse(const string &selection, @@ -475,45 +484,45 @@ TEST_F("Test that basic select works", TestFixture) cs = f.testParse("test.ia == \"hello\"", "test"); TEST_DO(assertEquals(Stats().fieldNodes(1).attrFieldNodes(0).svAttrFieldNodes(0), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::True)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::False)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::False)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::False)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::True)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::False)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::False)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::False)); cs = f.testParse("test.ia.foo == \"hello\"", "test"); TEST_DO(assertEquals(Stats().allInvalid(), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::Invalid)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::Invalid)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.ia[2] == \"hello\"", "test"); TEST_DO(assertEquals(Stats().allInvalid(), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::Invalid)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::Invalid)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.ia{foo} == \"hello\"", "test"); TEST_DO(assertEquals(Stats().allInvalid(), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::Invalid)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::Invalid)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.ia < \"hello\"", "test"); TEST_DO(assertEquals(Stats().fieldNodes(1).attrFieldNodes(0).svAttrFieldNodes(0), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::False)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::True)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::True)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::False)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::True)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::True)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.aa == 3", "test"); TEST_DO(assertEquals(Stats().preDocOnlySelect().fieldNodes(1).attrFieldNodes(1).svAttrFieldNodes(1), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::False)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::True)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::False)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::False)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::False)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::True)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::False)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::False)); TEST_DO(checkSelect(cs, 1u, Result::False)); TEST_DO(checkSelect(cs, 2u, Result::True)); TEST_DO(checkSelect(cs, 3u, Result::False)); @@ -521,24 +530,24 @@ TEST_F("Test that basic select works", TestFixture) cs = f.testParse("test.aa.foo == 3", "test"); TEST_DO(assertEquals(Stats().allInvalid(), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::Invalid)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::Invalid)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.aa[2] == 3", "test"); TEST_DO(assertEquals(Stats().allInvalid(), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::Invalid)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::Invalid)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.aa{4} > 3", "test"); TEST_DO(assertEquals(Stats().allInvalid(), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::Invalid)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::Invalid)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.aaa[2] == 3", "test"); TEST_DO(assertEquals(Stats().fieldNodes(1).attrFieldNodes(1).svAttrFieldNodes(0), *cs)); @@ -548,10 +557,10 @@ TEST_F("Test that basic select works", TestFixture) cs = f.testParse("test.aa < 45", "test"); TEST_DO(assertEquals(Stats().preDocOnlySelect().fieldNodes(1).attrFieldNodes(1).svAttrFieldNodes(1), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::False)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::True)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::False)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::True)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); TEST_DO(checkSelect(cs, 1u, Result::False, false)); TEST_DO(checkSelect(cs, 2u, Result::True, true)); TEST_DO(checkSelect(cs, 3u, Result::Invalid, false)); @@ -580,9 +589,9 @@ TEST_F("Test that single value attribute combined with non-attribute field resul TEST_DO(checkSelect(cs, 1u, Result::Invalid, true)); TEST_DO(checkSelect(cs, 2u, Result::Invalid, true)); TEST_DO(checkSelect(cs, 3u, Result::False, false)); - TEST_DO(checkSelect(cs, f.db().getDoc(1u), Result::True)); - TEST_DO(checkSelect(cs, f.db().getDoc(2u), Result::False)); - TEST_DO(checkSelect(cs, f.db().getDoc(3u), Result::False)); + TEST_DO(checkSelect(cs, 1u, f.db().getDoc(1u), Result::True)); + TEST_DO(checkSelect(cs, 2u, f.db().getDoc(2u), Result::False)); + TEST_DO(checkSelect(cs, 3u, f.db().getDoc(3u), Result::False)); } TEST_F("Test that single value attribute with complex attribute field results in pre-document select pruner", PreDocSelectFixture) @@ -593,9 +602,39 @@ TEST_F("Test that single value attribute with complex attribute field results in TEST_DO(checkSelect(cs, 1u, Result::Invalid, true)); TEST_DO(checkSelect(cs, 2u, Result::Invalid, true)); TEST_DO(checkSelect(cs, 3u, Result::False, false)); - TEST_DO(checkSelect(cs, f.db().getDoc(1u), Result::False)); - TEST_DO(checkSelect(cs, f.db().getDoc(2u), Result::False)); - TEST_DO(checkSelect(cs, f.db().getDoc(3u), Result::False)); + TEST_DO(checkSelect(cs, 1u, f.db().getDoc(1u), Result::False)); + TEST_DO(checkSelect(cs, 2u, f.db().getDoc(2u), Result::False)); + TEST_DO(checkSelect(cs, 3u, f.db().getDoc(3u), Result::False)); +} + +TEST_F("Imported field can be used in pre-doc selections with only attribute fields", PreDocSelectFixture) { + auto cs = f.testParse("test.my_imported_field == 3", "test"); + TEST_DO(assertEquals(Stats().preDocOnlySelect().fieldNodes(1).attrFieldNodes(1).svAttrFieldNodes(1), *cs)); + + TEST_DO(checkSelect(cs, 1u, Result::True, true)); + TEST_DO(checkSelect(cs, 2u, Result::True, true)); + TEST_DO(checkSelect(cs, 3u, Result::False, false)); + // Cannot match against document here since preDocOnly is set; will just return false. + TEST_DO(checkSelect(cs, 1u, f.db().getDoc(1u), Result::False)); + TEST_DO(checkSelect(cs, 2u, f.db().getDoc(2u), Result::False)); + TEST_DO(checkSelect(cs, 3u, f.db().getDoc(3u), Result::False)); +} + +TEST_F("Imported field can be used in doc selections with mixed attribute/non-attribute fields", PreDocSelectFixture) { + // `id.namespace` requires a doc store fetch and cannot be satisfied by attributes alone + auto cs = f.testParse("test.my_imported_field == 3 and id.namespace != 'foo'", "test"); + TEST_DO(assertEquals(Stats().preDocSelect().fieldNodes(2).attrFieldNodes(1).svAttrFieldNodes(1), *cs)); + + // 2 first checks cannot be completed in pre-doc stage alone + TEST_DO(checkSelect(cs, 1u, Result::Invalid, true)); // -> doc eval stage + TEST_DO(checkSelect(cs, 2u, Result::Invalid, true)); // -> doc eval stage + TEST_DO(checkSelect(cs, 3u, Result::False, false)); // short-circuited since attr value 7 != 3 + // When matching against a concrete document, it's crucial that the selection AST contains + // attribute references for at least all imported fields, or we'll implicitly fall back to + // returning null for all imported fields (as they do not exist in the document itself). + TEST_DO(checkSelect(cs, 1u, f.db().getDoc(1u), Result::True)); + TEST_DO(checkSelect(cs, 2u, f.db().getDoc(2u), Result::True)); + TEST_DO(checkSelect(cs, 3u, f.db().getDoc(3u), Result::False)); } TEST_F("Test performance when using attributes", TestFixture) diff --git a/searchcore/src/tests/proton/common/selectpruner_test.cpp b/searchcore/src/tests/proton/common/selectpruner_test.cpp index e175836b838..1f71da5aeda 100644 --- a/searchcore/src/tests/proton/common/selectpruner_test.cpp +++ b/searchcore/src/tests/proton/common/selectpruner_test.cpp @@ -799,6 +799,12 @@ TEST_F("Imported fields with matching attribute names are supported", TestFixtur "test.my_imported_field > 0"); } +TEST_F("Imported fields can be used alongside non-attribute fields", TestFixture) +{ + f.testPrune("test.my_imported_field > 0 and id.namespace != \"foo\"", + "test.my_imported_field > 0 and id.namespace != \"foo\""); +} + // Edge case: document type reconfigured but attribute not yet visible in Proton TEST_F("Imported fields without matching attribute are mapped to constant NullValue", TestFixture) { diff --git a/searchcore/src/tests/proton/feed_and_search/feed_and_search_test.cpp b/searchcore/src/tests/proton/feed_and_search/feed_and_search_test.cpp index 0936f05b222..ff740dd8801 100644 --- a/searchcore/src/tests/proton/feed_and_search/feed_and_search_test.cpp +++ b/searchcore/src/tests/proton/feed_and_search/feed_and_search_test.cpp @@ -23,15 +23,12 @@ #include <vespa/searchlib/queryeval/blueprint.h> #include <vespa/searchlib/queryeval/fake_requestcontext.h> #include <vespa/searchlib/queryeval/searchiterator.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/util/gate.h> #include <vespa/vespalib/util/destructor_callbacks.h> #include <vespa/vespalib/util/threadstackexecutor.h> #include <sstream> -#include <vespa/log/log.h> -LOG_SETUP("feed_and_search_test"); - using document::DataType; using document::Document; using document::FieldValue; @@ -75,38 +72,6 @@ void commit_memory_index_and_wait(MemoryIndex &memory_index) gate.await(); } -class Test : public vespalib::TestApp { - const char *current_state; - void DumpState(bool) { - fprintf(stderr, "%s: ERROR: in %s\n", __FILE__, current_state); - } - - void requireThatMemoryIndexCanBeDumpedAndSearched(); - - void testSearch(Searchable &source, - const string &term, uint32_t doc_id); - -public: - int Main() override; -}; - -#define TEST_CALL(func) \ - current_state = #func; \ - func(); - -int -Test::Main() -{ - TEST_INIT("feed_and_search_test"); - - if (_argc > 0) { - DummyFileHeaderContext::setCreator(_argv[0]); - } - TEST_CALL(requireThatMemoryIndexCanBeDumpedAndSearched); - - TEST_DONE(); -} - const string field_name = "string_field"; const string noise = "noise"; const string word1 = "foo"; @@ -123,7 +88,8 @@ Document::UP buildDocument(DocBuilder & doc_builder, int id, const string &word) } // Performs a search using a Searchable. -void Test::testSearch(Searchable &source, const string &term, uint32_t doc_id) +void +testSearch(Searchable &source, const string &term, uint32_t doc_id) { FakeRequestContext requestContext; uint32_t fieldId = 0; @@ -139,12 +105,12 @@ void Test::testSearch(Searchable &source, const string &term, uint32_t doc_id) search_iterator->initFullRange(); ASSERT_TRUE(search_iterator.get()); ASSERT_TRUE(search_iterator->seek(doc_id)); - EXPECT_EQUAL(doc_id, search_iterator->getDocId()); + EXPECT_EQ(doc_id, search_iterator->getDocId()); search_iterator->unpack(doc_id); FieldPositionsIterator it = match_data->resolveTermField(handle)->getIterator(); ASSERT_TRUE(it.valid()); - EXPECT_EQUAL(1u, it.size()); - EXPECT_EQUAL(1u, it.getPosition()); // All hits are at pos 1 in this index + EXPECT_EQ(1u, it.size()); + EXPECT_EQ(1u, it.getPosition()); // All hits are at pos 1 in this index EXPECT_TRUE(!search_iterator->seek(doc_id + 1)); EXPECT_TRUE(search_iterator->isAtEnd()); @@ -155,7 +121,8 @@ VESPA_THREAD_STACK_TAG(write_executor) // Creates a memory index, inserts documents, performs a few // searches, dumps the index to disk, and performs the searches // again. -void Test::requireThatMemoryIndexCanBeDumpedAndSearched() { +TEST(FeedAndSearchTest, require_that_memory_index_can_be_dumped_and_searched) +{ vespalib::ThreadStackExecutor sharedExecutor(2); auto indexFieldInverter = vespalib::SequencedTaskExecutor::create(invert_executor, 2); auto indexFieldWriter = vespalib::SequencedTaskExecutor::create(write_executor, 2); @@ -239,4 +206,12 @@ void Test::requireThatMemoryIndexCanBeDumpedAndSearched() { } } // namespace -TEST_APPHOOK(Test); +int +main(int argc, char* argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + if (argc > 0) { + DummyFileHeaderContext::setCreator(argv[0]); + } + return RUN_ALL_TESTS(); +} diff --git a/searchcore/src/tests/proton/feedtoken/CMakeLists.txt b/searchcore/src/tests/proton/feedtoken/CMakeLists.txt index 1a13e46eb41..8ddb3831c97 100644 --- a/searchcore/src/tests/proton/feedtoken/CMakeLists.txt +++ b/searchcore/src/tests/proton/feedtoken/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(searchcore_feedtoken_test_app TEST DEPENDS searchcore_pcommon searchcore_proton_metrics + GTest::gtest ) vespa_add_test(NAME searchcore_feedtoken_test_app COMMAND searchcore_feedtoken_test_app) diff --git a/searchcore/src/tests/proton/feedtoken/feedtoken_test.cpp b/searchcore/src/tests/proton/feedtoken/feedtoken_test.cpp index c3c67e74c70..d3eb7d08821 100644 --- a/searchcore/src/tests/proton/feedtoken/feedtoken_test.cpp +++ b/searchcore/src/tests/proton/feedtoken/feedtoken_test.cpp @@ -1,6 +1,6 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/searchcore/proton/common/feedtoken.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/util/exceptions.h> using namespace proton; @@ -21,47 +21,24 @@ public: size_t getReceivedCount() const { return _receivedCount; } }; -class Test : public vespalib::TestApp { -private: - void testAck(); - void testFail(); - void testHandover(); - -public: - int Main() override { - TEST_INIT("feedtoken_test"); - - testAck(); TEST_FLUSH(); - testFail(); TEST_FLUSH(); - testHandover(); TEST_FLUSH(); - - TEST_DONE(); - } -}; - -TEST_APPHOOK(Test); - -void -Test::testAck() +TEST(FeedTokenTest, test_ack) { LocalTransport transport; { FeedToken token = feedtoken::make(transport); } - EXPECT_EQUAL(1u, transport.getReceivedCount()); + EXPECT_EQ(1u, transport.getReceivedCount()); } -void -Test::testFail() +TEST(FeedTokenTest, test_fail) { LocalTransport transport; FeedToken token = feedtoken::make(transport); token->fail(); - EXPECT_EQUAL(1u, transport.getReceivedCount()); + EXPECT_EQ(1u, transport.getReceivedCount()); } -void -Test::testHandover() +TEST(FeedTokenTest, test_handover) { struct MyHandover { static FeedToken handover(FeedToken token) { @@ -75,7 +52,7 @@ Test::testHandover() FeedToken token = feedtoken::make(transport); token = MyHandover::handover(token); } - EXPECT_EQUAL(1u, transport.getReceivedCount()); + EXPECT_EQ(1u, transport.getReceivedCount()); } - +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchcore/src/tests/proton/index/CMakeLists.txt b/searchcore/src/tests/proton/index/CMakeLists.txt index 40e3d8e7b79..c1cc6155a52 100644 --- a/searchcore/src/tests/proton/index/CMakeLists.txt +++ b/searchcore/src/tests/proton/index/CMakeLists.txt @@ -22,6 +22,7 @@ vespa_add_executable(searchcore_fusionrunner_test_app TEST searchcore_server searchcore_index searchcore_pcommon + GTest::gtest ) vespa_add_test(NAME searchcore_fusionrunner_test_app @@ -32,6 +33,7 @@ vespa_add_executable(searchcore_diskindexcleaner_test_app TEST diskindexcleaner_test.cpp DEPENDS searchcore_index + GTest::gtest ) vespa_add_test(NAME searchcore_diskindexcleaner_test_app diff --git a/searchcore/src/tests/proton/index/diskindexcleaner_test.cpp b/searchcore/src/tests/proton/index/diskindexcleaner_test.cpp index 745d9c6a983..1aa79e11a57 100644 --- a/searchcore/src/tests/proton/index/diskindexcleaner_test.cpp +++ b/searchcore/src/tests/proton/index/diskindexcleaner_test.cpp @@ -3,53 +3,44 @@ #include <vespa/searchcorespi/index/disk_indexes.h> #include <vespa/searchcorespi/index/diskindexcleaner.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/fastos/file.h> #include <algorithm> #include <filesystem> -#include <vespa/log/log.h> -LOG_SETUP("diskindexcleaner_test"); - using std::string; using std::vector; using namespace searchcorespi::index; namespace { -class Test : public vespalib::TestApp { - void requireThatAllIndexesOlderThanLastFusionIsRemoved(); - void requireThatIndexesInUseAreNotRemoved(); - void requireThatInvalidFlushIndexesAreRemoved(); - void requireThatInvalidFusionIndexesAreRemoved(); - void requireThatRemoveDontTouchNewIndexes(); - -public: - int Main() override; -}; - const string index_dir = "diskindexcleaner_test_data"; void removeTestData() { std::filesystem::remove_all(std::filesystem::path(index_dir)); } -int -Test::Main() -{ - TEST_INIT("diskindexcleaner_test"); - - TEST_DO(removeTestData()); +class DiskIndexCleanerTest : public ::testing::Test { +protected: + DiskIndexCleanerTest(); + ~DiskIndexCleanerTest() override; + void SetUp() override; + void TearDown() override; +}; - TEST_DO(requireThatAllIndexesOlderThanLastFusionIsRemoved()); - TEST_DO(requireThatIndexesInUseAreNotRemoved()); - TEST_DO(requireThatInvalidFlushIndexesAreRemoved()); - TEST_DO(requireThatInvalidFusionIndexesAreRemoved()); - TEST_DO(requireThatRemoveDontTouchNewIndexes()); +DiskIndexCleanerTest::DiskIndexCleanerTest() = default; +DiskIndexCleanerTest::~DiskIndexCleanerTest() = default; - TEST_DO(removeTestData()); +void +DiskIndexCleanerTest::SetUp() +{ + removeTestData(); +} - TEST_DONE(); +void +DiskIndexCleanerTest::TearDown() +{ + removeTestData(); } void createIndex(const string &name) { @@ -87,18 +78,20 @@ void createIndexes() { createIndex("index.flush.4"); } -void Test::requireThatAllIndexesOlderThanLastFusionIsRemoved() { +TEST_F(DiskIndexCleanerTest, require_that_all_indexes_older_than_last_fusion_is_removed) +{ createIndexes(); DiskIndexes disk_indexes; DiskIndexCleaner::clean(index_dir, disk_indexes); vector<string> indexes = readIndexes(); - EXPECT_EQUAL(3u, indexes.size()); + EXPECT_EQ(3u, indexes.size()); EXPECT_TRUE(contains(indexes, "index.fusion.2")); EXPECT_TRUE(contains(indexes, "index.flush.3")); EXPECT_TRUE(contains(indexes, "index.flush.4")); } -void Test::requireThatIndexesInUseAreNotRemoved() { +TEST_F(DiskIndexCleanerTest, require_that_indexes_in_use_are_not_removed) +{ createIndexes(); DiskIndexes disk_indexes; disk_indexes.setActive(index_dir + "/index.fusion.1", 0); @@ -116,37 +109,40 @@ void Test::requireThatIndexesInUseAreNotRemoved() { EXPECT_TRUE(!contains(indexes, "index.flush.2")); } -void Test::requireThatInvalidFlushIndexesAreRemoved() { +TEST_F(DiskIndexCleanerTest, require_that_invalid_flush_indexes_are_removed) +{ createIndexes(); std::filesystem::remove(std::filesystem::path(index_dir + "/index.flush.4/serial.dat")); DiskIndexes disk_indexes; DiskIndexCleaner::clean(index_dir, disk_indexes); vector<string> indexes = readIndexes(); - EXPECT_EQUAL(2u, indexes.size()); + EXPECT_EQ(2u, indexes.size()); EXPECT_TRUE(contains(indexes, "index.fusion.2")); EXPECT_TRUE(contains(indexes, "index.flush.3")); } -void Test::requireThatInvalidFusionIndexesAreRemoved() { +TEST_F(DiskIndexCleanerTest, require_that_invalid_fusion_indexes_are_removed) +{ createIndexes(); std::filesystem::remove(std::filesystem::path(index_dir + "/index.fusion.2/serial.dat")); DiskIndexes disk_indexes; DiskIndexCleaner::clean(index_dir, disk_indexes); vector<string> indexes = readIndexes(); - EXPECT_EQUAL(4u, indexes.size()); + EXPECT_EQ(4u, indexes.size()); EXPECT_TRUE(contains(indexes, "index.fusion.1")); EXPECT_TRUE(contains(indexes, "index.flush.2")); EXPECT_TRUE(contains(indexes, "index.flush.3")); EXPECT_TRUE(contains(indexes, "index.flush.4")); } -void Test::requireThatRemoveDontTouchNewIndexes() { +TEST_F(DiskIndexCleanerTest, require_that_remove_doesnt_touch_new_indexes) +{ createIndexes(); std::filesystem::remove(std::filesystem::path(index_dir + "/index.flush.4/serial.dat")); DiskIndexes disk_indexes; DiskIndexCleaner::removeOldIndexes(index_dir, disk_indexes); vector<string> indexes = readIndexes(); - EXPECT_EQUAL(3u, indexes.size()); + EXPECT_EQ(3u, indexes.size()); EXPECT_TRUE(contains(indexes, "index.fusion.2")); EXPECT_TRUE(contains(indexes, "index.flush.3")); EXPECT_TRUE(contains(indexes, "index.flush.4")); @@ -154,4 +150,4 @@ void Test::requireThatRemoveDontTouchNewIndexes() { } // namespace -TEST_APPHOOK(Test); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchcore/src/tests/proton/index/fusionrunner_test.cpp b/searchcore/src/tests/proton/index/fusionrunner_test.cpp index a58d7540d7c..dd6e8fa1c4c 100644 --- a/searchcore/src/tests/proton/index/fusionrunner_test.cpp +++ b/searchcore/src/tests/proton/index/fusionrunner_test.cpp @@ -22,7 +22,7 @@ #include <vespa/searchlib/queryeval/blueprint.h> #include <vespa/vespalib/util/gate.h> #include <vespa/vespalib/util/destructor_callbacks.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/stllike/asciistream.h> #include <filesystem> #include <set> @@ -66,12 +66,8 @@ using namespace proton; namespace { -#define TEST_CALL(func) \ - setUp(); \ - func; \ - tearDown() - -class Test : public vespalib::TestApp { +class FusionRunnerTest : public ::testing::Test { +protected: std::unique_ptr<FusionRunner> _fusion_runner; FixedSourceSelector::UP _selector; FusionSpec _fusion_spec; @@ -79,8 +75,10 @@ class Test : public vespalib::TestApp { TransportAndExecutorService _service; IndexManager::MaintainerOperations _ops; - void setUp(); - void tearDown(); + FusionRunnerTest(); + ~FusionRunnerTest() override; + void SetUp() override; + void TearDown() override; void createIndex(const string &dir, uint32_t id, bool fusion = false); void checkResults(uint32_t fusion_id, const uint32_t *ids, size_t size); @@ -92,41 +90,19 @@ class Test : public vespalib::TestApp { void requireThatOldFusionIndexCanBePartOfNewFusion(); void requireThatSelectorsCanBeRebased(); void requireThatFusionCanBeStopped(); - -public: - Test(); - ~Test() override; - int Main() override; }; -Test::Test() - : _fusion_runner(), +FusionRunnerTest::FusionRunnerTest() + : ::testing::Test(), + _fusion_runner(), _selector(), _fusion_spec(), _fileHeaderContext(), _service(1), _ops(_fileHeaderContext,TuneFileIndexManager(), 0, _service.write()) { } -Test::~Test() = default; - -int -Test::Main() -{ - TEST_INIT("fusionrunner_test"); - if (_argc > 0) { - DummyFileHeaderContext::setCreator(_argv[0]); - } - TEST_CALL(requireThatNoDiskIndexesGiveId0()); - TEST_CALL(requireThatOneDiskIndexCausesCopy()); - TEST_CALL(requireThatTwoDiskIndexesCauseFusion()); - TEST_CALL(requireThatFusionCanRunOnMultipleDiskIndexes()); - TEST_CALL(requireThatOldFusionIndexCanBePartOfNewFusion()); - TEST_CALL(requireThatSelectorsCanBeRebased()); - TEST_CALL(requireThatFusionCanBeStopped()); - - TEST_DONE(); -} +FusionRunnerTest::~FusionRunnerTest() = default; const string base_dir = "fusion_test_data"; const string field_name = "field_name"; @@ -142,7 +118,9 @@ getSchema() return SchemaBuilder(db).add_all_indexes().build(); } -void Test::setUp() { +void +FusionRunnerTest::SetUp() +{ std::filesystem::remove_all(std::filesystem::path(base_dir)); _fusion_runner = std::make_unique<FusionRunner>(base_dir, getSchema(), TuneFileAttributes(), _fileHeaderContext); const string selector_base = base_dir + "/index.flush.0/selector"; @@ -150,12 +128,16 @@ void Test::setUp() { _fusion_spec = FusionSpec(); } -void Test::tearDown() { +void +FusionRunnerTest::TearDown() +{ std::filesystem::remove_all(std::filesystem::path(base_dir)); - _selector.reset(nullptr); + _selector.reset(); } -Document::UP buildDocument(DocBuilder & doc_builder, int id, const string &word) { +Document::UP +buildDocument(DocBuilder & doc_builder, int id, const string &word) +{ vespalib::asciistream ost; ost << "id:ns:searchdocument::" << id; auto doc = doc_builder.make_document(ost.str()); @@ -163,8 +145,10 @@ Document::UP buildDocument(DocBuilder & doc_builder, int id, const string &word) return doc; } -void addDocument(DocBuilder & doc_builder, MemoryIndex &index, ISourceSelector &selector, - uint8_t index_id, uint32_t docid, const string &word) { +void +addDocument(DocBuilder & doc_builder, MemoryIndex &index, ISourceSelector &selector, + uint8_t index_id, uint32_t docid, const string &word) +{ Document::UP doc = buildDocument(doc_builder, docid, word); index.insertDocument(docid, *doc, {}); vespalib::Gate gate; @@ -173,7 +157,9 @@ void addDocument(DocBuilder & doc_builder, MemoryIndex &index, ISourceSelector & gate.await(); } -void Test::createIndex(const string &dir, uint32_t id, bool fusion) { +void +FusionRunnerTest::createIndex(const string &dir, uint32_t id, bool fusion) +{ std::filesystem::create_directory(std::filesystem::path(dir)); vespalib::asciistream ost; if (fusion) { @@ -209,7 +195,9 @@ void Test::createIndex(const string &dir, uint32_t id, bool fusion) { _selector->extractSaveInfo(index_dir + "/selector")->save(tuneFileAttributes, _fileHeaderContext); } -set<uint32_t> readFusionIds(const string &dir) { +set<uint32_t> +readFusionIds(const string &dir) +{ set<uint32_t> ids; const vespalib::string prefix("index.fusion."); std::filesystem::directory_iterator dir_scan(dir); @@ -225,13 +213,17 @@ set<uint32_t> readFusionIds(const string &dir) { return ids; } -vespalib::string getFusionIndexName(uint32_t fusion_id) { +vespalib::string +getFusionIndexName(uint32_t fusion_id) +{ vespalib::asciistream ost; ost << base_dir << "/index.fusion." << fusion_id; return ost.str(); } -void Test::checkResults(uint32_t fusion_id, const uint32_t *ids, size_t size) { +void +FusionRunnerTest::checkResults(uint32_t fusion_id, const uint32_t *ids, size_t size) +{ FakeRequestContext requestContext; DiskIndex disk_index(getFusionIndexName(fusion_id)); ASSERT_TRUE(disk_index.setup(TuneFileSearch())); @@ -256,66 +248,72 @@ void Test::checkResults(uint32_t fusion_id, const uint32_t *ids, size_t size) { } } -void Test::requireThatNoDiskIndexesGiveId0() { +TEST_F(FusionRunnerTest, require_that_no_disk_indexes_give_id_0) +{ uint32_t fusion_id = _fusion_runner->fuse(_fusion_spec, 0u, _ops, std::make_shared<search::FlushToken>()); - EXPECT_EQUAL(0u, fusion_id); + EXPECT_EQ(0u, fusion_id); } -void Test::requireThatOneDiskIndexCausesCopy() { +TEST_F(FusionRunnerTest, rquire_that_one_disk_index_causes_copy) +{ createIndex(base_dir, disk_id[0]); uint32_t fusion_id = _fusion_runner->fuse(_fusion_spec, 0u, _ops, std::make_shared<search::FlushToken>()); - EXPECT_EQUAL(disk_id[0], fusion_id); + EXPECT_EQ(disk_id[0], fusion_id); set<uint32_t> fusion_ids = readFusionIds(base_dir); ASSERT_TRUE(!fusion_ids.empty()); - EXPECT_EQUAL(1u, fusion_ids.size()); - EXPECT_EQUAL(fusion_id, *fusion_ids.begin()); + EXPECT_EQ(1u, fusion_ids.size()); + EXPECT_EQ(fusion_id, *fusion_ids.begin()); checkResults(fusion_id, disk_id, 1); } -void Test::requireThatTwoDiskIndexesCauseFusion() { +TEST_F(FusionRunnerTest, require_that_two_disk_indexes_cause_fusion) +{ createIndex(base_dir, disk_id[0]); createIndex(base_dir, disk_id[1]); uint32_t fusion_id = _fusion_runner->fuse(_fusion_spec, 0u, _ops, std::make_shared<search::FlushToken>()); - EXPECT_EQUAL(disk_id[1], fusion_id); + EXPECT_EQ(disk_id[1], fusion_id); set<uint32_t> fusion_ids = readFusionIds(base_dir); ASSERT_TRUE(!fusion_ids.empty()); - EXPECT_EQUAL(1u, fusion_ids.size()); - EXPECT_EQUAL(fusion_id, *fusion_ids.begin()); + EXPECT_EQ(1u, fusion_ids.size()); + EXPECT_EQ(fusion_id, *fusion_ids.begin()); checkResults(fusion_id, disk_id, 2); } -void Test::requireThatFusionCanRunOnMultipleDiskIndexes() { +TEST_F(FusionRunnerTest, require_that_fusion_can_run_on_multiple_disk_indexes) +{ createIndex(base_dir, disk_id[0]); createIndex(base_dir, disk_id[1]); createIndex(base_dir, disk_id[2]); createIndex(base_dir, disk_id[3]); uint32_t fusion_id = _fusion_runner->fuse(_fusion_spec, 0u, _ops, std::make_shared<search::FlushToken>()); - EXPECT_EQUAL(disk_id[3], fusion_id); + EXPECT_EQ(disk_id[3], fusion_id); set<uint32_t> fusion_ids = readFusionIds(base_dir); ASSERT_TRUE(!fusion_ids.empty()); - EXPECT_EQUAL(1u, fusion_ids.size()); - EXPECT_EQUAL(fusion_id, *fusion_ids.begin()); + EXPECT_EQ(1u, fusion_ids.size()); + EXPECT_EQ(fusion_id, *fusion_ids.begin()); checkResults(fusion_id, disk_id, 4); } -void Test::requireThatOldFusionIndexCanBePartOfNewFusion() { +TEST_F(FusionRunnerTest, require_that_old_fusion_index_can_be_part_of_new_fusion) +{ createIndex(base_dir, disk_id[0], true); createIndex(base_dir, disk_id[1]); uint32_t fusion_id = _fusion_runner->fuse(_fusion_spec, 0u, _ops, std::make_shared<search::FlushToken>()); - EXPECT_EQUAL(disk_id[1], fusion_id); + EXPECT_EQ(disk_id[1], fusion_id); set<uint32_t> fusion_ids = readFusionIds(base_dir); ASSERT_TRUE(!fusion_ids.empty()); - EXPECT_EQUAL(2u, fusion_ids.size()); - EXPECT_EQUAL(disk_id[0], *fusion_ids.begin()); - EXPECT_EQUAL(fusion_id, *(++fusion_ids.begin())); + EXPECT_EQ(2u, fusion_ids.size()); + EXPECT_EQ(disk_id[0], *fusion_ids.begin()); + EXPECT_EQ(fusion_id, *(++fusion_ids.begin())); checkResults(fusion_id, disk_id, 2); } -void Test::requireThatSelectorsCanBeRebased() { +TEST_F(FusionRunnerTest, require_that_selectors_can_be_rebased) +{ createIndex(base_dir, disk_id[0]); createIndex(base_dir, disk_id[1]); uint32_t fusion_id = _fusion_runner->fuse(_fusion_spec, 0u, _ops, std::make_shared<search::FlushToken>()); @@ -328,17 +326,24 @@ void Test::requireThatSelectorsCanBeRebased() { checkResults(fusion_id, disk_id, 3); } -void -Test::requireThatFusionCanBeStopped() +TEST_F(FusionRunnerTest, require_that_fusion_can_be_stopped) { createIndex(base_dir, disk_id[0]); createIndex(base_dir, disk_id[1]); auto flush_token = std::make_shared<search::FlushToken>(); flush_token->request_stop(); uint32_t fusion_id = _fusion_runner->fuse(_fusion_spec, 0u, _ops, flush_token); - EXPECT_EQUAL(0u, fusion_id); + EXPECT_EQ(0u, fusion_id); } } // namespace -TEST_APPHOOK(Test); +int +main(int argc, char* argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + if (argc > 0) { + DummyFileHeaderContext::setCreator(argv[0]); + } + return RUN_ALL_TESTS(); +} diff --git a/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.cpp b/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.cpp index d94b0a4c909..d22fed89ad1 100644 --- a/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.cpp +++ b/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.cpp @@ -40,7 +40,7 @@ std::unique_ptr<document::select::Value> AttributeFieldValueNode:: getValue(const Context &context) const { - const auto &sc(static_cast<const SelectContext &>(context)); + const auto &sc(dynamic_cast<const SelectContext &>(context)); uint32_t docId(sc._docId); assert(docId != 0u); const auto& v = sc.guarded_attribute_at_index(_attr_guard_index); diff --git a/searchcore/src/vespa/searchcore/proton/common/cachedselect.cpp b/searchcore/src/vespa/searchcore/proton/common/cachedselect.cpp index 293ed3bdcb9..9f890f5d480 100644 --- a/searchcore/src/vespa/searchcore/proton/common/cachedselect.cpp +++ b/searchcore/src/vespa/searchcore/proton/common/cachedselect.cpp @@ -35,13 +35,16 @@ public: uint32_t _mvAttrs; uint32_t _complexAttrs; - uint32_t getFieldNodes() const { return _fieldNodes; } + [[nodiscard]] uint32_t getFieldNodes() const { return _fieldNodes; } - static uint32_t invalidIdx() { + constexpr static uint32_t invalidIdx() noexcept { return std::numeric_limits<uint32_t>::max(); } AttrVisitor(const search::IAttributeManager &amgr, CachedSelect::AttributeVectors &attributes); + AttrVisitor(const search::IAttributeManager &amgr, + CachedSelect::AttributeVectors &attributes, + AttrMap existing_attr_map); ~AttrVisitor() override; /* @@ -62,6 +65,18 @@ AttrVisitor::AttrVisitor(const search::IAttributeManager &amgr, CachedSelect::At _complexAttrs(0u) {} +AttrVisitor::AttrVisitor(const search::IAttributeManager &amgr, + CachedSelect::AttributeVectors &attributes, + AttrMap existing_attr_map) + : CloningVisitor(), + _amap(std::move(existing_attr_map)), + _amgr(amgr), + _attributes(attributes), + _svAttrs(0u), + _mvAttrs(0u), + _complexAttrs(0u) +{} + AttrVisitor::~AttrVisitor() = default; bool isSingleValueThatWeHandle(BasicType type) { @@ -130,7 +145,7 @@ CachedSelect::Session::Session(std::unique_ptr<document::select::Node> docSelect } bool -CachedSelect::Session::contains(const SelectContext &context) const +CachedSelect::Session::contains_pre_doc(const SelectContext &context) const { if (_preDocSelect && (_preDocSelect->contains(context) == document::select::Result::False)) { return false; @@ -140,10 +155,10 @@ CachedSelect::Session::contains(const SelectContext &context) const } bool -CachedSelect::Session::contains(const document::Document &doc) const +CachedSelect::Session::contains_doc(const SelectContext &context) const { return (_preDocOnlySelect) || - (_docSelect && (_docSelect->contains(doc) == document::select::Result::True)); + (_docSelect && (_docSelect->contains(context) == document::select::Result::True)); } const document::select::Node & @@ -177,8 +192,12 @@ CachedSelect::setPreDocumentSelect(const search::IAttributeManager &attrMgr, if (_fieldNodes == _svAttrFieldNodes) { _preDocOnlySelect = std::move(allAttrVisitor.getNode()); } else if (_svAttrFieldNodes > 0) { - _attributes.clear(); - AttrVisitor someAttrVisitor(attrMgr, _attributes); + // Also let document-level selection use attribute wiring; otherwise imported fields + // would not resolve to anything, as these do not exist in the concrete document itself. + _docSelect = std::move(allAttrVisitor.getNode()); + [[maybe_unused]] size_t attrs_before = _attributes.size(); + AttrVisitor someAttrVisitor(attrMgr, _attributes, std::move(allAttrVisitor._amap)); + assert(_attributes.size() == attrs_before); noDocsPruner.getNode()->visit(someAttrVisitor); _preDocSelect = std::move(someAttrVisitor.getNode()); } diff --git a/searchcore/src/vespa/searchcore/proton/common/cachedselect.h b/searchcore/src/vespa/searchcore/proton/common/cachedselect.h index b0660399f6f..89f002bd939 100644 --- a/searchcore/src/vespa/searchcore/proton/common/cachedselect.h +++ b/searchcore/src/vespa/searchcore/proton/common/cachedselect.h @@ -42,9 +42,10 @@ public: Session(std::unique_ptr<document::select::Node> docSelect, std::unique_ptr<document::select::Node> preDocOnlySelect, std::unique_ptr<document::select::Node> preDocSelect); - bool contains(const SelectContext &context) const; - bool contains(const document::Document &doc) const; - const document::select::Node &selectNode() const; + [[nodiscard]] bool contains_pre_doc(const SelectContext &context) const; + // Precondition: context must have non-nullptr _doc + [[nodiscard]] bool contains_doc(const SelectContext &context) const; + [[nodiscard]] const document::select::Node &selectNode() const; }; using AttributeVectors = std::vector<std::shared_ptr<search::attribute::ReadableAttributeVector>>; diff --git a/searchcore/src/vespa/searchcore/proton/common/selectpruner.h b/searchcore/src/vespa/searchcore/proton/common/selectpruner.h index 3612914fc6f..3322a07ebd7 100644 --- a/searchcore/src/vespa/searchcore/proton/common/selectpruner.h +++ b/searchcore/src/vespa/searchcore/proton/common/selectpruner.h @@ -36,7 +36,7 @@ public: class SelectPruner : public document::select::CloningVisitor, - public SelectPrunerBase + public SelectPrunerBase { public: private: @@ -53,16 +53,16 @@ public: bool hasFields, bool hasDocuments); - SelectPruner(const SelectPruner *rhs); - virtual ~SelectPruner(); + explicit SelectPruner(const SelectPruner *rhs); + ~SelectPruner() override; - uint32_t getFieldNodes() const { return _fieldNodes; } - uint32_t getAttrFieldNodes() const { return _attrFieldNodes; } - const document::select::ResultSet & getResultSet() const { return _resultSet; } - bool isFalse() const; - bool isTrue() const; - bool isInvalid() const; - bool isConst() const; + [[nodiscard]] uint32_t getFieldNodes() const noexcept { return _fieldNodes; } + [[nodiscard]] uint32_t getAttrFieldNodes() const noexcept { return _attrFieldNodes; } + [[nodiscard]] const document::select::ResultSet & getResultSet() const noexcept { return _resultSet; } + [[nodiscard]] bool isFalse() const; + [[nodiscard]] bool isTrue() const; + [[nodiscard]] bool isInvalid() const; + [[nodiscard]] bool isConst() const; void trace(std::ostream &t); void process(const document::select::Node &node); private: @@ -83,8 +83,8 @@ private: void setTernaryConst(bool val); void set_null_value_node(); void resolveTernaryConst(bool wantInverted); - bool isInvalidVal() const; - bool isNullVal() const; + [[nodiscard]] bool isInvalidVal() const; + [[nodiscard]] bool isNullVal() const; void swap(SelectPruner &rhs); }; diff --git a/searchcore/src/vespa/searchcore/proton/persistenceengine/document_iterator.cpp b/searchcore/src/vespa/searchcore/proton/persistenceengine/document_iterator.cpp index e9d233ef6ec..85c0eb0c1f2 100644 --- a/searchcore/src/vespa/searchcore/proton/persistenceengine/document_iterator.cpp +++ b/searchcore/src/vespa/searchcore/proton/persistenceengine/document_iterator.cpp @@ -171,28 +171,31 @@ public: } } - bool willAlwaysFail() const { return _willAlwaysFail; } + [[nodiscard]] bool willAlwaysFail() const noexcept { return _willAlwaysFail; } - bool match(const search::DocumentMetaData & meta) const { + [[nodiscard]] bool match(const search::DocumentMetaData & meta) const { if (meta.lid >= _docidLimit) { return false; } if (_dscTrue || _metaOnly) { return true; } - if (_selectCxt) { - _selectCxt->_docId = meta.lid; - } if (!_gidFilter.gid_might_match_selection(meta.gid)) { return false; } - return _selectSession->contains(*_selectCxt); + assert(_selectCxt); + _selectCxt->_docId = meta.lid; + _selectCxt->_doc = nullptr; + return _selectSession->contains_pre_doc(*_selectCxt); } - bool match(const search::DocumentMetaData & meta, const Document * doc) const { + [[nodiscard]] bool match(const search::DocumentMetaData & meta, const Document * doc) const { if (_dscTrue || _metaOnly) { return true; } - return (doc && (doc->getId().getGlobalId() == meta.gid) && _selectSession->contains(*doc)); + assert(_selectCxt); + _selectCxt->_docId = meta.lid; + _selectCxt->_doc = doc; + return (doc && (doc->getId().getGlobalId() == meta.gid) && _selectSession->contains_doc(*_selectCxt)); } private: bool _dscTrue; diff --git a/searchlib/CMakeLists.txt b/searchlib/CMakeLists.txt index ffc6cf75ab0..a5453ac5273 100644 --- a/searchlib/CMakeLists.txt +++ b/searchlib/CMakeLists.txt @@ -131,6 +131,7 @@ vespa_define_module( src/tests/engine/proto_rpc_adapter src/tests/expression/attributenode src/tests/expression/current_index_setup + src/tests/expression/interpolated_document_field_lookup_node src/tests/features src/tests/features/beta src/tests/features/bm25 diff --git a/searchlib/src/tests/attribute/guard/CMakeLists.txt b/searchlib/src/tests/attribute/guard/CMakeLists.txt index a956182e1e1..f5570377814 100644 --- a/searchlib/src/tests/attribute/guard/CMakeLists.txt +++ b/searchlib/src/tests/attribute/guard/CMakeLists.txt @@ -4,6 +4,7 @@ vespa_add_executable(searchlib_attributeguard_test_app TEST attributeguard_test.cpp DEPENDS searchlib + GTest::gtest ) vespa_add_test(NAME searchlib_attributeguard_test_app COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/attributeguard_test.sh DEPENDS searchlib_attributeguard_test_app) diff --git a/searchlib/src/tests/attribute/guard/attributeguard_test.cpp b/searchlib/src/tests/attribute/guard/attributeguard_test.cpp index 47df9d7c320..513fa7406b6 100644 --- a/searchlib/src/tests/attribute/guard/attributeguard_test.cpp +++ b/searchlib/src/tests/attribute/guard/attributeguard_test.cpp @@ -1,31 +1,17 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/log/log.h> -LOG_SETUP("attributeguard_test"); -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/searchlib/attribute/attributeguard.h> #include <vespa/searchlib/attribute/extendableattributes.h> +#include <vespa/vespalib/gtest/gtest.h> namespace search { -class AttributeGuardTest : public vespalib::TestApp +TEST(AttributeGuardTest, test_attribute_guard) { -public: - int Main() override; -}; - -int -AttributeGuardTest::Main() -{ - TEST_INIT("attributeguard_test"); - - AttributeVector::SP ssattr(new SingleStringExtAttribute("ss1")); AttributeGuard guard(ssattr); EXPECT_TRUE(guard.valid()); - - TEST_DONE(); } } -TEST_APPHOOK(search::AttributeGuardTest); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/attribute/postinglist/CMakeLists.txt b/searchlib/src/tests/attribute/postinglist/CMakeLists.txt index 20e2dff1b13..e88b37696fc 100644 --- a/searchlib/src/tests/attribute/postinglist/CMakeLists.txt +++ b/searchlib/src/tests/attribute/postinglist/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_postinglist_test_app TEST postinglist_test.cpp DEPENDS searchlib + GTest::gtest ) vespa_add_test(NAME searchlib_postinglist_test_app COMMAND searchlib_postinglist_test_app) diff --git a/searchlib/src/tests/attribute/postinglist/postinglist_test.cpp b/searchlib/src/tests/attribute/postinglist/postinglist_test.cpp index c6b627f97e2..16b28d038c5 100644 --- a/searchlib/src/tests/attribute/postinglist/postinglist_test.cpp +++ b/searchlib/src/tests/attribute/postinglist/postinglist_test.cpp @@ -8,7 +8,7 @@ #include <vespa/vespalib/btree/btreestore.hpp> #include <vespa/vespalib/datastore/datastore.h> #include <vespa/vespalib/util/rand48.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <set> #include <map> #include <cinttypes> @@ -24,9 +24,9 @@ using vespalib::GenerationHandler; * TODO: Make it pass MALLOC_OPTIONS=AJ on freebsd and valgrind on Linux. */ -class AttributePostingListTest : public vespalib::TestApp +class AttributePostingListTest : public ::testing::Test { -private: +protected: /* Limited STL version for validation of full version */ using STLPostingList = std::set<uint32_t>; using STLValueTree = std::map<int, STLPostingList>; @@ -96,7 +96,6 @@ private: }; std::vector<RandomValue> _randomValues; -public: using IntKeyStore = vespalib::datastore::DataStore<int>; using AttributePosting = vespalib::btree::BTreeKeyData<uint32_t, vespalib::btree::BTreeNoLeafData>; using PostingList = vespalib::btree::BTreeStore<uint32_t, @@ -134,7 +133,7 @@ public: using TreeManager = IntEnumNodeAllocator; using ValueHandle = IntKeyStore; using RandomValuesVector = std::vector<RandomValue>; -private: + GenerationHandler _handler; IntKeyStore *_intKeyStore; IntEnumNodeAllocator *_intNodeAlloc; @@ -210,15 +209,12 @@ private: { return frozen ? "frozen" : "thawed"; } -public: AttributePostingListTest(); - ~AttributePostingListTest(); - - int Main() override; + ~AttributePostingListTest() override; }; AttributePostingListTest::AttributePostingListTest() - : vespalib::TestApp(), + : ::testing::Test(), _randomValues(), _handler(), _intKeyStore(NULL), @@ -228,7 +224,8 @@ AttributePostingListTest::AttributePostingListTest() _stlTree(NULL), _randomGenerator() {} -AttributePostingListTest::~AttributePostingListTest() {} + +AttributePostingListTest::~AttributePostingListTest() = default; void AttributePostingListTest::allocTree() @@ -368,7 +365,7 @@ insertRandomValues(Tree &tree, } else { } ASSERT_TRUE(itr.valid()); - EXPECT_EQUAL(i->_value, valueHandle.getEntry(itr.getKey())); + EXPECT_EQ(i->_value, valueHandle.getEntry(itr.getKey())); /* TODO: Insert docid to postinglist */ PostingIdx oldIdx = itr.getData(); @@ -669,30 +666,21 @@ reclaim_memory(Tree &tree, postings.reclaim_memory(_handler.get_oldest_used_generation()); } -int -AttributePostingListTest::Main() +TEST_F(AttributePostingListTest, test_posting_list) { - TEST_INIT("postinglist_test"); - fillRandomValues(1000, 10); allocTree(); - insertRandomValues(*_intTree, *_intNodeAlloc, *_intKeyStore, *_intPostings, - _stlTree, _randomValues); - lookupRandomValues(*_intTree, *_intNodeAlloc, *_intKeyStore, *_intPostings, - _stlTree, _randomValues); + ASSERT_NO_FATAL_FAILURE(insertRandomValues(*_intTree, *_intNodeAlloc, *_intKeyStore, *_intPostings, _stlTree, _randomValues)); + ASSERT_NO_FATAL_FAILURE(lookupRandomValues(*_intTree, *_intNodeAlloc, *_intKeyStore, *_intPostings, _stlTree, _randomValues)); _intNodeAlloc->freeze(); _intNodeAlloc->assign_generation(_handler.getCurrentGeneration()); doCompactEnumStore(*_intTree, *_intNodeAlloc, *_intKeyStore); - removeRandomValues(*_intTree, *_intNodeAlloc, *_intKeyStore, *_intPostings, - _stlTree, _randomValues); - insertRandomValues(*_intTree, *_intNodeAlloc, *_intKeyStore, *_intPostings, - _stlTree, _randomValues); + ASSERT_NO_FATAL_FAILURE(removeRandomValues(*_intTree, *_intNodeAlloc, *_intKeyStore, *_intPostings, _stlTree, _randomValues)); + ASSERT_NO_FATAL_FAILURE(insertRandomValues(*_intTree, *_intNodeAlloc, *_intKeyStore, *_intPostings, _stlTree, _randomValues)); freeTree(true); - - TEST_DONE(); } } -TEST_APPHOOK(search::AttributePostingListTest); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/attribute/sourceselector/CMakeLists.txt b/searchlib/src/tests/attribute/sourceselector/CMakeLists.txt index 3c525a96b07..c70470852ba 100644 --- a/searchlib/src/tests/attribute/sourceselector/CMakeLists.txt +++ b/searchlib/src/tests/attribute/sourceselector/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_sourceselector_test_app TEST sourceselector_test.cpp DEPENDS searchlib + GTest::gtest ) vespa_add_test(NAME searchlib_sourceselector_test_app COMMAND searchlib_sourceselector_test_app) diff --git a/searchlib/src/tests/attribute/sourceselector/sourceselector_test.cpp b/searchlib/src/tests/attribute/sourceselector/sourceselector_test.cpp index f9567f83edf..2d6806257e6 100644 --- a/searchlib/src/tests/attribute/sourceselector/sourceselector_test.cpp +++ b/searchlib/src/tests/attribute/sourceselector/sourceselector_test.cpp @@ -4,13 +4,10 @@ #include <vespa/searchlib/attribute/fixedsourceselector.h> #include <vespa/searchlib/index/dummyfileheadercontext.h> #include <vespa/searchcommon/common/undefinedvalues.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/util/size_literals.h> #include <filesystem> -#include <vespa/log/log.h> -LOG_SETUP("sourceselector_test"); - using std::unique_ptr; using std::string; using namespace search; @@ -37,47 +34,17 @@ uint8_t capSource(uint8_t source, uint8_t defaultSource, bool cap) { return (cap ? std::min(source, defaultSource) : source); } -class Test : public vespalib::TestApp +class SourceSelectorTest : public ::testing::Test { -public: - int Main() override; -private: +protected: + SourceSelectorTest(); + ~SourceSelectorTest() override; void testSourceSelector(const DocSource *docSource, size_t sz, uint8_t defaultSource, ISourceSelector & selector, bool cap); - void testFixed(const DocSource *docSource, size_t sz); - template <typename SelectorType> - void requireThatSelectorCanCloneAndSubtract(); - void requireThatSelectorCanCloneAndSubtract(); - template <typename SelectorType> void requireThatSelectorCanSaveAndLoad(bool compactLidSpace); - void requireThatSelectorCanSaveAndLoad(); - template <typename SelectorType> - void requireThatCompleteSourceRangeIsHandled(); - void requireThatCompleteSourceRangeIsHandled(); - template <typename SelectorType> - void requireThatSourcesAreCountedCorrectly(); - void requireThatSourcesAreCountedCorrectly(); - void requireThatDocIdLimitIsCorrect(); - void requireThatCorrectDefaultValueIsUsedAfterCompaction(); }; -int -Test::Main() -{ - TEST_INIT("sourceselector_test"); - - if (_argc > 0) { - DummyFileHeaderContext::setCreator(_argv[0]); - } - testFixed(docs, arraysize(docs)); - TEST_DO(requireThatSelectorCanCloneAndSubtract()); - TEST_DO(requireThatSelectorCanSaveAndLoad()); - TEST_DO(requireThatCompleteSourceRangeIsHandled()); - TEST_DO(requireThatSourcesAreCountedCorrectly()); - TEST_DO(requireThatDocIdLimitIsCorrect()); - TEST_DO(requireThatCorrectDefaultValueIsUsedAfterCompaction()); - - TEST_DONE(); -} +SourceSelectorTest::SourceSelectorTest() = default; +SourceSelectorTest::~SourceSelectorTest() = default; void setSources(ISourceSelector &selector) { for (size_t i = 0; i < arraysize(docs); ++i) { @@ -85,75 +52,75 @@ void setSources(ISourceSelector &selector) { } } -void Test::testFixed(const DocSource *docSource, size_t sz) +TEST_F(SourceSelectorTest, test_fixed) { + const DocSource *docSource = docs; + size_t sz = arraysize(docs); FixedSourceSelector selector(default_source, base_file_name, 10); - EXPECT_EQUAL(default_source, selector.getDefaultSource()); - EXPECT_EQUAL(10u, selector.getDocIdLimit()); -// EXPECT_EQUAL(default_source, selector.createIterator()->getSource(maxDocId + 1)); + EXPECT_EQ(default_source, selector.getDefaultSource()); + EXPECT_EQ(10u, selector.getDocIdLimit()); setSources(selector); + /* + * One extra element beyond highest explicitly set element is + * initialized to accommodate a match loop optimization. See + * setSource() and reserve() member functions in + * FixedSourceSelector for details. + */ + EXPECT_EQ(default_source, selector.createIterator()->getSource(maxDocId + 1)); testSourceSelector(docSource, sz, selector.getDefaultSource(), selector, false); - EXPECT_EQUAL(maxDocId+1, selector.getDocIdLimit()); + EXPECT_EQ(maxDocId+1, selector.getDocIdLimit()); } -void Test::testSourceSelector(const DocSource *docSource, size_t sz, - uint8_t defaultSource, ISourceSelector &selector, bool cap) +void +SourceSelectorTest::testSourceSelector(const DocSource *docSource, size_t sz, + uint8_t defaultSource, ISourceSelector &selector, bool cap) { { auto it(selector.createIterator()); for (size_t i = 0; i < sz; ++i) { - EXPECT_EQUAL((uint32_t)capSource(docSource[i].source, defaultSource, cap), (uint32_t)it->getSource(docSource[i].docId)); + EXPECT_EQ((uint32_t)capSource(docSource[i].source, defaultSource, cap), (uint32_t)it->getSource(docSource[i].docId)); } } { auto it(selector.createIterator()); for (size_t i = 0, j = 0; i <= docSource[sz - 1].docId; ++i) { if (i != docSource[j].docId) { - EXPECT_EQUAL((uint32_t)defaultSource, (uint32_t)it->getSource(i)); + EXPECT_EQ((uint32_t)defaultSource, (uint32_t)it->getSource(i)); } else { - EXPECT_EQUAL((uint32_t)capSource(docSource[j].source, defaultSource, cap), (uint32_t)it->getSource(i)); + EXPECT_EQ((uint32_t)capSource(docSource[j].source, defaultSource, cap), (uint32_t)it->getSource(i)); ++j; } } } } -template <typename SelectorType> -void -Test::requireThatSelectorCanCloneAndSubtract() +TEST_F(SourceSelectorTest, require_that_selector_can_clone_and_subtract) { - SelectorType selector(default_source, base_file_name); + FixedSourceSelector selector(default_source, base_file_name); setSources(selector); selector.setBaseId(base_id); const uint32_t diff = 3; - typename SelectorType::UP - new_selector(selector.cloneAndSubtract(base_file_name2, diff)); - EXPECT_EQUAL(default_source - diff, new_selector->getDefaultSource()); - EXPECT_EQUAL(base_id + diff, new_selector->getBaseId()); - EXPECT_EQUAL(maxDocId+1, new_selector->getDocIdLimit()); + auto new_selector(selector.cloneAndSubtract(base_file_name2, diff)); + EXPECT_EQ(default_source - diff, new_selector->getDefaultSource()); + EXPECT_EQ(base_id + diff, new_selector->getBaseId()); + EXPECT_EQ(maxDocId+1, new_selector->getDocIdLimit()); auto it(new_selector->createIterator()); for(size_t i = 0; i < arraysize(docs); ++i) { if (docs[i].source > diff) { - EXPECT_EQUAL(docs[i].source - diff, it->getSource(docs[i].docId)); + EXPECT_EQ(docs[i].source - diff, it->getSource(docs[i].docId)); } else { - EXPECT_EQUAL(0, it->getSource(docs[i].docId)); + EXPECT_EQ(0, it->getSource(docs[i].docId)); } } } void -Test::requireThatSelectorCanCloneAndSubtract() -{ - requireThatSelectorCanCloneAndSubtract<FixedSourceSelector>(); -} - -template <typename SelectorType> -void -Test::requireThatSelectorCanSaveAndLoad(bool compactLidSpace) +SourceSelectorTest::requireThatSelectorCanSaveAndLoad(bool compactLidSpace) { - SelectorType selector(default_source, base_file_name2); + SCOPED_TRACE(compactLidSpace ? "compactLidSpace=true" : "compactLidSpace=false"); + FixedSourceSelector selector(default_source, base_file_name2); setSources(selector); selector.setBaseId(base_id); selector.setSource(maxDocId + 1, default_source); @@ -167,105 +134,93 @@ Test::requireThatSelectorCanSaveAndLoad(bool compactLidSpace) SourceSelector::SaveInfo::UP save_info = selector.extractSaveInfo(base_file_name); save_info->save(TuneFileAttributes(), DummyFileHeaderContext()); - typename SelectorType::UP - selector2(SelectorType::load(base_file_name, default_source + base_id)); + auto selector2(FixedSourceSelector::load(base_file_name, default_source + base_id)); testSourceSelector(docs, arraysize(docs) - compactLidSpace, default_source, *selector2, true); - EXPECT_EQUAL(base_id, selector2->getBaseId()); + EXPECT_EQ(base_id, selector2->getBaseId()); if (compactLidSpace) { - EXPECT_EQUAL(maxDocId - 4, selector2->getDocIdLimit()); + EXPECT_EQ(maxDocId - 4, selector2->getDocIdLimit()); } else { - EXPECT_EQUAL(maxDocId + 2, selector2->getDocIdLimit()); + EXPECT_EQ(maxDocId + 2, selector2->getDocIdLimit()); } std::filesystem::remove_all(std::filesystem::path(index_dir)); } -void -Test::requireThatSelectorCanSaveAndLoad() +TEST_F(SourceSelectorTest, require_that_selector_can_save_and_Load) { - requireThatSelectorCanSaveAndLoad<FixedSourceSelector>(false); - requireThatSelectorCanSaveAndLoad<FixedSourceSelector>(true); + requireThatSelectorCanSaveAndLoad(false); + requireThatSelectorCanSaveAndLoad(true); } -template <typename SelectorType> -void -Test::requireThatCompleteSourceRangeIsHandled() +TEST_F(SourceSelectorTest, require_that_complete_source_range_is_handled) { - SelectorType selector(default_source, base_file_name); + FixedSourceSelector selector(default_source, base_file_name); for (uint32_t i = 0; i < ISourceSelector::SOURCE_LIMIT; ++i) { selector.setSource(i, i); } auto itr = selector.createIterator(); for (uint32_t i = 0; i < ISourceSelector::SOURCE_LIMIT; ++i) { - EXPECT_EQUAL((queryeval::Source)i, itr->getSource(i)); + EXPECT_EQ((queryeval::Source)i, itr->getSource(i)); } } -void -Test::requireThatCompleteSourceRangeIsHandled() -{ - requireThatCompleteSourceRangeIsHandled<FixedSourceSelector>(); -} - -template <typename SelectorType> -void -Test::requireThatSourcesAreCountedCorrectly() +TEST_F(SourceSelectorTest, require_that_sources_are_counted_correctly) { - SelectorType selector(default_source, base_file_name); + FixedSourceSelector selector(default_source, base_file_name); for (uint32_t i = 0; i < 256; ++i) { selector.setSource(i, i%16); } SourceSelector::Histogram hist = selector.getDistribution(); for (uint32_t i = 0; i < 16; ++i) { - EXPECT_EQUAL(16u, hist[i]); + EXPECT_EQ(16u, hist[i]); } for (uint32_t i = 16; i < 256; ++i) { - EXPECT_EQUAL(0u, hist[i]); + EXPECT_EQ(0u, hist[i]); } } -void -Test::requireThatSourcesAreCountedCorrectly() -{ - requireThatSourcesAreCountedCorrectly<FixedSourceSelector>(); -} - -void -Test::requireThatDocIdLimitIsCorrect() +TEST_F(SourceSelectorTest, require_that_doc_id_limit_is_correct) { FixedSourceSelector selector(default_source, base_file_name); - EXPECT_EQUAL(0u, selector.getDocIdLimit()); + EXPECT_EQ(0u, selector.getDocIdLimit()); selector.setSource(8, 10); - EXPECT_EQUAL(9u, selector.getDocIdLimit()); + EXPECT_EQ(9u, selector.getDocIdLimit()); selector.compactLidSpace(4); - EXPECT_EQUAL(4u, selector.getDocIdLimit()); + EXPECT_EQ(4u, selector.getDocIdLimit()); selector.setSource(6, 10); - EXPECT_EQUAL(7u, selector.getDocIdLimit()); + EXPECT_EQ(7u, selector.getDocIdLimit()); auto selector2 = selector.cloneAndSubtract(base_file_name2, 3); - EXPECT_EQUAL(7u, selector2->getDocIdLimit()); + EXPECT_EQ(7u, selector2->getDocIdLimit()); } -void -Test::requireThatCorrectDefaultValueIsUsedAfterCompaction() +TEST_F(SourceSelectorTest, require_that_correct_default_value_is_used_after_compaction) { FixedSourceSelector selector(default_source, base_file_name); - EXPECT_EQUAL(0u, selector.getDocIdLimit()); + EXPECT_EQ(0u, selector.getDocIdLimit()); auto it(selector.createIterator()); selector.setSource(8, 4); - EXPECT_EQUAL(default_source, (uint32_t) it->getSource(9)); - EXPECT_EQUAL(default_source, (uint32_t) it->getSource(6)); + EXPECT_EQ(default_source, (uint32_t) it->getSource(9)); + EXPECT_EQ(default_source, (uint32_t) it->getSource(6)); selector.compactLidSpace(4); - EXPECT_EQUAL(4u, selector.getDocIdLimit()); - EXPECT_EQUAL(default_source, (uint32_t) it->getSource(4)); - EXPECT_EQUAL(invalid_source, (uint32_t) it->getSource(5)); // beyond guard + EXPECT_EQ(4u, selector.getDocIdLimit()); + EXPECT_EQ(default_source, (uint32_t) it->getSource(4)); + EXPECT_EQ(invalid_source, (uint32_t) it->getSource(5)); // beyond guard selector.setSource(6, 4); - EXPECT_EQUAL(7u, selector.getDocIdLimit()); - EXPECT_EQUAL(default_source, (uint32_t) it->getSource(5)); - EXPECT_EQUAL(4u, (uint8_t) it->getSource(6)); - EXPECT_EQUAL(default_source, (uint32_t) it->getSource(7)); + EXPECT_EQ(7u, selector.getDocIdLimit()); + EXPECT_EQ(default_source, (uint32_t) it->getSource(5)); + EXPECT_EQ(4u, (uint8_t) it->getSource(6)); + EXPECT_EQ(default_source, (uint32_t) it->getSource(7)); } } // namespace -TEST_APPHOOK(Test); +int +main(int argc, char* argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + if (argc > 0) { + DummyFileHeaderContext::setCreator(argv[0]); + } + return RUN_ALL_TESTS(); +} diff --git a/searchlib/src/tests/diskindex/bitvector/CMakeLists.txt b/searchlib/src/tests/diskindex/bitvector/CMakeLists.txt index b227d3d5fa8..f70a1efd23c 100644 --- a/searchlib/src/tests/diskindex/bitvector/CMakeLists.txt +++ b/searchlib/src/tests/diskindex/bitvector/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_bitvector_test-diskindex_app TEST bitvector_test.cpp DEPENDS searchlib + GTest::gtest ) vespa_add_test(NAME searchlib_bitvector_test-diskindex_app COMMAND searchlib_bitvector_test-diskindex_app) diff --git a/searchlib/src/tests/diskindex/bitvector/bitvector_test.cpp b/searchlib/src/tests/diskindex/bitvector/bitvector_test.cpp index 6032b7156ff..5e4b8763534 100644 --- a/searchlib/src/tests/diskindex/bitvector/bitvector_test.cpp +++ b/searchlib/src/tests/diskindex/bitvector/bitvector_test.cpp @@ -1,16 +1,13 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/searchlib/index/field_length_info.h> #include <vespa/searchlib/diskindex/bitvectordictionary.h> #include <vespa/searchlib/diskindex/fieldwriter.h> #include <vespa/searchlib/index/dummyfileheadercontext.h> #include <vespa/searchcommon/common/schema.h> +#include <vespa/vespalib/gtest/gtest.h> #include <filesystem> -#include <vespa/log/log.h> -LOG_SETUP("bitvector_test"); - using namespace search::index; using search::index::schema::DataType; @@ -58,38 +55,57 @@ FieldWriterWrapper::add(uint32_t docId) daf.elements().emplace_back(0); daf.elements().back().setNumOccs(1); daf.word_positions().emplace_back(0); - //LOG(info, "add(%" PRIu64 ", %u)", wordNum, docId); _writer.add(daf); return *this; } -class Test : public vespalib::TestApp +struct TestParam { + bool directio; + bool readmmap; +}; + +std::ostream& operator<<(std::ostream& os, const TestParam& param) +{ + os << (param.directio ? "directio" : "normal") << (param.readmmap ? "mmap" : "read"); + return os; +} + +class BitVectorTest : public ::testing::TestWithParam<TestParam> { -private: +protected: Schema _schema; uint32_t _indexId; -public: - void requireThatDictionaryHandlesNoEntries(bool directio, bool readmmap); - void requireThatDictionaryHandlesMultipleEntries(bool directio, bool readmmap); - - Test(); - ~Test() override; - int Main() override; + BitVectorTest(); + ~BitVectorTest() override; }; -void -Test::requireThatDictionaryHandlesNoEntries(bool directio, bool readmmap) +BitVectorTest::BitVectorTest() + : ::testing::TestWithParam<TestParam>(), + _schema(), + _indexId(0) +{ + _schema.addIndexField(Schema::IndexField("f1", DataType::STRING)); +} + +BitVectorTest::~BitVectorTest() = default; + +INSTANTIATE_TEST_SUITE_P(BitVectorMultiTest, BitVectorTest, + ::testing::Values(TestParam{false, false}, TestParam{true, false}, TestParam{false, true}), + ::testing::PrintToStringParamName()); + +TEST_P(BitVectorTest, require_that_dictionary_handles_no_entries) { TuneFileSeqWrite tuneFileWrite; TuneFileRandRead tuneFileRead; DummyFileHeaderContext fileHeaderContext; - if (directio) { + if (GetParam().directio) { tuneFileWrite.setWantDirectIO(); tuneFileRead.setWantDirectIO(); } - if (readmmap) + if (GetParam().readmmap) { tuneFileRead.setWantMemoryMap(); + } std::filesystem::create_directory(std::filesystem::path("dump")); FieldWriterWrapper fww(5, 2, "dump/1/"); EXPECT_TRUE(fww.open(_schema, _indexId, tuneFileWrite, fileHeaderContext)); @@ -100,25 +116,25 @@ Test::requireThatDictionaryHandlesNoEntries(bool directio, bool readmmap) BitVectorDictionary dict; BitVectorKeyScope bvScope(BitVectorKeyScope::PERFIELD_WORDS); EXPECT_TRUE(dict.open("dump/1/", tuneFileRead, bvScope)); - EXPECT_EQUAL(5u, dict.getDocIdLimit()); - EXPECT_EQUAL(0u, dict.getEntries().size()); + EXPECT_EQ(5u, dict.getDocIdLimit()); + EXPECT_EQ(0u, dict.getEntries().size()); EXPECT_FALSE(dict.lookup(1)); EXPECT_FALSE(dict.lookup(2)); } -void -Test::requireThatDictionaryHandlesMultipleEntries(bool directio, bool readmmap) +TEST_P(BitVectorTest, require_that_dictionary_handles_multiple_entries) { TuneFileSeqWrite tuneFileWrite; TuneFileRandRead tuneFileRead; DummyFileHeaderContext fileHeaderContext; - if (directio) { + if (GetParam().directio) { tuneFileWrite.setWantDirectIO(); tuneFileRead.setWantDirectIO(); } - if (readmmap) + if (GetParam().readmmap) { tuneFileRead.setWantMemoryMap(); + } FieldWriterWrapper fww(64, 6, "dump/2/"); EXPECT_TRUE(fww.open(_schema, _indexId, tuneFileWrite, fileHeaderContext)); // must have >16 docs in order to create bitvector for a word @@ -149,16 +165,16 @@ Test::requireThatDictionaryHandlesMultipleEntries(bool directio, bool readmmap) BitVectorDictionary dict; BitVectorKeyScope bvScope(BitVectorKeyScope::PERFIELD_WORDS); EXPECT_TRUE(dict.open("dump/2/", tuneFileRead, bvScope)); - EXPECT_EQUAL(64u, dict.getDocIdLimit()); - EXPECT_EQUAL(2u, dict.getEntries().size()); + EXPECT_EQ(64u, dict.getDocIdLimit()); + EXPECT_EQ(2u, dict.getEntries().size()); BitVectorWordSingleKey e; e = dict.getEntries()[0]; - EXPECT_EQUAL(1u, e._wordNum); - EXPECT_EQUAL(17u, e._numDocs); + EXPECT_EQ(1u, e._wordNum); + EXPECT_EQ(17u, e._numDocs); e = dict.getEntries()[1]; - EXPECT_EQUAL(5u, e._wordNum); - EXPECT_EQUAL(23u, e._numDocs); + EXPECT_EQ(5u, e._wordNum); + EXPECT_EQ(23u, e._numDocs); EXPECT_FALSE(dict.lookup(2)); EXPECT_FALSE(dict.lookup(3)); @@ -174,33 +190,14 @@ Test::requireThatDictionaryHandlesMultipleEntries(bool directio, bool readmmap) EXPECT_TRUE(*bv5exp == *bv5act); } -Test::Test() - : _schema(), - _indexId(0) -{ - _schema.addIndexField(Schema::IndexField("f1", DataType::STRING)); } -Test::~Test() = default; - int -Test::Main() +main(int argc, char* argv[]) { - TEST_INIT("bitvector_test"); - - if (_argc > 0) { - DummyFileHeaderContext::setCreator(_argv[0]); + ::testing::InitGoogleTest(&argc, argv); + if (argc > 0) { + search::index::DummyFileHeaderContext::setCreator(argv[0]); } - TEST_DO(requireThatDictionaryHandlesNoEntries(false, false)); - TEST_DO(requireThatDictionaryHandlesMultipleEntries(false, false)); - TEST_DO(requireThatDictionaryHandlesNoEntries(true, false)); - TEST_DO(requireThatDictionaryHandlesMultipleEntries(true, false)); - TEST_DO(requireThatDictionaryHandlesNoEntries(false, true)); - TEST_DO(requireThatDictionaryHandlesMultipleEntries(false, true)); - - TEST_DONE(); + return RUN_ALL_TESTS(); } - -} - -TEST_APPHOOK(search::diskindex::Test); diff --git a/searchlib/src/tests/expression/interpolated_document_field_lookup_node/CMakeLists.txt b/searchlib/src/tests/expression/interpolated_document_field_lookup_node/CMakeLists.txt new file mode 100644 index 00000000000..267848d9468 --- /dev/null +++ b/searchlib/src/tests/expression/interpolated_document_field_lookup_node/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(searchlib_interpolated_document_field_lookup_node_test_app + SOURCES + interpolated_document_field_lookup_node_test.cpp + DEPENDS + searchlib_test +) +vespa_add_test(NAME searchlib_interpolated_document_field_lookup_node_test_app COMMAND searchlib_interpolated_document_field_lookup_node_test_app) diff --git a/searchlib/src/tests/expression/interpolated_document_field_lookup_node/interpolated_document_field_lookup_node_test.cpp b/searchlib/src/tests/expression/interpolated_document_field_lookup_node/interpolated_document_field_lookup_node_test.cpp new file mode 100644 index 00000000000..c131efcacb2 --- /dev/null +++ b/searchlib/src/tests/expression/interpolated_document_field_lookup_node/interpolated_document_field_lookup_node_test.cpp @@ -0,0 +1,98 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/document/fieldvalue/arrayfieldvalue.h> +#include <vespa/document/fieldvalue/document.h> +#include <vespa/document/fieldvalue/doublefieldvalue.h> +#include <vespa/document/repo/configbuilder.h> +#include <vespa/searchlib/expression/constantnode.h> +#include <vespa/searchlib/expression/floatresultnode.h> +#include <vespa/searchlib/expression/interpolated_document_field_lookup_node.h> +#include <vespa/searchlib/test/doc_builder.h> +#include <vespa/vespalib/gtest/gtest.h> + +using document::DataType; +using document::Document; +using document::DoubleFieldValue; +using search::expression::ConstantNode; +using search::expression::DocumentAccessorNode; +using search::expression::FloatResultNode; +using search::expression::InterpolatedDocumentFieldLookupNode; +using search::test::DocBuilder; + +const vespalib::string field_name("f"); + +struct Fixture { + DocBuilder _builder; + std::unique_ptr<Document> _doc; + std::unique_ptr<DocumentAccessorNode> _node; + + Fixture(); + ~Fixture(); + + Fixture& setup_doc(std::vector<double> field_value); + Fixture& setup_node(double lookup_value); + double evaluate(); +}; + +Fixture::Fixture() + : _builder([](auto& header) + { header.addField(field_name, document::config_builder::Array(DataType::T_DOUBLE)); }), + _doc(_builder.make_document("id:ns:searchdocument::0")), + _node() +{ +} + +Fixture::~Fixture() = default; + + +Fixture& +Fixture::setup_doc(std::vector<double> field_value) +{ + auto array = _builder.make_array(field_name); + for (auto& v : field_value) { + array.add(DoubleFieldValue(v)); + } + _doc->setValue(field_name, array); + return *this; +} + +Fixture& +Fixture::setup_node(double lookup_value) +{ + _node = std::make_unique<InterpolatedDocumentFieldLookupNode>(field_name, std::make_unique<ConstantNode>(std::make_unique<FloatResultNode>(lookup_value))); + _node->prepare(true); + _node->setDocType(_doc->getType()); + _node->setDoc(*_doc); + return *this; +} + +double +Fixture::evaluate() +{ + EXPECT_TRUE(_node->execute()); + return _node->getResult()->getFloat(); +} + + +class InterpolatedDocumentFieldLookupNodeTest : public Fixture, + public ::testing::Test +{ +protected: + InterpolatedDocumentFieldLookupNodeTest(); + ~InterpolatedDocumentFieldLookupNodeTest() override; +}; + +InterpolatedDocumentFieldLookupNodeTest::InterpolatedDocumentFieldLookupNodeTest() = default; +InterpolatedDocumentFieldLookupNodeTest::~InterpolatedDocumentFieldLookupNodeTest() = default; + +TEST_F(InterpolatedDocumentFieldLookupNodeTest, test_interpolated_lookup_in_document_field) +{ + EXPECT_EQ(0.0, setup_doc({ 2, 10 }).setup_node(1.0).evaluate()); + EXPECT_EQ(0.0, setup_node(2.0).evaluate()); + EXPECT_EQ(0.3125, setup_node(4.5).evaluate()); + EXPECT_EQ(1.0, setup_node(10).evaluate()); + EXPECT_EQ(1.0, setup_node(11).evaluate()); + EXPECT_EQ(2.5, setup_doc({1.5, 5.25, 8.0, 14.0 }).evaluate()); +} + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/fef/attributecontent/CMakeLists.txt b/searchlib/src/tests/fef/attributecontent/CMakeLists.txt index 48d8375dbb9..d9c88fb9eaf 100644 --- a/searchlib/src/tests/fef/attributecontent/CMakeLists.txt +++ b/searchlib/src/tests/fef/attributecontent/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_attributecontent_test_app TEST attributecontent_test.cpp DEPENDS searchlib + GTest::gtest ) vespa_add_test(NAME searchlib_attributecontent_test_app COMMAND searchlib_attributecontent_test_app) diff --git a/searchlib/src/tests/fef/attributecontent/attributecontent_test.cpp b/searchlib/src/tests/fef/attributecontent/attributecontent_test.cpp index 1c75d47a134..d501d259ea5 100644 --- a/searchlib/src/tests/fef/attributecontent/attributecontent_test.cpp +++ b/searchlib/src/tests/fef/attributecontent/attributecontent_test.cpp @@ -1,34 +1,21 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/searchcommon/attribute/attributecontent.h> #include <vespa/searchcommon/attribute/config.h> #include <vespa/searchlib/attribute/attributefactory.h> #include <vespa/searchlib/attribute/integerbase.h> -#include <vespa/log/log.h> -LOG_SETUP("attributecontent_test"); +#include <vespa/vespalib/gtest/gtest.h> using namespace search::attribute; -namespace search { -namespace fef { +namespace search::fef { -class Test : public vespalib::TestApp { -private: - void testWriteAndRead(); - void testFill(); - -public: - int Main() override; -}; - -void -Test::testWriteAndRead() +TEST(AttributeContentTest, test_write_and_read) { using UintContent = search::attribute::AttributeContent<uint32_t>; UintContent buf; - EXPECT_EQUAL(buf.capacity(), 16u); - EXPECT_EQUAL(buf.size(), 0u); + EXPECT_EQ(buf.capacity(), 16u); + EXPECT_EQ(buf.size(), 0u); uint32_t i; uint32_t * data; @@ -37,34 +24,33 @@ Test::testWriteAndRead() *data = i; } buf.setSize(16); - EXPECT_EQUAL(buf.size(), 16u); + EXPECT_EQ(buf.size(), 16u); for (i = 0, itr = buf.begin(); itr != buf.end(); ++i, ++itr) { - EXPECT_EQUAL(*itr, i); - EXPECT_EQUAL(buf[i], i); + EXPECT_EQ(*itr, i); + EXPECT_EQ(buf[i], i); } - EXPECT_EQUAL(i, 16u); + EXPECT_EQ(i, 16u); buf.allocate(10); - EXPECT_EQUAL(buf.capacity(), 16u); - EXPECT_EQUAL(buf.size(), 16u); + EXPECT_EQ(buf.capacity(), 16u); + EXPECT_EQ(buf.size(), 16u); buf.allocate(32); - EXPECT_EQUAL(buf.capacity(), 32u); - EXPECT_EQUAL(buf.size(), 0u); + EXPECT_EQ(buf.capacity(), 32u); + EXPECT_EQ(buf.size(), 0u); for (i = 0, data = buf.data(); i < 32; ++i, ++data) { *data = i; } buf.setSize(32); - EXPECT_EQUAL(buf.size(), 32u); + EXPECT_EQ(buf.size(), 32u); for (i = 0, itr = buf.begin(); itr != buf.end(); ++i, ++itr) { - EXPECT_EQUAL(*itr, i); - EXPECT_EQUAL(buf[i], i); + EXPECT_EQ(*itr, i); + EXPECT_EQ(buf[i], i); } - EXPECT_EQUAL(i, 32u); + EXPECT_EQ(i, 32u); } -void -Test::testFill() +TEST(AttributeContentTest, test_fill) { Config cfg(BasicType::INT32, CollectionType::ARRAY); AttributeVector::SP av = AttributeFactory::createAttribute("aint32", cfg); @@ -77,29 +63,17 @@ Test::testFill() const IAttributeVector & iav = *av.get(); IntegerContent buf; buf.fill(iav, 0); - EXPECT_EQUAL(1u, buf.size()); - EXPECT_EQUAL(10, buf[0]); + EXPECT_EQ(1u, buf.size()); + EXPECT_EQ(10, buf[0]); buf.fill(iav, 1); - EXPECT_EQUAL(2u, buf.size()); - EXPECT_EQUAL(20, buf[0]); - EXPECT_EQUAL(30, buf[1]); + EXPECT_EQ(2u, buf.size()); + EXPECT_EQ(20, buf[0]); + EXPECT_EQ(30, buf[1]); buf.fill(iav, 0); - EXPECT_EQUAL(1u, buf.size()); - EXPECT_EQUAL(10, buf[0]); + EXPECT_EQ(1u, buf.size()); + EXPECT_EQ(10, buf[0]); } -int -Test::Main() -{ - TEST_INIT("attributecontent_test"); - - testWriteAndRead(); - testFill(); - - TEST_DONE(); } -} // namespace fef -} // namespace search - -TEST_APPHOOK(search::fef::Test); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/fef/featurenameparser/CMakeLists.txt b/searchlib/src/tests/fef/featurenameparser/CMakeLists.txt index e7874558122..cb040472a6f 100644 --- a/searchlib/src/tests/fef/featurenameparser/CMakeLists.txt +++ b/searchlib/src/tests/fef/featurenameparser/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_featurenameparser_test_app TEST featurenameparser_test.cpp DEPENDS searchlib + GTest::gtest ) vespa_add_test(NAME searchlib_featurenameparser_test_app COMMAND searchlib_featurenameparser_test_app) diff --git a/searchlib/src/tests/fef/featurenameparser/featurenameparser_test.cpp b/searchlib/src/tests/fef/featurenameparser/featurenameparser_test.cpp index 90a9135389a..ee22a49f8db 100644 --- a/searchlib/src/tests/fef/featurenameparser/featurenameparser_test.cpp +++ b/searchlib/src/tests/fef/featurenameparser/featurenameparser_test.cpp @@ -1,13 +1,15 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/log/log.h> -LOG_SETUP("featurenameparser_test"); -#include <vespa/vespalib/testkit/test_kit.h> -#include <vespa/vespalib/testkit/testapp.h> -#include <vespa/vespalib/util/size_literals.h> + #include <vespa/searchlib/fef/featurenameparser.h> +#include <vespa/vespalib/gtest/gtest.h> +#include <vespa/vespalib/testkit/test_path.h> +#include <vespa/vespalib/util/size_literals.h> #include <vector> #include <string> +#include <vespa/log/log.h> +LOG_SETUP("featurenameparser_test"); + using namespace search::fef; struct ParamList { @@ -31,20 +33,10 @@ std::ostream &operator<<(std::ostream &os, const ParamList &pl) { return os; } -class Test : public vespalib::TestApp -{ -public: - bool testParse(const vespalib::string &input, bool valid, - const vespalib::string &base, ParamList pl, - const vespalib::string &output); - void testFile(const vespalib::string &name); - int Main() override; -}; - bool -Test::testParse(const vespalib::string &input, bool valid, - const vespalib::string &base, ParamList pl, - const vespalib::string &output) +testParse(const vespalib::string &input, bool valid, + const vespalib::string &base, ParamList pl, + const vespalib::string &output) { bool ok = true; FeatureNameParser parser(input); @@ -52,15 +44,15 @@ Test::testParse(const vespalib::string &input, bool valid, LOG(warning, "parse error: input:'%s', rest:'%s'", input.c_str(), input.substr(parser.parsedBytes()).c_str()); } - ok &= EXPECT_EQUAL(parser.valid(), valid); - ok &= EXPECT_EQUAL(parser.baseName(), base); - ok &= EXPECT_EQUAL(ParamList(parser.parameters()), pl); - ok &= EXPECT_EQUAL(parser.output(), output); + EXPECT_EQ(parser.valid(), valid) << (ok = false, ""); + EXPECT_EQ(parser.baseName(), base) << (ok = false, ""); + EXPECT_EQ(ParamList(parser.parameters()), pl) << (ok = false, ""); + EXPECT_EQ(parser.output(), output) << (ok = false, ""); return ok; } void -Test::testFile(const vespalib::string &name) +testFile(const vespalib::string &name) { char buf[4_Ki]; uint32_t lineN = 0; @@ -76,13 +68,16 @@ Test::testFile(const vespalib::string &name) continue; } uint32_t idx = line.find("<=>"); - if (!EXPECT_TRUE(idx < line.size())) { + bool failed = false; + EXPECT_TRUE(idx < line.size()) << (failed = true, ""); + if (failed) { LOG(error, "(%s:%u): malformed line: '%s'", name.c_str(), lineN, line.c_str()); } else { vespalib::string input = line.substr(0, idx); vespalib::string expect = line.substr(idx + strlen("<=>")); - if (!EXPECT_EQUAL(FeatureNameParser(input).featureName(), expect)) { + EXPECT_EQ(FeatureNameParser(input).featureName(), expect) << (failed = true, ""); + if (failed) { LOG(error, "(%s:%u): test failed: '%s'", name.c_str(), lineN, line.c_str()); } @@ -92,42 +87,54 @@ Test::testFile(const vespalib::string &name) fclose(f); } -int -Test::Main() +TEST(FeatureNameParserTest, test_normal_cases) { - TEST_INIT("featurenameparser_test"); - // normal cases EXPECT_TRUE(testParse("foo", true, "foo", ParamList(), "")); EXPECT_TRUE(testParse("foo.out", true, "foo", ParamList(), "out")); EXPECT_TRUE(testParse("foo(a)", true, "foo", ParamList().add("a"), "")); EXPECT_TRUE(testParse("foo(a,b)", true, "foo", ParamList().add("a").add("b"), "")); EXPECT_TRUE(testParse("foo(a,b).out", true, "foo", ParamList().add("a").add("b"), "out")); +} +TEST(FeatureNameParserTest, test_0_in_feature_name) +{ // @ in feature name (for macros) EXPECT_TRUE(testParse("foo@", true, "foo@", ParamList(), "")); EXPECT_TRUE(testParse("foo@.out", true, "foo@", ParamList(), "out")); EXPECT_TRUE(testParse("foo@(a)", true, "foo@", ParamList().add("a"), "")); EXPECT_TRUE(testParse("foo@(a,b)", true, "foo@", ParamList().add("a").add("b"), "")); EXPECT_TRUE(testParse("foo@(a,b).out", true, "foo@", ParamList().add("a").add("b"), "out")); +} +TEST(FeatureNameParserTest, test_dollar_in_feature_name) +{ // $ in feature name (for macros) EXPECT_TRUE(testParse("foo$", true, "foo$", ParamList(), "")); EXPECT_TRUE(testParse("foo$.out", true, "foo$", ParamList(), "out")); EXPECT_TRUE(testParse("foo$(a)", true, "foo$", ParamList().add("a"), "")); EXPECT_TRUE(testParse("foo$(a,b)", true, "foo$", ParamList().add("a").add("b"), "")); EXPECT_TRUE(testParse("foo$(a,b).out", true, "foo$", ParamList().add("a").add("b"), "out")); +} +TEST(FeatureNameParserTest, test_de_quoting_of_parameters) +{ // de-quoting of parameters EXPECT_TRUE(testParse("foo(a,\"b\")", true, "foo", ParamList().add("a").add("b"), "")); EXPECT_TRUE(testParse("foo(a,\" b \")", true, "foo", ParamList().add("a").add(" b "), "")); EXPECT_TRUE(testParse("foo( \"a\" , \" b \" )", true, "foo", ParamList().add("a").add(" b "), "")); EXPECT_TRUE(testParse("foo(\"\\\"\\\\\\t\\n\\r\\f\\x20\")", true, "foo", ParamList().add("\"\\\t\n\r\f "), "")); +} +TEST(FeatureNameParserTest, test_no_default_output_when_ending_with_dot) +{ // only default output if '.' not specified EXPECT_TRUE(testParse("foo.", false, "", ParamList(), "")); EXPECT_TRUE(testParse("foo(a,b).", false, "", ParamList(), "")); +} +TEST(FeatureNameParserTest, test_string_cannot_end_in_parmeter_list) +{ // string cannot end in parameter list EXPECT_TRUE(testParse("foo(", false, "", ParamList(), "")); EXPECT_TRUE(testParse("foo(a", false, "", ParamList(), "")); @@ -135,7 +142,10 @@ Test::Main() EXPECT_TRUE(testParse("foo(a\\)", false, "", ParamList(), "")); EXPECT_TRUE(testParse("foo(a,", false, "", ParamList(), "")); EXPECT_TRUE(testParse("foo(a,b", false, "", ParamList(), "")); +} +TEST(FeatureNameParserTest, test_empty_parameters) +{ // empty parameters EXPECT_TRUE(testParse("foo()", true, "foo", ParamList().add(""), "")); EXPECT_TRUE(testParse("foo(,)", true, "foo", ParamList().add("").add(""), "")); @@ -144,9 +154,11 @@ Test::Main() EXPECT_TRUE(testParse("foo( )", true, "foo", ParamList().add(""), "")); EXPECT_TRUE(testParse("foo( , , )", true, "foo", ParamList().add("").add("").add(""), "")); EXPECT_TRUE(testParse("foo( \t , \n , \r , \f )", true, "foo", ParamList().add("").add("").add("").add(""), "")); +} +TEST(FeatureNameParserTest, test_cases_from_file) +{ testFile(TEST_PATH("parsetest.txt")); - TEST_DONE(); } -TEST_APPHOOK(Test); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/fef/parameter/CMakeLists.txt b/searchlib/src/tests/fef/parameter/CMakeLists.txt index da847e061f9..b238e09c98b 100644 --- a/searchlib/src/tests/fef/parameter/CMakeLists.txt +++ b/searchlib/src/tests/fef/parameter/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_parameter_test_app TEST parameter_test.cpp DEPENDS searchlib + GTest::gtest ) vespa_add_test(NAME searchlib_parameter_test_app NO_VALGRIND COMMAND searchlib_parameter_test_app) diff --git a/searchlib/src/tests/fef/parameter/parameter_test.cpp b/searchlib/src/tests/fef/parameter/parameter_test.cpp index fa29f16f1d5..a8acd2ea34d 100644 --- a/searchlib/src/tests/fef/parameter/parameter_test.cpp +++ b/searchlib/src/tests/fef/parameter/parameter_test.cpp @@ -1,32 +1,34 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/log/log.h> -LOG_SETUP("parameter_test"); -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/searchlib/fef/parametervalidator.h> #include <vespa/searchlib/fef/test/indexenvironment.h> #include <vespa/searchlib/fef/test/indexenvironmentbuilder.h> +#include <vespa/vespalib/gtest/gtest.h> + +#include <vespa/log/log.h> +LOG_SETUP("parameter_test"); using namespace search::fef::test; using CollectionType = search::fef::FieldInfo::CollectionType; using DataType = search::fef::FieldInfo::DataType; -namespace search { -namespace fef { +namespace search::fef { class StringList : public std::vector<vespalib::string> { public: StringList & add(const vespalib::string & str) { push_back(str); return *this; } }; -class ParameterTest : public vespalib::TestApp { -private: +class ParameterTest : public ::testing::Test { +protected: using PDS = ParameterDescriptions; using PT = ParameterType; using P = Parameter; using SL = StringList; using PVR = ParameterValidator::Result; + ParameterTest(); + ~ParameterTest() override; bool assertParameter(const Parameter & exp, const Parameter & act); bool validate(const IIndexEnvironment & env, const std::vector<vespalib::string> & params, @@ -35,24 +37,20 @@ private: const std::vector<vespalib::string> & params, const ParameterDescriptions & descs, const ParameterValidator::Result & result); - - void testDescriptions(); - void testValidator(); - void testParameters(); - -public: - int Main() override; }; +ParameterTest::ParameterTest() = default; +ParameterTest::~ParameterTest() = default; + bool ParameterTest::assertParameter(const Parameter & exp, const Parameter & act) { bool retval = true; - if (!EXPECT_EQUAL(exp.getType(), act.getType())) retval = false; - if (!EXPECT_EQUAL(exp.getValue(), act.getValue())) retval = false; - if (!EXPECT_EQUAL(exp.asDouble(), act.asDouble())) retval = false; - if (!EXPECT_EQUAL(exp.asInteger(), act.asInteger())) retval = false; - if (!EXPECT_EQUAL(exp.asField(), act.asField())) retval = false; + EXPECT_EQ(exp.getType(), act.getType()) << (retval = false, ""); + EXPECT_EQ(exp.getValue(), act.getValue()) << (retval = false, ""); + EXPECT_EQ(exp.asDouble(), act.asDouble()) << (retval = false, ""); + EXPECT_EQ(exp.asInteger(), act.asInteger()) << (retval = false, ""); + EXPECT_EQ(exp.asField(), act.asField()) << (retval = false, ""); return retval; } @@ -76,8 +74,15 @@ ParameterTest::validate(const IIndexEnvironment & env, if (!validate(env, params, descs)) return false; ParameterValidator pv(env, params, descs); ParameterValidator::Result actual = pv.validate(); - if (!EXPECT_EQUAL(result.getTag(), actual.getTag())) return false; - if (!EXPECT_EQUAL(result.getParameters().size(), actual.getParameters().size())) return false; + bool failed = false; + EXPECT_EQ(result.getTag(), actual.getTag()) << (failed = true, ""); + if (failed) { + return false; + } + EXPECT_EQ(result.getParameters().size(), actual.getParameters().size()) << (failed = true, ""); + if (failed) { + return false; + } bool retval = true; for (size_t i = 0; i < result.getParameters().size(); ++i) { if (!assertParameter(result.getParameters()[i], actual.getParameters()[i])) retval = false; @@ -85,52 +90,50 @@ ParameterTest::validate(const IIndexEnvironment & env, return retval; } -void -ParameterTest::testDescriptions() +TEST_F(ParameterTest, test_descriptions) { PDS descs = PDS(). desc().indexField(ParameterCollection::SINGLE).indexField(ParameterCollection::ARRAY).indexField(ParameterCollection::WEIGHTEDSET).attribute(ParameterCollection::ANY).attributeField(ParameterCollection::ANY).field(). desc(5).feature().number().string().attribute(ParameterCollection::ANY). desc().string().number().repeat(2); const PDS::DescriptionVector & v = descs.getDescriptions(); - EXPECT_EQUAL(v.size(), 3u); - EXPECT_EQUAL(v[0].getTag(), 0u); + EXPECT_EQ(v.size(), 3u); + EXPECT_EQ(v[0].getTag(), 0u); EXPECT_TRUE(!v[0].hasRepeat()); - EXPECT_EQUAL(v[0].getParams().size(), 6u); - EXPECT_EQUAL(v[0].getParam(0).type, ParameterType::INDEX_FIELD); - EXPECT_EQUAL(v[0].getParam(1).type, ParameterType::INDEX_FIELD); - EXPECT_EQUAL(v[0].getParam(2).type, ParameterType::INDEX_FIELD); - EXPECT_EQUAL(v[0].getParam(3).type, ParameterType::ATTRIBUTE); - EXPECT_EQUAL(v[0].getParam(4).type, ParameterType::ATTRIBUTE_FIELD); - EXPECT_EQUAL(v[0].getParam(5).type, ParameterType::FIELD); - EXPECT_EQUAL(v[0].getParam(0).collection, ParameterCollection::SINGLE); - EXPECT_EQUAL(v[0].getParam(1).collection, ParameterCollection::ARRAY); - EXPECT_EQUAL(v[0].getParam(2).collection, ParameterCollection::WEIGHTEDSET); - EXPECT_EQUAL(v[0].getParam(3).collection, ParameterCollection::ANY); - EXPECT_EQUAL(v[0].getParam(4).collection, ParameterCollection::ANY); - EXPECT_EQUAL(v[0].getParam(5).collection, ParameterCollection::ANY); + EXPECT_EQ(v[0].getParams().size(), 6u); + EXPECT_EQ(v[0].getParam(0).type, ParameterType::INDEX_FIELD); + EXPECT_EQ(v[0].getParam(1).type, ParameterType::INDEX_FIELD); + EXPECT_EQ(v[0].getParam(2).type, ParameterType::INDEX_FIELD); + EXPECT_EQ(v[0].getParam(3).type, ParameterType::ATTRIBUTE); + EXPECT_EQ(v[0].getParam(4).type, ParameterType::ATTRIBUTE_FIELD); + EXPECT_EQ(v[0].getParam(5).type, ParameterType::FIELD); + EXPECT_EQ(v[0].getParam(0).collection, ParameterCollection::SINGLE); + EXPECT_EQ(v[0].getParam(1).collection, ParameterCollection::ARRAY); + EXPECT_EQ(v[0].getParam(2).collection, ParameterCollection::WEIGHTEDSET); + EXPECT_EQ(v[0].getParam(3).collection, ParameterCollection::ANY); + EXPECT_EQ(v[0].getParam(4).collection, ParameterCollection::ANY); + EXPECT_EQ(v[0].getParam(5).collection, ParameterCollection::ANY); - EXPECT_EQUAL(v[1].getTag(), 5u); + EXPECT_EQ(v[1].getTag(), 5u); EXPECT_TRUE(!v[1].hasRepeat()); - EXPECT_EQUAL(v[1].getParams().size(), 4u); - EXPECT_EQUAL(v[1].getParam(0).type, ParameterType::FEATURE); - EXPECT_EQUAL(v[1].getParam(1).type, ParameterType::NUMBER); - EXPECT_EQUAL(v[1].getParam(2).type, ParameterType::STRING); - EXPECT_EQUAL(v[1].getParam(3).type, ParameterType::ATTRIBUTE); + EXPECT_EQ(v[1].getParams().size(), 4u); + EXPECT_EQ(v[1].getParam(0).type, ParameterType::FEATURE); + EXPECT_EQ(v[1].getParam(1).type, ParameterType::NUMBER); + EXPECT_EQ(v[1].getParam(2).type, ParameterType::STRING); + EXPECT_EQ(v[1].getParam(3).type, ParameterType::ATTRIBUTE); - EXPECT_EQUAL(v[2].getTag(), 6u); + EXPECT_EQ(v[2].getTag(), 6u); EXPECT_TRUE(v[2].hasRepeat()); - EXPECT_EQUAL(v[2].getParams().size(), 2u); - EXPECT_EQUAL(v[2].getParam(0).type, ParameterType::STRING); - EXPECT_EQUAL(v[2].getParam(1).type, ParameterType::NUMBER); - EXPECT_EQUAL(v[2].getParam(2).type, ParameterType::STRING); - EXPECT_EQUAL(v[2].getParam(3).type, ParameterType::NUMBER); - EXPECT_EQUAL(v[2].getParam(4).type, ParameterType::STRING); - EXPECT_EQUAL(v[2].getParam(5).type, ParameterType::NUMBER); + EXPECT_EQ(v[2].getParams().size(), 2u); + EXPECT_EQ(v[2].getParam(0).type, ParameterType::STRING); + EXPECT_EQ(v[2].getParam(1).type, ParameterType::NUMBER); + EXPECT_EQ(v[2].getParam(2).type, ParameterType::STRING); + EXPECT_EQ(v[2].getParam(3).type, ParameterType::NUMBER); + EXPECT_EQ(v[2].getParam(4).type, ParameterType::STRING); + EXPECT_EQ(v[2].getParam(5).type, ParameterType::NUMBER); } -void -ParameterTest::testValidator() +TEST_F(ParameterTest, test_validator) { IndexEnvironment env; IndexEnvironmentBuilder builder(env); @@ -201,8 +204,7 @@ ParameterTest::testValidator() EXPECT_TRUE(!validate(env, SL().add("str").add("bar").add("foo").add("bar"), d2)); } -void -ParameterTest::testParameters() +TEST_F(ParameterTest, test_parameters) { IndexEnvironment env; IndexEnvironmentBuilder builder(env); @@ -254,20 +256,6 @@ ParameterTest::testParameters() PVR(20).addParameter(P(PT::STRING, "baz")))); // second desc matching } -int -ParameterTest::Main() -{ - TEST_INIT("parameter_test"); - - testDescriptions(); - testValidator(); - testParameters(); - - TEST_DONE(); } -} -} - -TEST_APPHOOK(search::fef::ParameterTest); - +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/fef/phrasesplitter/CMakeLists.txt b/searchlib/src/tests/fef/phrasesplitter/CMakeLists.txt index 95f6eaad705..8f3946d110c 100644 --- a/searchlib/src/tests/fef/phrasesplitter/CMakeLists.txt +++ b/searchlib/src/tests/fef/phrasesplitter/CMakeLists.txt @@ -4,6 +4,7 @@ vespa_add_executable(searchlib_phrasesplitter_test_app TEST phrasesplitter_test.cpp DEPENDS searchlib + GTest::gtest ) vespa_add_test(NAME searchlib_phrasesplitter_test_app COMMAND searchlib_phrasesplitter_test_app) vespa_add_executable(searchlib_benchmark_app diff --git a/searchlib/src/tests/fef/phrasesplitter/phrasesplitter_test.cpp b/searchlib/src/tests/fef/phrasesplitter/phrasesplitter_test.cpp index c4767c571b9..f4b3c878a06 100644 --- a/searchlib/src/tests/fef/phrasesplitter/phrasesplitter_test.cpp +++ b/searchlib/src/tests/fef/phrasesplitter/phrasesplitter_test.cpp @@ -1,41 +1,25 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/log/log.h> -LOG_SETUP("phrasesplitter_test"); -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/searchlib/fef/matchdatalayout.h> #include <vespa/searchlib/fef/phrasesplitter.h> #include <vespa/searchlib/fef/phrase_splitter_query_env.h> #include <vespa/searchlib/fef/test/queryenvironment.h> +#include <vespa/vespalib/gtest/gtest.h> -namespace search { -namespace fef { - -class PhraseSplitterTest : public vespalib::TestApp -{ -private: - void assertTermData(const ITermData * td, uint32_t uniqueId, uint32_t numTerms, - uint32_t fieldId, uint32_t termHandle); - void testCopyTermFieldMatchData(); - void testSplitter(); - void testSplitterUpdate(); - -public: - int Main() override; -}; +namespace search::fef { void -PhraseSplitterTest::assertTermData(const ITermData *td, uint32_t uniqueId, uint32_t numTerms, - uint32_t fieldId, uint32_t tfHandle) +assertTermData(const ITermData *td, uint32_t uniqueId, uint32_t numTerms, + uint32_t fieldId, uint32_t tfHandle, const vespalib::string& label) { + SCOPED_TRACE(label); // fprintf(stderr, "checking uid=%d numterms=%d field=%d handle=%d\n", uniqueId, numTerms, fieldId, tfHandle); - EXPECT_EQUAL(uniqueId, td->getUniqueId()); - EXPECT_EQUAL(numTerms, td->getPhraseLength()); - EXPECT_EQUAL(tfHandle, td->lookupField(fieldId)->getHandle()); + EXPECT_EQ(uniqueId, td->getUniqueId()); + EXPECT_EQ(numTerms, td->getPhraseLength()); + EXPECT_EQ(tfHandle, td->lookupField(fieldId)->getHandle()); } -void -PhraseSplitterTest::testCopyTermFieldMatchData() +TEST(PhraseSplitterTest, test_copy_term_field_match_data) { TermFieldMatchData src; src.reset(1); @@ -49,34 +33,33 @@ PhraseSplitterTest::testCopyTermFieldMatchData() dst.appendPosition(TermFieldMatchDataPosition(0, 10, 0, 1000)); { FieldPositionsIterator itr = dst.getIterator(); - EXPECT_EQUAL(itr.getPosition(), 10u); + EXPECT_EQ(itr.getPosition(), 10u); itr.next(); ASSERT_TRUE(!itr.valid()); } PhraseSplitter::copyTermFieldMatchData(dst, src, 2); - EXPECT_EQUAL(dst.getDocId(), 1u); + EXPECT_EQ(dst.getDocId(), 1u); { TermFieldMatchData::PositionsIterator itr = dst.begin(); - EXPECT_EQUAL(itr->getPosition(), 7u); + EXPECT_EQ(itr->getPosition(), 7u); ++itr; - EXPECT_EQUAL(itr->getPosition(), 17u); + EXPECT_EQ(itr->getPosition(), 17u); ++itr; ASSERT_TRUE(itr == dst.end()); } { FieldPositionsIterator itr = dst.getIterator(); - EXPECT_EQUAL(itr.getPosition(), 7u); + EXPECT_EQ(itr.getPosition(), 7u); itr.next(); - EXPECT_EQUAL(itr.getPosition(), 17u); + EXPECT_EQ(itr.getPosition(), 17u); itr.next(); ASSERT_TRUE(!itr.valid()); } } -void -PhraseSplitterTest::testSplitter() +TEST(PhraseSplitterTest, test_splitter) { { // single term test::QueryEnvironment qe; @@ -91,9 +74,9 @@ PhraseSplitterTest::testSplitter() ps.bind_match_data(*md); ps.update(); // check that nothing is served from the splitter - EXPECT_EQUAL(ps.get_query_env().getTerm(0), &terms[0]); + EXPECT_EQ(ps.get_query_env().getTerm(0), &terms[0]); TermFieldHandle handle = terms[0].lookupField(0)->getHandle(); - EXPECT_EQUAL(ps.resolveTermField(handle), md->resolveTermField(handle)); + EXPECT_EQ(ps.resolveTermField(handle), md->resolveTermField(handle)); } { // single phrase test::QueryEnvironment qe; @@ -114,14 +97,14 @@ PhraseSplitterTest::testSplitter() for (size_t i = 0; i < 3; ++i) { // fprintf(stderr, "checking term %d\n", (int)i); const ITermData *td = ps.get_query_env().getTerm(i); - EXPECT_NOT_EQUAL(td, &terms[0]); - EXPECT_NOT_EQUAL(td->lookupField(7), (ITermFieldData *)0); - EXPECT_EQUAL(td->lookupField(0), (ITermFieldData *)0); - TEST_DO(assertTermData(td, 1, 1, 7, i + 4)); // skipHandles = 4 - EXPECT_NOT_EQUAL(td->lookupField(7)->getHandle(), - terms[0].lookupField(7)->getHandle()); - EXPECT_NOT_EQUAL(ps.resolveTermField(td->lookupField(7)->getHandle()), - md->resolveTermField(terms[0].lookupField(7)->getHandle())); + EXPECT_NE(td, &terms[0]); + EXPECT_NE(td->lookupField(7), (ITermFieldData *)0); + EXPECT_EQ(td->lookupField(0), (ITermFieldData *)0); + assertTermData(td, 1, 1, 7, i + 4, "single phrase"); // skipHandles = 4 + EXPECT_NE(td->lookupField(7)->getHandle(), + terms[0].lookupField(7)->getHandle()); + EXPECT_NE(ps.resolveTermField(td->lookupField(7)->getHandle()), + md->resolveTermField(terms[0].lookupField(7)->getHandle())); } } { // combination @@ -145,40 +128,39 @@ PhraseSplitterTest::testSplitter() ps.update(); { // first term // fprintf(stderr, "first term\n"); - EXPECT_EQUAL(ps.get_query_env().getTerm(0), &terms[0]); - TEST_DO(assertTermData(ps.get_query_env().getTerm(0), 0, 1, 4, 0)); - TEST_DO(assertTermData(ps.get_query_env().getTerm(0), 0, 1, 7, 1)); + EXPECT_EQ(ps.get_query_env().getTerm(0), &terms[0]); + assertTermData(ps.get_query_env().getTerm(0), 0, 1, 4, 0, "first term 1"); + assertTermData(ps.get_query_env().getTerm(0), 0, 1, 7, 1, "first term 2"); TermFieldHandle handle = terms[0].lookupField(4)->getHandle(); - EXPECT_EQUAL(ps.resolveTermField(handle), md->resolveTermField(handle)); + EXPECT_EQ(ps.resolveTermField(handle), md->resolveTermField(handle)); handle = terms[0].lookupField(7)->getHandle(); - EXPECT_EQUAL(ps.resolveTermField(handle), md->resolveTermField(handle)); + EXPECT_EQ(ps.resolveTermField(handle), md->resolveTermField(handle)); } for (size_t i = 0; i < 3; ++i) { // phrase // fprintf(stderr, "phrase term %zd\n", i); const ITermData *td = ps.get_query_env().getTerm(i + 1); - EXPECT_NOT_EQUAL(td, &terms[1]); - TEST_DO(assertTermData(td, 1, 1, 4, i + 11)); // skipHandles == 11 - EXPECT_EQUAL(td->lookupField(7), (ITermFieldData *)0); - EXPECT_NOT_EQUAL(ps.resolveTermField(td->lookupField(4)->getHandle()), - md->resolveTermField(terms[1].lookupField(4)->getHandle())); + EXPECT_NE(td, &terms[1]); + assertTermData(td, 1, 1, 4, i + 11, "phrase term"); // skipHandles == 11 + EXPECT_EQ(td->lookupField(7), (ITermFieldData *)0); + EXPECT_NE(ps.resolveTermField(td->lookupField(4)->getHandle()), + md->resolveTermField(terms[1].lookupField(4)->getHandle())); } { // last term // fprintf(stderr, "last term\n"); - EXPECT_EQUAL(ps.get_query_env().getTerm(4), &terms[2]); - TEST_DO(assertTermData(ps.get_query_env().getTerm(4), 2, 1, 4, 4)); - TEST_DO(assertTermData(ps.get_query_env().getTerm(4), 2, 1, 7, 5)); + EXPECT_EQ(ps.get_query_env().getTerm(4), &terms[2]); + assertTermData(ps.get_query_env().getTerm(4), 2, 1, 4, 4, "last term 1"); + assertTermData(ps.get_query_env().getTerm(4), 2, 1, 7, 5, "last term 2"); // fprintf(stderr, "inspect term %p #f %zd\n", &terms[2], terms[2].numFields()); fflush(stderr); TermFieldHandle handle = terms[2].lookupField(4)->getHandle(); - EXPECT_EQUAL(ps.resolveTermField(handle), md->resolveTermField(handle)); + EXPECT_EQ(ps.resolveTermField(handle), md->resolveTermField(handle)); } } } -void -PhraseSplitterTest::testSplitterUpdate() +TEST(PhraseSplitterTest, test_splitter_update) { { test::QueryEnvironment qe; @@ -213,38 +195,24 @@ PhraseSplitterTest::testSplitterUpdate() for (size_t i = 0; i < 2; ++i) { // first phrase const TermFieldMatchData * tmd = ps.resolveTermField(ps.get_query_env().getTerm(i)->lookupField(0)->getHandle()); TermFieldMatchData::PositionsIterator itr = tmd->begin(); - EXPECT_EQUAL((itr++)->getPosition(), 10 + i); + EXPECT_EQ((itr++)->getPosition(), 10 + i); ASSERT_TRUE(itr == tmd->end()); } { // first term TermFieldMatchData * tmd = md->resolveTermField(ps.get_query_env().getTerm(2)->lookupField(0)->getHandle()); TermFieldMatchData::PositionsIterator itr = tmd->begin(); - EXPECT_EQUAL((itr++)->getPosition(), 20u); + EXPECT_EQ((itr++)->getPosition(), 20u); ASSERT_TRUE(itr == tmd->end()); } for (size_t i = 0; i < 2; ++i) { // second phrase const TermFieldMatchData * tmd = ps.resolveTermField(ps.get_query_env().getTerm(i + 3)->lookupField(0)->getHandle()); TermFieldMatchData::PositionsIterator itr = tmd->begin(); - EXPECT_EQUAL((itr++)->getPosition(), 30 + i); + EXPECT_EQ((itr++)->getPosition(), 30 + i); ASSERT_TRUE(itr == tmd->end()); } } } -int -PhraseSplitterTest::Main() -{ - - TEST_INIT("phrasesplitter_test"); - - testCopyTermFieldMatchData(); - testSplitter(); - testSplitterUpdate(); - - TEST_DONE(); -} - -} } -TEST_APPHOOK(search::fef::PhraseSplitterTest); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/vespa/searchlib/queryeval/flow_tuning.h b/searchlib/src/vespa/searchlib/queryeval/flow_tuning.h index ce5a24d9c2f..53f2be88c1f 100644 --- a/searchlib/src/vespa/searchlib/queryeval/flow_tuning.h +++ b/searchlib/src/vespa/searchlib/queryeval/flow_tuning.h @@ -22,6 +22,8 @@ inline double array_cost(double my_est, size_t num_children) { * The following tests were executed on a machine with an Intel Xeon 2.5 GHz CPU with 48 cores and 256 Gb of memory: * ./searchlib_iterator_benchmark_test_app --gtest_filter='*analyze_term_search*' * + * TODO: Add details on OR benchmarking. + * * The benchmark summary shows the 'average ms per cost' of the different benchmark cases. * The following constants and formulas were derived to balance 'average ms per cost' to be similar * across the different benchmark cases. @@ -29,7 +31,7 @@ inline double array_cost(double my_est, size_t num_children) { // Non-strict cost of lookup based matching in an attribute (not fast-search). inline double lookup_cost(size_t num_indirections) { - return 1.0 + (num_indirections * 4.0); + return 1.0 + (num_indirections * 1.0); } // Strict cost of lookup based matching in an attribute (not fast-search). @@ -39,7 +41,7 @@ inline double lookup_strict_cost(size_t num_indirections) { // Non-strict cost of matching in a btree posting list (e.g. fast-search attribute or memory index field). inline double btree_cost() { - return 7.0; + return 1.0; } // Strict cost of matching in a btree posting list (e.g. fast-search attribute or memory index field). @@ -49,7 +51,7 @@ inline double btree_strict_cost(double my_est) { // Non-strict cost of matching in a disk index posting list. inline double disk_index_cost() { - return 12.0; + return 1.5; } // Strict cost of matching in a disk index posting list. diff --git a/streamingvisitors/src/vespa/searchvisitor/searchvisitor.cpp b/streamingvisitors/src/vespa/searchvisitor/searchvisitor.cpp index 52dd1c52fc2..dc58b607848 100644 --- a/streamingvisitors/src/vespa/searchvisitor/searchvisitor.cpp +++ b/streamingvisitors/src/vespa/searchvisitor/searchvisitor.cpp @@ -55,15 +55,24 @@ using vespalib::string; namespace { -std::optional<vespalib::string> +vespalib::stringref extract_search_cluster(const vdslib::Parameters& params) { - Parameters::ValueRef searchClusterBlob; - if (params.lookup("searchcluster", searchClusterBlob)) { - LOG(spam, "Received searchcluster blob of %zd bytes", searchClusterBlob.size()); - return {{searchClusterBlob.data(), searchClusterBlob.size()}}; + Parameters::ValueRef searchCluster; + if (params.lookup("searchcluster", searchCluster)) { + LOG(spam, "Received searchcluster blob of %zd bytes", searchCluster.size()); } - return std::nullopt; + return searchCluster; +} + +vespalib::stringref +extract_schema(const vdslib::Parameters& params) +{ + Parameters::ValueRef schema; + if (params.lookup("schema", schema)) { + LOG(spam, "Received searchcluster blob of %zd bytes", schema.size()); + } + return schema; } std::shared_ptr<const SearchEnvironmentSnapshot> @@ -71,8 +80,11 @@ get_search_environment_snapshot(VisitorEnvironment& v_env, const Parameters& par { auto& env = dynamic_cast<SearchEnvironment&>(v_env); auto search_cluster = extract_search_cluster(params); - if (search_cluster.has_value()) { - return env.get_snapshot(search_cluster.value()); + if ( !search_cluster.empty()) { + auto schema = extract_schema(params); + return schema.empty() + ? env.get_snapshot(search_cluster) + : env.get_snapshot(search_cluster + "/" + schema); } return {}; } diff --git a/vespaclient-java/src/main/java/com/yahoo/vespa/feed/perf/SimpleFeeder.java b/vespaclient-java/src/main/java/com/yahoo/vespa/feed/perf/SimpleFeeder.java index b4ca98f316f..386468e85e8 100644 --- a/vespaclient-java/src/main/java/com/yahoo/vespa/feed/perf/SimpleFeeder.java +++ b/vespaclient-java/src/main/java/com/yahoo/vespa/feed/perf/SimpleFeeder.java @@ -2,7 +2,6 @@ package com.yahoo.vespa.feed.perf; import com.yahoo.concurrent.ThreadFactoryFactory; -import com.yahoo.config.subscription.ConfigSubscriber; import com.yahoo.document.Document; import com.yahoo.document.DocumentId; import com.yahoo.document.DocumentPut; @@ -66,7 +65,6 @@ import java.util.stream.Stream; public class SimpleFeeder implements ReplyHandler { private final DocumentTypeManager docTypeMgr = new DocumentTypeManager(); - private final ConfigSubscriber documentTypeConfigSubscriber; private final List<InputStream> inputStreams; private final PrintStream out; private final RPCMessageBus mbus; @@ -185,21 +183,40 @@ public class SimpleFeeder implements ReplyHandler { } } public void send(FeedOperation op) { - if (op.getType() == FeedOperation.Type.DOCUMENT) { - if (!isFirst) { - try { - outputStream.write(','); - outputStream.write('\n'); - } catch (IOException e) { - failure.set(e); - } - } else { - isFirst = false; + switch (op.getType()) { + case DOCUMENT -> { + addCommaAndNewline(); + writer.write(op.getDocumentPut().getDocument()); } - writer.write(op.getDocumentPut().getDocument()); + case REMOVE -> { + addCommaAndNewline(); + writer.write(op.getDocumentRemove()); + } + case UPDATE -> { + addCommaAndNewline(); + writer.write(op.getDocumentUpdate()); + } + default -> { /* TODO: No more operations supported yet */ } } numReplies.incrementAndGet(); } + + private void addCommaAndNewline() { + try { + if (isFirst) { + outputStream.write(' '); + outputStream.write(' '); + isFirst = false; + } else { + outputStream.write(','); + outputStream.write('\n'); + outputStream.write(' '); + } + } catch (IOException e) { + failure.set(e); + } + } + public void close() throws Exception { outputStream.write('\n'); outputStream.write(']'); @@ -378,7 +395,7 @@ public class SimpleFeeder implements ReplyHandler { numMessagesToSend = params.getNumMessagesToSend(); mbus = newMessageBus(docTypeMgr, params); session = newSession(mbus, this, params); - documentTypeConfigSubscriber = DocumentTypeManagerConfigurer.configure(docTypeMgr, params.getConfigId()); + DocumentTypeManagerConfigurer.configure(docTypeMgr, params.getConfigId()); benchmarkMode = params.isBenchmarkMode(); destination = (params.getDumpStream() != null) ? createDumper(params) @@ -469,6 +486,7 @@ public class SimpleFeeder implements ReplyHandler { numReplies.incrementAndGet(); accumulateReplies(now, latency); } + private synchronized void accumulateReplies(long now, long latency) { minLatency = Math.min(minLatency, latency); maxLatency = Math.max(maxLatency, latency); @@ -479,6 +497,7 @@ public class SimpleFeeder implements ReplyHandler { nextReport += REPORT_INTERVAL; } } + private static void printHeader(PrintStream out) { out.println("# Time used, num ok, num error, min latency, max latency, average latency"); } diff --git a/vespaclient-java/src/test/java/com/yahoo/vespa/feed/perf/SimpleFeederTest.java b/vespaclient-java/src/test/java/com/yahoo/vespa/feed/perf/SimpleFeederTest.java index 582148e8eaa..6776b71eea6 100644 --- a/vespaclient-java/src/test/java/com/yahoo/vespa/feed/perf/SimpleFeederTest.java +++ b/vespaclient-java/src/test/java/com/yahoo/vespa/feed/perf/SimpleFeederTest.java @@ -87,8 +87,14 @@ public class SimpleFeederTest { "", "(.+\n)+" + "\\s*\\d+,\\s*3,.+\n"); - assertEquals(58, dump.size()); - assertEquals("[\n{\"id\":\"id:simple:simple::0\",\"fields\":{\"my_str\":\"foo\"}}\n]", dump.toString()); + assertEquals(169, dump.size()); + assertEquals(""" + [ + {"id":"id:simple:simple::0","fields":{"my_str":"foo"}}, + {"update":"id:simple:simple::1","fields":{"my_str":{"assign":"bar"}}}, + {"remove":"id:simple:simple::2"} + ]""", + dump.toString()); } @Test @@ -116,8 +122,14 @@ public class SimpleFeederTest { "", "(.+\n)+" + "\\s*\\d+,\\s*3,.+\n"); - assertEquals(115, dump.size()); - assertEquals("[\n{\"id\":\"id:simple:simple::0\",\"fields\":{\"my_str\":\"foo\"}},\n {\"id\":\"id:simple:simple::1\",\"fields\":{\"my_str\":\"bar\"}}\n]", dump.toString()); + assertEquals(154, dump.size()); + assertEquals(""" + [ + {"id":"id:simple:simple::0","fields":{"my_str":"foo"}}, + {"id":"id:simple:simple::1","fields":{"my_str":"bar"}}, + {"remove":"id:simple:simple::2"} + ]""", + dump.toString()); assertFeed(dump.toString(), new MessageHandler() { @Override @@ -129,7 +141,7 @@ public class SimpleFeederTest { }, "", "(.+\n)+" + - "\\s*\\d+,\\s*2,.+\n"); + "\\s*\\d+,\\s*3,.+\n"); } @Test diff --git a/vespajlib/src/main/java/com/yahoo/collections/TinyIdentitySet.java b/vespajlib/src/main/java/com/yahoo/collections/TinyIdentitySet.java index 1cc68777c88..bb540f82ea4 100644 --- a/vespajlib/src/main/java/com/yahoo/collections/TinyIdentitySet.java +++ b/vespajlib/src/main/java/com/yahoo/collections/TinyIdentitySet.java @@ -67,9 +67,12 @@ public final class TinyIdentitySet<E> implements Set<E> { * @param initSize * initial size of internal element array */ - public TinyIdentitySet(final int initSize) { + public TinyIdentitySet(int initSize) { entries = new Object[initSize]; } + public TinyIdentitySet() { + this(4); + } /** * Expose the index in the internal array of a given object. -1 is returned diff --git a/vespalib/src/tests/btree/CMakeLists.txt b/vespalib/src/tests/btree/CMakeLists.txt index bf4edc9e5e9..3b6f012a888 100644 --- a/vespalib/src/tests/btree/CMakeLists.txt +++ b/vespalib/src/tests/btree/CMakeLists.txt @@ -20,6 +20,7 @@ vespa_add_executable(vespalib_btreeaggregation_test_app TEST btreeaggregation_test.cpp DEPENDS vespalib + GTest::gtest ) vespa_add_test(NAME vespalib_btreeaggregation_test_app COMMAND vespalib_btreeaggregation_test_app COST 30) vespa_add_executable(vespalib_iteratespeed_app diff --git a/vespalib/src/tests/btree/btreeaggregation_test.cpp b/vespalib/src/tests/btree/btreeaggregation_test.cpp index b33242b918e..34c1ca76772 100644 --- a/vespalib/src/tests/btree/btreeaggregation_test.cpp +++ b/vespalib/src/tests/btree/btreeaggregation_test.cpp @@ -16,8 +16,8 @@ #include <vespa/vespalib/btree/btreeaggregator.hpp> #include <vespa/vespalib/datastore/buffer_type.hpp> #include <vespa/vespalib/datastore/compaction_strategy.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/test/btree/btree_printer.h> -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/vespalib/util/rand48.h> #include <iostream> @@ -216,115 +216,95 @@ cleanup(GenerationHandler & g, cleanup(g, m); } -class Test : public vespalib::TestApp { -private: +class BTreeAggregationTest : public ::testing::Test { +protected: + BTreeAggregationTest(); + ~BTreeAggregationTest() override; template <typename Tree> bool assertTree(const std::string & exp, const Tree &t); template <typename Tree> bool - assertAggregated(const MockTree &m, const Tree &t); + assertAggregated(const MockTree &m, const Tree &t, const vespalib::string& label); template <typename TreeStore> bool - assertAggregated(const MockTree &m, const TreeStore &s, EntryRef ref); + assertAggregated(const MockTree &m, const TreeStore &s, EntryRef ref, const vespalib::string& label); void buildSubTree(const std::vector<LeafPair> &sub, size_t numEntries); - - void requireThatNodeInsertWorks(); - void keys_are_aggregated_correctly_on_node_insertions(); - void requireThatNodeSplitInsertWorks(); - void keys_are_aggregated_correctly_when_node_split_on_insert(); - void requireThatTreeInsertWorks(); - void requireThatNodeStealWorks(); - void requireThatNodeRemoveWorks(); - void keys_are_aggregated_correctly_on_node_removal(); - void requireThatWeCanInsertAndRemoveFromTree(); - void requireThatSortedTreeInsertWorks(); - void requireThatCornerCaseTreeFindWorks(); - void requireThatBasicTreeIteratorWorks(); - void requireThatTreeIteratorAssignWorks(); - void requireThatUpdateOfKeyWorks(); - void requireThatUpdateOfDataWorks(); - void requireThatFrozenViewProvidesAggregatedValues(); - - void - requireThatSmallNodesWorks(); -public: - int Main() override; }; +BTreeAggregationTest::BTreeAggregationTest() = default; +BTreeAggregationTest::~BTreeAggregationTest() = default; template<typename Tree> bool -Test::assertTree(const std::string &exp, const Tree &t) +BTreeAggregationTest::assertTree(const std::string &exp, const Tree &t) { std::stringstream ss; test::BTreePrinter<std::stringstream, typename Tree::NodeAllocatorType> printer(ss, t.getAllocator()); printer.print(t.getRoot()); - if (!EXPECT_EQUAL(exp, ss.str())) return false; - return true; + bool failed = false; + EXPECT_EQ(exp, ss.str()) << (failed = true, ""); + return !failed; } template <typename Tree> bool -Test::assertAggregated(const MockTree &m, const Tree &t) +BTreeAggregationTest::assertAggregated(const MockTree &m, const Tree &t, const vespalib::string& label) { + SCOPED_TRACE(label); const MinMaxAggregated &ta(t.getAggregated()); + bool failed = false; if (t.getRoot().valid()) { - return - EXPECT_FALSE(m._rtree.empty()) && - EXPECT_EQUAL(m._rtree.rbegin()->first, - ta.getMax()) && - EXPECT_EQUAL(m._rtree.begin()->first, - ta.getMin()); + EXPECT_FALSE(m._rtree.empty()) << (failed = true, ""); + if (failed) { + return false; + } + EXPECT_EQ(m._rtree.rbegin()->first, ta.getMax()) << (failed = true, ""); + EXPECT_EQ(m._rtree.begin()->first, ta.getMin()) << (failed = true, ""); } else { - return EXPECT_TRUE(m._rtree.empty()) && - EXPECT_EQUAL(std::numeric_limits<int32_t>::min(), - ta.getMax()) && - EXPECT_EQUAL(std::numeric_limits<int32_t>::max(), - ta.getMin()); + EXPECT_TRUE(m._rtree.empty()) << (failed = true, ""); + EXPECT_EQ(std::numeric_limits<int32_t>::min(), ta.getMax()) << (failed = true, ""); + EXPECT_EQ(std::numeric_limits<int32_t>::max(), ta.getMin()) << (failed = true, ""); } + return !failed; } template <typename TreeStore> bool -Test::assertAggregated(const MockTree &m, const TreeStore &s, EntryRef ref) +BTreeAggregationTest::assertAggregated(const MockTree &m, const TreeStore &s, EntryRef ref, const vespalib::string& label) { + SCOPED_TRACE(label); typename TreeStore::Iterator i(s.begin(ref)); MinMaxAggregated sa(s.getAggregated(ref)); const MinMaxAggregated &ia(i.getAggregated()); + bool failed = false; if (ref.valid()) { - return - EXPECT_FALSE(m._rtree.empty()) && - EXPECT_EQUAL(m._rtree.rbegin()->first, - ia.getMax()) && - EXPECT_EQUAL(m._rtree.begin()->first, - ia.getMin()) && - EXPECT_EQUAL(m._rtree.rbegin()->first, - sa.getMax()) && - EXPECT_EQUAL(m._rtree.begin()->first, - sa.getMin()); + EXPECT_FALSE(m._rtree.empty()) << (failed = true, ""); + if (failed) { + return false; + } + EXPECT_EQ(m._rtree.rbegin()->first, ia.getMax()) << (failed = true, ""); + EXPECT_EQ(m._rtree.begin()->first, ia.getMin()) << (failed = true, ""); + EXPECT_EQ(m._rtree.rbegin()->first, sa.getMax()) << (failed = true, ""); + EXPECT_EQ(m._rtree.begin()->first, sa.getMin()) << (failed = true, ""); } else { - return EXPECT_TRUE(m._rtree.empty()) && - EXPECT_EQUAL(std::numeric_limits<int32_t>::min(), - ia.getMax()) && - EXPECT_EQUAL(std::numeric_limits<int32_t>::max(), - ia.getMin()) && - EXPECT_EQUAL(std::numeric_limits<int32_t>::min(), - sa.getMax()) && - EXPECT_EQUAL(std::numeric_limits<int32_t>::max(), - sa.getMin()); + EXPECT_TRUE(m._rtree.empty()) << (failed = true, ""); + EXPECT_EQ(std::numeric_limits<int32_t>::min(), ia.getMax()) << (failed = true, ""); + EXPECT_EQ(std::numeric_limits<int32_t>::max(), ia.getMin()) << (failed = true, ""); + EXPECT_EQ(std::numeric_limits<int32_t>::min(), sa.getMax()) << (failed =true, ""); + EXPECT_EQ(std::numeric_limits<int32_t>::max(), sa.getMin()) << (failed =true, ""); } + return !failed; } -void -Test::requireThatNodeInsertWorks() +TEST_F(BTreeAggregationTest, require_that_node_insert_works) { MyTree t; t.insert(20, 102); @@ -336,7 +316,8 @@ Test::requireThatNodeInsertWorks() EXPECT_TRUE(assertTree("{{10:101,20:102,30:103,40:104[min=101,max=104]}}", t)); } -void Test::keys_are_aggregated_correctly_on_node_insertions() { +TEST_F(BTreeAggregationTest, keys_are_aggregated_correctly_on_node_insertions) +{ MyKeyAggrTree t; t.insert(20, 102); EXPECT_TRUE(assertTree("{{20:102[min=20,max=20]}}", t)); @@ -367,8 +348,7 @@ populateLeafNode(Tree &t) populateTree(t, 4, 2); } -void -Test::requireThatNodeSplitInsertWorks() +TEST_F(BTreeAggregationTest, require_that_node_split_insert_works) { { // new entry in current node MyTree t; @@ -396,7 +376,8 @@ Test::requireThatNodeSplitInsertWorks() } } -void Test::keys_are_aggregated_correctly_when_node_split_on_insert() { +TEST_F(BTreeAggregationTest, keys_are_aggregated_correctly_when_node_split_on_insert) +{ { // new entry in current node MyKeyAggrTree t; populateLeafNode(t); @@ -423,8 +404,7 @@ void Test::keys_are_aggregated_correctly_when_node_split_on_insert() { } } -void -Test::requireThatTreeInsertWorks() +TEST_F(BTreeAggregationTest, require_that_tree_insert_works) { { // multi level node split MyTree t; @@ -523,8 +503,7 @@ struct BTreeStealTraits } -void -Test::requireThatNodeStealWorks() +TEST_F(BTreeAggregationTest, require_that_node_steal_works) { typedef BTree<MyKey, int32_t, btree::MinMaxAggregated, @@ -602,8 +581,7 @@ Test::requireThatNodeStealWorks() } } -void -Test::requireThatNodeRemoveWorks() +TEST_F(BTreeAggregationTest, require_that_node_remove_works) { MyTree t; populateLeafNode(t); @@ -615,7 +593,8 @@ Test::requireThatNodeRemoveWorks() EXPECT_TRUE(assertTree("{{5:105[min=105,max=105]}}", t)); } -void Test::keys_are_aggregated_correctly_on_node_removal() { +TEST_F(BTreeAggregationTest, keys_are_aggregated_correctly_on_node_removal) +{ MyKeyAggrTree t; populateLeafNode(t); t.remove(3); @@ -640,7 +619,7 @@ generateData(std::vector<LeafPair> & data, size_t numEntries) } void -Test::buildSubTree(const std::vector<LeafPair> &sub, +BTreeAggregationTest::buildSubTree(const std::vector<LeafPair> &sub, size_t numEntries) { GenerationHandler g; @@ -660,31 +639,31 @@ Test::buildSubTree(const std::vector<LeafPair> &sub, assert(numEntries == tree.size()); assert(tree.isValid()); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, tree))); - EXPECT_EQUAL(numEntries, tree.size()); + EXPECT_TRUE(assertAggregated(mock, tree, "build_sub_tree")); + EXPECT_EQ(numEntries, tree.size()); EXPECT_TRUE(tree.isValid()); MyTree::Iterator itr = tree.begin(); MyTree::Iterator ritr = itr; if (numEntries > 0) { EXPECT_TRUE(ritr.valid()); - EXPECT_EQUAL(0u, ritr.position()); + EXPECT_EQ(0u, ritr.position()); --ritr; EXPECT_TRUE(!ritr.valid()); - EXPECT_EQUAL(numEntries, ritr.position()); + EXPECT_EQ(numEntries, ritr.position()); --ritr; EXPECT_TRUE(ritr.valid()); - EXPECT_EQUAL(numEntries - 1, ritr.position()); + EXPECT_EQ(numEntries - 1, ritr.position()); } else { EXPECT_TRUE(!ritr.valid()); - EXPECT_EQUAL(0u, ritr.position()); + EXPECT_EQ(0u, ritr.position()); --ritr; EXPECT_TRUE(!ritr.valid()); - EXPECT_EQUAL(0u, ritr.position()); + EXPECT_EQ(0u, ritr.position()); } for (size_t i = 0; i < numEntries; ++i) { EXPECT_TRUE(itr.valid()); - EXPECT_EQUAL(sorted[i].first, itr.getKey()); - EXPECT_EQUAL(sorted[i].second, itr.getData()); + EXPECT_EQ(sorted[i].first, itr.getKey()); + EXPECT_EQ(sorted[i].second, itr.getData()); ++itr; } EXPECT_TRUE(!itr.valid()); @@ -693,22 +672,21 @@ Test::buildSubTree(const std::vector<LeafPair> &sub, --ritr; for (size_t i = 0; i < numEntries; ++i) { EXPECT_TRUE(ritr.valid()); - EXPECT_EQUAL(sorted[numEntries - 1 - i].first, ritr.getKey()); - EXPECT_EQUAL(sorted[numEntries - 1 - i].second, ritr.getData()); + EXPECT_EQ(sorted[numEntries - 1 - i].first, ritr.getKey()); + EXPECT_EQ(sorted[numEntries - 1 - i].second, ritr.getData()); --ritr; } EXPECT_TRUE(!ritr.valid()); } -void -Test::requireThatWeCanInsertAndRemoveFromTree() +TEST_F(BTreeAggregationTest, require_that_we_can_insert_and_remove_from_tree) { GenerationHandler g; MyTree tree; MockTree mock; std::vector<LeafPair> exp; std::vector<LeafPair> sorted; - TEST_DO(EXPECT_TRUE(assertAggregated(mock, tree))); + EXPECT_TRUE(assertAggregated(mock, tree, "insert_and_remove_1")); size_t numEntries = 1000; generateData(exp, numEntries); sorted = exp; @@ -722,15 +700,15 @@ Test::requireThatWeCanInsertAndRemoveFromTree() EXPECT_TRUE(tree.insert(num, val)); EXPECT_TRUE(!tree.insert(num, val)); mock.insert(num, val); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, tree))); + EXPECT_TRUE(assertAggregated(mock, tree, "insert_and_remove_2")); for (size_t j = 0; j <= i; ++j) { //LOG(info, "find[%zu](%d)", j, exp[j].first._val); MyTree::Iterator itr = tree.find(exp[j].first); EXPECT_TRUE(itr.valid()); - EXPECT_EQUAL(exp[j].first, itr.getKey()); - EXPECT_EQUAL(exp[j].second, itr.getData()); + EXPECT_EQ(exp[j].first, itr.getKey()); + EXPECT_EQ(exp[j].second, itr.getData()); } - EXPECT_EQUAL(i + 1u, tree.size()); + EXPECT_EQ(i + 1u, tree.size()); EXPECT_TRUE(tree.isValid()); buildSubTree(exp, i + 1); } @@ -745,36 +723,36 @@ Test::requireThatWeCanInsertAndRemoveFromTree() ++itre; if (numEntries > 0) { EXPECT_TRUE(ritr.valid()); - EXPECT_EQUAL(0u, ritr.position()); + EXPECT_EQ(0u, ritr.position()); --ritr; EXPECT_TRUE(!ritr.valid()); - EXPECT_EQUAL(numEntries, ritr.position()); + EXPECT_EQ(numEntries, ritr.position()); --ritr; EXPECT_TRUE(ritr.valid()); - EXPECT_EQUAL(numEntries - 1, ritr.position()); + EXPECT_EQ(numEntries - 1, ritr.position()); } else { EXPECT_TRUE(!ritr.valid()); - EXPECT_EQUAL(0u, ritr.position()); + EXPECT_EQ(0u, ritr.position()); --ritr; EXPECT_TRUE(!ritr.valid()); - EXPECT_EQUAL(0u, ritr.position()); + EXPECT_EQ(0u, ritr.position()); } MyTree::Iterator pitr = itr; for (size_t i = 0; i < numEntries; ++i) { ssize_t si = i; ssize_t sileft = numEntries - i; EXPECT_TRUE(itr.valid()); - EXPECT_EQUAL(i, itr.position()); - EXPECT_EQUAL(sileft, itre - itr); - EXPECT_EQUAL(-sileft, itr - itre); - EXPECT_EQUAL(sileft, itre2 - itr); - EXPECT_EQUAL(-sileft, itr - itre2); - EXPECT_EQUAL(si, itr - tree.begin()); - EXPECT_EQUAL(-si, tree.begin() - itr); - EXPECT_EQUAL(i != 0, itr - pitr); - EXPECT_EQUAL(-(i != 0), pitr - itr); - EXPECT_EQUAL(sorted[i].first, itr.getKey()); - EXPECT_EQUAL(sorted[i].second, itr.getData()); + EXPECT_EQ(i, itr.position()); + EXPECT_EQ(sileft, itre - itr); + EXPECT_EQ(-sileft, itr - itre); + EXPECT_EQ(sileft, itre2 - itr); + EXPECT_EQ(-sileft, itr - itre2); + EXPECT_EQ(si, itr - tree.begin()); + EXPECT_EQ(-si, tree.begin() - itr); + EXPECT_EQ(i != 0, itr - pitr); + EXPECT_EQ(-(i != 0), pitr - itr); + EXPECT_EQ(sorted[i].first, itr.getKey()); + EXPECT_EQ(sorted[i].second, itr.getData()); pitr = itr; ++itr; ritr = itr; @@ -783,12 +761,12 @@ Test::requireThatWeCanInsertAndRemoveFromTree() EXPECT_TRUE(ritr == pitr); } EXPECT_TRUE(!itr.valid()); - EXPECT_EQUAL(numEntries, itr.position()); + EXPECT_EQ(numEntries, itr.position()); ssize_t sNumEntries = numEntries; - EXPECT_EQUAL(sNumEntries, itr - tree.begin()); - EXPECT_EQUAL(-sNumEntries, tree.begin() - itr); - EXPECT_EQUAL(1, itr - pitr); - EXPECT_EQUAL(-1, pitr - itr); + EXPECT_EQ(sNumEntries, itr - tree.begin()); + EXPECT_EQ(-sNumEntries, tree.begin() - itr); + EXPECT_EQ(1, itr - pitr); + EXPECT_EQ(-1, pitr - itr); } // compact full tree by calling incremental compaction methods in a loop { @@ -818,52 +796,50 @@ Test::requireThatWeCanInsertAndRemoveFromTree() EXPECT_TRUE(!tree.remove(num)); EXPECT_TRUE(tree.isValid()); mock.erase(num); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, tree))); + EXPECT_TRUE(assertAggregated(mock, tree, "insert_and_remove3")); for (size_t j = i + 1; j < numEntries; ++j) { MyTree::Iterator itr = tree.find(exp[j].first); EXPECT_TRUE(itr.valid()); - EXPECT_EQUAL(exp[j].first, itr.getKey()); - EXPECT_EQUAL(exp[j].second, itr.getData()); + EXPECT_EQ(exp[j].first, itr.getKey()); + EXPECT_EQ(exp[j].second, itr.getData()); } - EXPECT_EQUAL(numEntries - 1 - i, tree.size()); + EXPECT_EQ(numEntries - 1 - i, tree.size()); } } -void -Test::requireThatSortedTreeInsertWorks() +TEST_F(BTreeAggregationTest, require_that_sorted_tree_insert_works) { { MyTree tree; MockTree mock; - TEST_DO(EXPECT_TRUE(assertAggregated(mock, tree))); + EXPECT_TRUE(assertAggregated(mock, tree, "sorted_tree_insert1")); for (int i = 0; i < 1000; ++i) { EXPECT_TRUE(tree.insert(i, toVal(i))); mock.insert(i, toVal(i)); MyTree::Iterator itr = tree.find(i); EXPECT_TRUE(itr.valid()); - EXPECT_EQUAL(toVal(i), itr.getData()); + EXPECT_EQ(toVal(i), itr.getData()); EXPECT_TRUE(tree.isValid()); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, tree))); + EXPECT_TRUE(assertAggregated(mock, tree, "sorted_tree_insert2")); } } { MyTree tree; MockTree mock; - TEST_DO(EXPECT_TRUE(assertAggregated(mock, tree))); + EXPECT_TRUE(assertAggregated(mock, tree, "sorted_tree_insert3")); for (int i = 1000; i > 0; --i) { EXPECT_TRUE(tree.insert(i, toVal(i))); mock.insert(i, toVal(i)); MyTree::Iterator itr = tree.find(i); EXPECT_TRUE(itr.valid()); - EXPECT_EQUAL(toVal(i), itr.getData()); + EXPECT_EQ(toVal(i), itr.getData()); EXPECT_TRUE(tree.isValid()); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, tree))); + EXPECT_TRUE(assertAggregated(mock, tree, "sorted_tree_insert4")); } } } -void -Test::requireThatCornerCaseTreeFindWorks() +TEST_F(BTreeAggregationTest, require_that_corner_case_tree_find_works) { GenerationHandler g; MyTree tree; @@ -874,8 +850,7 @@ Test::requireThatCornerCaseTreeFindWorks() EXPECT_TRUE(!tree.find(1000).valid()); // higher than highest } -void -Test::requireThatBasicTreeIteratorWorks() +TEST_F(BTreeAggregationTest, require_that_basic_tree_iterator_works) { GenerationHandler g; MyTree tree; @@ -890,27 +865,24 @@ Test::requireThatBasicTreeIteratorWorks() size_t ei = 0; MyTree::Iterator itr = tree.begin(); MyTree::Iterator ritr; - EXPECT_EQUAL(1000u, itr.size()); + EXPECT_EQ(1000u, itr.size()); for (; itr.valid(); ++itr) { //LOG(info, "itr(%d, %s)", itr.getKey(), itr.getData().c_str()); - EXPECT_EQUAL(UNWRAP(exp[ei].first), UNWRAP(itr.getKey())); - EXPECT_EQUAL(exp[ei].second, itr.getData()); + EXPECT_EQ(UNWRAP(exp[ei].first), UNWRAP(itr.getKey())); + EXPECT_EQ(exp[ei].second, itr.getData()); ei++; ritr = itr; } - EXPECT_EQUAL(numEntries, ei); + EXPECT_EQ(numEntries, ei); for (; ritr.valid(); --ritr) { --ei; //LOG(info, "itr(%d, %s)", itr.getKey(), itr.getData().c_str()); - EXPECT_EQUAL(UNWRAP(exp[ei].first), UNWRAP(ritr.getKey())); - EXPECT_EQUAL(exp[ei].second, ritr.getData()); + EXPECT_EQ(UNWRAP(exp[ei].first), UNWRAP(ritr.getKey())); + EXPECT_EQ(exp[ei].second, ritr.getData()); } } - - -void -Test::requireThatTreeIteratorAssignWorks() +TEST_F(BTreeAggregationTest, require_that_tree_iterator_assign_works) { GenerationHandler g; MyTree tree; @@ -923,9 +895,9 @@ Test::requireThatTreeIteratorAssignWorks() EXPECT_TRUE(itr == itr2); int expNum = i; for (; itr2.valid(); ++itr2) { - EXPECT_EQUAL(expNum++, UNWRAP(itr2.getKey())); + EXPECT_EQ(expNum++, UNWRAP(itr2.getKey())); } - EXPECT_EQUAL(1000, expNum); + EXPECT_EQ(1000, expNum); } } @@ -940,8 +912,7 @@ struct UpdKeyComp { } }; -void -Test::requireThatUpdateOfKeyWorks() +TEST_F(BTreeAggregationTest, require_that_update_of_key_works) { using UpdKeyTree = BTree<int, BTreeNoLeafData, btree::NoAggregated, UpdKeyComp &>; using UpdKeyTreeIterator = UpdKeyTree::Iterator; @@ -951,7 +922,7 @@ Test::requireThatUpdateOfKeyWorks() for (int i = 0; i < 1000; i+=2) { EXPECT_TRUE(t.insert(i, BTreeNoLeafData(), cmp1)); } - EXPECT_EQUAL(0u, cmp1._numErrors); + EXPECT_EQ(0u, cmp1._numErrors); for (int i = 0; i < 1000; i+=2) { UpdKeyTreeIterator itr = t.find(i, cmp1); itr.writeKey(i + 1); @@ -961,23 +932,22 @@ Test::requireThatUpdateOfKeyWorks() UpdKeyTreeIterator itr = t.find(i, cmp2); EXPECT_TRUE(itr.valid()); } - EXPECT_EQUAL(0u, cmp2._numErrors); + EXPECT_EQ(0u, cmp2._numErrors); } -void -Test::requireThatUpdateOfDataWorks() +TEST_F(BTreeAggregationTest, require_that_update_of_data_works) { GenerationHandler g; MyTree t; MockTree mock; MyAggrCalc ac; MyTree::NodeAllocatorType &manager = t.getAllocator(); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, t))); + EXPECT_TRUE(assertAggregated(mock, t, "update_data1")); for (int i = 0; i < 1000; i+=2) { EXPECT_TRUE(t.insert(i, toVal(i))); mock.insert(i, toVal(i)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, t))); + EXPECT_TRUE(assertAggregated(mock, t, "udate_data2")); } freezeTree(g, manager); for (int i = 0; i < 1000; i+=2) { @@ -985,31 +955,31 @@ Test::requireThatUpdateOfDataWorks() MyTree::Iterator itr2 = itr; t.thaw(itr); itr.updateData(toHighVal(i), ac); - EXPECT_EQUAL(toHighVal(i), itr.getData()); - EXPECT_EQUAL(toVal(i), itr2.getData()); + EXPECT_EQ(toHighVal(i), itr.getData()); + EXPECT_EQ(toVal(i), itr2.getData()); mock.erase(i); mock.insert(i, toHighVal(i)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, t))); + EXPECT_TRUE(assertAggregated(mock, t, "update_data3")); freezeTree(g, manager); itr = t.find(i); itr2 = itr; t.thaw(itr); itr.updateData(toLowVal(i), ac); - EXPECT_EQUAL(toLowVal(i), itr.getData()); - EXPECT_EQUAL(toHighVal(i), itr2.getData()); + EXPECT_EQ(toLowVal(i), itr.getData()); + EXPECT_EQ(toHighVal(i), itr2.getData()); mock.erase(i); mock.insert(i, toLowVal(i)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, t))); + EXPECT_TRUE(assertAggregated(mock, t, "update_data4")); freezeTree(g, manager); itr = t.find(i); itr2 = itr; t.thaw(itr); itr.updateData(toVal(i), ac); - EXPECT_EQUAL(toVal(i), itr.getData()); - EXPECT_EQUAL(toLowVal(i), itr2.getData()); + EXPECT_EQ(toVal(i), itr.getData()); + EXPECT_EQ(toLowVal(i), itr2.getData()); mock.erase(i); mock.insert(i, toVal(i)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, t))); + EXPECT_TRUE(assertAggregated(mock, t, "update_data5")); freezeTree(g, manager); } } @@ -1030,68 +1000,67 @@ remove(MyTreeStore& s, EntryRef& root, MyTreeStore::KeyType removal) } -void -Test::requireThatSmallNodesWorks() +TEST_F(BTreeAggregationTest, require_that_small_nodes_works) { GenerationHandler g; MyTreeStore s; MockTree mock; EntryRef root; - EXPECT_EQUAL(0u, s.size(root)); + EXPECT_EQ(0u, s.size(root)); EXPECT_TRUE(s.isSmallArray(root)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, s, root))); + EXPECT_TRUE(assertAggregated(mock, s, root, "small1")); insert(s, root, {40, toVal(40)}); mock.insert(40, toVal(40)); - EXPECT_EQUAL(1u, s.size(root)); + EXPECT_EQ(1u, s.size(root)); EXPECT_TRUE(s.isSmallArray(root)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, s, root))); + EXPECT_TRUE(assertAggregated(mock, s, root, "small2")); insert(s, root, {20, toVal(20)}); mock.insert(20, toVal(20)); - EXPECT_EQUAL(2u, s.size(root)); + EXPECT_EQ(2u, s.size(root)); EXPECT_TRUE(s.isSmallArray(root)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, s, root))); + EXPECT_TRUE(assertAggregated(mock, s, root, "small3")); insert(s, root, {60, toVal(60)}); mock.insert(60, toVal(60)); - EXPECT_EQUAL(3u, s.size(root)); + EXPECT_EQ(3u, s.size(root)); EXPECT_TRUE(s.isSmallArray(root)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, s, root))); + EXPECT_TRUE(assertAggregated(mock, s, root, "small4")); insert(s, root, {50, toVal(50)}); mock.insert(50, toVal(50)); - EXPECT_EQUAL(4u, s.size(root)); + EXPECT_EQ(4u, s.size(root)); EXPECT_TRUE(s.isSmallArray(root)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, s, root))); + EXPECT_TRUE(assertAggregated(mock, s, root, "small5")); for (uint32_t i = 0; i < 100; ++i) { insert(s, root, {int(1000 + i), 42}); mock.insert(1000 + i, 42); - EXPECT_EQUAL(5u + i, s.size(root)); - EXPECT_EQUAL(5u + i <= MyTreeStore::clusterLimit, s.isSmallArray(root)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, s, root))); + EXPECT_EQ(5u + i, s.size(root)); + EXPECT_EQ(5u + i <= MyTreeStore::clusterLimit, s.isSmallArray(root)); + EXPECT_TRUE(assertAggregated(mock, s, root, "small6")); } remove(s, root, 40); mock.erase(40); - EXPECT_EQUAL(103u, s.size(root)); + EXPECT_EQ(103u, s.size(root)); EXPECT_TRUE(!s.isSmallArray(root)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, s, root))); + EXPECT_TRUE(assertAggregated(mock, s, root, "small7")); remove(s, root, 20); mock.erase(20); - EXPECT_EQUAL(102u, s.size(root)); + EXPECT_EQ(102u, s.size(root)); EXPECT_TRUE(!s.isSmallArray(root)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, s, root))); + EXPECT_TRUE(assertAggregated(mock, s, root, "small8")); remove(s, root, 50); mock.erase(50); - EXPECT_EQUAL(101u, s.size(root)); + EXPECT_EQ(101u, s.size(root)); EXPECT_TRUE(!s.isSmallArray(root)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, s, root))); + EXPECT_TRUE(assertAggregated(mock, s, root, "small9")); for (uint32_t i = 0; i < 100; ++i) { remove(s, root, 1000 + i); mock.erase(1000 + i); - EXPECT_EQUAL(100 - i, s.size(root)); - EXPECT_EQUAL(100 - i <= MyTreeStore::clusterLimit, s.isSmallArray(root)); - TEST_DO(EXPECT_TRUE(assertAggregated(mock, s, root))); + EXPECT_EQ(100 - i, s.size(root)); + EXPECT_EQ(100 - i <= MyTreeStore::clusterLimit, s.isSmallArray(root)); + EXPECT_TRUE(assertAggregated(mock, s, root, "small10")); } - EXPECT_EQUAL(1u, s.size(root)); + EXPECT_EQ(1u, s.size(root)); EXPECT_TRUE(s.isSmallArray(root)); s.clear(root); @@ -1102,8 +1071,7 @@ Test::requireThatSmallNodesWorks() s.reclaim_memory(g.get_oldest_used_generation()); } -void -Test::requireThatFrozenViewProvidesAggregatedValues() +TEST_F(BTreeAggregationTest, require_that_frozen_view_provides_aggregated_values) { MyTree t; t.insert(20, 102); @@ -1114,39 +1082,13 @@ Test::requireThatFrozenViewProvidesAggregatedValues() t.getAllocator().freeze(); auto new_view = t.getFrozenView(); auto new_aggregated = new_view.getAggregated(); - EXPECT_EQUAL(new_aggregated.getMin(), 101); - EXPECT_EQUAL(new_aggregated.getMax(), 104); + EXPECT_EQ(new_aggregated.getMin(), 101); + EXPECT_EQ(new_aggregated.getMax(), 104); auto old_aggregated = old_view.getAggregated(); - EXPECT_EQUAL(old_aggregated.getMin(), std::numeric_limits<int32_t>::max()); - EXPECT_EQUAL(old_aggregated.getMax(), std::numeric_limits<int32_t>::min()); -} - -int -Test::Main() -{ - TEST_INIT("btreeaggregation_test"); - - requireThatNodeInsertWorks(); - keys_are_aggregated_correctly_on_node_insertions(); - requireThatNodeSplitInsertWorks(); - keys_are_aggregated_correctly_when_node_split_on_insert(); - requireThatTreeInsertWorks(); - requireThatNodeStealWorks(); - requireThatNodeRemoveWorks(); - keys_are_aggregated_correctly_on_node_removal(); - requireThatWeCanInsertAndRemoveFromTree(); - requireThatSortedTreeInsertWorks(); - requireThatCornerCaseTreeFindWorks(); - requireThatBasicTreeIteratorWorks(); - requireThatTreeIteratorAssignWorks(); - requireThatUpdateOfKeyWorks(); - requireThatUpdateOfDataWorks(); - TEST_DO(requireThatSmallNodesWorks()); - TEST_DO(requireThatFrozenViewProvidesAggregatedValues()); - - TEST_DONE(); + EXPECT_EQ(old_aggregated.getMin(), std::numeric_limits<int32_t>::max()); + EXPECT_EQ(old_aggregated.getMax(), std::numeric_limits<int32_t>::min()); } } -TEST_APPHOOK(vespalib::btree::Test); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/tests/btree/frozenbtree_test.cpp b/vespalib/src/tests/btree/frozenbtree_test.cpp index ffe8b4516aa..bc8230e2ded 100644 --- a/vespalib/src/tests/btree/frozenbtree_test.cpp +++ b/vespalib/src/tests/btree/frozenbtree_test.cpp @@ -416,37 +416,22 @@ TEST_F(FrozenBTreeTest, test_frozen_btree) sortRandomValues(); allocTree(); - insertRandomValues(*_tree, *_allocator, _randomValues); - lookupRandomValues(*_tree, *_allocator, _randomValues); + ASSERT_NO_FATAL_FAILURE(insertRandomValues(*_tree, *_allocator, _randomValues)); + ASSERT_NO_FATAL_FAILURE(lookupRandomValues(*_tree, *_allocator, _randomValues)); EXPECT_TRUE(_tree->getFrozenView(*_allocator).empty()); _allocator->freeze(); EXPECT_FALSE(_tree->getFrozenView(*_allocator).empty()); _allocator->assign_generation(_generationHandler->getCurrentGeneration()); lookupFrozenRandomValues(*_tree, *_allocator, _randomValues); - traverseTreeIterator(*_tree, - *_allocator, - _sortedRandomValues, - false); - traverseTreeIterator(*_tree, - *_allocator, - _sortedRandomValues, - true); - traverseTreeIterator(*_tree, - *_allocator, - _sortedRandomValues, - false); - traverseTreeIterator(*_tree, - *_allocator, - _sortedRandomValues, - true); - removeRandomValues(*_tree, *_allocator, _randomValues); - lookupGoneRandomValues(*_tree, *_allocator, _randomValues); - lookupFrozenRandomValues(*_tree, *_allocator,_randomValues); - traverseTreeIterator(*_tree, - *_allocator, - _sortedRandomValues, - true); - insertRandomValues(*_tree, *_allocator, _randomValues); + ASSERT_NO_FATAL_FAILURE(traverseTreeIterator(*_tree, *_allocator, _sortedRandomValues, false)); + ASSERT_NO_FATAL_FAILURE(traverseTreeIterator(*_tree, *_allocator, _sortedRandomValues, true)); + ASSERT_NO_FATAL_FAILURE(traverseTreeIterator(*_tree, *_allocator, _sortedRandomValues, false)); + ASSERT_NO_FATAL_FAILURE(traverseTreeIterator(*_tree, *_allocator, _sortedRandomValues, true)); + ASSERT_NO_FATAL_FAILURE(removeRandomValues(*_tree, *_allocator, _randomValues)); + ASSERT_NO_FATAL_FAILURE(lookupGoneRandomValues(*_tree, *_allocator, _randomValues)); + ASSERT_NO_FATAL_FAILURE(lookupFrozenRandomValues(*_tree, *_allocator,_randomValues)); + ASSERT_NO_FATAL_FAILURE(traverseTreeIterator(*_tree, *_allocator, _sortedRandomValues, true)); + ASSERT_NO_FATAL_FAILURE(insertRandomValues(*_tree, *_allocator, _randomValues)); freeTree(true); } diff --git a/vespalib/src/tests/datastore/array_store/array_store_test.cpp b/vespalib/src/tests/datastore/array_store/array_store_test.cpp index 583f6590e87..dc248ec2fed 100644 --- a/vespalib/src/tests/datastore/array_store/array_store_test.cpp +++ b/vespalib/src/tests/datastore/array_store/array_store_test.cpp @@ -145,7 +145,7 @@ struct ArrayStoreTest : public TestT } void assert_ref_reused(const ElemVector& first, const ElemVector& second, bool should_reuse) { EntryRef ref1 = add(first); - remove(ref1); + ASSERT_NO_FATAL_FAILURE(remove(ref1)); reclaim_memory(); EntryRef ref2 = add(second); EXPECT_EQ(should_reuse, (ref2 == ref1)); @@ -372,7 +372,7 @@ TYPED_TEST(NumberStoreFreeListsDisabledTest, large_arrays_are_NOT_allocated_from TYPED_TEST(NumberStoreTest, track_size_of_large_array_allocations_with_free_lists_enabled) { EntryRef ref = this->add({1,2,3,4,5}); this->assert_buffer_stats(ref, TestBufferStats().used(2).hold(0).dead(1).extra_used(20)); - this->remove({1,2,3,4,5}); + ASSERT_NO_FATAL_FAILURE(this->remove({1,2,3,4,5})); this->assert_buffer_stats(ref, TestBufferStats().used(2).hold(1).dead(1).extra_hold(20).extra_used(20)); this->reclaim_memory(); this->assert_buffer_stats(ref, TestBufferStats().used(2).hold(0).dead(2).extra_used(0)); @@ -406,7 +406,7 @@ test_compaction(NumberStoreBasicTest &f) EntryRef size1Ref = f.add({1}); EntryRef size2Ref = f.add({2,2}); EntryRef size3Ref = f.add({3,3,3}); - f.remove(f.add({5,5})); + ASSERT_NO_FATAL_FAILURE(f.remove(f.add({5,5}))); f.reclaim_memory(); f.assertBufferState(size1Ref, MemStats().used(1).dead(0)); f.assertBufferState(size2Ref, MemStats().used(2).dead(1)); @@ -416,7 +416,7 @@ test_compaction(NumberStoreBasicTest &f) uint32_t size3BufferId = f.getBufferId(size3Ref); EXPECT_EQ(3u, f.refStore.size()); - f.compactWorst(true, false); + ASSERT_NO_FATAL_FAILURE(f.compactWorst(true, false)); EXPECT_EQ(3u, f.refStore.size()); f.assertStoreContent(); @@ -449,9 +449,9 @@ void testCompaction(Fixture &f, bool compactMemory, bool compactAddressSpace) EntryRef size1Ref = f.add({1}); EntryRef size2Ref = f.add({2,2}); EntryRef size3Ref = f.add({3,3,3}); - f.remove(f.add({5,5,5})); - f.remove(f.add({6})); - f.remove(f.add({7})); + ASSERT_NO_FATAL_FAILURE(f.remove(f.add({5,5,5}))); + ASSERT_NO_FATAL_FAILURE(f.remove(f.add({6}))); + ASSERT_NO_FATAL_FAILURE(f.remove(f.add({7}))); f.reclaim_memory(); f.assertBufferState(size1Ref, MemStats().used(3).dead(2)); f.assertBufferState(size2Ref, MemStats().used(1).dead(0)); @@ -461,7 +461,7 @@ void testCompaction(Fixture &f, bool compactMemory, bool compactAddressSpace) uint32_t size3BufferId = f.getBufferId(size3Ref); EXPECT_EQ(3u, f.refStore.size()); - f.compactWorst(compactMemory, compactAddressSpace); + ASSERT_NO_FATAL_FAILURE(f.compactWorst(compactMemory, compactAddressSpace)); EXPECT_EQ(3u, f.refStore.size()); f.assertStoreContent(); @@ -527,7 +527,7 @@ TYPED_TEST(NumberStoreTest, used_onHold_and_dead_memory_usage_is_tracked_for_sma this->add({1,2,3}); uint32_t exp_entry_size = this->simple_buffers() ? (this->elem_size() * 3) : (this->elem_size() * 4 + 4); this->assertMemoryUsage(exp.used(exp_entry_size)); - this->remove({1,2,3}); + ASSERT_NO_FATAL_FAILURE(this->remove({1,2,3})); this->assertMemoryUsage(exp.hold(exp_entry_size)); this->reclaim_memory(); this->assertMemoryUsage(exp.holdToDead(exp_entry_size)); @@ -538,7 +538,7 @@ TYPED_TEST(NumberStoreTest, used_onHold_and_dead_memory_usage_is_tracked_for_lar MemStats exp(this->store.getMemoryUsage()); this->add({1,2,3,4,5}); this->assertMemoryUsage(exp.used(this->largeArraySize() + this->elem_size() * 5)); - this->remove({1,2,3,4,5}); + ASSERT_NO_FATAL_FAILURE(this->remove({1,2,3,4,5})); this->assertMemoryUsage(exp.hold(this->largeArraySize() + this->elem_size() * 5)); this->reclaim_memory(); this->assertMemoryUsage(exp.decUsed(this->elem_size() * 5).decHold(this->largeArraySize() + this->elem_size() * 5). @@ -599,8 +599,8 @@ TYPED_TEST(NumberStoreTest, provided_memory_allocator_is_used) EXPECT_EQ(AllocStats(5, 0), this->stats); this->assertAdd({2,3,4,5,6,7}); EXPECT_EQ(AllocStats(6, 0), this->stats); - this->remove({1,2,3,4,5}); - this->remove({2,3,4,5,6,7}); + ASSERT_NO_FATAL_FAILURE(this->remove({1,2,3,4,5})); + ASSERT_NO_FATAL_FAILURE(this->remove({2,3,4,5,6,7})); this->reclaim_memory(); EXPECT_EQ(AllocStats(6, 2), this->stats); this->assertAdd({1,2,3,4,5}); diff --git a/vespalib/src/tests/datastore/sharded_hash_map/sharded_hash_map_test.cpp b/vespalib/src/tests/datastore/sharded_hash_map/sharded_hash_map_test.cpp index 08b9b96e202..6b4aa51a481 100644 --- a/vespalib/src/tests/datastore/sharded_hash_map/sharded_hash_map_test.cpp +++ b/vespalib/src/tests/datastore/sharded_hash_map/sharded_hash_map_test.cpp @@ -306,7 +306,7 @@ void DataStoreShardedHashTest::test_normalize_values(bool use_filter, bool one_filter) { populate_sample_data(large_population); - populate_sample_values(large_population); + ASSERT_NO_FATAL_FAILURE(populate_sample_values(large_population)); if (use_filter) { auto filter = make_entry_ref_filter<RefT>(one_filter); EXPECT_TRUE(_hash_map.normalize_values([](std::vector<EntryRef> &refs) noexcept { for (auto &ref : refs) { RefT iref(ref); ref = RefT(iref.offset() + 300, iref.bufferId()); } }, filter)); @@ -332,7 +332,7 @@ void DataStoreShardedHashTest::test_foreach_value(bool one_filter) { populate_sample_data(large_population); - populate_sample_values(large_population); + ASSERT_NO_FATAL_FAILURE(populate_sample_values(large_population)); auto filter = make_entry_ref_filter<RefT>(one_filter); std::vector<EntryRef> exp_refs; @@ -340,7 +340,7 @@ DataStoreShardedHashTest::test_foreach_value(bool one_filter) std::vector<EntryRef> act_refs; _hash_map.foreach_value([&act_refs](const std::vector<EntryRef> &refs) { act_refs.insert(act_refs.end(), refs.begin(), refs.end()); }, filter); EXPECT_EQ(exp_refs, act_refs); - clear_sample_values(large_population); + ASSERT_NO_FATAL_FAILURE(clear_sample_values(large_population)); } TEST_F(DataStoreShardedHashTest, single_threaded_reader_without_updates) diff --git a/vespalib/src/tests/datastore/unique_store/unique_store_test.cpp b/vespalib/src/tests/datastore/unique_store/unique_store_test.cpp index 7e96ab7b7a2..2c359db59b1 100644 --- a/vespalib/src/tests/datastore/unique_store/unique_store_test.cpp +++ b/vespalib/src/tests/datastore/unique_store/unique_store_test.cpp @@ -352,14 +352,14 @@ TYPED_TEST(TestBase, store_can_be_compacted) { EntryRef val0Ref = this->add(this->values()[0]); EntryRef val1Ref = this->add(this->values()[1]); - this->remove(this->add(this->values()[2])); + ASSERT_NO_FATAL_FAILURE(this->remove(this->add(this->values()[2]))); this->reclaim_memory(); size_t reserved = this->get_reserved(val0Ref); this->assertBufferState(val0Ref, TestBufferStats().used(reserved + 3).dead(reserved + 1)); uint32_t val1BufferId = this->getBufferId(val0Ref); EXPECT_EQ(2u, this->refStore.size()); - this->compactWorst(); + ASSERT_NO_FATAL_FAILURE(this->compactWorst()); EXPECT_EQ(2u, this->refStore.size()); this->assertStoreContent(); @@ -401,7 +401,7 @@ TYPED_TEST(TestBase, store_can_be_enumerated) { EntryRef val0Ref = this->add(this->values()[0]); EntryRef val1Ref = this->add(this->values()[1]); - this->remove(this->add(this->values()[2])); + ASSERT_NO_FATAL_FAILURE(this->remove(this->add(this->values()[2]))); this->reclaim_memory(); auto enumerator = this->getEnumerator(true); diff --git a/vespalib/src/tests/fileheader/CMakeLists.txt b/vespalib/src/tests/fileheader/CMakeLists.txt index 1b3f527ebd7..be8e91ef414 100644 --- a/vespalib/src/tests/fileheader/CMakeLists.txt +++ b/vespalib/src/tests/fileheader/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(vespalib_fileheader_test_app TEST fileheader_test.cpp DEPENDS vespalib + GTest::gtest ) vespa_add_test(NAME vespalib_fileheader_test_app COMMAND vespalib_fileheader_test_app) diff --git a/vespalib/src/tests/fileheader/fileheader_test.cpp b/vespalib/src/tests/fileheader/fileheader_test.cpp index 0dfa28cb24c..db2c7f7c65d 100644 --- a/vespalib/src/tests/fileheader/fileheader_test.cpp +++ b/vespalib/src/tests/fileheader/fileheader_test.cpp @@ -1,8 +1,9 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/vespalib/data/fileheader.h> #include <vespa/vespalib/data/databuffer.h> +#include <vespa/vespalib/gtest/gtest.h> +#include <vespa/vespalib/testkit/test_path.h> #include <vespa/fastos/file.h> #include <filesystem> @@ -14,63 +15,20 @@ vespalib::string fileheader_tmp("fileheader.tmp"); } -class Test : public vespalib::TestApp { -private: - void testTag(); - void testTagErrors(); - void testTagIteration(); - void testGenericHeader(); - void testBufferReader(); - void testBufferWriter(); - void testBufferAccess(); - void testFileReader(); - void testFileWriter(); - void testFileHeader(); - void testFileAlign(); - void testFileSize(); - void testReadErrors(); +class FileHeaderTest : public ::testing::Test { +protected: + FileHeaderTest(); + ~FileHeaderTest() override; bool testReadError(DataBuffer &buf, const std::string &expected); - void testWriteErrors(); - void testRewriteErrors(); - void testLayout(); - void testReadSize(bool mapped); void testReadSizeErrors(bool mapped); bool testReadSizeError(DataBuffer &buf, const std::string &expected, bool mapped); - -public: - int Main() override { - TEST_INIT("fileheader_test"); - - testTag(); TEST_FLUSH(); - testTagErrors(); TEST_FLUSH(); - testTagIteration(); TEST_FLUSH(); - testGenericHeader(); TEST_FLUSH(); - testBufferReader(); TEST_FLUSH(); - testBufferWriter(); TEST_FLUSH(); - testBufferAccess(); TEST_FLUSH(); - testFileReader(); TEST_FLUSH(); - testFileWriter(); TEST_FLUSH(); - testFileHeader(); TEST_FLUSH(); - testFileAlign(); TEST_FLUSH(); - testFileSize(); TEST_FLUSH(); - testReadErrors(); TEST_FLUSH(); - testWriteErrors(); TEST_FLUSH(); - testRewriteErrors(); TEST_FLUSH(); - testLayout(); TEST_FLUSH(); - testReadSize(false); TEST_FLUSH(); - testReadSizeErrors(false); TEST_FLUSH(); - testReadSize(true); TEST_FLUSH(); - testReadSizeErrors(true); TEST_FLUSH(); - - TEST_DONE(); - } }; -TEST_APPHOOK(Test); +FileHeaderTest::FileHeaderTest() = default; +FileHeaderTest::~FileHeaderTest() = default; -void -Test::testTag() +TEST_F(FileHeaderTest, test_tag) { { std::vector<GenericHeader::Tag> tags; @@ -81,18 +39,18 @@ Test::testTag() { GenericHeader::Tag tag = *it; for (uint32_t i = 0; i < 2; ++i) { - EXPECT_EQUAL(GenericHeader::Tag::TYPE_FLOAT, tag.getType()); - EXPECT_EQUAL("foo", tag.getName()); + EXPECT_EQ(GenericHeader::Tag::TYPE_FLOAT, tag.getType()); + EXPECT_EQ("foo", tag.getName()); EXPECT_TRUE(tag.asString().empty()); - EXPECT_APPROX(6.9, tag.asFloat(), 1E-6); - EXPECT_EQUAL(0, tag.asInteger()); + EXPECT_NEAR(6.9, tag.asFloat(), 1E-6); + EXPECT_EQ(0, tag.asInteger()); uint32_t len = tag.getSize(); DataBuffer buf(len); - EXPECT_EQUAL(len, tag.write(buf)); + EXPECT_EQ(len, tag.write(buf)); GenericHeader::Tag tmp; - EXPECT_EQUAL(len, tmp.read(buf)); + EXPECT_EQ(len, tmp.read(buf)); tag = tmp; } } @@ -111,18 +69,18 @@ Test::testTag() { GenericHeader::Tag tag = *it; for (uint32_t i = 0; i < 2; ++i) { - EXPECT_EQUAL(GenericHeader::Tag::TYPE_INTEGER, tag.getType()); - EXPECT_EQUAL("foo", tag.getName()); + EXPECT_EQ(GenericHeader::Tag::TYPE_INTEGER, tag.getType()); + EXPECT_EQ("foo", tag.getName()); EXPECT_TRUE(tag.asString().empty()); - EXPECT_EQUAL(0.0, tag.asFloat()); - EXPECT_EQUAL(69l, tag.asInteger()); + EXPECT_EQ(0.0, tag.asFloat()); + EXPECT_EQ(69l, tag.asInteger()); uint32_t len = tag.getSize(); DataBuffer buf(len); - EXPECT_EQUAL(len, tag.write(buf)); + EXPECT_EQ(len, tag.write(buf)); GenericHeader::Tag tmp; - EXPECT_EQUAL(len, tmp.read(buf)); + EXPECT_EQ(len, tmp.read(buf)); tag = tmp; } } @@ -130,35 +88,34 @@ Test::testTag() { GenericHeader::Tag tag("foo", "bar"); for (uint32_t i = 0; i < 2; ++i) { - EXPECT_EQUAL(GenericHeader::Tag::TYPE_STRING, tag.getType()); - EXPECT_EQUAL("foo", tag.getName()); - EXPECT_EQUAL("bar", tag.asString()); - EXPECT_EQUAL(0.0, tag.asFloat()); - EXPECT_EQUAL(0, tag.asInteger()); + EXPECT_EQ(GenericHeader::Tag::TYPE_STRING, tag.getType()); + EXPECT_EQ("foo", tag.getName()); + EXPECT_EQ("bar", tag.asString()); + EXPECT_EQ(0.0, tag.asFloat()); + EXPECT_EQ(0, tag.asInteger()); uint32_t len = tag.getSize(); DataBuffer buf(len); - EXPECT_EQUAL(len, tag.write(buf)); + EXPECT_EQ(len, tag.write(buf)); GenericHeader::Tag tmp; - EXPECT_EQUAL(len, tmp.read(buf)); + EXPECT_EQ(len, tmp.read(buf)); tag = tmp; } } { GenericHeader::Tag trueTag("foo", true); GenericHeader::Tag falseTag("foo", false); - EXPECT_EQUAL(GenericHeader::Tag::TYPE_INTEGER, trueTag.getType()); - EXPECT_EQUAL(GenericHeader::Tag::TYPE_INTEGER, falseTag.getType()); - EXPECT_EQUAL(1, trueTag.asInteger()); - EXPECT_EQUAL(0, falseTag.asInteger()); + EXPECT_EQ(GenericHeader::Tag::TYPE_INTEGER, trueTag.getType()); + EXPECT_EQ(GenericHeader::Tag::TYPE_INTEGER, falseTag.getType()); + EXPECT_EQ(1, trueTag.asInteger()); + EXPECT_EQ(0, falseTag.asInteger()); EXPECT_TRUE(trueTag.asBool()); EXPECT_FALSE(falseTag.asBool()); } } -void -Test::testTagErrors() +TEST_F(FileHeaderTest, test_tag_errors) { DataBuffer buf(1024); buf.writeBytes("foo", 3); @@ -170,33 +127,31 @@ Test::testTagErrors() tag.read(buf); EXPECT_TRUE(false); } catch (IllegalHeaderException &e) { - EXPECT_EQUAL("Can not deserialize empty tag.", e.getMessage()); + EXPECT_EQ("Can not deserialize empty tag.", e.getMessage()); } - EXPECT_EQUAL("bar", tag.getName()); - EXPECT_EQUAL(GenericHeader::Tag::TYPE_FLOAT, tag.getType()); - EXPECT_EQUAL(6.9, tag.asFloat()); + EXPECT_EQ("bar", tag.getName()); + EXPECT_EQ(GenericHeader::Tag::TYPE_FLOAT, tag.getType()); + EXPECT_EQ(6.9, tag.asFloat()); } -void -Test::testTagIteration() +TEST_F(FileHeaderTest, test_tag_iteration) { GenericHeader header; header.putTag(GenericHeader::Tag("foo", 6.9)); header.putTag(GenericHeader::Tag("bar", 6699)); header.putTag(GenericHeader::Tag("baz", "666999")); - EXPECT_EQUAL(3u, header.getNumTags()); - EXPECT_EQUAL("bar", header.getTag(0).getName()); - EXPECT_EQUAL("baz", header.getTag(1).getName()); - EXPECT_EQUAL("foo", header.getTag(2).getName()); + EXPECT_EQ(3u, header.getNumTags()); + EXPECT_EQ("bar", header.getTag(0).getName()); + EXPECT_EQ("baz", header.getTag(1).getName()); + EXPECT_EQ("foo", header.getTag(2).getName()); } -void -Test::testGenericHeader() +TEST_F(FileHeaderTest, test_generic_header) { GenericHeader header; EXPECT_TRUE(header.isEmpty()); - EXPECT_EQUAL(0u, header.getNumTags()); + EXPECT_EQ(0u, header.getNumTags()); EXPECT_TRUE(!header.hasTag("foo")); EXPECT_TRUE(header.getTag("foo").isEmpty()); EXPECT_TRUE(!header.hasTag("bar")); @@ -206,9 +161,9 @@ Test::testGenericHeader() header.putTag(GenericHeader::Tag("foo", 6.9)); EXPECT_TRUE(!header.isEmpty()); - EXPECT_EQUAL(1u, header.getNumTags()); + EXPECT_EQ(1u, header.getNumTags()); EXPECT_TRUE(header.hasTag("foo")); - EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_EQ(6.9, header.getTag("foo").asFloat()); EXPECT_TRUE(!header.hasTag("bar")); EXPECT_TRUE(header.getTag("bar").isEmpty()); EXPECT_TRUE(!header.hasTag("baz")); @@ -216,29 +171,29 @@ Test::testGenericHeader() header.putTag(GenericHeader::Tag("bar", 6699)); EXPECT_TRUE(!header.isEmpty()); - EXPECT_EQUAL(2u, header.getNumTags()); + EXPECT_EQ(2u, header.getNumTags()); EXPECT_TRUE(header.hasTag("foo")); - EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_EQ(6.9, header.getTag("foo").asFloat()); EXPECT_TRUE(header.hasTag("bar")); - EXPECT_EQUAL(6699, header.getTag("bar").asInteger()); + EXPECT_EQ(6699, header.getTag("bar").asInteger()); EXPECT_TRUE(!header.hasTag("baz")); EXPECT_TRUE(header.getTag("baz").isEmpty()); header.putTag(GenericHeader::Tag("baz", "666999")); EXPECT_TRUE(header.hasTag("foo")); - EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_EQ(6.9, header.getTag("foo").asFloat()); EXPECT_TRUE(header.hasTag("bar")); - EXPECT_EQUAL(6699, header.getTag("bar").asInteger()); + EXPECT_EQ(6699, header.getTag("bar").asInteger()); EXPECT_TRUE(header.hasTag("baz")); - EXPECT_EQUAL("666999", header.getTag("baz").asString()); + EXPECT_EQ("666999", header.getTag("baz").asString()); header.removeTag("bar"); EXPECT_TRUE(header.hasTag("foo")); - EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_EQ(6.9, header.getTag("foo").asFloat()); EXPECT_TRUE(!header.hasTag("bar")); EXPECT_TRUE(header.getTag("bar").isEmpty()); EXPECT_TRUE(header.hasTag("baz")); - EXPECT_EQUAL("666999", header.getTag("baz").asString()); + EXPECT_EQ("666999", header.getTag("baz").asString()); header.removeTag("foo"); EXPECT_TRUE(!header.hasTag("foo")); @@ -246,7 +201,7 @@ Test::testGenericHeader() EXPECT_TRUE(!header.hasTag("bar")); EXPECT_TRUE(header.getTag("bar").isEmpty()); EXPECT_TRUE(header.hasTag("baz")); - EXPECT_EQUAL("666999", header.getTag("baz").asString()); + EXPECT_EQ("666999", header.getTag("baz").asString()); header.removeTag("baz"); EXPECT_TRUE(!header.hasTag("foo")); @@ -257,8 +212,7 @@ Test::testGenericHeader() EXPECT_TRUE(header.getTag("baz").isEmpty()); } -void -Test::testBufferReader() +TEST_F(FileHeaderTest, test_buffer_reader) { DataBuffer src(256); for (uint32_t i = 0; i < 256; ++i) { @@ -272,15 +226,14 @@ Test::testBufferReader() while (sum < 256) { uint32_t len = (uint32_t)reader.getData(dst, 7); for (uint32_t i = 0; i < len; ++i) { - EXPECT_EQUAL(sum + i, (uint8_t)dst[i]); + EXPECT_EQ(sum + i, (uint8_t)dst[i]); } sum += len; } - EXPECT_EQUAL(256u, sum); + EXPECT_EQ(256u, sum); } -void -Test::testBufferWriter() +TEST_F(FileHeaderTest, test_buffer_writer) { DataBuffer dst(256); GenericHeader::BufferWriter writer(dst); @@ -292,20 +245,19 @@ Test::testBufferWriter() src[i] = (uint8_t)(sum + i); } uint32_t len = std::min(7u, 256 - sum); - EXPECT_EQUAL(len, (uint32_t)writer.putData(src, len)); + EXPECT_EQ(len, (uint32_t)writer.putData(src, len)); sum += len; } - EXPECT_EQUAL(256u, sum); + EXPECT_EQ(256u, sum); // flip dst for (uint32_t i = 0; i < 256; ++i) { uint8_t b = dst.readInt8(); - EXPECT_EQUAL(i, (uint32_t)b); + EXPECT_EQ(i, (uint32_t)b); } } -void -Test::testBufferAccess() +TEST_F(FileHeaderTest, test_buffer_access) { DataBuffer buf; uint32_t len; @@ -321,26 +273,25 @@ Test::testBufferAccess() len = header.getSize(); buf.ensureFree(len); GenericHeader::BufferWriter writer(buf); - EXPECT_EQUAL(len, header.write(writer)); + EXPECT_EQ(len, header.write(writer)); } { GenericHeader header; GenericHeader::BufferReader reader(buf); - EXPECT_EQUAL(len, header.read(reader)); + EXPECT_EQ(len, header.read(reader)); EXPECT_TRUE(header.hasTag("foo")); - EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_EQ(6.9, header.getTag("foo").asFloat()); EXPECT_TRUE(header.hasTag("bar")); - EXPECT_EQUAL(6699, header.getTag("bar").asInteger()); + EXPECT_EQ(6699, header.getTag("bar").asInteger()); EXPECT_TRUE(header.hasTag("baz")); - EXPECT_EQUAL("666999", header.getTag("baz").asString()); + EXPECT_EQ("666999", header.getTag("baz").asString()); EXPECT_TRUE(header.hasTag("big")); - EXPECT_EQUAL(0x1234567890abcdefLL, header.getTag("big").asInteger()); + EXPECT_EQ(0x1234567890abcdefLL, header.getTag("big").asInteger()); } } -void -Test::testFileReader() +TEST_F(FileHeaderTest, test_file_reader) { { FastOS_File file; @@ -350,7 +301,7 @@ Test::testFileReader() for (uint32_t i = 0; i < 256; ++i) { buf[i] = (uint8_t)i; } - EXPECT_EQUAL(256, file.Write2(buf, 256)); + EXPECT_EQ(256, file.Write2(buf, 256)); } { FastOS_File file; @@ -362,19 +313,18 @@ Test::testFileReader() while(sum < 256) { uint32_t len = (uint32_t)reader.getData(buf, 7); for (uint32_t i = 0; i < len; ++i) { - EXPECT_EQUAL(sum + i, (uint8_t)buf[i]); + EXPECT_EQ(sum + i, (uint8_t)buf[i]); } sum += len; } - EXPECT_EQUAL(256u, sum); + EXPECT_EQ(256u, sum); ASSERT_TRUE(file.Close()); std::filesystem::remove(std::filesystem::path(fileheader_tmp)); } } -void -Test::testFileWriter() +TEST_F(FileHeaderTest, test_file_writer) { { FastOS_File file; @@ -388,19 +338,19 @@ Test::testFileWriter() src[i] = (uint8_t)(sum + i); } uint32_t len = std::min(7u, 256 - sum); - EXPECT_EQUAL(len, (uint32_t)writer.putData(src, len)); + EXPECT_EQ(len, (uint32_t)writer.putData(src, len)); sum += len; } - EXPECT_EQUAL(256u, sum); + EXPECT_EQ(256u, sum); } { FastOS_File file; ASSERT_TRUE(file.OpenReadOnly(fileheader_tmp.c_str())); uint8_t buf[256]; - EXPECT_EQUAL(256, file.Read(buf, 256)); + EXPECT_EQ(256, file.Read(buf, 256)); for (uint32_t i = 0; i < 256; ++i) { - EXPECT_EQUAL(i, (uint32_t)buf[i]); + EXPECT_EQ(i, (uint32_t)buf[i]); } ASSERT_TRUE(file.Close()); @@ -408,8 +358,7 @@ Test::testFileWriter() } } -void -Test::testFileHeader() +TEST_F(FileHeaderTest, test_file_header) { uint32_t len = 0; { @@ -421,60 +370,58 @@ Test::testFileHeader() FastOS_File file; ASSERT_TRUE(file.OpenWriteOnlyTruncate(fileheader_tmp.c_str())); len = header.writeFile(file); - EXPECT_EQUAL(len, header.getSize()); + EXPECT_EQ(len, header.getSize()); } { FastOS_File file; ASSERT_TRUE(file.OpenReadWrite(fileheader_tmp.c_str())); FileHeader header; - EXPECT_EQUAL(len, header.readFile(file)); - EXPECT_EQUAL(len, header.getSize()); + EXPECT_EQ(len, header.readFile(file)); + EXPECT_EQ(len, header.getSize()); EXPECT_TRUE(header.hasTag("foo")); - EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_EQ(6.9, header.getTag("foo").asFloat()); EXPECT_TRUE(header.hasTag("bar")); - EXPECT_EQUAL(6699, header.getTag("bar").asInteger()); + EXPECT_EQ(6699, header.getTag("bar").asInteger()); EXPECT_TRUE(header.hasTag("baz")); - EXPECT_EQUAL("666999", header.getTag("baz").asString()); + EXPECT_EQ("666999", header.getTag("baz").asString()); header.putTag(FileHeader::Tag("foo", 9.6)); header.putTag(FileHeader::Tag("bar", 9966)); header.putTag(FileHeader::Tag("baz", "999666")); - EXPECT_EQUAL(len, header.getSize()); - EXPECT_EQUAL(len, header.rewriteFile(file)); + EXPECT_EQ(len, header.getSize()); + EXPECT_EQ(len, header.rewriteFile(file)); } { FileHeader header; FastOS_File file; ASSERT_TRUE(file.OpenReadOnly(fileheader_tmp.c_str())); - EXPECT_EQUAL(len, header.readFile(file)); - EXPECT_EQUAL(len, header.getSize()); + EXPECT_EQ(len, header.readFile(file)); + EXPECT_EQ(len, header.getSize()); ASSERT_TRUE(file.Close()); std::filesystem::remove(std::filesystem::path(fileheader_tmp)); EXPECT_TRUE(header.hasTag("foo")); - EXPECT_EQUAL(9.6, header.getTag("foo").asFloat()); + EXPECT_EQ(9.6, header.getTag("foo").asFloat()); EXPECT_TRUE(header.hasTag("bar")); - EXPECT_EQUAL(9966, header.getTag("bar").asInteger()); + EXPECT_EQ(9966, header.getTag("bar").asInteger()); EXPECT_TRUE(header.hasTag("baz")); - EXPECT_EQUAL("999666", header.getTag("baz").asString()); + EXPECT_EQ("999666", header.getTag("baz").asString()); } } -void -Test::testFileAlign() +TEST_F(FileHeaderTest, test_file_align) { for (uint32_t alignTo = 1; alignTo < 16; ++alignTo) { FileHeader header(alignTo); header.putTag(FileHeader::Tag("foo", "bar")); - EXPECT_EQUAL(0u, header.getSize() % alignTo); + EXPECT_EQ(0u, header.getSize() % alignTo); } } -void -Test::testFileSize() +TEST_F(FileHeaderTest, test_file_size) { for (uint32_t minSize = 0; minSize < 512; ++minSize) { FileHeader header(1u, minSize); @@ -483,8 +430,7 @@ Test::testFileSize() } } -void -Test::testReadErrors() +TEST_F(FileHeaderTest, test_read_errors) { { DataBuffer buf; @@ -524,7 +470,7 @@ Test::testReadErrors() } bool -Test::testReadError(DataBuffer &buf, const std::string &expected) +FileHeaderTest::testReadError(DataBuffer &buf, const std::string &expected) { GenericHeader header; header.putTag(GenericHeader::Tag("foo", "bar")); @@ -534,21 +480,22 @@ Test::testReadError(DataBuffer &buf, const std::string &expected) EXPECT_TRUE(false); return false; } catch (IllegalHeaderException &e) { - if (!EXPECT_EQUAL(expected, e.getMessage())) { + bool failed = false; + EXPECT_EQ(expected, e.getMessage()) << (failed = true, ""); + if (failed) { return false; } } - if (!EXPECT_EQUAL(1u, header.getNumTags())) { + bool failed = false; + EXPECT_EQ(1u, header.getNumTags()) << (failed = true, ""); + if (failed) { return false; } - if (!EXPECT_EQUAL("bar", header.getTag("foo").asString())) { - return false; - } - return true; + EXPECT_EQ("bar", header.getTag("foo").asString()) << (failed = true, ""); + return !failed; } -void -Test::testWriteErrors() +TEST_F(FileHeaderTest, test_write_errors) { GenericHeader header; header.putTag(GenericHeader::Tag("foo", 69)); @@ -562,15 +509,14 @@ Test::testWriteErrors() header.write(writer); EXPECT_TRUE(false); } catch (IllegalHeaderException &e) { - EXPECT_EQUAL("Failed to write header.", e.getMessage()); + EXPECT_EQ("Failed to write header.", e.getMessage()); } EXPECT_TRUE(header.hasTag("foo")); - EXPECT_EQUAL(69, header.getTag("foo").asInteger()); + EXPECT_EQ(69, header.getTag("foo").asInteger()); } -void -Test::testRewriteErrors() +TEST_F(FileHeaderTest, test_rewrite_errors) { FileHeader header; header.putTag(FileHeader::Tag("foo", "bar")); @@ -579,7 +525,7 @@ Test::testRewriteErrors() { FastOS_File file; ASSERT_TRUE(file.OpenWriteOnlyTruncate(fileheader_tmp.c_str())); - EXPECT_EQUAL(len, header.writeFile(file)); + EXPECT_EQ(len, header.writeFile(file)); } { FastOS_File file; @@ -590,13 +536,12 @@ Test::testRewriteErrors() header.rewriteFile(file); EXPECT_TRUE(false); } catch (IllegalHeaderException &e) { - EXPECT_EQUAL("Failed to rewrite resized header.", e.getMessage()); + EXPECT_EQ("Failed to rewrite resized header.", e.getMessage()); } } } -void -Test::testLayout() +TEST_F(FileHeaderTest, test_layout) { FileHeader header; { @@ -604,20 +549,20 @@ Test::testLayout() const std::string fileName = TEST_PATH("fileheader.dat"); ASSERT_TRUE(file.OpenReadOnly(fileName.c_str())); uint32_t len = header.readFile(file); - EXPECT_EQUAL(len, header.getSize()); + EXPECT_EQ(len, header.getSize()); } EXPECT_TRUE(header.hasTag("foo")); - EXPECT_EQUAL(6.9, header.getTag("foo").asFloat()); + EXPECT_EQ(6.9, header.getTag("foo").asFloat()); EXPECT_TRUE(header.hasTag("bar")); - EXPECT_EQUAL(6699, header.getTag("bar").asInteger()); + EXPECT_EQ(6699, header.getTag("bar").asInteger()); EXPECT_TRUE(header.hasTag("baz")); - EXPECT_EQUAL("666999", header.getTag("baz").asString()); + EXPECT_EQ("666999", header.getTag("baz").asString()); } void -Test::testReadSize(bool mapped) +FileHeaderTest::testReadSize(bool mapped) { DataBuffer buf; buf.writeInt32(GenericHeader::MAGIC); @@ -632,12 +577,21 @@ Test::testReadSize(bool mapped) GenericHeader::BufferReader reader(buf); headerLen = FileHeader::readSize(reader); } - EXPECT_EQUAL(21u, headerLen); + EXPECT_EQ(21u, headerLen); +} + +TEST_F(FileHeaderTest, test_read_size_unmapped) +{ + testReadSize(false); } +TEST_F(FileHeaderTest, test_read_size_mapped) +{ + testReadSize(true); +} void -Test::testReadSizeErrors(bool mapped) +FileHeaderTest::testReadSizeErrors(bool mapped) { { DataBuffer buf; @@ -674,9 +628,18 @@ Test::testReadSizeErrors(bool mapped) } } +TEST_F(FileHeaderTest, test_read_size_errors_unmapped) +{ + testReadSizeErrors(false); +} + +TEST_F(FileHeaderTest, test_read_size_errors_mapped) +{ + testReadSizeErrors(true); +} bool -Test::testReadSizeError(DataBuffer &buf, const std::string &expected, +FileHeaderTest::testReadSizeError(DataBuffer &buf, const std::string &expected, bool mapped) { uint32_t headerLen = 0u; @@ -691,11 +654,14 @@ Test::testReadSizeError(DataBuffer &buf, const std::string &expected, EXPECT_TRUE(false); return false; } catch (IllegalHeaderException &e) { - if (!EXPECT_EQUAL(expected, e.getMessage())) { + bool failed = false; + EXPECT_EQ(expected, e.getMessage()) << (failed = true, ""); + if (failed) { return false; } } - EXPECT_EQUAL(headerLen, 0u); + EXPECT_EQ(headerLen, 0u); return true; } +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/tests/floatingpointtype/CMakeLists.txt b/vespalib/src/tests/floatingpointtype/CMakeLists.txt index ed003fe7b83..9bcd2236eea 100644 --- a/vespalib/src/tests/floatingpointtype/CMakeLists.txt +++ b/vespalib/src/tests/floatingpointtype/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(vespalib_floatingpointtype_test_app TEST floatingpointtypetest.cpp DEPENDS vespalib + GTest::gtest ) vespa_add_test(NAME vespalib_floatingpointtype_test_app COMMAND vespalib_floatingpointtype_test_app) diff --git a/vespalib/src/tests/floatingpointtype/floatingpointtypetest.cpp b/vespalib/src/tests/floatingpointtype/floatingpointtypetest.cpp index 8e09d297a84..4b9718f1199 100644 --- a/vespalib/src/tests/floatingpointtype/floatingpointtypetest.cpp +++ b/vespalib/src/tests/floatingpointtype/floatingpointtypetest.cpp @@ -1,17 +1,9 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/objects/floatingpointtype.h> -class Test : public vespalib::TestApp -{ -public: - void testFloatingPoint(); - int Main() override; -}; - -void -Test::testFloatingPoint() +TEST(FloatingPointTypeTest, test_floating_point) { vespalib::Double d1(1.0); vespalib::Double d2(1.000000000000001); @@ -20,11 +12,11 @@ Test::testFloatingPoint() EXPECT_TRUE(d1.getValue() != d2.getValue()); - EXPECT_EQUAL(d1, d2); - EXPECT_EQUAL(d2, d1); + EXPECT_EQ(d1, d2); + EXPECT_EQ(d2, d1); - EXPECT_NOT_EQUAL(d1, d3); - EXPECT_NOT_EQUAL(d1, d4); + EXPECT_NE(d1, d3); + EXPECT_NE(d1, d4); EXPECT_TRUE(d1 - d2 == 0); EXPECT_TRUE(d2 - d1 == 0); @@ -40,34 +32,26 @@ Test::testFloatingPoint() EXPECT_TRUE(!(d1 < 1)); EXPECT_TRUE(!(d1 > 1)); - EXPECT_EQUAL(d2 * 4, d4); + EXPECT_EQ(d2 * 4, d4); - EXPECT_EQUAL(++d4, 5.0); - EXPECT_EQUAL(d4++, 5.0); - EXPECT_EQUAL(d4, 6.0); + EXPECT_EQ(++d4, 5.0); + EXPECT_EQ(d4++, 5.0); + EXPECT_EQ(d4, 6.0); d4 /= 3; - EXPECT_EQUAL(d4, 2.00000000001); + EXPECT_EQ(d4, 2.00000000001); d4 *= 2; - EXPECT_EQUAL(d4, 4.000000000001); + EXPECT_EQ(d4, 4.000000000001); - EXPECT_EQUAL(--d4, 3.0); - EXPECT_EQUAL(d4--, 3.0); - EXPECT_EQUAL(d4, 2.0); + EXPECT_EQ(--d4, 3.0); + EXPECT_EQ(d4--, 3.0); + EXPECT_EQ(d4, 2.0); d4 /= 0.50000000001; - EXPECT_EQUAL(d4, 4.0); + EXPECT_EQ(d4, 4.0); EXPECT_TRUE(!(d3 + 1 > 0)); EXPECT_TRUE(!(d3 + 1 < 0)); } -int -Test::Main() -{ - TEST_INIT("floatingpointtype_test"); - testFloatingPoint(); - TEST_DONE(); -} - -TEST_APPHOOK(Test) +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/tests/growablebytebuffer/CMakeLists.txt b/vespalib/src/tests/growablebytebuffer/CMakeLists.txt index be3ba82594d..0448eedd488 100644 --- a/vespalib/src/tests/growablebytebuffer/CMakeLists.txt +++ b/vespalib/src/tests/growablebytebuffer/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(vespalib_growablebytebuffer_test_app TEST growablebytebuffer_test.cpp DEPENDS vespalib + GTest::gtest ) vespa_add_test(NAME vespalib_growablebytebuffer_test_app COMMAND vespalib_growablebytebuffer_test_app) diff --git a/vespalib/src/tests/growablebytebuffer/growablebytebuffer_test.cpp b/vespalib/src/tests/growablebytebuffer/growablebytebuffer_test.cpp index a94a150c4e1..00cc77d19cb 100644 --- a/vespalib/src/tests/growablebytebuffer/growablebytebuffer_test.cpp +++ b/vespalib/src/tests/growablebytebuffer/growablebytebuffer_test.cpp @@ -1,19 +1,11 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/util/growablebytebuffer.h> using namespace vespalib; -class Test : public TestApp -{ -public: - void testGrowing(); - int Main() override; -}; - -void -Test::testGrowing() +TEST(GrowableByteBufferTest, test_growing) { GrowableByteBuffer buf(10); @@ -23,15 +15,7 @@ Test::testGrowing() buf.putDouble(1234); buf.putString("hei der"); - EXPECT_EQUAL(35u, buf.position()); -} - -int -Test::Main() -{ - TEST_INIT("guard_test"); - testGrowing(); - TEST_DONE(); + EXPECT_EQ(35u, buf.position()); } -TEST_APPHOOK(Test) +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/tests/json/CMakeLists.txt b/vespalib/src/tests/json/CMakeLists.txt index 720f8e3a040..89471e18d74 100644 --- a/vespalib/src/tests/json/CMakeLists.txt +++ b/vespalib/src/tests/json/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(vespalib_json_test_app TEST json.cpp DEPENDS vespalib + GTest::gtest ) vespa_add_test(NAME vespalib_json_test_app COMMAND vespalib_json_test_app boost) diff --git a/vespalib/src/tests/json/json.cpp b/vespalib/src/tests/json/json.cpp index 2638c6638c3..024d9045cc1 100644 --- a/vespalib/src/tests/json/json.cpp +++ b/vespalib/src/tests/json/json.cpp @@ -1,124 +1,108 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/util/jsonstream.h> #include <vespa/vespalib/util/jsonexception.h> #include <vespa/vespalib/stllike/asciistream.h> using namespace vespalib; -class JSONTest : public vespalib::TestApp -{ -private: - void testJSONWriterValues(); - void testJSONWriterObject(); - void testJSONWriterArray(); - void testJSONWriterComplex(); - void testJsonStream(); - void testJsonStreamErrors(); - void testJsonStreamStateReporting(); - -public: - int Main() override; -}; -void -JSONTest::testJSONWriterValues() +TEST(JSONTest, test_json_writer_values) { JSONStringer js; { // bool js.appendBool(true); - EXPECT_EQUAL(js.toString(), "true"); + EXPECT_EQ(js.toString(), "true"); js.clear().appendBool(false); - EXPECT_EQUAL(js.toString(), "false"); + EXPECT_EQ(js.toString(), "false"); } { // double js.clear().appendDouble(1234.5678); - EXPECT_EQUAL(js.toString(), "1234.5678"); + EXPECT_EQ(js.toString(), "1234.5678"); js.clear().appendDouble(-1234.5678); - EXPECT_EQUAL(js.toString(), "-1234.5678"); + EXPECT_EQ(js.toString(), "-1234.5678"); js.clear().appendDouble(0.0); - EXPECT_EQUAL(js.toString(), "0.0"); + EXPECT_EQ(js.toString(), "0.0"); js.clear().appendDouble(0.00000000012345678912356789123456789); - EXPECT_EQUAL(js.toString(), "1.234567891235679e-10"); + EXPECT_EQ(js.toString(), "1.234567891235679e-10"); js.clear().appendDouble(std::numeric_limits<double>::max()); - EXPECT_EQUAL(js.toString(), "1.797693134862316e+308"); + EXPECT_EQ(js.toString(), "1.797693134862316e+308"); js.clear().appendDouble(std::numeric_limits<double>::min()); - EXPECT_EQUAL(js.toString(), "2.225073858507201e-308"); + EXPECT_EQ(js.toString(), "2.225073858507201e-308"); js.clear().appendDouble(1.0 * (uint64_t(1) << 53)); - EXPECT_EQUAL(js.toString(), "9007199254740992.0"); + EXPECT_EQ(js.toString(), "9007199254740992.0"); js.clear().appendDouble(1000); - EXPECT_EQUAL(js.toString(), "1000.0"); + EXPECT_EQ(js.toString(), "1000.0"); } { // float js.clear().appendFloat(1234.5678f); - EXPECT_EQUAL(js.toString(), "1234.5677"); + EXPECT_EQ(js.toString(), "1234.5677"); js.clear().appendFloat(-1234.5678f); - EXPECT_EQUAL(js.toString(), "-1234.5677"); + EXPECT_EQ(js.toString(), "-1234.5677"); js.clear().appendFloat(0.0f); - EXPECT_EQUAL(js.toString(), "0.0"); + EXPECT_EQ(js.toString(), "0.0"); js.clear().appendFloat(0.00000000012345678912356789123456789f); - EXPECT_EQUAL(js.toString(), "1.2345679e-10"); + EXPECT_EQ(js.toString(), "1.2345679e-10"); js.clear().appendFloat(std::numeric_limits<float>::max()); - EXPECT_EQUAL(js.toString(), "3.4028235e+38"); + EXPECT_EQ(js.toString(), "3.4028235e+38"); js.clear().appendFloat(std::numeric_limits<float>::min()); - EXPECT_EQUAL(js.toString(), "1.1754944e-38"); + EXPECT_EQ(js.toString(), "1.1754944e-38"); js.clear().appendFloat(1.0 * (uint64_t(1) << 24)); - EXPECT_EQUAL(js.toString(), "16777216.0"); + EXPECT_EQ(js.toString(), "16777216.0"); js.clear().appendFloat(1000); - EXPECT_EQUAL(js.toString(), "1000.0"); + EXPECT_EQ(js.toString(), "1000.0"); } { // long js.clear().appendInt64(4294967296ll); - EXPECT_EQUAL(js.toString(), "4294967296"); + EXPECT_EQ(js.toString(), "4294967296"); js.clear().appendInt64(-4294967296ll); - EXPECT_EQUAL(js.toString(), "-4294967296"); + EXPECT_EQ(js.toString(), "-4294967296"); } { // string js.clear().appendString("string"); - EXPECT_EQUAL(js.toString(), "\"string\""); + EXPECT_EQ(js.toString(), "\"string\""); } { // NULL js.clear().appendNull(); - EXPECT_EQUAL(js.toString(), "null"); + EXPECT_EQ(js.toString(), "null"); } { // quote js.clear().appendString("x\"y"); - EXPECT_EQUAL(js.toString(), "\"x\\\"y\""); + EXPECT_EQ(js.toString(), "\"x\\\"y\""); js.clear().appendString("x\\y"); - EXPECT_EQUAL(js.toString(), "\"x\\\\y\""); + EXPECT_EQ(js.toString(), "\"x\\\\y\""); js.clear().appendString("x/y"); - EXPECT_EQUAL(js.toString(), "\"x/y\""); + EXPECT_EQ(js.toString(), "\"x/y\""); js.clear().appendString("x\by"); - EXPECT_EQUAL(js.toString(), "\"x\\by\""); + EXPECT_EQ(js.toString(), "\"x\\by\""); js.clear().appendString("x\fy"); - EXPECT_EQUAL(js.toString(), "\"x\\fy\""); + EXPECT_EQ(js.toString(), "\"x\\fy\""); js.clear().appendString("x\ny"); - EXPECT_EQUAL(js.toString(), "\"x\\ny\""); + EXPECT_EQ(js.toString(), "\"x\\ny\""); js.clear().appendString("x\ry"); - EXPECT_EQUAL(js.toString(), "\"x\\ry\""); + EXPECT_EQ(js.toString(), "\"x\\ry\""); js.clear().appendString("x\ty"); - EXPECT_EQUAL(js.toString(), "\"x\\ty\""); + EXPECT_EQ(js.toString(), "\"x\\ty\""); } } -void -JSONTest::testJSONWriterObject() +TEST(JSONTest, test_json_writer_object) { JSONStringer js; { // single pair js.beginObject().appendKey("k1").appendInt64(1l).endObject(); - EXPECT_EQUAL(js.toString(), "{\"k1\":1}"); + EXPECT_EQ(js.toString(), "{\"k1\":1}"); } { // multiple pairs js.clear().beginObject().appendKey("k1").appendInt64(1l).appendKey("k2").appendInt64(2l).endObject(); - EXPECT_EQUAL(js.toString(), "{\"k1\":1,\"k2\":2}"); + EXPECT_EQ(js.toString(), "{\"k1\":1,\"k2\":2}"); } { // object in object js.clear().beginObject().appendKey("k1").beginObject().appendKey("k1.1").appendInt64(11l).endObject().endObject(); - EXPECT_EQUAL(js.toString(), "{\"k1\":{\"k1.1\":11}}"); + EXPECT_EQ(js.toString(), "{\"k1\":{\"k1.1\":11}}"); } { // object in object (multiple pairs) js.clear().beginObject(). @@ -133,65 +117,61 @@ JSONTest::testJSONWriterObject() appendKey("k2.2").appendInt64(22l). endObject(). endObject(); - EXPECT_EQUAL(js.toString(), "{\"k1\":{\"k1.1\":11,\"k1.2\":12},\"k2\":{\"k2.1\":21,\"k2.2\":22}}"); + EXPECT_EQ(js.toString(), "{\"k1\":{\"k1.1\":11,\"k1.2\":12},\"k2\":{\"k2.1\":21,\"k2.2\":22}}"); } { // array in object js.clear().beginObject().appendKey("k1"). beginArray().appendInt64(1l).appendInt64(2l).endArray().endObject(); - EXPECT_EQUAL(js.toString(), "{\"k1\":[1,2]}"); + EXPECT_EQ(js.toString(), "{\"k1\":[1,2]}"); } { // array in object (multiple pairs) js.clear().beginObject(). appendKey("k1").beginArray().appendInt64(1l).appendInt64(2l).endArray(). appendKey("k2").beginArray().appendInt64(3l).appendInt64(4l).endArray(). endObject(); - EXPECT_EQUAL(js.toString(), "{\"k1\":[1,2],\"k2\":[3,4]}"); + EXPECT_EQ(js.toString(), "{\"k1\":[1,2],\"k2\":[3,4]}"); } } - -void -JSONTest::testJSONWriterArray() +TEST(JSONTest, test_json_writer_array) { JSONStringer js; { // single element js.beginArray().appendInt64(1l).endArray(); - EXPECT_EQUAL(js.toString(), "[1]"); + EXPECT_EQ(js.toString(), "[1]"); } { // multiple elements js.clear().beginArray().appendInt64(1l).appendInt64(2l).endArray(); - EXPECT_EQUAL(js.toString(), "[1,2]"); + EXPECT_EQ(js.toString(), "[1,2]"); } { // array in array js.clear().beginArray().beginArray().appendInt64(1l).endArray().endArray(); - EXPECT_EQUAL(js.toString(), "[[1]]"); + EXPECT_EQ(js.toString(), "[[1]]"); } { // array in array (multiple elements) js.clear().beginArray(). beginArray().appendInt64(1l).appendInt64(2l).endArray(). beginArray().appendInt64(3l).appendInt64(4l).endArray(). endArray(); - EXPECT_EQUAL(js.toString(), "[[1,2],[3,4]]"); + EXPECT_EQ(js.toString(), "[[1,2],[3,4]]"); } { // object in array js.clear().beginArray(). beginObject().appendKey("k1").appendInt64(1l).endObject(). endArray(); - EXPECT_EQUAL(js.toString(), "[{\"k1\":1}]"); + EXPECT_EQ(js.toString(), "[{\"k1\":1}]"); } { // object in array (multiple elements) js.clear().beginArray(). beginObject().appendKey("k1").appendInt64(1l).appendKey("k2").appendInt64(2l).endObject(). beginObject().appendKey("k3").appendInt64(3l).appendKey("k4").appendInt64(4l).endObject(). endArray(); - EXPECT_EQUAL(js.toString(), "[{\"k1\":1,\"k2\":2},{\"k3\":3,\"k4\":4}]"); + EXPECT_EQ(js.toString(), "[{\"k1\":1,\"k2\":2},{\"k3\":3,\"k4\":4}]"); } } - -void -JSONTest::testJSONWriterComplex() +TEST(JSONTest, test_json_writer_complex) { JSONStringer js; @@ -269,7 +249,7 @@ JSONTest::testJSONWriterComplex() js.endArray(); } js.endObject(); - EXPECT_EQUAL(js.toString(), "{\"k1\":{\"k1.1\":1,\"k1.2\":[2,3]},\"k2\":{\"k2.1\":{\"k2.1.1\":4,\"k2.1.2\":[5,6]}},\"k3\":[{\"k3.1\":7,\"k3.2\":[8,9]},{\"k3.1\":10,\"k3.2\":[11,12]}]}"); + EXPECT_EQ(js.toString(), "{\"k1\":{\"k1.1\":1,\"k1.2\":[2,3]},\"k2\":{\"k2.1\":{\"k2.1.1\":4,\"k2.1.2\":[5,6]}},\"k3\":[{\"k3.1\":7,\"k3.2\":[8,9]},{\"k3.1\":10,\"k3.2\":[11,12]}]}"); } namespace { @@ -304,19 +284,17 @@ namespace { }; } -void -JSONTest::testJsonStream() +TEST(JSONTest, test_json_stream) { vespalib::asciistream as; vespalib::JsonStream stream(as); Builder b; b.build(stream); stream.finalize(); - EXPECT_EQUAL(as.str(), "{\"k1\":{\"k1.1\":1,\"k1.2\":[2,3]},\"k2\":{\"k2.1\":{\"k2.1.1\":4,\"k2.1.2\":[5,6]}},\"k3\":[{\"k3.1\":-7,\"k3.2\":[-8,-9]},{\"k3.1\":10,\"k3.2\":[11,12]}]}"); + EXPECT_EQ(as.str(), "{\"k1\":{\"k1.1\":1,\"k1.2\":[2,3]},\"k2\":{\"k2.1\":{\"k2.1.1\":4,\"k2.1.2\":[5,6]}},\"k3\":[{\"k3.1\":-7,\"k3.2\":[-8,-9]},{\"k3.1\":10,\"k3.2\":[11,12]}]}"); } -void -JSONTest::testJsonStreamErrors() +TEST(JSONTest, test_json_stream_errors) { using namespace vespalib::jsonstream; // Unsupported object keys @@ -325,42 +303,42 @@ JSONTest::testJsonStreamErrors() vespalib::JsonStream stream(as); stream << Object() << Object(); } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: An object value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); + EXPECT_EQ("Invalid state on call: An object value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); } try{ vespalib::asciistream as; vespalib::JsonStream stream(as); stream << Object() << true; } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: A bool value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); + EXPECT_EQ("Invalid state on call: A bool value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); } try{ vespalib::asciistream as; vespalib::JsonStream stream(as); stream << Object() << 13; } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: An int64_t value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); + EXPECT_EQ("Invalid state on call: An int64_t value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); } try{ vespalib::asciistream as; vespalib::JsonStream stream(as); stream << Object() << uint64_t(13); } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: A uint64_t value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); + EXPECT_EQ("Invalid state on call: A uint64_t value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); } try{ vespalib::asciistream as; vespalib::JsonStream stream(as); stream << Object() << 0.5; } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: A double value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); + EXPECT_EQ("Invalid state on call: A double value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); } try{ vespalib::asciistream as; vespalib::JsonStream stream(as); stream << Object() << jsonstream::Array(); } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: An array value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); + EXPECT_EQ("Invalid state on call: An array value cannot be an object key ({}(ObjectExpectingKey))", e.getReason()); } // Invalid points to add End() try{ @@ -368,14 +346,14 @@ JSONTest::testJsonStreamErrors() vespalib::JsonStream stream(as); stream << Object() << "foo" << End(); } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: Object got key but not value. Cannot end it now ({foo}(ObjectExpectingValue))", e.getReason()); + EXPECT_EQ("Invalid state on call: Object got key but not value. Cannot end it now ({foo}(ObjectExpectingValue))", e.getReason()); } try{ vespalib::asciistream as; vespalib::JsonStream stream(as); stream << End(); } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: No tag to end. At root ((RootExpectingArrayOrObjectStart))", e.getReason()); + EXPECT_EQ("Invalid state on call: No tag to end. At root ((RootExpectingArrayOrObjectStart))", e.getReason()); } // Adding to finalized stream try{ @@ -383,61 +361,60 @@ JSONTest::testJsonStreamErrors() vespalib::JsonStream stream(as); stream << Object() << End() << "foo"; } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add a string value. (Finalized)", e.getReason()); + EXPECT_EQ("Invalid state on call: Stream already finalized. Can't add a string value. (Finalized)", e.getReason()); } try{ vespalib::asciistream as; vespalib::JsonStream stream(as); stream << Object() << End() << false; } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add a bool value. (Finalized)", e.getReason()); + EXPECT_EQ("Invalid state on call: Stream already finalized. Can't add a bool value. (Finalized)", e.getReason()); } try{ vespalib::asciistream as; vespalib::JsonStream stream(as); stream << Object() << End() << 13; } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add a long long value. (Finalized)", e.getReason()); + EXPECT_EQ("Invalid state on call: Stream already finalized. Can't add a long long value. (Finalized)", e.getReason()); } try{ vespalib::asciistream as; vespalib::JsonStream stream(as); stream << Object() << End() << 13u; } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add an unsigned long long value. (Finalized)", e.getReason()); + EXPECT_EQ("Invalid state on call: Stream already finalized. Can't add an unsigned long long value. (Finalized)", e.getReason()); } try{ vespalib::asciistream as; vespalib::JsonStream stream(as); stream << Object() << End() << 0.2; } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add a double value. (Finalized)", e.getReason()); + EXPECT_EQ("Invalid state on call: Stream already finalized. Can't add a double value. (Finalized)", e.getReason()); } try{ vespalib::asciistream as; vespalib::JsonStream stream(as); stream << Object() << End() << Object(); } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't start a new object. (Finalized)", e.getReason()); + EXPECT_EQ("Invalid state on call: Stream already finalized. Can't start a new object. (Finalized)", e.getReason()); } try{ vespalib::asciistream as; vespalib::JsonStream stream(as); stream << Object() << End() << jsonstream::Array(); } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't start a new array. (Finalized)", e.getReason()); + EXPECT_EQ("Invalid state on call: Stream already finalized. Can't start a new array. (Finalized)", e.getReason()); } try{ vespalib::asciistream as; vespalib::JsonStream stream(as); stream << Object() << End() << End(); } catch (vespalib::JsonStreamException& e) { - EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't end it. (Finalized)", e.getReason()); + EXPECT_EQ("Invalid state on call: Stream already finalized. Can't end it. (Finalized)", e.getReason()); } } -void -JSONTest::testJsonStreamStateReporting() +TEST(JSONTest, test_json_stream_state_reporting) { using namespace vespalib::jsonstream; vespalib::asciistream as; @@ -447,24 +424,8 @@ JSONTest::testJsonStreamStateReporting() << Object() << "key" << "value" << End() << false << End(); - EXPECT_EQUAL("Current: Finalized", stream.getJsonStreamState()); -} - -int -JSONTest::Main() -{ - TEST_INIT("json_test"); - - testJSONWriterValues(); - testJSONWriterObject(); - testJSONWriterArray(); - testJSONWriterComplex(); - testJsonStream(); - testJsonStreamErrors(); - testJsonStreamStateReporting(); - - TEST_DONE(); + EXPECT_EQ("Current: Finalized", stream.getJsonStreamState()); } -TEST_APPHOOK(JSONTest); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/tests/objects/identifiable/CMakeLists.txt b/vespalib/src/tests/objects/identifiable/CMakeLists.txt index e8227a8fa14..c3e8a932e20 100644 --- a/vespalib/src/tests/objects/identifiable/CMakeLists.txt +++ b/vespalib/src/tests/objects/identifiable/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(vespalib_identifiable_test_app TEST namedobject.cpp DEPENDS vespalib + GTest::gtest ) vespa_add_test(NAME vespalib_identifiable_test_app COMMAND vespalib_identifiable_test_app) diff --git a/vespalib/src/tests/objects/identifiable/identifiable_test.cpp b/vespalib/src/tests/objects/identifiable/identifiable_test.cpp index 4b31ba6e870..6296c7c5922 100644 --- a/vespalib/src/tests/objects/identifiable/identifiable_test.cpp +++ b/vespalib/src/tests/objects/identifiable/identifiable_test.cpp @@ -1,27 +1,26 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "namedobject.h" +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/objects/identifiable.hpp> #include <vespa/vespalib/objects/nbostream.h> #include <vespa/vespalib/util/exceptions.h> -#include <vespa/vespalib/testkit/testapp.h> using namespace vespalib; -class IdentifiableTest : public TestApp { - void requireThatIdentifiableCastCanCastPointers(); - void requireThatIdentifiableCastCanCastReferences(); - void testNamedObject(); - void testNboStream(); +class IdentifiableTest : public ::testing::Test { +protected: + IdentifiableTest(); + ~IdentifiableTest() override; template <typename T> void testStream(const T & a); - void testNboSerializer(); template <typename T> void testSerializer(const T & a); -public: - int Main() override; }; +IdentifiableTest::IdentifiableTest() = default; +IdentifiableTest::~IdentifiableTest() = default; + #define CID_Abstract 0x700000 #define CID_A 0x700001 #define CID_B 0x700002 @@ -74,22 +73,21 @@ IMPLEMENT_IDENTIFIABLE(A, Abstract); IMPLEMENT_IDENTIFIABLE(B, A); IMPLEMENT_IDENTIFIABLE(C, Identifiable); -void -IdentifiableTest::testNamedObject() +TEST_F(IdentifiableTest, test_named_object) { NamedObject a("first"), b("second");; nbostream os; NBOSerializer nos(os); nos << a << b; - EXPECT_EQUAL(27u,os.size()); + EXPECT_EQ(27u,os.size()); Identifiable::UP o1; o1 = Identifiable::create(nos); - EXPECT_EQUAL(14u, os.size()); + EXPECT_EQ(14u, os.size()); ASSERT_TRUE(o1->inherits(NamedObject::classId)); ASSERT_TRUE(o1->getClass().id() == NamedObject::classId); EXPECT_TRUE(static_cast<const NamedObject &>(*o1).getName() == "first"); o1 = Identifiable::create(nos); - EXPECT_EQUAL(0u, os.size()); + EXPECT_EQ(0u, os.size()); ASSERT_TRUE(o1->inherits(NamedObject::classId)); ASSERT_TRUE(o1->getClass().id() == NamedObject::classId); EXPECT_TRUE(static_cast<const NamedObject &>(*o1).getName() == "second"); @@ -103,8 +101,8 @@ void IdentifiableTest::testStream(const T & a) T b; s >> b; EXPECT_TRUE(s.empty()); - EXPECT_EQUAL(a, b); - EXPECT_EQUAL(nbostream::ok, s.state()); + EXPECT_EQ(a, b); + EXPECT_EQ(nbostream::ok, s.state()); EXPECT_TRUE(s.good()); } @@ -117,11 +115,11 @@ void IdentifiableTest::testSerializer(const T & a) T b; s >> b; EXPECT_TRUE(s.getStream().empty()); - EXPECT_EQUAL(a, b); - EXPECT_EQUAL(nbostream::ok, s.getStream().state()); + EXPECT_EQ(a, b); + EXPECT_EQ(nbostream::ok, s.getStream().state()); } -void IdentifiableTest::testNboSerializer() +TEST_F(IdentifiableTest, test_nbo_serializer) { testSerializer(true); testSerializer(false); @@ -138,7 +136,7 @@ void IdentifiableTest::testNboSerializer() testSerializer(vespalib::string("abcdefgh")); } -void IdentifiableTest::testNboStream() +TEST_F(IdentifiableTest, test_nbo_stream) { testStream(true); testStream(false); @@ -156,94 +154,85 @@ void IdentifiableTest::testNboStream() testStream(vespalib::string("abcdefgh")); { nbostream s(4); - EXPECT_EQUAL(4u, s.capacity()); + EXPECT_EQ(4u, s.capacity()); s << "abcdef"; - EXPECT_EQUAL(nbostream::ok, s.state()); - EXPECT_EQUAL(10u, s.size()); - EXPECT_EQUAL(16u, s.capacity()); - EXPECT_EQUAL(0, strncmp(s.data() + 4, "abcdef", 6)); + EXPECT_EQ(nbostream::ok, s.state()); + EXPECT_EQ(10u, s.size()); + EXPECT_EQ(16u, s.capacity()); + EXPECT_EQ(0, strncmp(s.data() + 4, "abcdef", 6)); } { nbostream s(8); - EXPECT_EQUAL(0u, s.size()); - EXPECT_EQUAL(8u, s.capacity()); + EXPECT_EQ(0u, s.size()); + EXPECT_EQ(8u, s.capacity()); const char * prev = s.data(); s << "ABCD"; - EXPECT_EQUAL(8u, s.size()); - EXPECT_EQUAL(8u, s.capacity()); - EXPECT_EQUAL(prev, s.data()); + EXPECT_EQ(8u, s.size()); + EXPECT_EQ(8u, s.capacity()); + EXPECT_EQ(prev, s.data()); s << "A long string that will cause resizing"; - EXPECT_EQUAL(50u, s.size()); - EXPECT_EQUAL(64u, s.capacity()); - EXPECT_NOT_EQUAL(prev, s.data()); + EXPECT_EQ(50u, s.size()); + EXPECT_EQ(64u, s.capacity()); + EXPECT_NE(prev, s.data()); } { nbostream s(8); - EXPECT_EQUAL(0u, s.size()); - EXPECT_EQUAL(8u, s.capacity()); + EXPECT_EQ(0u, s.size()); + EXPECT_EQ(8u, s.capacity()); const char * prev = s.data(); s << "ABCD"; - EXPECT_EQUAL(8u, s.size()); - EXPECT_EQUAL(8u, s.capacity()); - EXPECT_EQUAL(prev, s.data()); + EXPECT_EQ(8u, s.size()); + EXPECT_EQ(8u, s.capacity()); + EXPECT_EQ(prev, s.data()); s.reserve(50); - EXPECT_NOT_EQUAL(prev, s.data()); - EXPECT_EQUAL(8u, s.size()); - EXPECT_EQUAL(64u, s.capacity()); + EXPECT_NE(prev, s.data()); + EXPECT_EQ(8u, s.size()); + EXPECT_EQ(64u, s.capacity()); prev = s.data(); s << "A long string that will cause resizing"; - EXPECT_EQUAL(50u, s.size()); - EXPECT_EQUAL(64u, s.capacity()); - EXPECT_EQUAL(prev, s.data()); + EXPECT_EQ(50u, s.size()); + EXPECT_EQ(64u, s.capacity()); + EXPECT_EQ(prev, s.data()); } { nbostream s; s << int64_t(9); - EXPECT_EQUAL(8u, s.size()); - EXPECT_EQUAL(0u, s.rp()); + EXPECT_EQ(8u, s.size()); + EXPECT_EQ(0u, s.rp()); int64_t a(7), b(1); s >> a; - EXPECT_EQUAL(0u, s.size()); - EXPECT_EQUAL(8u, s.rp()); + EXPECT_EQ(0u, s.size()); + EXPECT_EQ(8u, s.rp()); EXPECT_TRUE(s.empty()); EXPECT_TRUE(s.good()); - EXPECT_EQUAL(9, a); + EXPECT_EQ(9, a); try { s >> b; EXPECT_TRUE(false); } catch (const IllegalStateException & e) { - EXPECT_EQUAL("Stream failed bufsize(1024), readp(8), writep(8)", e.getMessage()); + EXPECT_EQ("Stream failed bufsize(1024), readp(8), writep(8)", e.getMessage()); } - EXPECT_EQUAL(0u, s.size()); - EXPECT_EQUAL(8u, s.rp()); + EXPECT_EQ(0u, s.size()); + EXPECT_EQ(8u, s.rp()); EXPECT_TRUE(s.empty()); EXPECT_FALSE(s.good()); - EXPECT_EQUAL(1, b); - EXPECT_EQUAL(nbostream::eof, s.state()); + EXPECT_EQ(1, b); + EXPECT_EQ(nbostream::eof, s.state()); } } -int -IdentifiableTest::Main() +TEST_F(IdentifiableTest, test_identifiable) { - TEST_INIT("identifiable_test"); - - TEST_DO(requireThatIdentifiableCastCanCastPointers()); - TEST_DO(requireThatIdentifiableCastCanCastReferences()); - testNamedObject(); - testNboStream(); - testNboSerializer(); - A a; B b; const Identifiable::RuntimeClass & rtcA = a.getClass(); - EXPECT_EQUAL(rtcA.id(), static_cast<unsigned int>(A::classId)); - EXPECT_EQUAL(strcmp(rtcA.name(), "A"), 0); + EXPECT_EQ(rtcA.id(), static_cast<unsigned int>(A::classId)); + EXPECT_EQ(strcmp(rtcA.name(), "A"), 0); const Identifiable::RuntimeClass & rtcB = b.getClass(); - EXPECT_EQUAL(rtcB.id(), static_cast<unsigned int>(B::classId)); - EXPECT_EQUAL(strcmp(rtcB.name(), "B"), 0); + EXPECT_EQ(rtcB.id(), static_cast<unsigned int>(B::classId)); + EXPECT_EQ(strcmp(rtcB.name(), "B"), 0); const Identifiable::RuntimeClass * rt(Identifiable::classFromId(0x1ab76245)); ASSERT_TRUE(rt == NULL); @@ -270,7 +259,7 @@ IdentifiableTest::Main() nbostream os; NBOSerializer nos(os); nos << *o; - EXPECT_EQUAL(os.size(), 4u); + EXPECT_EQ(os.size(), 4u); Identifiable::UP o2 = Identifiable::create(nos); EXPECT_TRUE(os.empty()); ASSERT_TRUE(o->inherits(B::classId)); @@ -297,18 +286,17 @@ IdentifiableTest::Main() IdentifiablePtr<C> c1(new C(10)); IdentifiablePtr<C> c2(new C(20)); - EXPECT_LESS(c0.cmp(c1), 0); - EXPECT_EQUAL(c0.cmp(c0), 0); - EXPECT_GREATER(c1.cmp(c0), 0); + EXPECT_LT(c0.cmp(c1), 0); + EXPECT_EQ(c0.cmp(c0), 0); + EXPECT_GT(c1.cmp(c0), 0); - EXPECT_LESS(c1.cmp(c2), 0); - EXPECT_EQUAL(c1.cmp(c1), 0); - EXPECT_GREATER(c2.cmp(c1), 0); - - TEST_DONE(); + EXPECT_LT(c1.cmp(c2), 0); + EXPECT_EQ(c1.cmp(c1), 0); + EXPECT_GT(c2.cmp(c1), 0); } -void IdentifiableTest::requireThatIdentifiableCastCanCastPointers() { +TEST_F(IdentifiableTest, require_that_identifiable_cast_can_cast_pointers) +{ A a; B b; EXPECT_TRUE(Identifiable::cast<A *>(&a)); @@ -319,7 +307,8 @@ void IdentifiableTest::requireThatIdentifiableCastCanCastPointers() { EXPECT_TRUE(Identifiable::cast<Abstract *>(&b)); } -void IdentifiableTest::requireThatIdentifiableCastCanCastReferences() { +TEST_F(IdentifiableTest, require_that_identifiable_cast_can_cast_references) +{ A a; B b; try { @@ -330,9 +319,9 @@ void IdentifiableTest::requireThatIdentifiableCastCanCastReferences() { Identifiable::cast<Abstract &>(a); Identifiable::cast<Abstract &>(b); } catch (std::bad_cast &e) { - TEST_FATAL(e.what()); + FAIL() << e.what(); } - EXPECT_EXCEPTION(Identifiable::cast<B &>(a), std::bad_cast, "bad_cast"); + EXPECT_THROW(Identifiable::cast<B &>(a), std::bad_cast); } -TEST_APPHOOK(IdentifiableTest) +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/tests/optimized/CMakeLists.txt b/vespalib/src/tests/optimized/CMakeLists.txt index 0e7e85b6678..ce1c3a7cf67 100644 --- a/vespalib/src/tests/optimized/CMakeLists.txt +++ b/vespalib/src/tests/optimized/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(vespalib_optimized_test_app TEST optimized_test.cpp DEPENDS vespalib + GTest::gtest ) vespa_add_test(NAME vespalib_optimized_test_app COMMAND vespalib_optimized_test_app) diff --git a/vespalib/src/tests/optimized/optimized_test.cpp b/vespalib/src/tests/optimized/optimized_test.cpp index 9dffefeb012..ec14750f919 100644 --- a/vespalib/src/tests/optimized/optimized_test.cpp +++ b/vespalib/src/tests/optimized/optimized_test.cpp @@ -1,82 +1,64 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/util/optimized.h> using namespace vespalib; -class Test : public vespalib::TestApp +template <typename TestType> +class OptimizedTest : public ::testing::Test { -private: - template<typename T> - void testMsbIdx(); - template<typename T> - void testLsbIdx(); - template<typename T> - void testPopCount(); -public: - int Main() override; +protected: + OptimizedTest(); + ~OptimizedTest() override; }; -template<typename T> -void Test::testMsbIdx() +template <typename TestType> +OptimizedTest<TestType>::OptimizedTest() = default; +template <typename TestType> +OptimizedTest<TestType>::~OptimizedTest() = default; + +using OptimizedTestTypes = ::testing::Types<unsigned int, unsigned long, unsigned long long>; +TYPED_TEST_SUITE(OptimizedTest, OptimizedTestTypes); + +TYPED_TEST(OptimizedTest, test_msb_idx) { - EXPECT_EQUAL(Optimized::msbIdx(T(0)), 0); - EXPECT_EQUAL(Optimized::msbIdx(T(1)), 0); - EXPECT_EQUAL(Optimized::msbIdx(T(-1)), int(sizeof(T)*8 - 1)); + using T = TypeParam; + EXPECT_EQ(Optimized::msbIdx(T(0)), 0); + EXPECT_EQ(Optimized::msbIdx(T(1)), 0); + EXPECT_EQ(Optimized::msbIdx(T(-1)), int(sizeof(T)*8 - 1)); T v(static_cast<T>(-1)); for (size_t i(0); i < sizeof(T); i++) { for (size_t j(0); j < 8; j++) { - EXPECT_EQUAL(Optimized::msbIdx(v), int(sizeof(T)*8 - (i*8+j) - 1)); + EXPECT_EQ(Optimized::msbIdx(v), int(sizeof(T)*8 - (i*8+j) - 1)); v = v >> 1; } } } -template<typename T> -void Test::testLsbIdx() +TYPED_TEST(OptimizedTest, test_lsb_idx) { - EXPECT_EQUAL(Optimized::lsbIdx(T(0)), 0); - EXPECT_EQUAL(Optimized::lsbIdx(T(1)), 0); - EXPECT_EQUAL(Optimized::lsbIdx(T(T(1)<<(sizeof(T)*8 - 1))), int(sizeof(T)*8 - 1)); - EXPECT_EQUAL(Optimized::lsbIdx(T(-1)), 0); + using T = TypeParam; + EXPECT_EQ(Optimized::lsbIdx(T(0)), 0); + EXPECT_EQ(Optimized::lsbIdx(T(1)), 0); + EXPECT_EQ(Optimized::lsbIdx(T(T(1)<<(sizeof(T)*8 - 1))), int(sizeof(T)*8 - 1)); + EXPECT_EQ(Optimized::lsbIdx(T(-1)), 0); T v(static_cast<T>(-1)); for (size_t i(0); i < sizeof(T); i++) { for (size_t j(0); j < 8; j++) { - EXPECT_EQUAL(Optimized::lsbIdx(v), int(i*8+j)); + EXPECT_EQ(Optimized::lsbIdx(v), int(i*8+j)); v = v << 1; } } } -template<typename T> -void Test::testPopCount() +TYPED_TEST(OptimizedTest, test_pop_count) { - EXPECT_EQUAL(0, Optimized::popCount(T(0))); - EXPECT_EQUAL(1, Optimized::popCount(T(1))); - EXPECT_EQUAL(int(8 * sizeof(T)), Optimized::popCount(T(-1))); + using T = TypeParam; + EXPECT_EQ(0, Optimized::popCount(T(0))); + EXPECT_EQ(1, Optimized::popCount(T(1))); + EXPECT_EQ(int(8 * sizeof(T)), Optimized::popCount(T(-1))); } -int Test::Main() -{ - TEST_INIT("optimized_test"); - - testMsbIdx<unsigned int>(); - testMsbIdx<unsigned long>(); - testMsbIdx<unsigned long long>(); - - TEST_FLUSH(); - testLsbIdx<unsigned int>(); - testLsbIdx<unsigned long>(); - testLsbIdx<unsigned long long>(); - - TEST_FLUSH(); - testPopCount<unsigned int>(); - testPopCount<unsigned long>(); - testPopCount<unsigned long long>(); - - TEST_FLUSH(); - TEST_DONE(); -} +GTEST_MAIN_RUN_ALL_TESTS() -TEST_APPHOOK(Test) diff --git a/vespalib/src/tests/printable/CMakeLists.txt b/vespalib/src/tests/printable/CMakeLists.txt index e9332bba309..4781e9b8f54 100644 --- a/vespalib/src/tests/printable/CMakeLists.txt +++ b/vespalib/src/tests/printable/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(vespalib_printabletest_app TEST printabletest.cpp DEPENDS vespalib + GTest::gtest ) vespa_add_test(NAME vespalib_printabletest_app COMMAND vespalib_printabletest_app) diff --git a/vespalib/src/tests/printable/printabletest.cpp b/vespalib/src/tests/printable/printabletest.cpp index 03e3c777a25..5b6c0058bf0 100644 --- a/vespalib/src/tests/printable/printabletest.cpp +++ b/vespalib/src/tests/printable/printabletest.cpp @@ -1,8 +1,8 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/util/printable.h> #include <vespa/vespalib/stllike/asciistream.h> -#include <vespa/vespalib/testkit/testapp.h> struct Foo : public vespalib::Printable { int val; @@ -74,80 +74,61 @@ struct AsciiBar : public vespalib::AsciiPrintable { } }; -class Test : public vespalib::TestApp -{ -public: - void testSimple(); - void testAsciiVariant(); - int Main() override; -}; - -void -Test::testSimple() +TEST(PrintableTest, test_simple) { Foo foo(3, "myval"); Bar bar(7, 3, "otherval"); - EXPECT_EQUAL("Foo(val = 3, other size 5)", foo.toString()); - EXPECT_EQUAL("Foo(val = 3, other size 5)", foo.toString(false, " ")); - EXPECT_EQUAL("Foo(val = 3, other:\n" - " myval)", foo.toString(true)); - EXPECT_EQUAL("Foo(val = 3, other:\n" - " myval)", foo.toString(true, " ")); + EXPECT_EQ("Foo(val = 3, other size 5)", foo.toString()); + EXPECT_EQ("Foo(val = 3, other size 5)", foo.toString(false, " ")); + EXPECT_EQ("Foo(val = 3, other:\n" + " myval)", foo.toString(true)); + EXPECT_EQ("Foo(val = 3, other:\n" + " myval)", foo.toString(true, " ")); std::ostringstream ost; ost << foo; - EXPECT_EQUAL("Foo(val = 3, other size 5)", ost.str()); - - EXPECT_EQUAL("Bar(7)", bar.toString()); - EXPECT_EQUAL("Bar(7)", bar.toString(false, " ")); - EXPECT_EQUAL("Bar(7) : Foo(val = 3, other:\n" - " otherval)", bar.toString(true)); - EXPECT_EQUAL("Bar(7) : Foo(val = 3, other:\n" - " otherval)", bar.toString(true, " ")); + EXPECT_EQ("Foo(val = 3, other size 5)", ost.str()); + + EXPECT_EQ("Bar(7)", bar.toString()); + EXPECT_EQ("Bar(7)", bar.toString(false, " ")); + EXPECT_EQ("Bar(7) : Foo(val = 3, other:\n" + " otherval)", bar.toString(true)); + EXPECT_EQ("Bar(7) : Foo(val = 3, other:\n" + " otherval)", bar.toString(true, " ")); } -void -Test::testAsciiVariant() +TEST(PrintableTest, test_ascii_variant) { AsciiFoo foo(19); - EXPECT_EQUAL("19", foo.toString()); - EXPECT_EQUAL("AsciiFoo(19)", - foo.toString(vespalib::AsciiPrintable::VERBOSE)); + EXPECT_EQ("19", foo.toString()); + EXPECT_EQ("AsciiFoo(19)", + foo.toString(vespalib::AsciiPrintable::VERBOSE)); { vespalib::asciistream as; as << foo; - EXPECT_EQUAL("19", as.str()); + EXPECT_EQ("19", as.str()); std::ostringstream ost; ost << foo; - EXPECT_EQUAL("19", ost.str()); + EXPECT_EQ("19", ost.str()); } AsciiBar bar(3); - EXPECT_EQUAL("3", bar.toString()); - EXPECT_EQUAL("AsciiBar() {\n" - " AsciiFoo(3)\n" - "}", bar.toString(vespalib::AsciiPrintable::VERBOSE)); + EXPECT_EQ("3", bar.toString()); + EXPECT_EQ("AsciiBar() {\n" + " AsciiFoo(3)\n" + "}", bar.toString(vespalib::AsciiPrintable::VERBOSE)); { vespalib::asciistream as; as << bar; - EXPECT_EQUAL("3", as.str()); + EXPECT_EQ("3", as.str()); std::ostringstream ost; ost << bar; - EXPECT_EQUAL("3", ost.str()); + EXPECT_EQ("3", ost.str()); } } -int -Test::Main() -{ - TEST_INIT("printabletest"); - testSimple(); - testAsciiVariant(); - TEST_DONE(); -} - -TEST_APPHOOK(Test) +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/tests/programoptions/CMakeLists.txt b/vespalib/src/tests/programoptions/CMakeLists.txt index 81066b19104..524ea8dc416 100644 --- a/vespalib/src/tests/programoptions/CMakeLists.txt +++ b/vespalib/src/tests/programoptions/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(vespalib_programoptions_test_app TEST programoptions_testutils.cpp DEPENDS vespalib + GTest::gtest ) vespa_add_test(NAME vespalib_programoptions_test_app COMMAND vespalib_programoptions_test_app) diff --git a/vespalib/src/tests/programoptions/programoptions_test.cpp b/vespalib/src/tests/programoptions/programoptions_test.cpp index bbb5e2ffc20..4f5ff2fc4d1 100644 --- a/vespalib/src/tests/programoptions/programoptions_test.cpp +++ b/vespalib/src/tests/programoptions/programoptions_test.cpp @@ -2,38 +2,11 @@ #include "programoptions_testutils.h" #include <vespa/vespalib/util/programoptions.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <iostream> namespace vespalib { -class Test : public vespalib::TestApp -{ -public: - void testSyntaxPage(); - void testNormalUsage(); - void testFailures(); - void testVectorArgument(); - void testAllHiddenOption(); - void testOptionsAfterArguments(); - int Main() override; -}; - -int -Test::Main() -{ - TEST_INIT("programoptions_test"); - srandom(1); - testSyntaxPage(); - testNormalUsage(); - testFailures(); - testVectorArgument(); - testAllHiddenOption(); - // Currently not supported - // testOptionsAfterArguments(); - TEST_DONE(); -} - struct MyOptions : public ProgramOptions { bool boolOpt; bool boolWithDefOpt; @@ -86,7 +59,8 @@ MyOptions::MyOptions(int argc, const char* const* argv) MyOptions::~MyOptions() { } -void Test::testSyntaxPage() { +TEST(ProgramOptionsTest, test_syntax_page) +{ AppOptions opts("myapp"); MyOptions options(opts.getArgCount(), opts.getArguments()); std::ostringstream actual; @@ -116,41 +90,42 @@ void Test::testSyntaxPage() { "Advanced options:\n" " -p --properties <key> <value> : Property map (default empty)\n" ); - EXPECT_EQUAL(expected, actual.str()); + EXPECT_EQ(expected, actual.str()); } -void Test::testNormalUsage() { +TEST(ProgramOptionsTest, test_normal_usage) +{ { AppOptions opts("myapp -b --uintopt 4 -s foo tit 1 tei 6"); MyOptions options(opts.getArgCount(), opts.getArguments()); options.parse(); - EXPECT_EQUAL(true, options.boolOpt); - EXPECT_EQUAL(true, options.boolWithDefOpt); - EXPECT_EQUAL(5, options.intOpt); - EXPECT_EQUAL(4u, options.uintOpt); - EXPECT_APPROX(4, options.floatOpt, 0.00001); - EXPECT_EQUAL("foo", options.stringOpt); - EXPECT_EQUAL("tit", options.argString); - EXPECT_EQUAL(1, options.argInt); - EXPECT_EQUAL("tei", options.argOptionalString); - EXPECT_EQUAL(0u, options.properties.size()); - EXPECT_EQUAL(6, options.anotherOptionalArg); + EXPECT_EQ(true, options.boolOpt); + EXPECT_EQ(true, options.boolWithDefOpt); + EXPECT_EQ(5, options.intOpt); + EXPECT_EQ(4u, options.uintOpt); + EXPECT_NEAR(4, options.floatOpt, 0.00001); + EXPECT_EQ("foo", options.stringOpt); + EXPECT_EQ("tit", options.argString); + EXPECT_EQ(1, options.argInt); + EXPECT_EQ("tei", options.argOptionalString); + EXPECT_EQ(0u, options.properties.size()); + EXPECT_EQ(6, options.anotherOptionalArg); } { AppOptions opts("myapp --uintopt 6 tit 1"); MyOptions options(opts.getArgCount(), opts.getArguments()); options.parse(); - EXPECT_EQUAL(false, options.boolOpt); - EXPECT_EQUAL(true, options.boolWithDefOpt); - EXPECT_EQUAL(5, options.intOpt); - EXPECT_EQUAL(6u, options.uintOpt); - EXPECT_APPROX(4, options.floatOpt, 0.00001); - EXPECT_EQUAL("ballalaika", options.stringOpt); - EXPECT_EQUAL("tit", options.argString); - EXPECT_EQUAL(1, options.argInt); - EXPECT_EQUAL("foo", options.argOptionalString); - EXPECT_EQUAL(0u, options.properties.size()); - EXPECT_EQUAL(3, options.anotherOptionalArg); + EXPECT_EQ(false, options.boolOpt); + EXPECT_EQ(true, options.boolWithDefOpt); + EXPECT_EQ(5, options.intOpt); + EXPECT_EQ(6u, options.uintOpt); + EXPECT_NEAR(4, options.floatOpt, 0.00001); + EXPECT_EQ("ballalaika", options.stringOpt); + EXPECT_EQ("tit", options.argString); + EXPECT_EQ(1, options.argInt); + EXPECT_EQ("foo", options.argOptionalString); + EXPECT_EQ(0u, options.properties.size()); + EXPECT_EQ(3, options.anotherOptionalArg); } // Arguments coming after options. // (Required for nesting of short options) @@ -158,62 +133,63 @@ void Test::testNormalUsage() { AppOptions opts("myapp --uintopt --intopt 6 -8 tit 1 tei"); MyOptions options(opts.getArgCount(), opts.getArguments()); options.parse(); - EXPECT_EQUAL(false, options.boolOpt); - EXPECT_EQUAL(true, options.boolWithDefOpt); - EXPECT_EQUAL(-8, options.intOpt); - EXPECT_EQUAL(6u, options.uintOpt); - EXPECT_APPROX(4, options.floatOpt, 0.00001); - EXPECT_EQUAL("ballalaika", options.stringOpt); - EXPECT_EQUAL("tit", options.argString); - EXPECT_EQUAL(1, options.argInt); - EXPECT_EQUAL("tei", options.argOptionalString); - EXPECT_EQUAL(0u, options.properties.size()); + EXPECT_EQ(false, options.boolOpt); + EXPECT_EQ(true, options.boolWithDefOpt); + EXPECT_EQ(-8, options.intOpt); + EXPECT_EQ(6u, options.uintOpt); + EXPECT_NEAR(4, options.floatOpt, 0.00001); + EXPECT_EQ("ballalaika", options.stringOpt); + EXPECT_EQ("tit", options.argString); + EXPECT_EQ(1, options.argInt); + EXPECT_EQ("tei", options.argOptionalString); + EXPECT_EQ(0u, options.properties.size()); } { AppOptions opts( "myapp -uib 6 -8 --boolwithdef tit 1 tei"); MyOptions options(opts.getArgCount(), opts.getArguments()); options.parse(); - EXPECT_EQUAL(true, options.boolOpt); - EXPECT_EQUAL(false, options.boolWithDefOpt); - EXPECT_EQUAL(-8, options.intOpt); - EXPECT_EQUAL(6u, options.uintOpt); - EXPECT_APPROX(4, options.floatOpt, 0.00001); - EXPECT_EQUAL("ballalaika", options.stringOpt); - EXPECT_EQUAL("tit", options.argString); - EXPECT_EQUAL(1, options.argInt); - EXPECT_EQUAL("tei", options.argOptionalString); - EXPECT_EQUAL(0u, options.properties.size()); + EXPECT_EQ(true, options.boolOpt); + EXPECT_EQ(false, options.boolWithDefOpt); + EXPECT_EQ(-8, options.intOpt); + EXPECT_EQ(6u, options.uintOpt); + EXPECT_NEAR(4, options.floatOpt, 0.00001); + EXPECT_EQ("ballalaika", options.stringOpt); + EXPECT_EQ("tit", options.argString); + EXPECT_EQ(1, options.argInt); + EXPECT_EQ("tei", options.argOptionalString); + EXPECT_EQ(0u, options.properties.size()); } // Properties { AppOptions opts("myapp -u 6 -p foo bar --prop hmm brr tit 1 tei"); MyOptions options(opts.getArgCount(), opts.getArguments()); options.parse(); - EXPECT_EQUAL(false, options.boolOpt); - EXPECT_EQUAL(true, options.boolWithDefOpt); - EXPECT_EQUAL(5, options.intOpt); - EXPECT_EQUAL(6u, options.uintOpt); - EXPECT_APPROX(4, options.floatOpt, 0.00001); - EXPECT_EQUAL("ballalaika", options.stringOpt); - EXPECT_EQUAL("tit", options.argString); - EXPECT_EQUAL(1, options.argInt); - EXPECT_EQUAL("tei", options.argOptionalString); - EXPECT_EQUAL(2u, options.properties.size()); - EXPECT_EQUAL("bar", options.properties["foo"]); - EXPECT_EQUAL("brr", options.properties["hmm"]); + EXPECT_EQ(false, options.boolOpt); + EXPECT_EQ(true, options.boolWithDefOpt); + EXPECT_EQ(5, options.intOpt); + EXPECT_EQ(6u, options.uintOpt); + EXPECT_NEAR(4, options.floatOpt, 0.00001); + EXPECT_EQ("ballalaika", options.stringOpt); + EXPECT_EQ("tit", options.argString); + EXPECT_EQ(1, options.argInt); + EXPECT_EQ("tei", options.argOptionalString); + EXPECT_EQ(2u, options.properties.size()); + EXPECT_EQ("bar", options.properties["foo"]); + EXPECT_EQ("brr", options.properties["hmm"]); } } -void Test::testFailures() { +TEST(ProgramOptionsTest, test_failures) +{ // Non-existing long option { AppOptions opts("myapp -b --uintopt 4 -s foo --none"); MyOptions options(opts.getArgCount(), opts.getArguments()); try{ options.parse(); - TEST_FATAL("Expected exception"); + FAIL() << "Expected exception"; } catch (InvalidCommandLineArgumentsException& e) { - EXPECT_EQUAL("Invalid option 'none'.", e.getMessage()); + EXPECT_EQ("Invalid option 'none'.", e.getMessage()); } } // Non-existing short option @@ -222,9 +198,9 @@ void Test::testFailures() { MyOptions options(opts.getArgCount(), opts.getArguments()); try{ options.parse(); - TEST_FATAL("Expected exception"); + FAIL() << "Expected exception"; } catch (InvalidCommandLineArgumentsException& e) { - EXPECT_EQUAL("Invalid option 'q'.", e.getMessage()); + EXPECT_EQ("Invalid option 'q'.", e.getMessage()); } } // Lacking option argument @@ -233,9 +209,9 @@ void Test::testFailures() { MyOptions options(opts.getArgCount(), opts.getArguments()); try{ options.parse(); - TEST_FATAL("Expected exception"); + FAIL() << "Expected exception"; } catch (InvalidCommandLineArgumentsException& e) { - EXPECT_EQUAL("Option 's' needs 1 arguments. Only 0 available.", + EXPECT_EQ("Option 's' needs 1 arguments. Only 0 available.", e.getMessage()); } } @@ -245,35 +221,21 @@ void Test::testFailures() { MyOptions options(opts.getArgCount(), opts.getArguments()); try{ options.parse(); - TEST_FATAL("Expected exception"); + FAIL() << "Expected exception"; } catch (InvalidCommandLineArgumentsException& e) { - EXPECT_EQUAL("The argument '3000000000' can not be interpreted as a " + EXPECT_EQ("The argument '3000000000' can not be interpreted as a " "number of type int.", e.getMessage()); } } - // Negative value to unsigned var (Currently doesnt fail) -/* - { - AppOptions opts("myapp -b --uintopt -1 foo 0"); - MyOptions options(opts.getArgCount(), opts.getArguments()); - try{ - options.parse(); - TEST_FATAL("Expected exception"); - } catch (InvalidCommandLineArgumentsException& e) { - EXPECT_EQUAL("The argument '-1' can not be interpreted as a " - "number of type uint.", e.getMessage()); - } - } - */ // Lacking required option { AppOptions opts("myapp -b"); MyOptions options(opts.getArgCount(), opts.getArguments()); try{ options.parse(); - TEST_FATAL("Expected exception"); + FAIL() << "Expected exception"; } catch (InvalidCommandLineArgumentsException& e) { - EXPECT_EQUAL("Option 'uintopt' has no default and must be set.", + EXPECT_EQ("Option 'uintopt' has no default and must be set.", e.getMessage()); } } @@ -283,9 +245,9 @@ void Test::testFailures() { MyOptions options(opts.getArgCount(), opts.getArguments()); try{ options.parse(); - TEST_FATAL("Expected exception"); + FAIL() << "Expected exception"; } catch (InvalidCommandLineArgumentsException& e) { - EXPECT_EQUAL("Insufficient data is given to set required argument " + EXPECT_EQ("Insufficient data is given to set required argument " "'argInt'.", e.getMessage()); } @@ -296,16 +258,16 @@ void Test::testFailures() { MyOptions options(opts.getArgCount(), opts.getArguments()); try{ options.parse(); - TEST_FATAL("Expected exception"); + FAIL() << "Expected exception"; } catch (InvalidCommandLineArgumentsException& e) { - EXPECT_EQUAL("The argument 'en' can not be interpreted as a number " + EXPECT_EQ("The argument 'en' can not be interpreted as a number " "of type int.", e.getMessage()); } } } -void Test::testVectorArgument() +TEST(ProgramOptionsTest, test_vector_argument) { AppOptions opts("myapp foo bar baz"); std::vector<std::string> args; @@ -318,16 +280,16 @@ void Test::testVectorArgument() "Arguments:\n" " ids (string[]) : Vector element\n" ); - EXPECT_EQUAL(expected, actual.str()); + EXPECT_EQ(expected, actual.str()); options.parse(); - EXPECT_EQUAL(3u, args.size()); - EXPECT_EQUAL("foo", args[0]); - EXPECT_EQUAL("bar", args[1]); - EXPECT_EQUAL("baz", args[2]); + EXPECT_EQ(3u, args.size()); + EXPECT_EQ("foo", args[0]); + EXPECT_EQ("bar", args[1]); + EXPECT_EQ("baz", args[2]); } -void Test::testAllHiddenOption() +TEST(ProgramOptionsTest, test_all_hidden_options) { AppOptions opts("myapp --foo bar"); std::string option; @@ -337,25 +299,12 @@ void Test::testAllHiddenOption() std::ostringstream actual; options.writeSyntaxPage(actual); std::string expected("\nUsage: myapp\n"); - EXPECT_EQUAL(expected, actual.str()); + EXPECT_EQ(expected, actual.str()); options.parse(); - EXPECT_EQUAL("bar", option); -} - -void Test::testOptionsAfterArguments() -{ - AppOptions opts("myapp bar --foo baz"); - std::string option; - std::string argument; - ProgramOptions options(opts.getArgCount(), opts.getArguments()); - options.addOption("foo", option, "Description"); - options.addArgument("arg", argument, "Description"); - options.parse(); - EXPECT_EQUAL("baz", option); - EXPECT_EQUAL("bar", argument); + EXPECT_EQ("bar", option); } } // vespalib -TEST_APPHOOK(vespalib::Test) +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/tests/random/CMakeLists.txt b/vespalib/src/tests/random/CMakeLists.txt index 9984f3a52ba..75d9ce75f1a 100644 --- a/vespalib/src/tests/random/CMakeLists.txt +++ b/vespalib/src/tests/random/CMakeLists.txt @@ -4,6 +4,7 @@ vespa_add_executable(vespalib_random_test_app TEST random_test.cpp DEPENDS vespalib + GTest::gtest ) vespa_add_test(NAME vespalib_random_test_app COMMAND vespalib_random_test_app) vespa_add_executable(vespalib_friendfinder_test_app diff --git a/vespalib/src/tests/random/random_test.cpp b/vespalib/src/tests/random/random_test.cpp index d505d51efd7..34b4e3d0389 100644 --- a/vespalib/src/tests/random/random_test.cpp +++ b/vespalib/src/tests/random/random_test.cpp @@ -1,30 +1,17 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/util/random.h> using namespace vespalib; +namespace { + +constexpr double eps = 1.0e-9; -class Test : public vespalib::TestApp -{ -public: - int getFive() { return 5; } - void testJavaCompatibility(); - void testFloatingPoint(); - void testNormalDistribution(); - int Main() override; -}; - -bool eqD(double a, double b) { - if (a == b) return true; - printf("is %f approx equal to %f ?\n", a, b); - if ((a + 1.0e-9) > b && b > (a - 1.0e-9)) return true; - return false; } -void -Test::testJavaCompatibility() +TEST(RandomTest, test_java_compatibility) { RandomGen rnd(1); @@ -42,16 +29,16 @@ Test::testJavaCompatibility() EXPECT_TRUE(rnd.nextInt32() == 655996946); rnd.setSeed(1); - EXPECT_TRUE(eqD(rnd.nextDouble(), 0.7308781907032909)); - EXPECT_TRUE(eqD(rnd.nextDouble(), 0.41008081149220166)); - EXPECT_TRUE(eqD(rnd.nextDouble(), 0.20771484130971707)); - EXPECT_TRUE(eqD(rnd.nextDouble(), 0.3327170559595112)); - EXPECT_TRUE(eqD(rnd.nextDouble(), 0.9677559094241207)); - EXPECT_TRUE(eqD(rnd.nextDouble(), 0.006117182265761301)); - EXPECT_TRUE(eqD(rnd.nextDouble(), 0.9637047970232077)); - EXPECT_TRUE(eqD(rnd.nextDouble(), 0.9398653887819098)); - EXPECT_TRUE(eqD(rnd.nextDouble(), 0.9471949176631939)); - EXPECT_TRUE(eqD(rnd.nextDouble(), 0.9370821488959696)); + EXPECT_NEAR(rnd.nextDouble(), 0.7308781907032909, eps); + EXPECT_NEAR(rnd.nextDouble(), 0.41008081149220166, eps); + EXPECT_NEAR(rnd.nextDouble(), 0.20771484130971707, eps); + EXPECT_NEAR(rnd.nextDouble(), 0.3327170559595112, eps); + EXPECT_NEAR(rnd.nextDouble(), 0.9677559094241207, eps); + EXPECT_NEAR(rnd.nextDouble(), 0.006117182265761301, eps); + EXPECT_NEAR(rnd.nextDouble(), 0.9637047970232077, eps); + EXPECT_NEAR(rnd.nextDouble(), 0.9398653887819098, eps); + EXPECT_NEAR(rnd.nextDouble(), 0.9471949176631939, eps); + EXPECT_NEAR(rnd.nextDouble(), 0.9370821488959696, eps); RandomGen rnd2(-1); EXPECT_TRUE(rnd2.nextInt32() == 1155099827); @@ -64,8 +51,7 @@ Test::testJavaCompatibility() EXPECT_TRUE(rnd2.nextInt32() == 52699159); } -void -Test::testFloatingPoint() +TEST(RandoMTest, test_floating_point) { RandomGen rnd; @@ -88,8 +74,7 @@ Test::testFloatingPoint() } } -void -Test::testNormalDistribution() +TEST(RandoMTest, test_normal_distribution) { RandomGen rnd; @@ -149,16 +134,4 @@ Test::testNormalDistribution() EXPECT_TRUE(buckets[90] > buckets[100]); } -int -Test::Main() -{ - TEST_INIT("random_test"); - testJavaCompatibility(); - TEST_FLUSH(); - testFloatingPoint(); - TEST_FLUSH(); - testNormalDistribution(); - TEST_DONE(); -} - -TEST_APPHOOK(Test) +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/tests/sharedptr/CMakeLists.txt b/vespalib/src/tests/sharedptr/CMakeLists.txt index 052efb19447..6e038ed31c5 100644 --- a/vespalib/src/tests/sharedptr/CMakeLists.txt +++ b/vespalib/src/tests/sharedptr/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(vespalib_ptrholder_test_app TEST ptrholder.cpp DEPENDS vespalib + GTest::gtest ) vespa_add_test(NAME vespalib_ptrholder_test_app COMMAND vespalib_ptrholder_test_app) diff --git a/vespalib/src/tests/sharedptr/ptrholder.cpp b/vespalib/src/tests/sharedptr/ptrholder.cpp index 8dc3bba2722..e6d1710247b 100644 --- a/vespalib/src/tests/sharedptr/ptrholder.cpp +++ b/vespalib/src/tests/sharedptr/ptrholder.cpp @@ -1,20 +1,11 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/vespalib/util/ptrholder.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> using vespalib::PtrHolder; -class Test : public vespalib::TestApp -{ -public: - void testEmpty(); - void testSimple(); - int Main() override; -}; - - struct Data { int ctorCnt; @@ -39,8 +30,7 @@ using PT = std::shared_ptr<DataRef>; using HOLD = PtrHolder<DataRef>; -void -Test::testEmpty() +TEST(PtrHolderTest, test_empty) { HOLD hold; EXPECT_TRUE(hold.get().get() == NULL); @@ -56,8 +46,7 @@ Test::testEmpty() } -void -Test::testSimple() +TEST(PtrHolderTest, test_simple) { Data data; HOLD hold; @@ -86,14 +75,4 @@ Test::testSimple() EXPECT_TRUE(data.dtorCnt == 2); } - -int -Test::Main() -{ - TEST_INIT("ptrholder_test"); - testEmpty(); - testSimple(); - TEST_DONE(); -} - -TEST_APPHOOK(Test) +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/tests/stllike/CMakeLists.txt b/vespalib/src/tests/stllike/CMakeLists.txt index 7fa8e0cbd1f..644bd4f66d2 100644 --- a/vespalib/src/tests/stllike/CMakeLists.txt +++ b/vespalib/src/tests/stllike/CMakeLists.txt @@ -25,6 +25,7 @@ vespa_add_executable(vespalib_asciistream_test_app TEST asciistream_test.cpp DEPENDS vespalib + GTest::gtest ) vespa_add_test(NAME vespalib_asciistream_test_app COMMAND vespalib_asciistream_test_app) vespa_add_executable(vespalib_hashtable_test_app TEST diff --git a/vespalib/src/tests/stllike/asciistream_test.cpp b/vespalib/src/tests/stllike/asciistream_test.cpp index 05068fb102c..cd710c0adb4 100644 --- a/vespalib/src/tests/stllike/asciistream_test.cpp +++ b/vespalib/src/tests/stllike/asciistream_test.cpp @@ -1,49 +1,31 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/test_kit.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/stllike/asciistream.h> +#include <vespa/vespalib/testkit/test_path.h> #include <vespa/vespalib/util/exceptions.h> #include <vespa/vespalib/locale/c.h> +#include <cmath> #include <iomanip> #include <float.h> using namespace vespalib; -class AsciistreamTest : public TestApp -{ -public: - int Main() override; - template <typename T> - void verify(T first, T second, const char * firstResult, const char * secondResult, char delim); - template <typename T> - void verifyBothWays(T value, const char * firstResult); - void testIntegerManip(); - void testFill(); - void testString(); - void testCreateFromFile(); - void testWriteThenRead(); - void testGetLine(); - void testCopyConstruct(); - void testMoveIsWellDefined(); - void testIllegalNumbers(); - void testDouble(); - void testFloat(); - void testStateSaver(); -}; +namespace { template <typename T> void -AsciistreamTest::verifyBothWays(T value, const char * expected) +verifyBothWays(T value, const char * expected, const vespalib::string& label) { + SCOPED_TRACE(label); asciistream os; os << value; - EXPECT_EQUAL(os.str(), string(expected)); - EXPECT_EQUAL(os.size(), strlen(expected)); + EXPECT_EQ(os.str(), string(expected)); + EXPECT_EQ(os.size(), strlen(expected)); { T v; os >> v; - EXPECT_EQUAL(value, v); + EXPECT_EQ(value, v); EXPECT_TRUE(os.empty()); } @@ -51,255 +33,253 @@ AsciistreamTest::verifyBothWays(T value, const char * expected) os << " " << expected; T v; os >> v; - EXPECT_EQUAL(value, v); + EXPECT_EQ(value, v); EXPECT_TRUE(os.empty()); - EXPECT_EQUAL(0u, os.size()); + EXPECT_EQ(0u, os.size()); } } template <typename T> void -AsciistreamTest::verify(T first, T second, const char * firstResult, const char * secondResult, char delim) +verify(T first, T second, const char * firstResult, const char * secondResult, char delim, const vespalib::string& label) { + SCOPED_TRACE(label); asciistream os; std::ostringstream ss; os << first; ss << first; - EXPECT_EQUAL(os.str(), string(firstResult)); - EXPECT_EQUAL(os.size(), strlen(firstResult)); - EXPECT_EQUAL(ss.str().size(), strlen(firstResult)); - EXPECT_EQUAL(strcmp(ss.str().c_str(), firstResult), 0); + EXPECT_EQ(os.str(), string(firstResult)); + EXPECT_EQ(os.size(), strlen(firstResult)); + EXPECT_EQ(ss.str().size(), strlen(firstResult)); + EXPECT_EQ(strcmp(ss.str().c_str(), firstResult), 0); os << delim << second; ss << delim << second; - EXPECT_EQUAL(os.size(), strlen(secondResult)); - EXPECT_EQUAL(ss.str().size(), strlen(secondResult)); - EXPECT_EQUAL(strcmp(os.c_str(), secondResult), 0); - EXPECT_EQUAL(strcmp(ss.str().c_str(), secondResult), 0); + EXPECT_EQ(os.size(), strlen(secondResult)); + EXPECT_EQ(ss.str().size(), strlen(secondResult)); + EXPECT_EQ(strcmp(os.c_str(), secondResult), 0); + EXPECT_EQ(strcmp(ss.str().c_str(), secondResult), 0); } -void -AsciistreamTest::testIllegalNumbers() +} + +TEST(AsciistreamTest, test_illegal_numbers) { { asciistream is("777777777777"); uint16_t s(0); - EXPECT_EXCEPTION(is >> s, IllegalArgumentException, "strToInt value '777777777777' is outside of range"); - EXPECT_EQUAL(12u, is.size()); + EXPECT_THROW(is >> s, IllegalArgumentException); + EXPECT_EQ(12u, is.size()); uint32_t i(0); - EXPECT_EXCEPTION(is >> i, IllegalArgumentException, "strToInt value '777777777777' is outside of range"); - EXPECT_EQUAL(12u, is.size()); + EXPECT_THROW(is >> i, IllegalArgumentException); + EXPECT_EQ(12u, is.size()); int16_t si(0); - EXPECT_EXCEPTION(is >> si, IllegalArgumentException, "strToInt value '777777777777' is outside of range"); - EXPECT_EQUAL(12u, is.size()); + EXPECT_THROW(is >> si, IllegalArgumentException); + EXPECT_EQ(12u, is.size()); int32_t ii(0); - EXPECT_EXCEPTION(is >> ii, IllegalArgumentException, "strToInt value '777777777777' is outside of range"); - EXPECT_EQUAL(12u, is.size()); + EXPECT_THROW(is >> ii, IllegalArgumentException); + EXPECT_EQ(12u, is.size()); is << "777777777777"; - EXPECT_EQUAL(24u, is.size()); + EXPECT_EQ(24u, is.size()); uint64_t l(0); - EXPECT_EXCEPTION(is >> l, IllegalArgumentException, "value '777777777777777777777777' is outside of range"); - EXPECT_EQUAL(24u, is.size()); + EXPECT_THROW(is >> l, IllegalArgumentException); + EXPECT_EQ(24u, is.size()); int64_t li(0); - EXPECT_EXCEPTION(is >> li, IllegalArgumentException, "value '777777777777777777777777' is outside of range"); - EXPECT_EQUAL(24u, is.size()); + EXPECT_THROW(is >> li, IllegalArgumentException); + EXPECT_EQ(24u, is.size()); } { asciistream is("-77"); uint16_t s(0); - EXPECT_EXCEPTION(is >> s, IllegalArgumentException, "Illegal strToInt value '-77'"); - EXPECT_EQUAL(3u, is.size()); + EXPECT_THROW(is >> s, IllegalArgumentException); + EXPECT_EQ(3u, is.size()); uint32_t i(0); - EXPECT_EXCEPTION(is >> i, IllegalArgumentException, "Illegal strToInt value '-77'"); - EXPECT_EQUAL(3u, is.size()); + EXPECT_THROW(is >> i, IllegalArgumentException); + EXPECT_EQ(3u, is.size()); } { asciistream is("7777777777777777777777777777777777777777"); - EXPECT_EQUAL(40u, is.size()); + EXPECT_EQ(40u, is.size()); float f(0); - EXPECT_EXCEPTION(is >> f, IllegalArgumentException, "float value '7777777777777777777777777777777777777777' is outside of range"); - EXPECT_EQUAL(40u, is.size()); + EXPECT_THROW(is >> f, IllegalArgumentException); + EXPECT_EQ(40u, is.size()); vespalib::string tmp = is.str(); is << "e" << tmp; - EXPECT_EQUAL(81u, is.size()); + EXPECT_EQ(81u, is.size()); double d(0); - EXPECT_EXCEPTION(is >> d, IllegalArgumentException, "double value '7777777777777777777777777777777777777777e7777777777777777777777777777777777777777' is outside of range"); - EXPECT_EQUAL(81u, is.size()); + EXPECT_THROW(is >> d, IllegalArgumentException); + EXPECT_EQ(81u, is.size()); } { asciistream is("a"); char c(' '); - EXPECT_EQUAL(1u, is.size()); + EXPECT_EQ(1u, is.size()); is >> c; - EXPECT_EQUAL('a', c); + EXPECT_EQ('a', c); EXPECT_TRUE(is.empty()); - EXPECT_EXCEPTION(is >> c, IllegalArgumentException, "buffer underflow at pos 1."); + EXPECT_THROW(is >> c, IllegalArgumentException); EXPECT_TRUE(is.empty()); unsigned char u(' '); - EXPECT_EXCEPTION(is >> u, IllegalArgumentException, "buffer underflow at pos 1."); + EXPECT_THROW(is >> u, IllegalArgumentException); EXPECT_TRUE(is.empty()); bool b(false); - EXPECT_EXCEPTION(is >> b, IllegalArgumentException, "buffer underflow at pos 1."); + EXPECT_THROW(is >> b, IllegalArgumentException); EXPECT_TRUE(is.empty()); { uint32_t l(0); - EXPECT_EXCEPTION(is >> l, IllegalArgumentException, "buffer underflow at pos 0."); + EXPECT_THROW(is >> l, IllegalArgumentException); EXPECT_TRUE(is.empty()); } { int32_t l(0); - EXPECT_EXCEPTION(is >> l, IllegalArgumentException, "buffer underflow at pos 0"); + EXPECT_THROW(is >> l, IllegalArgumentException); EXPECT_TRUE(is.empty()); } { float l(0); - EXPECT_EXCEPTION(is >> l, IllegalArgumentException, "Failed decoding a float from ''."); + EXPECT_THROW(is >> l, IllegalArgumentException); EXPECT_TRUE(is.empty()); } { double l(0); - EXPECT_EXCEPTION(is >> l, IllegalArgumentException, "Failed decoding a double from ''."); + EXPECT_THROW(is >> l, IllegalArgumentException); EXPECT_TRUE(is.empty()); } } } -void -AsciistreamTest::testCopyConstruct() +TEST(AsciistreamTest, test_copy_construct) { asciistream os; os << "test1"; asciistream os2(os); - EXPECT_EQUAL(os.str(), os2.str()); + EXPECT_EQ(os.str(), os2.str()); os2 << " test2"; EXPECT_FALSE(os.str() == os2.str()); asciistream os3(os); os3 = os2; - EXPECT_EQUAL(os2.str(), os3.str()); + EXPECT_EQ(os2.str(), os3.str()); os.swap(os2); - EXPECT_EQUAL(os.str(), os3.str()); + EXPECT_EQ(os.str(), os3.str()); EXPECT_FALSE(os3.str() == os2.str()); os.swap(os2); EXPECT_TRUE(os3.str() == os2.str()); } -void -AsciistreamTest::testMoveIsWellDefined() +TEST(AsciistreamTest, test_move_is_well_defined) { asciistream read_only("hello world"); asciistream dest(std::move(read_only)); - EXPECT_EQUAL("hello world", dest.str()); + EXPECT_EQ("hello world", dest.str()); read_only = asciistream("a string long enough to not be short string optimized"); dest = std::move(read_only); - EXPECT_EQUAL("a string long enough to not be short string optimized", dest.str()); + EXPECT_EQ("a string long enough to not be short string optimized", dest.str()); asciistream written_src; written_src << "a foo walks into a bar"; dest = std::move(written_src); - EXPECT_EQUAL("a foo walks into a bar", dest.str()); + EXPECT_EQ("a foo walks into a bar", dest.str()); } -void -AsciistreamTest::testIntegerManip() +TEST(AsciistreamTest, test_integer_manip) { asciistream os; std::ostringstream ss; os << 10; ss << 10; - EXPECT_EQUAL(os.size(), 2u); - EXPECT_EQUAL(ss.str().size(), 2u); - EXPECT_EQUAL(strcmp(os.c_str(), "10"), 0); - EXPECT_EQUAL(strcmp(ss.str().c_str(), "10"), 0); + EXPECT_EQ(os.size(), 2u); + EXPECT_EQ(ss.str().size(), 2u); + EXPECT_EQ(strcmp(os.c_str(), "10"), 0); + EXPECT_EQ(strcmp(ss.str().c_str(), "10"), 0); os << ' ' << dec << 10; ss << ' ' << std::dec << 10; - EXPECT_EQUAL(os.size(), 5u); - EXPECT_EQUAL(ss.str().size(), 5u); - EXPECT_EQUAL(strcmp(os.c_str(), "10 10"), 0); - EXPECT_EQUAL(strcmp(ss.str().c_str(), "10 10"), 0); + EXPECT_EQ(os.size(), 5u); + EXPECT_EQ(ss.str().size(), 5u); + EXPECT_EQ(strcmp(os.c_str(), "10 10"), 0); + EXPECT_EQ(strcmp(ss.str().c_str(), "10 10"), 0); os << ' ' << hex << 10 << ' ' << 11; ss << ' ' << std::hex << 10 << ' ' << 11; - EXPECT_EQUAL(os.size(), 9u); - EXPECT_EQUAL(ss.str().size(), 9u); - EXPECT_EQUAL(strcmp(os.c_str(), "10 10 a b"), 0); - EXPECT_EQUAL(strcmp(ss.str().c_str(), "10 10 a b"), 0); + EXPECT_EQ(os.size(), 9u); + EXPECT_EQ(ss.str().size(), 9u); + EXPECT_EQ(strcmp(os.c_str(), "10 10 a b"), 0); + EXPECT_EQ(strcmp(ss.str().c_str(), "10 10 a b"), 0); os << ' ' << oct << 10; ss << ' ' << std::oct << 10; - EXPECT_EQUAL(os.size(), 12u); - EXPECT_EQUAL(ss.str().size(), 12u); - EXPECT_EQUAL(strcmp(os.c_str(), "10 10 a b 12"), 0); - EXPECT_EQUAL(strcmp(ss.str().c_str(), "10 10 a b 12"), 0); + EXPECT_EQ(os.size(), 12u); + EXPECT_EQ(ss.str().size(), 12u); + EXPECT_EQ(strcmp(os.c_str(), "10 10 a b 12"), 0); + EXPECT_EQ(strcmp(ss.str().c_str(), "10 10 a b 12"), 0); // std::bin not supported by std::streams. os << ' ' << bin << 10; - EXPECT_EQUAL(os.size(), 19u); - EXPECT_EQUAL(strcmp(os.c_str(), "10 10 a b 12 0b1010"), 0); + EXPECT_EQ(os.size(), 19u); + EXPECT_EQ(strcmp(os.c_str(), "10 10 a b 12 0b1010"), 0); void *fooptr = reinterpret_cast<void*>(0x1badbadc0ffeeull); // Also test that number base is restored OK after ptr print os << dec << ' ' << fooptr << ' ' << 1234; ss << std::dec << ' ' << fooptr << ' ' << 1234; - EXPECT_EQUAL(std::string("10 10 a b 12 0b1010 0x1badbadc0ffee 1234"), os.str()); - EXPECT_EQUAL(std::string("10 10 a b 12 0x1badbadc0ffee 1234"), ss.str()); + EXPECT_EQ(std::string("10 10 a b 12 0b1010 0x1badbadc0ffee 1234"), os.str()); + EXPECT_EQ(std::string("10 10 a b 12 0x1badbadc0ffee 1234"), ss.str()); int i = 0; const char *digits = "12345"; std::string ffs(digits, 4); std::istringstream std_istr(ffs); std_istr >> i; - EXPECT_EQUAL(1234, i); + EXPECT_EQ(1234, i); stringref firstfour(digits, 4); asciistream istr(firstfour); istr >> i; - EXPECT_EQUAL(1234, i); + EXPECT_EQ(1234, i); } -void -AsciistreamTest::testFill() +TEST(AsciistreamTest, test_fill) { { asciistream os; std::ostringstream ss; os << 10 << ' ' << setfill('h') << 11; ss << 10 << ' ' << std::setfill('h') << 11; - EXPECT_EQUAL(os.size(), 5u); - EXPECT_EQUAL(ss.str().size(), 5u); - EXPECT_EQUAL(strcmp(os.c_str(), "10 11"), 0); - EXPECT_EQUAL(strcmp(ss.str().c_str(), "10 11"), 0); + EXPECT_EQ(os.size(), 5u); + EXPECT_EQ(ss.str().size(), 5u); + EXPECT_EQ(strcmp(os.c_str(), "10 11"), 0); + EXPECT_EQ(strcmp(ss.str().c_str(), "10 11"), 0); os << setw(4) << 10 << ' ' << 11; ss << std::setw(4) << 10 << ' ' << 11; - EXPECT_EQUAL(os.size(), 12u); - EXPECT_EQUAL(ss.str().size(), 12u); - EXPECT_EQUAL(strcmp(os.c_str(), "10 11hh10 11"), 0); - EXPECT_EQUAL(strcmp(ss.str().c_str(), "10 11hh10 11"), 0); + EXPECT_EQ(os.size(), 12u); + EXPECT_EQ(ss.str().size(), 12u); + EXPECT_EQ(strcmp(os.c_str(), "10 11hh10 11"), 0); + EXPECT_EQ(strcmp(ss.str().c_str(), "10 11hh10 11"), 0); os << setw(4) << 10 << ' ' << 11; ss << std::setw(4) << 10 << ' ' << 11; - EXPECT_EQUAL(os.size(), 19u); - EXPECT_EQUAL(ss.str().size(), 19u); - EXPECT_EQUAL(strcmp(os.c_str(), "10 11hh10 11hh10 11"), 0); - EXPECT_EQUAL(strcmp(ss.str().c_str(), "10 11hh10 11hh10 11"), 0); + EXPECT_EQ(os.size(), 19u); + EXPECT_EQ(ss.str().size(), 19u); + EXPECT_EQ(strcmp(os.c_str(), "10 11hh10 11hh10 11"), 0); + EXPECT_EQ(strcmp(ss.str().c_str(), "10 11hh10 11hh10 11"), 0); } { asciistream os; std::ostringstream ss; os << setfill('X') << setw(19) << 'a'; ss << std::setfill('X') << std::setw(19) << 'a'; - EXPECT_EQUAL(os.size(), 19u); - EXPECT_EQUAL(ss.str().size(), 19u); - EXPECT_EQUAL(strcmp(os.c_str(), "XXXXXXXXXXXXXXXXXXa"), 0); - EXPECT_EQUAL(strcmp(ss.str().c_str(), "XXXXXXXXXXXXXXXXXXa"), 0); + EXPECT_EQ(os.size(), 19u); + EXPECT_EQ(ss.str().size(), 19u); + EXPECT_EQ(strcmp(os.c_str(), "XXXXXXXXXXXXXXXXXXa"), 0); + EXPECT_EQ(strcmp(ss.str().c_str(), "XXXXXXXXXXXXXXXXXXa"), 0); } { asciistream os; std::ostringstream ss; os << setfill('X') << setw(19) << "a"; ss << std::setfill('X') << std::setw(19) << "a"; - EXPECT_EQUAL(os.size(), 19u); - EXPECT_EQUAL(ss.str().size(), 19u); - EXPECT_EQUAL(strcmp(os.c_str(), "XXXXXXXXXXXXXXXXXXa"), 0); - EXPECT_EQUAL(strcmp(ss.str().c_str(), "XXXXXXXXXXXXXXXXXXa"), 0); + EXPECT_EQ(os.size(), 19u); + EXPECT_EQ(ss.str().size(), 19u); + EXPECT_EQ(strcmp(os.c_str(), "XXXXXXXXXXXXXXXXXXa"), 0); + EXPECT_EQ(strcmp(ss.str().c_str(), "XXXXXXXXXXXXXXXXXXa"), 0); } { float f(8.9); @@ -307,10 +287,10 @@ AsciistreamTest::testFill() std::ostringstream ss; os << setfill('X') << setw(19) << f; ss << std::setfill('X') << std::setw(19) << f; - EXPECT_EQUAL(os.size(), 19u); - EXPECT_EQUAL(ss.str().size(), 19u); - EXPECT_EQUAL(strcmp(os.c_str(), "XXXXXXXXXXXXXXXX8.9"), 0); - EXPECT_EQUAL(strcmp(ss.str().c_str(), "XXXXXXXXXXXXXXXX8.9"), 0); + EXPECT_EQ(os.size(), 19u); + EXPECT_EQ(ss.str().size(), 19u); + EXPECT_EQ(strcmp(os.c_str(), "XXXXXXXXXXXXXXXX8.9"), 0); + EXPECT_EQ(strcmp(ss.str().c_str(), "XXXXXXXXXXXXXXXX8.9"), 0); } { double f(8.9); @@ -318,16 +298,15 @@ AsciistreamTest::testFill() std::ostringstream ss; os << setfill('X') << setw(19) << f; ss << std::setfill('X') << std::setw(19) << f; - EXPECT_EQUAL(os.size(), 19u); - EXPECT_EQUAL(ss.str().size(), 19u); - EXPECT_EQUAL(strcmp(os.c_str(), "XXXXXXXXXXXXXXXX8.9"), 0); - EXPECT_EQUAL(strcmp(ss.str().c_str(), "XXXXXXXXXXXXXXXX8.9"), 0); + EXPECT_EQ(os.size(), 19u); + EXPECT_EQ(ss.str().size(), 19u); + EXPECT_EQ(strcmp(os.c_str(), "XXXXXXXXXXXXXXXX8.9"), 0); + EXPECT_EQ(strcmp(ss.str().c_str(), "XXXXXXXXXXXXXXXX8.9"), 0); } } -void -AsciistreamTest::testString() +TEST(AsciistreamTest, test_string) { std::string ss("a"); @@ -335,56 +314,55 @@ AsciistreamTest::testString() { std::ostringstream oss; oss << ss << vs; - EXPECT_EQUAL("aa", oss.str()); + EXPECT_EQ("aa", oss.str()); } { asciistream oss; oss << ss << vs; - EXPECT_EQUAL("aa", oss.str()); + EXPECT_EQ("aa", oss.str()); } { std::istringstream iss("b c"); iss >> ss >> vs; - EXPECT_EQUAL("b", ss); - EXPECT_EQUAL("c", vs); + EXPECT_EQ("b", ss); + EXPECT_EQ("c", vs); } { std::istringstream iss("b c"); iss >> vs >> ss; - EXPECT_EQUAL("b", vs); - EXPECT_EQUAL("c", ss); + EXPECT_EQ("b", vs); + EXPECT_EQ("c", ss); } { asciistream iss("b c"); iss >> ss >> vs; - EXPECT_EQUAL("b", ss); - EXPECT_EQUAL("c", vs); + EXPECT_EQ("b", ss); + EXPECT_EQ("c", vs); } { asciistream iss("b c"); iss >> vs >> ss; - EXPECT_EQUAL("b", vs); - EXPECT_EQUAL("c", ss); + EXPECT_EQ("b", vs); + EXPECT_EQ("c", ss); } } -void -AsciistreamTest::testCreateFromFile() +TEST(AsciistreamTest, test_create_from_file) { asciistream is(asciistream::createFromFile("non-existing.txt")); EXPECT_TRUE(is.eof()); is = asciistream::createFromFile(TEST_PATH("test.txt")); EXPECT_FALSE(is.eof()); - EXPECT_EQUAL(12u, is.size()); + EXPECT_EQ(12u, is.size()); string s; is >> s; - EXPECT_EQUAL("line1", s); + EXPECT_EQ("line1", s); is >> s; - EXPECT_EQUAL("line2", s); + EXPECT_EQ("line2", s); EXPECT_FALSE(is.eof()); is >> s; - EXPECT_EQUAL("", s); + EXPECT_EQ("", s); EXPECT_TRUE(is.eof()); #ifdef __linux__ @@ -393,30 +371,28 @@ AsciistreamTest::testCreateFromFile() #endif } -void -AsciistreamTest::testWriteThenRead() +TEST(AsciistreamTest, test_write_then_read) { asciistream ios; ios << "3 words"; int n(0); string v; ios >> n >> v; - EXPECT_EQUAL(3, n); - EXPECT_EQUAL("words", v); + EXPECT_EQ(3, n); + EXPECT_EQ("words", v); EXPECT_TRUE(ios.eof()); } -void -AsciistreamTest::testGetLine() +TEST(AsciistreamTest, test_get_line) { asciistream is = asciistream("line 1\nline 2\nline 3"); string s; getline(is, s); - EXPECT_EQUAL("line 1", s); + EXPECT_EQ("line 1", s); getline(is, s); - EXPECT_EQUAL("line 2", s); + EXPECT_EQ("line 2", s); getline(is, s); - EXPECT_EQUAL("line 3", s); + EXPECT_EQ("line 3", s); } #define VERIFY_DOUBLE_SERIALIZATION(value, expected, format, precision) { \ @@ -424,11 +400,11 @@ AsciistreamTest::testGetLine() mystream << format; \ if (precision > 0) mystream << asciistream::Precision(precision); \ mystream << value; \ - EXPECT_EQUAL(expected, mystream.str()); \ + EXPECT_EQ(expected, mystream.str()); \ } -void -AsciistreamTest::testDouble() { +TEST(AsciistreamTest, test_double) +{ VERIFY_DOUBLE_SERIALIZATION(0.0, "0.000000", fixed, -1); VERIFY_DOUBLE_SERIALIZATION(0.0, "0.000000e+00", scientific, -1); VERIFY_DOUBLE_SERIALIZATION(0.0, "0", automatic, -1); @@ -502,119 +478,101 @@ AsciistreamTest::testDouble() { as << "1.0e-325"; dv = 42.0; as >> dv; - EXPECT_EQUAL(dv, 0.0); + EXPECT_EQ(dv, 0.0); as.clear(); as << "1.0e666"; dv = 42.0; - EXPECT_EXCEPTION(as >> dv, IllegalArgumentException, "double value '1.0e666' is outside of range."); - EXPECT_EQUAL(dv, 42.0); + EXPECT_THROW(as >> dv, IllegalArgumentException); + EXPECT_EQ(dv, 42.0); } -void -AsciistreamTest::testFloat() { +TEST(AsciistreamTest, test_float) +{ float f = 0; asciistream as("-5.490412E-39"); as >> f; - EXPECT_EQUAL(f, -5.490412E-39f); + EXPECT_EQ(f, -5.490412E-39f); as.clear(); as << "0.0001E-50"; f = 42.0; as >> f; - EXPECT_EQUAL(f, 0.0); + EXPECT_EQ(f, 0.0); as.clear(); as << "123.4E50"; f = 42.0; - EXPECT_EXCEPTION(as >> f, IllegalArgumentException, "float value '123.4E50' is outside of range."); - EXPECT_EQUAL(f, 42.0); + EXPECT_THROW(as >> f, IllegalArgumentException); + EXPECT_EQ(f, 42.0); errno = 0; char *ep; f = locale::c::strtof_au("-5.490412E-39", &ep); - EXPECT_EQUAL(f, -5.490412E-39f); - EXPECT_EQUAL(errno, 0); - EXPECT_EQUAL(*ep, 0); + EXPECT_EQ(f, -5.490412E-39f); + EXPECT_EQ(errno, 0); + EXPECT_EQ(*ep, 0); f = locale::c::strtof_au("0.0001E-50", &ep); - EXPECT_EQUAL(f, 0.0); - EXPECT_EQUAL(errno, 0); - EXPECT_EQUAL(*ep, 0); + EXPECT_EQ(f, 0.0); + EXPECT_EQ(errno, 0); + EXPECT_EQ(*ep, 0); f = locale::c::strtof_au("123.4E50", &ep); - EXPECT_EQUAL(f, HUGE_VALF); - EXPECT_EQUAL(errno, ERANGE); - EXPECT_EQUAL(*ep, 0); + EXPECT_EQ(f, HUGE_VALF); + EXPECT_EQ(errno, ERANGE); + EXPECT_EQ(*ep, 0); } -void -AsciistreamTest::testStateSaver() +TEST(AsciistreamTest, test_state_saver) { asciistream as; as << vespalib::hex << vespalib::setfill('0'); { asciistream::StateSaver stateSaver(as); as << vespalib::dec << vespalib::setfill('1'); - EXPECT_EQUAL(vespalib::dec, as.getBase()); - EXPECT_EQUAL('1', as.getFill()); + EXPECT_EQ(vespalib::dec, as.getBase()); + EXPECT_EQ('1', as.getFill()); } - ASSERT_EQUAL(vespalib::hex, as.getBase()); - ASSERT_EQUAL('0', as.getFill()); + ASSERT_EQ(vespalib::hex, as.getBase()); + ASSERT_EQ('0', as.getFill()); } -int -AsciistreamTest::Main() +TEST(AsciistreamTest, test_ascii_stream) { - TEST_INIT("asciistream_test"); - - TEST_DO(verify("per", "paal", "per", "per paal", ' ')); - TEST_DO(verify<float>(7.89, -1.3, "7.89", "7.89 -1.3", ' ')); - TEST_DO(verify<double>(7.89, -1.3, "7.89", "7.89 -1.3", ' ')); - TEST_DO(verify<bool>(true, false, "1", "1 0", ' ')); - TEST_DO(verify<char>(65, 66, "A", "A B", ' ')); - TEST_DO(verify<unsigned char>(65, 66, "A", "A B", ' ')); - TEST_DO(verify<signed char>(65, 66, "A", "A B", ' ')); -// TEST_DO(verify<int8_t>(65, -1, "65", "65 -1", ' ')); - TEST_DO(verify<int16_t>(0, -1, "0", "0 -1", ' ')); - TEST_DO(verify<int16_t>(789, -1, "789", "789 -1", ' ')); - TEST_DO(verify<int32_t>(789, -1, "789", "789 -1", ' ')); - TEST_DO(verify<int64_t>(789789789789789l, -1, "789789789789789", "789789789789789 -1", ' ')); -// TEST_DO(verify<uint8_t>(65, -1, "65", "65 255", ' ')); - TEST_DO(verify<uint16_t>(789, -1, "789", "789 65535", ' ')); - TEST_DO(verify<uint32_t>(789, -1, "789", "789 4294967295", ' ')); - TEST_DO(verify<uint64_t>(789789789789789l, -1, "789789789789789", "789789789789789 18446744073709551615", ' ')); - - TEST_DO(verifyBothWays<vespalib::string>("7.89", "7.89")); - TEST_DO(verifyBothWays<std::string>("7.89", "7.89")); - TEST_DO(verifyBothWays<float>(7.89, "7.89")); - TEST_DO(verifyBothWays<double>(7.89, "7.89")); - TEST_DO(verifyBothWays<bool>(true, "1")); - TEST_DO(verifyBothWays<bool>(false, "0")); - TEST_DO(verifyBothWays<char>(65, "A")); - TEST_DO(verifyBothWays<unsigned char>(65, "A")); - //TEST_DO(verifyBothWays<int8_t>(7, "7")); - //TEST_DO(verifyBothWays<uint8_t>(7, "7")); - TEST_DO(verifyBothWays<int16_t>(7, "7")); - TEST_DO(verifyBothWays<uint16_t>(7, "7")); - TEST_DO(verifyBothWays<int32_t>(7, "7")); - TEST_DO(verifyBothWays<uint32_t>(7, "7")); - TEST_DO(verifyBothWays<int64_t>(7, "7")); - TEST_DO(verifyBothWays<uint64_t>(7, "7")); - - testCopyConstruct(); - testMoveIsWellDefined(); - testIntegerManip(); - testFill(); - testString(); - testCreateFromFile(); - testWriteThenRead(); - testGetLine(); - testIllegalNumbers(); - testDouble(); - testFloat(); - testStateSaver(); - TEST_DONE(); + verify("per", "paal", "per", "per paal", ' ', "string"); + verify<float>(7.89, -1.3, "7.89", "7.89 -1.3", ' ', "float"); + verify<double>(7.89, -1.3, "7.89", "7.89 -1.3", ' ', "double"); + verify<bool>(true, false, "1", "1 0", ' ', "bool"); + verify<char>(65, 66, "A", "A B", ' ', "char"); + verify<unsigned char>(65, 66, "A", "A B", ' ', "unsigned char"); + verify<signed char>(65, 66, "A", "A B", ' ', "signed char"); +// verify<int8_t>(65, -1, "65", "65 -1", ' ', "int8_t"); + verify<int16_t>(0, -1, "0", "0 -1", ' ', "int16_t"); + verify<int16_t>(789, -1, "789", "789 -1", ' ', "int16_t again"); + verify<int32_t>(789, -1, "789", "789 -1", ' ', "int32_t"); + verify<int64_t>(789789789789789l, -1, "789789789789789", "789789789789789 -1", ' ', "int64_t"); +// verify<uint8_t>(65, -1, "65", "65 255", ' ', "uint8_t"); + verify<uint16_t>(789, -1, "789", "789 65535", ' ', "uint16_t"); + verify<uint32_t>(789, -1, "789", "789 4294967295", ' ', "uint32_t"); + verify<uint64_t>(789789789789789l, -1, "789789789789789", "789789789789789 18446744073709551615", ' ', "uint64_t"); + + verifyBothWays<vespalib::string>("7.89", "7.89", "vespalib::string"); + verifyBothWays<std::string>("7.89", "7.89", "stsd::string"); + verifyBothWays<float>(7.89, "7.89", "float"); + verifyBothWays<double>(7.89, "7.89", "double"); + verifyBothWays<bool>(true, "1", "bool"); + verifyBothWays<bool>(false, "0", "bool again"); + verifyBothWays<char>(65, "A", "char"); + verifyBothWays<unsigned char>(65, "A", "unsigned char"); + // verifyBothWays<int8_t>(7, "7", "int8_t"); + // verifyBothWays<uint8_t>(7, "7", "uint8_t"); + verifyBothWays<int16_t>(7, "7", "int16_t"); + verifyBothWays<uint16_t>(7, "7", "uint16_t"); + verifyBothWays<int32_t>(7, "7", "int32_t"); + verifyBothWays<uint32_t>(7, "7", "uint32_t"); + verifyBothWays<int64_t>(7, "7", "int64_t"); + verifyBothWays<uint64_t>(7, "7", "uint64_t"); } -TEST_APPHOOK(AsciistreamTest) +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/tests/xmlserializable/CMakeLists.txt b/vespalib/src/tests/xmlserializable/CMakeLists.txt index 740f1f49bfb..4bd28a668a0 100644 --- a/vespalib/src/tests/xmlserializable/CMakeLists.txt +++ b/vespalib/src/tests/xmlserializable/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(vespalib_xmlserializable_test_app TEST xmlserializabletest.cpp DEPENDS vespalib + GTest::gtest ) vespa_add_test(NAME vespalib_xmlserializable_test_app COMMAND vespalib_xmlserializable_test_app) diff --git a/vespalib/src/tests/xmlserializable/xmlserializabletest.cpp b/vespalib/src/tests/xmlserializable/xmlserializabletest.cpp index c4d3fb9f1b9..3a6b933491a 100644 --- a/vespalib/src/tests/xmlserializable/xmlserializabletest.cpp +++ b/vespalib/src/tests/xmlserializable/xmlserializabletest.cpp @@ -1,35 +1,11 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/util/xmlstream.h> namespace vespalib { -class Test : public vespalib::TestApp -{ -public: - void testNormalUsage(); - void testEscaping(); - void testNesting(); - void testIndent(); - - int Main() override; -}; - -int -Test::Main() -{ - TEST_INIT("xmlserializables_test"); - srandom(1); - testNormalUsage(); - testEscaping(); - testNesting(); - testIndent(); - TEST_DONE(); -} - -void -Test::testNormalUsage() +TEST(XmlSerializableTest, test_normal_usage) { std::ostringstream ost; XmlOutputStream xos(ost); @@ -47,11 +23,10 @@ Test::testNormalUsage() "<door windowstate=\"up\"/>\n" "<description>This is a car description used to test</description>\n" "</car>"; - EXPECT_EQUAL(expected, ost.str()); + EXPECT_EQ(expected, ost.str()); } -void -Test::testEscaping() +TEST(XmlSerializableTest, test_escaping) { std::ostringstream ost; XmlOutputStream xos(ost); @@ -83,7 +58,7 @@ Test::testEscaping() "<auto1><>&	 \nfoo</auto1>\n" "<auto2 binaryencoding=\"base64\">PD4mCQANCmZvbw==</auto2>\n" "</__trash_->"; - EXPECT_EQUAL(expected, ost.str()); + EXPECT_EQ(expected, ost.str()); } namespace { @@ -103,8 +78,7 @@ namespace { }; } -void -Test::testNesting() +TEST(XmlSerializableTest, test_nesting) { std::ostringstream ost; XmlOutputStream xos(ost); @@ -127,11 +101,10 @@ Test::testNesting() "</door>\n" "<description>This is a car description used to test</description>\n" "</car>"; - EXPECT_EQUAL(expected, ost.str()); + EXPECT_EQ(expected, ost.str()); } -void -Test::testIndent() +TEST(XmlSerializableTest, test_indent) { std::ostringstream ost; XmlOutputStream xos(ost, " "); @@ -155,9 +128,9 @@ Test::testIndent() " <base binaryencoding=\"base64\">Zm9vYmFy</base>\n" " </nytag>\n" "</foo>"; - EXPECT_EQUAL(expected, ost.str()); + EXPECT_EQ(expected, ost.str()); } } // vespalib -TEST_APPHOOK(vespalib::Test) +GTEST_MAIN_RUN_ALL_TESTS() |