#!/bin/bash # Tests for Serval rhizome operations. # # Copyright 2013 Serval Project, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. source "${0%/*}/../testframework.sh" source "${0%/*}/../testdefs.sh" source "${0%/*}/../testdefs_rhizome.sh" shopt -s extglob setup() { CR=' ' setup_curl 7 setup_jq 1.2 setup_servald set_instance +A set_rhizome_config executeOk_servald config \ set rhizome.api.restful.users.harry.password potter \ set rhizome.api.restful.users.ron.password weasley \ set rhizome.api.restful.users.hermione.password grainger create_single_identity echo "$SIDA1" >sids start_servald_instances +A wait_until rhizome_http_server_started +A get_rhizome_server_port PORTA +A } finally() { stop_all_servald_servers } teardown() { kill_all_servald_processes assert_no_servald_processes report_all_servald_servers } set_rhizome_config() { executeOk_servald config \ set debug.httpd on \ set debug.rhizome_httpd on \ set debug.rhizome on \ set debug.verbose on \ set log.console.level debug } doc_AuthBasicMissing="Basic Authentication credentials are required" test_AuthBasicMissing() { executeOk curl \ --silent --show-error --write-out '%{http_code}' \ --output http.output \ --dump-header http.headers \ "http://$addr_localhost:$PORTA/restful/rhizome/bundlelist.json" assertStdoutIs '401' assertGrep http.headers "^WWW-Authenticate: Basic realm=\"Serval Rhizome\"$CR\$" } teardown_AuthBasicMissing() { tfw_cat http.headers http.output teardown } doc_AuthBasicWrong="Basic Authentication credentials must be correct" test_AuthBasicWrong() { executeOk curl \ --silent --show-error --write-out '%{http_code}' \ --output http.output \ --dump-header http.headers \ --basic --user fred:nurks \ "http://$addr_localhost:$PORTA/restful/rhizome/bundlelist.json" assertStdoutIs '401' assertGrep http.headers "^WWW-Authenticate: Basic realm=\"Serval Rhizome\"$CR\$" executeOk curl \ --silent --fail --show-error --write-out '%{http_code}' \ --output http.output \ --dump-header http.headers \ --basic --user ron:weasley \ "http://$addr_localhost:$PORTA/restful/rhizome/bundlelist.json" assertStdoutIs '200' } teardown_AuthBasicWrong() { tfw_cat http.headers http.output teardown } add_bundles() { local encrypted=false case "$1" in --encrypted) encrypted=true; shift;; esac local n for ((n = $1; n <= $2; ++n)); do create_file file$n $((1000 + $n)) if $encrypted; then echo "crypt=1" >file$n.manifest fi executeOk_servald rhizome add file $SIDA file$n file$n.manifest extract_stdout_manifestid BID[$n] extract_stdout_version VERSION[$n] extract_stdout_filesize SIZE[$n] extract_stdout_filehash HASH[$n] extract_stdout_date DATE[$n] extract_stdout_BK BK[$n] extract_stdout_rowid ROWID[$n] extract_stdout_author AUTHOR[$n] extract_stdout_secret SECRET[$n] extract_stdout_inserttime INSERTTIME[$n] if $encrypted; then extract_stdout_crypt CRYPT[$n] assert [ "${CRYPT[$n]}" = 1 ] else CRYPT[$n]= fi executeOk_servald rhizome export file ${HASH[$n]} raw$n if $encrypted; then assert ! cmp file$n raw$n else assert cmp file$n raw$n fi [ "${ROWID[$n]}" -gt "${ROWID_MAX:-0}" ] && ROWID_MAX=${ROWID[$n]} done } transform_bundlelist_json() { # The following jq(1) incantation transforms the JSON array in # bundlelist.json from the following form (which is optimised for # transmission size): # { # "header":[ # ".token", "_id", "service", "id", "version","date",".inserttime", # ".author",".fromhere","filesize","filehash","sender","recipient", # "name" # ], # "rows":[ # [ "xx", rowid1, "service1", bundleid1, version1, .... ], # [ null, rowid2, "service2", bundleid2, version2, .... ], # ... # [ null, rowidN, "serviceN", bundleidN, versionN, .... ] # ] # } # # into an array of JSON objects: # [ # { # "__index": 0, # ".token": "xx", # "_id": rowid1, # "service": service1, # "id": bundleid1, # "version": version1, # ... # }, # { # "__index": 1, # ".token": null, # "_id": rowid2, # "service": service2, # "id": bundleid2, # "version": version2, # ... # }, # ... # { # "__index": 2, # ".token": null, # "_id": rowidN, # "service": serviceN, # "id": bundleidN, # "version": versionN, # ... # } # ] # which is much easier to test with jq(1) expressions. jq ' [ .header as $header | .rows as $rows | $rows | keys | .[] as $index | [ $rows[$index] as $d | $d | keys | .[] as $i | {key:$header[$i], value:$d[$i]} ] | from_entries | .["__index"] = $index ] ' "$1" >"$2" } assertJq() { local json="$1" local jqscript="$2" assert --message="$jqscript" [ "$(jq "$jqscript" "$json")" = true ] } doc_RhizomeList="Fetch Rhizome bundle list in JSON format" setup_RhizomeList() { setup NBUNDLES=100 add_bundles 0 $((NBUNDLES-1)) assert [ "$ROWID_MAX" -ge "$NBUNDLES" ] } test_RhizomeList() { executeOk curl \ --silent --fail --show-error \ --output bundlelist.json \ --dump-header http.headers \ --basic --user harry:potter \ "http://$addr_localhost:$PORTA/restful/rhizome/bundlelist.json" tfw_cat http.headers bundlelist.json tfw_preserve bundlelist.json assert [ "$(jq '.rows | length' bundlelist.json)" = $NBUNDLES ] transform_bundlelist_json bundlelist.json array_of_objects.json tfw_preserve array_of_objects.json for ((n = 0; n != NBUNDLES; ++n)); do if [ "${ROWID[$n]}" -eq "$ROWID_MAX" ]; then # The first row must contain a non-null token string. token=',".token":"","__index":0,' else token=',".token":null,' fi assertJq array_of_objects.json \ "contains([ { name:\"file$n\", service:\"file\", id:\"${BID[$n]}\", version:${VERSION[$n]}, filesize:${SIZE[$n]}, filehash:\"${HASH[$n]}\", date:${DATE[$n]}, _id:${ROWID[$n]}, \".fromhere\":1, \".author\":\"$SIDA\" $token } ])" done } curl_newsince() { curl \ --silent --fail --show-error \ --no-buffer \ --output "$1" \ --basic --user harry:potter \ "http://$addr_localhost:$PORTA/restful/rhizome/newsince/$token/bundlelist.json" } doc_RhizomeNewSince="Fetch Rhizome bundle list since token in JSON format" setup_RhizomeNewSince() { setup executeOk_servald config set rhizome.api.restful.newsince_timeout 60s executeOk_servald config set rhizome.api.restful.newsince_poll_ms 500 add_bundles 0 5 executeOk curl \ --silent --fail --show-error \ --output bundlelist.json \ --dump-header http.headers \ --basic --user harry:potter \ "http://$addr_localhost:$PORTA/restful/rhizome/bundlelist.json" assert [ "$(jq '.rows | length' bundlelist.json)" = 6 ] transform_bundlelist_json bundlelist.json array_of_objects.json token=$(jq --raw-output '.[0][".token"]' array_of_objects.json) assert [ -n "$token" ] } test_RhizomeNewSince() { fork %curl1 curl_newsince newsince1.json fork %curl2 curl_newsince newsince2.json fork %curl3 curl_newsince newsince3.json wait_until [ -e newsince1.json -a -e newsince2.json -a -e newsince3.json ] add_bundles 6 10 wait_until --timeout=10 grep "${BID[10]}" newsince1.json wait_until --timeout=10 grep "${BID[10]}" newsince2.json wait_until --timeout=10 grep "${BID[10]}" newsince3.json fork_terminate_all fork_wait_all for i in 1 2 3; do if [ $(jq . newsince$i | wc -c) -eq 0 ]; then echo ']}' >>newsince$i.json assert [ $(jq . newsince$i.json | wc -c) -ne 0 ] fi transform_bundlelist_json newsince$i.json objects$i.json tfw_preserve newsince$i.json objects$i.json for ((n = 0; n <= 5; ++n)); do assertJq objects$i.json "contains([{id:\"${BID[$n]}\"}]) | not" done for ((n = 6; n <= 10; ++n)); do assertJq objects$i.json \ "contains([ { name:\"file$n\", service:\"file\", id:\"${BID[$n]}\", version:${VERSION[$n]}, filesize:${SIZE[$n]}, filehash:\"${HASH[$n]}\", date:${DATE[$n]}, _id:${ROWID[$n]}, \".fromhere\":1, \".author\":\"$SIDA\", \".token\":\"\" } ])" done done } assert_http_response_headers() { local n=$1 assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Id: ${BID[$n]}$CR\$" assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Version: ${VERSION[$n]}$CR\$" assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Filesize: ${SIZE[$n]}$CR\$" assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Filehash: ${HASH[$n]}$CR\$" assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-BK: ${BK[$n]}$CR\$" assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Date: ${DATE[$n]}$CR\$" assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Name: \"file$n\"$CR\$" assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Service: file$CR\$" assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Author: ${AUTHOR[$n]}$CR\$" assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Secret: ${SECRET[$n]}$CR\$" assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Inserttime: ${INSERTTIME[$n]}$CR\$" assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Rowid: ${ROWID[$n]}$CR\$" } doc_RhizomeManifest="Fetch Rhizome bundle manifest" setup_RhizomeManifest() { setup add_bundles 0 2 } test_RhizomeManifest() { for n in 0 1 2; do executeOk curl \ --silent --fail --show-error \ --output bundle$n.rhm \ --dump-header http.headers$n \ --basic --user harry:potter \ "http://$addr_localhost:$PORTA/restful/rhizome/${BID[$n]}.rhm" tfw_cat http.headers$n bundle$n.rhm tfw_preserve bundle$n.rhm done for n in 0 1 2; do assert diff file$n.manifest bundle$n.rhm assert_http_response_headers $n done } doc_RhizomePayloadRaw="Fetch Rhizome raw payload" setup_RhizomePayloadRaw() { setup add_bundles 0 1 add_bundles --encrypted 2 3 } test_RhizomePayloadRaw() { for n in 0 1 2 3; do executeOk curl \ --silent --fail --show-error \ --output raw.bin$n \ --dump-header http.headers$n \ --basic --user harry:potter \ "http://$addr_localhost:$PORTA/restful/rhizome/${BID[$n]}/raw.bin" tfw_cat http.headers$n raw.bin$n done for n in 0 1 2 3; do assert cmp raw$n raw.bin$n assert_http_response_headers $n done } doc_RhizomePayloadDecrypted="Fetch Rhizome decrypted payload" setup_RhizomePayloadDecrypted() { setup add_bundles 0 1 add_bundles --encrypted 2 3 } test_RhizomePayloadDecrypted() { for n in 0 1 2 3; do executeOk curl \ --silent --fail --show-error \ --output decrypted.bin$n \ --dump-header http.headers$n \ --basic --user harry:potter \ "http://$addr_localhost:$PORTA/restful/rhizome/${BID[$n]}/decrypted.bin" tfw_cat http.headers$n decrypted.bin$n done for n in 0 1 2 3; do assert cmp file$n decrypted.bin$n assert_http_response_headers $n done } doc_RhizomeInsert="Insert new Rhizome bundle" test_RhizomeInsert() { : } doc_MeshmsListConversations="List MeshMS conversations" test_MeshmsListConversations() { : } doc_MeshmsListMessages="List all MeshMS messages in a single conversation" test_MeshmsListMessages() { : } doc_MeshmsListMessagesSince="List MeshMS messages in a single conversation since token" test_MeshmsListMessagesSince() { : } doc_MeshmsSend="Send MeshMS message" test_MeshmsSend() { : } runTests "$@"