From 5685e944b0e9808d6f3edc9e14000c3879818ffc Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Mon, 11 Nov 2024 13:16:01 +0100 Subject: test: Prettify JSON tests using jq This also ensures that our JSON is actually correct JSON. echo may fail now with EPIPE, given that it is multiline, so wrap it in 2>/dev/null --- test/integration/test-apt-cli-json-hooks | 1010 ++++++++++++++++++++++++++++-- 1 file changed, 968 insertions(+), 42 deletions(-) (limited to 'test') diff --git a/test/integration/test-apt-cli-json-hooks b/test/integration/test-apt-cli-json-hooks index 9a3208c3c..d319265bb 100755 --- a/test/integration/test-apt-cli-json-hooks +++ b/test/integration/test-apt-cli-json-hooks @@ -29,25 +29,29 @@ export TEST_HOOK_VERSION=0.2 cat >> json-hook.sh << EOF #!/bin/bash trap '' SIGPIPE +clean_json() { + jq 'del (.params.options[]? | select(.name != "APT::Architecture"))' +} while true; do read request <&\$APT_HOOK_SOCKET || exit 1 - if echo "\$request" | grep -q ".hello"; then + if echo "\$request" 2>/dev/null | grep -q ".hello"; then echo "HOOK: HELLO" fi - if echo "\$request" | grep -q ".bye"; then + if echo "\$request" 2>/dev/null | grep -q ".bye"; then echo "HOOK: BYE" exit 0; fi - echo HOOK: request \$request + request="\$(printf "%s" "\$request" | clean_json)" + echo "HOOK: request \$request" read empty <&\$APT_HOOK_SOCKET || exit 1 echo HOOK: empty \$empty - if echo "\$request" | grep -q ".hello"; then + if echo "\$request" 2>/dev/null | grep -q ".hello"; then printf '{"jsonrpc": "2.0", "result": {"version": "'\$TEST_HOOK_VERSION'"}, "id": 0}\n\n' >&\$APT_HOOK_SOCKET 2>/dev/null || exit 1 fi @@ -69,9 +73,30 @@ EOF ############################# Success search ####################### testsuccessequal 'HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.search.pre","params":{"command":"search","search-terms":["foo"],"unknown-packages":[],"packages":[]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.search.pre", + "params": { + "command": "search", + "search-terms": [ + "foo" + ], + "unknown-packages": [], + "packages": [] + } +} HOOK: empty HOOK: BYE Sorting... @@ -80,25 +105,88 @@ foo/unstable 1.0 all Some description that has a unusual word xxyyzz and aabbcc and a UPPERCASE HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.search.post","params":{"command":"search","search-terms":["foo"],"unknown-packages":[],"packages":[]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.search.post", + "params": { + "command": "search", + "search-terms": [ + "foo" + ], + "unknown-packages": [], + "packages": [] + } +} HOOK: empty HOOK: BYE' apt search foo ############################# Failed search ####################### testsuccessequal 'HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.search.pre","params":{"command":"search","search-terms":["foox"],"unknown-packages":[],"packages":[]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.search.pre", + "params": { + "command": "search", + "search-terms": [ + "foox" + ], + "unknown-packages": [], + "packages": [] + } +} HOOK: empty HOOK: BYE Sorting... Full Text Search... HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.search.fail","params":{"command":"search","search-terms":["foox"],"unknown-packages":[],"packages":[]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.search.fail", + "params": { + "command": "search", + "search-terms": [ + "foox" + ], + "unknown-packages": [], + "packages": [] + } +} HOOK: empty HOOK: BYE' apt search foox @@ -108,9 +196,32 @@ HOOK: BYE' apt search foox testfailureequal 'Reading package lists... Building dependency tree... HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.fail","params":{"command":"install","search-terms":["foxxx"],"unknown-packages":["foxxx"],"packages":[]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.fail", + "params": { + "command": "install", + "search-terms": [ + "foxxx" + ], + "unknown-packages": [ + "foxxx" + ], + "packages": [] + } +} HOOK: empty HOOK: BYE E: Unable to locate package foxxx' apt install foxxx @@ -120,32 +231,276 @@ E: Unable to locate package foxxx' apt install foxxx testsuccessequal 'Reading package lists... Building dependency tree... HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.pre-prompt","params":{"command":"install","search-terms":["foo"],"unknown-packages":[],"packages":[{"id":2,"name":"foo","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]}}}]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.pre-prompt", + "params": { + "command": "install", + "search-terms": [ + "foo" + ], + "unknown-packages": [], + "packages": [ + { + "id": 2, + "name": "foo", + "architecture": "i386", + "mode": "install", + "automatic": false, + "versions": { + "candidate": { + "id": 2, + "version": "1.0", + "architecture": "all", + "pin": 500, + "origins": [ + { + "archive": "unstable", + "codename": "sid", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "install": { + "id": 2, + "version": "1.0", + "architecture": "all", + "pin": 500, + "origins": [ + { + "archive": "unstable", + "codename": "sid", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + } + } + } + ] + } +} HOOK: empty HOOK: BYE The following NEW packages will be installed: foo HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.package-list","params":{"command":"install","search-terms":["foo"],"unknown-packages":[],"packages":[{"id":2,"name":"foo","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]}}}]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.package-list", + "params": { + "command": "install", + "search-terms": [ + "foo" + ], + "unknown-packages": [], + "packages": [ + { + "id": 2, + "name": "foo", + "architecture": "i386", + "mode": "install", + "automatic": false, + "versions": { + "candidate": { + "id": 2, + "version": "1.0", + "architecture": "all", + "pin": 500, + "origins": [ + { + "archive": "unstable", + "codename": "sid", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "install": { + "id": 2, + "version": "1.0", + "architecture": "all", + "pin": 500, + "origins": [ + { + "archive": "unstable", + "codename": "sid", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + } + } + } + ] + } +} HOOK: empty HOOK: BYE 0 upgraded, 1 newly installed, 0 to remove and 1 not upgraded. HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.statistics","params":{"command":"install","search-terms":["foo"],"unknown-packages":[],"packages":[{"id":2,"name":"foo","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]}}}]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.statistics", + "params": { + "command": "install", + "search-terms": [ + "foo" + ], + "unknown-packages": [], + "packages": [ + { + "id": 2, + "name": "foo", + "architecture": "i386", + "mode": "install", + "automatic": false, + "versions": { + "candidate": { + "id": 2, + "version": "1.0", + "architecture": "all", + "pin": 500, + "origins": [ + { + "archive": "unstable", + "codename": "sid", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "install": { + "id": 2, + "version": "1.0", + "architecture": "all", + "pin": 500, + "origins": [ + { + "archive": "unstable", + "codename": "sid", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + } + } + } + ] + } +} HOOK: empty HOOK: BYE Inst foo (1.0 Lemons:unstable [all]) Conf foo (1.0 Lemons:unstable [all]) HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.post","params":{"command":"install","search-terms":["foo"],"unknown-packages":[],"packages":[{"id":2,"name":"foo","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]}}}]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.post", + "params": { + "command": "install", + "search-terms": [ + "foo" + ], + "unknown-packages": [], + "packages": [ + { + "id": 2, + "name": "foo", + "architecture": "i386", + "mode": "install", + "automatic": false, + "versions": { + "candidate": { + "id": 2, + "version": "1.0", + "architecture": "all", + "pin": 500, + "origins": [ + { + "archive": "unstable", + "codename": "sid", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "install": { + "id": 2, + "version": "1.0", + "architecture": "all", + "pin": 500, + "origins": [ + { + "archive": "unstable", + "codename": "sid", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + } + } + } + ] + } +} HOOK: empty HOOK: BYE' apt install foo -s @@ -154,9 +509,32 @@ HOOK: BYE' apt install foo -s testfailureequal 'Reading package lists... Building dependency tree... HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.fail","params":{"command":"dist-upgrade","search-terms":["foxxx"],"unknown-packages":["foxxx"],"packages":[]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.fail", + "params": { + "command": "dist-upgrade", + "search-terms": [ + "foxxx" + ], + "unknown-packages": [ + "foxxx" + ], + "packages": [] + } +} HOOK: empty HOOK: BYE E: Unable to locate package foxxx' apt dist-upgrade foxxx @@ -167,32 +545,296 @@ testsuccessequal 'Reading package lists... Building dependency tree... Calculating upgrade... HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.pre-prompt","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"upgrade","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":3,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.pre-prompt", + "params": { + "command": "dist-upgrade", + "search-terms": [], + "unknown-packages": [], + "packages": [ + { + "id": 1, + "name": "upgrade", + "architecture": "i386", + "mode": "upgrade", + "automatic": false, + "versions": { + "candidate": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "install": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "current": { + "id": 3, + "version": "1.0", + "architecture": "i386", + "pin": 100, + "origins": [] + } + } + } + ] + } +} HOOK: empty HOOK: BYE The following packages will be upgraded: upgrade HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.package-list","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"upgrade","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":3,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.package-list", + "params": { + "command": "dist-upgrade", + "search-terms": [], + "unknown-packages": [], + "packages": [ + { + "id": 1, + "name": "upgrade", + "architecture": "i386", + "mode": "upgrade", + "automatic": false, + "versions": { + "candidate": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "install": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "current": { + "id": 3, + "version": "1.0", + "architecture": "i386", + "pin": 100, + "origins": [] + } + } + } + ] + } +} HOOK: empty HOOK: BYE 1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.statistics","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"upgrade","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":3,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.statistics", + "params": { + "command": "dist-upgrade", + "search-terms": [], + "unknown-packages": [], + "packages": [ + { + "id": 1, + "name": "upgrade", + "architecture": "i386", + "mode": "upgrade", + "automatic": false, + "versions": { + "candidate": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "install": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "current": { + "id": 3, + "version": "1.0", + "architecture": "i386", + "pin": 100, + "origins": [] + } + } + } + ] + } +} HOOK: empty HOOK: BYE Inst upgrade [1.0] (2.0 Lemons:testing [i386]) Conf upgrade (2.0 Lemons:testing [i386]) HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.post","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"upgrade","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":3,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.post", + "params": { + "command": "dist-upgrade", + "search-terms": [], + "unknown-packages": [], + "packages": [ + { + "id": 1, + "name": "upgrade", + "architecture": "i386", + "mode": "upgrade", + "automatic": false, + "versions": { + "candidate": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "install": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "current": { + "id": 3, + "version": "1.0", + "architecture": "i386", + "pin": 100, + "origins": [] + } + } + } + ] + } +} HOOK: empty HOOK: BYE' apt dist-upgrade -s @@ -204,32 +846,296 @@ testsuccessequal 'Reading package lists... Building dependency tree... Calculating upgrade... HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.pre-prompt","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":3,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.pre-prompt", + "params": { + "command": "dist-upgrade", + "search-terms": [], + "unknown-packages": [], + "packages": [ + { + "id": 1, + "name": "upgrade", + "architecture": "i386", + "mode": "install", + "automatic": false, + "versions": { + "candidate": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "install": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "current": { + "id": 3, + "version": "1.0", + "architecture": "i386", + "pin": 100, + "origins": [] + } + } + } + ] + } +} HOOK: empty HOOK: BYE The following packages will be upgraded: upgrade HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.package-list","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":3,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.package-list", + "params": { + "command": "dist-upgrade", + "search-terms": [], + "unknown-packages": [], + "packages": [ + { + "id": 1, + "name": "upgrade", + "architecture": "i386", + "mode": "install", + "automatic": false, + "versions": { + "candidate": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "install": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "current": { + "id": 3, + "version": "1.0", + "architecture": "i386", + "pin": 100, + "origins": [] + } + } + } + ] + } +} HOOK: empty HOOK: BYE 1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.statistics","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":3,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.statistics", + "params": { + "command": "dist-upgrade", + "search-terms": [], + "unknown-packages": [], + "packages": [ + { + "id": 1, + "name": "upgrade", + "architecture": "i386", + "mode": "install", + "automatic": false, + "versions": { + "candidate": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "install": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "current": { + "id": 3, + "version": "1.0", + "architecture": "i386", + "pin": 100, + "origins": [] + } + } + } + ] + } +} HOOK: empty HOOK: BYE Inst upgrade [1.0] (2.0 Lemons:testing [i386]) Conf upgrade (2.0 Lemons:testing [i386]) HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.post","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":3,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.install.post", + "params": { + "command": "dist-upgrade", + "search-terms": [], + "unknown-packages": [], + "packages": [ + { + "id": 1, + "name": "upgrade", + "architecture": "i386", + "mode": "install", + "automatic": false, + "versions": { + "candidate": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "install": { + "id": 1, + "version": "2.0", + "architecture": "i386", + "pin": 500, + "origins": [ + { + "archive": "testing", + "codename": "testing", + "origin": "Oranges", + "label": "Lemons", + "site": "" + } + ] + }, + "current": { + "id": 3, + "version": "1.0", + "architecture": "i386", + "pin": 100, + "origins": [] + } + } + } + ] + } +} HOOK: empty HOOK: BYE' apt dist-upgrade -s @@ -241,10 +1147,30 @@ testfailureequal 'Reading package lists... Building dependency tree... Calculating upgrade... HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty HOOK: HELLO -HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}} +HOOK: request { + "jsonrpc": "2.0", + "method": "org.debian.apt.hooks.hello", + "id": 0, + "params": { + "versions": [ + "0.1", + "0.2" + ] + } +} HOOK: empty E: Unknown hook version in handshake from hook '$HOOK': {"jsonrpc": "2.0", "result": {"version": "42"}, "id": 0} E: Sub-process '$HOOK' returned an error code (1) -- cgit v1.2.3-70-g09d2 From d936557579090fa7a5ce7edaebc61f55b3fa3ab8 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Mon, 2 Sep 2024 18:11:28 +0200 Subject: json: Add "options" array to JSON hooks See the attached documentation. Note that defaults are missing, so using this is not particularly easy so far. --- apt-private/private-json-hooks.cc | 34 ++++++++- doc/json-hooks-protocol.md | 32 ++++++++- test/integration/test-apt-cli-json-hooks | 120 +++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/apt-private/private-json-hooks.cc b/apt-private/private-json-hooks.cc index 58185181e..6169488f6 100644 --- a/apt-private/private-json-hooks.cc +++ b/apt-private/private-json-hooks.cc @@ -350,11 +350,43 @@ static void NotifyHook(std::ostream &os, std::string const &method, const char * jsonWriter.endObject(); // main } +static JsonWriter &BuildOptionsArray(JsonWriter &writer) +{ + const Configuration::Item *Top = _config->Tree(nullptr); + if (Top == 0) + return writer.beginArray().endArray(); + + writer.beginArray(); + do + { + if (not Top->Value.empty()) + writer.beginObject().name("name").value(Top->FullTag()).name("value").value(Top->Value).endObject(); + if (Top->Child != 0) + { + Top = Top->Child; + continue; + } + + while (Top != 0 && Top->Next == 0) + Top = Top->Parent; + if (Top != 0) + Top = Top->Next; + + } while (Top != 0); + + writer.endArray(); + + return writer; +} + /// @brief Build the hello handshake message for 0.1 protocol static std::string BuildHelloMessage() { std::stringstream Hello; - JsonWriter(Hello).beginObject().name("jsonrpc").value("2.0").name("method").value("org.debian.apt.hooks.hello").name("id").value(0).name("params").beginObject().name("versions").beginArray().value("0.1").value("0.2").endArray().endObject().endObject(); + auto writer = JsonWriter(Hello).beginObject().name("jsonrpc").value("2.0").name("method").value("org.debian.apt.hooks.hello").name("id").value(0).name("params").beginObject().name("versions").beginArray().value("0.1").value("0.2").endArray().name("options"); + + BuildOptionsArray(writer); + writer.endObject().endObject(); return Hello.str(); } diff --git a/doc/json-hooks-protocol.md b/doc/json-hooks-protocol.md index 2d8410c8d..4dcbced0d 100644 --- a/doc/json-hooks-protocol.md +++ b/doc/json-hooks-protocol.md @@ -38,13 +38,39 @@ started multiple times. Hooks should thus be stateless. APT performs a call to the method `org.debian.apt.hooks.hello` with the named parameter `versions` containing a list of supported protocol -versions. The hook picks the version it supports. The current version -is `"0.1"`, and support for that version is mandatory. +versions, and an optional `options` array. The hook picks the version it supports. The current version +is `"0.2"`, and support for "0.1" or "0.2" is mandatory. + +The `options` array is an optional list of all options currently set in the apt +configuration object. Note that not all options are present, and the default can vary, +you cannot rely on the default being `true` or `false` for example for a boolean option +-- it depends on the context. + +APT options are internally stored as a tree leading to the awkward situation that a list +item could have a name, e.g. `APT::Architectures "unused" { first "amd64"; "i386"; };`. This will +be represented as + +```json +[ + {"name": "APT::Architectures", "value": "unused"}, + {"name": "APT::Architectures::first", "amd64"}, + {"name": "APT::Architectures::", ""} +] +``` + +To interpret an option name as a list, with trailing `::`, for example, `APT::Architectures`, you +will need to write a function similar to: + +```python +def get_list(options, key): + """key includes trailing ::""" + return [value for name, value in options if name.startswith(key) and "::" not in name[len(key):]] +``` *Example*: 1. APT: - ```{"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}``` + ```{"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1", "0.2"], "options": [{"name": "APT::Architecture", "value": "amd64"}]}}``` 2. Hook: diff --git a/test/integration/test-apt-cli-json-hooks b/test/integration/test-apt-cli-json-hooks index d319265bb..ee936e116 100755 --- a/test/integration/test-apt-cli-json-hooks +++ b/test/integration/test-apt-cli-json-hooks @@ -81,6 +81,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -113,6 +119,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -142,6 +154,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -171,6 +189,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -204,6 +228,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -239,6 +269,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -308,6 +344,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -376,6 +418,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -445,6 +493,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -517,6 +571,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -553,6 +613,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -627,6 +693,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -700,6 +772,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -774,6 +852,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -854,6 +938,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -928,6 +1018,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -1001,6 +1097,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -1075,6 +1177,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -1155,6 +1263,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } @@ -1168,6 +1282,12 @@ HOOK: request { "versions": [ "0.1", "0.2" + ], + "options": [ + { + "name": "APT::Architecture", + "value": "i386" + } ] } } -- cgit v1.2.3-70-g09d2