diff --git a/rhizome.c b/rhizome.c index 34a0d873..8d095c8c 100644 --- a/rhizome.c +++ b/rhizome.c @@ -205,10 +205,13 @@ int rhizome_manifest_bind_file(rhizome_manifest *m_in,const char *filename,int e int rhizome_manifest_check_file(rhizome_manifest *m_in) { - int gotfile= sqlite_exec_int64("SELECT COUNT(*) FROM FILES WHERE ID='%s' and datavalid=1;", - m_in->fileHexHash); - if (gotfile==1) { - WHYF("Skipping file checks for bundle, as file is already in the database"); + long long gotfile = 0; + if (sqlite_exec_int64(&gotfile, "SELECT COUNT(*) FROM FILES WHERE ID='%s' and datavalid=1;", m_in->fileHexHash) != 1) { + WHYF("Failed to count files"); + return 0; + } + if (gotfile) { + DEBUGF("Skipping file checks for bundle, as file is already in the database"); return 0; } @@ -254,7 +257,7 @@ int rhizome_manifest_check_file(rhizome_manifest *m_in) (Debounce!) */ int rhizome_manifest_check_duplicate(rhizome_manifest *m_in,rhizome_manifest **m_out) { - WHY("Checking for duplicate"); + if (debug & DEBUG_RHIZOME) DEBUG("Checking for duplicate"); if (m_out) *m_out = NULL; rhizome_manifest *dupm = NULL; if (rhizome_find_duplicate(m_in, &dupm,0 /* version doesn't matter */) == -1) @@ -266,10 +269,10 @@ int rhizome_manifest_check_duplicate(rhizome_manifest *m_in,rhizome_manifest **m } else rhizome_manifest_free(dupm); - WHY("Found a duplicate"); + if (debug & DEBUG_RHIZOME) DEBUG("Found a duplicate"); return 2; } - WHY("No duplicate found"); + if (debug & DEBUG_RHIZOME) DEBUG("No duplicate found"); return 0; } @@ -308,16 +311,23 @@ int rhizome_add_manifest(rhizome_manifest *m_in,int ttl) if (rhizome_manifest_get(m_in, "id", id, SID_STRLEN + 1)) { str_toupper_inplace(id); /* Discard the new manifest unless it is newer than the most recent known version with the same ID */ - long long storedversion = sqlite_exec_int64("SELECT version from manifests where id='%s';", id); - if (debug & DEBUG_RHIZOME) - DEBUGF("Found existing version=%lld, new version=%lld", storedversion, m_in->version); - if (m_in->version < storedversion) { - return WHY("Newer version exists"); + long long storedversion = -1; + switch (sqlite_exec_int64(&storedversion, "SELECT version from manifests where id='%s';", id)) { + case -1: + return WHY("Select failed"); + case 0: + if (debug & DEBUG_RHIZOME) DEBUG("No existing manifest"); + break; + case 1: + if (debug & DEBUG_RHIZOME) DEBUGF("Found existing version=%lld, new version=%lld", storedversion, m_in->version); + if (m_in->version < storedversion) + return WHY("Newer version exists"); + if (m_in->version == storedversion) + return WHY("Same version of manifest exists, not adding"); + break; + default: + return WHY("Select found too many rows!"); } - if (m_in->version == storedversion) { - return WHY("Same version of manifest exists, not adding"); - } - strbuf b = strbuf_local(ofilehash, sizeof ofilehash); sqlite_exec_strbuf(b, "SELECT filehash from manifests where id='%s';", id); if (strbuf_overrun(b)) @@ -331,7 +341,7 @@ int rhizome_add_manifest(rhizome_manifest *m_in,int ttl) if (rhizome_store_bundle(m_in) == -1) return WHY("rhizome_store_bundle() failed."); - WHYF("Announcing arrival of manifest %s* version %lld", + DEBUGF("Announcing arrival of manifest %s* version %lld", overlay_render_sid_prefix(m_in->cryptoSignPublic,8),m_in->version); monitor_announce_bundle(m_in); return 0; diff --git a/rhizome.h b/rhizome.h index b486559a..9b0f1af2 100644 --- a/rhizome.h +++ b/rhizome.h @@ -73,7 +73,7 @@ typedef struct rhizome_http_request { /* The source specification data which are used in different ways by different request types */ - unsigned char source[1024]; + char source[1024]; long long source_index; long long source_count; int source_record_size; @@ -249,7 +249,7 @@ int rhizome_server_http_send_bytes(int rn,rhizome_http_request *r); int rhizome_server_parse_http_request(int rn,rhizome_http_request *r); int rhizome_server_simple_http_response(rhizome_http_request *r,int result, char *response); int sqlite_exec_void(const char *sqlformat,...); -long long sqlite_exec_int64(const char *sqlformat,...); +int sqlite_exec_int64(long long *result, const char *sqlformat,...); int sqlite_exec_strbuf(strbuf sb, const char *sqlformat,...); int rhizome_server_http_response_header(rhizome_http_request *r,int result, char *mime_type,unsigned long long bytes); diff --git a/rhizome_crypto.c b/rhizome_crypto.c index 97c32de9..52e1a095 100644 --- a/rhizome_crypto.c +++ b/rhizome_crypto.c @@ -328,7 +328,7 @@ int rhizome_manifest_extract_signature(rhizome_manifest *m,int *ofs) bcopy(&publicKey[0],m->signatories[m->sig_count], crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES); m->sig_count++; - if (debug&DEBUG_RHIZOME) WHY("Signature passed."); + if (debug&DEBUG_RHIZOME) DEBUG("Signature passed."); } break; default: diff --git a/rhizome_database.c b/rhizome_database.c index c773fa13..274cd47e 100644 --- a/rhizome_database.c +++ b/rhizome_database.c @@ -113,8 +113,17 @@ sqlite3 *rhizome_db=NULL; /* XXX Requires a messy join that might be slow. */ int rhizome_manifest_priority(char *id) { - long long result = sqlite_exec_int64("select max(grouplist.priorty) from grouplist,manifests,groupmemberships where manifests.id='%s' and grouplist.id=groupmemberships.groupid and groupmemberships.manifestid=manifests.id;",id); - return result; + long long result = 0; + if (sqlite_exec_int64(&result, + "select max(grouplist.priorty) from grouplist,manifests,groupmemberships" + " where manifests.id='%s'" + " and grouplist.id=groupmemberships.groupid" + " and groupmemberships.manifestid=manifests.id;", + id + ) == -1 + ) + return -1; + return (int) result; } int rhizome_opendb() @@ -201,8 +210,10 @@ int sqlite_exec_void(const char *sqlformat,...) return -1; } int stepcode; + int rows = 0; while ((stepcode = sqlite3_step(statement)) == SQLITE_ROW) - ; + ++rows; + if (rows) WARNF("query unexpectedly returned %d row%s", rows, rows == 1 ? "" : "s"); switch (stepcode) { case SQLITE_OK: case SQLITE_DONE: @@ -218,12 +229,15 @@ int sqlite_exec_void(const char *sqlformat,...) return 0; } -/* - Convenience wrapper for executing an SQL command that returns a single int64 value - Returns -1 if an error occurs, otherwise the value of the column in the first row. - If there are no rows, return zero. +/* + Convenience wrapper for executing an SQL command that returns a single int64 value. + Returns -1 if an error occurs. + If no row is found, then returns 0 and does not alter *result. + If exactly one row is found, the assigns its value to *result and returns 1. + If more than one row is found, then assigns the value of the first row to *result and returns the + number of rows. */ -long long sqlite_exec_int64(const char *sqlformat,...) +int sqlite_exec_int64(long long *result, const char *sqlformat,...) { if (!rhizome_db) rhizome_opendb(); strbuf stmt = strbuf_alloca(8192); @@ -243,18 +257,30 @@ long long sqlite_exec_int64(const char *sqlformat,...) sqlite3_finalize(statement); return -1; } - if (sqlite3_step(statement) == SQLITE_ROW) { + int stepcode; + int rowcount = 0; + if ((stepcode = sqlite3_step(statement)) == SQLITE_ROW) { int n = sqlite3_column_count(statement); if (n != 1) { sqlite3_finalize(statement); return WHYF("Incorrect column count %d (should be 1): %s", n, strbuf_str(stmt)); } - long long result= sqlite3_column_int64(statement, 0); - sqlite3_finalize(statement); - return result; + *result = sqlite3_column_int64(statement, 0); + rowcount = 1; + while ((stepcode = sqlite3_step(statement)) == SQLITE_ROW) + ++rowcount; + } + switch (stepcode) { + case SQLITE_OK: case SQLITE_DONE: + break; + default: + WHY(strbuf_str(stmt)); + WHY(sqlite3_errmsg(rhizome_db)); + sqlite3_finalize(statement); + return -1; } sqlite3_finalize(statement); - return WHY("No rows found"); + return rowcount; } /* @@ -380,8 +406,7 @@ int rhizome_drop_stored_file(const char *id,int maximum_priority) return -1; } - snprintf(sql,1024,"select id from manifests where filehash='%s'", - id); + snprintf(sql,1024,"select id from manifests where filehash='%s'", id); if(sqlite3_prepare_v2(rhizome_db,sql, -1, &statement, NULL) != SQLITE_OK ) { WHYF("SQLite error running query '%s': %s",sql,sqlite3_errmsg(rhizome_db)); @@ -406,8 +431,11 @@ int rhizome_drop_stored_file(const char *id,int maximum_priority) If so, we cannot drop the manifest or the file. However, we will keep iterating, as we can still drop any other manifests pointing to this file that are lower priority, and thus free up a little space. */ - if (rhizome_manifest_priority((char *)manifestId)>maximum_priority) { - WHYF("Cannot drop due to manifest %s",id); + int priority = rhizome_manifest_priority((char *)manifestId); + if (priority == -1) + WHYF("Cannot drop due to error, manifestId=%s", manifestId); + else if (priority > maximum_priority) { + WHYF("Cannot drop due to manifest %s", manifestId); cannot_drop=1; } else { printf("removing stale manifests, groupmemberships\n"); @@ -689,7 +717,7 @@ int rhizome_list_manifests(const char *service, const char *sender_sid, const ch long long blob_date = rhizome_manifest_get_ll(m, "date"); const char *blob_filehash = rhizome_manifest_get(m, "filehash", NULL, 0); long long blob_filesize = rhizome_manifest_get_ll(m, "filesize"); - WHYF("Manifest payload size = %lld",blob_filesize); + DEBUGF("Manifest payload size = %lld",blob_filesize); cli_puts(blob_service ? blob_service : ""); cli_delim(":"); cli_puts(q_manifestid); cli_delim(":"); cli_printf("%lld", blob_version); cli_delim(":"); @@ -761,20 +789,24 @@ int rhizome_store_file(rhizome_manifest *m,const unsigned char *key) const char *cmdtail; /* See if the file is already stored, and if so, don't bother storing it again */ - int count=sqlite_exec_int64("SELECT COUNT(*) FROM FILES WHERE id='%s' AND datavalid<>0;",hash); - if (count==1) { + long long count = 0; + if (sqlite_exec_int64(&count, "SELECT COUNT(*) FROM FILES WHERE id='%s' AND datavalid<>0;", hash) < 1) { + close(fd); + return WHY("Failed to count stored files"); + } + if (count >= 1) { /* File is already stored, so just update the highestPriority field if required. */ - long long storedPriority = sqlite_exec_int64("SELECT highestPriority FROM FILES WHERE id='%s' AND datavalid!=0",hash); - if (storedPriority=0) - sqlite_exec_void("UPDATE files set highestPriority=%d WHERE id='%s';", highestPriority,fileid); + long long highestPriority = -1; + if (sqlite_exec_int64(&highestPriority, + "SELECT max(grouplist.priority) FROM MANIFESTS,GROUPMEMBERSHIPS,GROUPLIST" + " where manifests.filehash='%s'" + " AND groupmemberships.manifestid=manifests.id" + " AND groupmemberships.groupid=grouplist.id;", + fileid) == -1) + return -1; + if (highestPriority >= 0) + return sqlite_exec_void("UPDATE files set highestPriority=%lld WHERE id='%s';", highestPriority, fileid); return 0; } @@ -961,7 +1000,7 @@ int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found, int ret = 0; sqlite3_stmt *statement; const char *cmdtail; - if (debug&DEBUG_RHIZOME) WHYF("sql query: %s",sqlcmd); + if (debug&DEBUG_RHIZOME) DEBUGF("sql query: %s",sqlcmd); if (sqlite3_prepare_v2(rhizome_db, sqlcmd, strlen(sqlcmd) + 1, &statement, &cmdtail) != SQLITE_OK) { ret = WHY(sqlite3_errmsg(rhizome_db)); } else { @@ -1185,7 +1224,10 @@ int rhizome_retrieve_file(const char *fileid, const char *filepath, const unsigned char *key) { sqlite3_blob *blob=NULL; - rhizome_update_file_priority(fileid); + if (rhizome_update_file_priority(fileid) == -1) { + WHY("Failed to update file priority"); + return 0; + } char sqlcmd[1024]; int n = snprintf(sqlcmd, sizeof(sqlcmd), "SELECT id, rowid, length FROM files WHERE id = ? AND datavalid != 0"); if (n >= sizeof(sqlcmd)) diff --git a/rhizome_fetch.c b/rhizome_fetch.c index 33b6fd10..398e031f 100644 --- a/rhizome_fetch.c +++ b/rhizome_fetch.c @@ -147,11 +147,11 @@ int rhizome_manifest_version_cache_lookup(rhizome_manifest *m) m->version = rhizome_manifest_get_ll(m, "version"); // skip the cache for now - long long dbVersion = sqlite_exec_int64("SELECT version FROM MANIFESTS WHERE id='%s';", id); - if (dbVersion >= m->version){ - WHYF("We already have %s (%lld vs %lld)", id, dbVersion, m->version); - return -1; - } + long long dbVersion = -1; + if (sqlite_exec_int64(&dbVersion, "SELECT version FROM MANIFESTS WHERE id='%s';", id) == -1) + return WHY("Select failure"); + if (dbVersion >= m->version) + return WHYF("We already have %s (%lld vs %lld)", id, dbVersion, m->version); return 0; /* Work out bin number in cache */ @@ -175,17 +175,16 @@ int rhizome_manifest_version_cache_lookup(rhizome_manifest *m) } if (i==24) { /* Entries match -- so check version */ - long long rev = rhizome_manifest_get_ll(m,"version"); - if (1) WHYF("cached version %lld vs manifest version %lld", - entry->version,rev); - if (rev>entry->version) { - /* If we only have an old version, try refreshing the cache + long long rev = rhizome_manifest_get_ll(m,"version"); + if (1) DEBUGF("cached version %lld vs manifest version %lld", entry->version,rev); + if (rev > entry->version) { + /* If we only have an old version, try refreshing the cache by querying the database */ - entry->version = sqlite_exec_int64("select version from manifests where id='%s'", id); - WHYF("Refreshed stored version from database: entry->version=%lld", - entry->version); + if (sqlite_exec_int64(&entry->version, "select version from manifests where id='%s'", id) != 1) + return WHY("failed to select stored manifest version"); + DEBUGF("Refreshed stored version from database: entry->version=%lld", entry->version); } - if (revversion) { + if (rev < entry->version) { /* the presented manifest is older than we have. This allows the caller to know that they can tell whoever gave them the manifest it's time to get with the times. May or not ever be @@ -195,18 +194,17 @@ int rhizome_manifest_version_cache_lookup(rhizome_manifest *m) return -2; } else if (rev<=entry->version) { /* the presented manifest is already stored. */ - if (1) WHY("cached version is NEWER/SAME as presented version"); + if (1) DEBUG("cached version is NEWER/SAME as presented version"); return -1; } else { /* the presented manifest is newer than we have */ - WHY("cached version is older than presented version"); + DEBUG("cached version is older than presented version"); return 0; - } - } else { + } } } - WHY("Not in manifest cache"); + DEBUG("Not in manifest cache"); /* Not in cache, so all is well, well, maybe. What we do know is that it is unlikely to be in the database, so it probably @@ -230,27 +228,34 @@ int rhizome_manifest_version_cache_lookup(rhizome_manifest *m) a fairly large cache here. */ long long manifest_version = rhizome_manifest_get_ll(m, "version"); - if (sqlite_exec_int64("select count(*) from manifests where id='%s' and version>=%lld", - id,manifest_version)>0) { - /* Okay, so we have a stored version which is newer, so update the cache - using a random replacement strategy. */ - - long long stored_version = sqlite_exec_int64("select version from manifests where id='%s'", id); - if (stored_version == -1) - return WHY("database error reading stored manifest version"); // database is broken, we can't confirm that it is here - WHYF("stored version=%lld, manifest_version=%lld (not fetching; remembering in cache)", - stored_version,manifest_version); - slot=random()%RHIZOME_VERSION_CACHE_ASSOCIATIVITY; - rhizome_manifest_version_cache_slot *entry - =&rhizome_manifest_version_cache[bin][slot]; - entry->version=stored_version; - for(i=0;i<24;i++) - { - int byte=(chartonybl(id[(i*2)])<<4)|chartonybl(id[(i*2)+1]); - entry->idprefix[i]=byte; + long long count; + switch (sqlite_exec_int64(&count, "select count(*) from manifests where id='%s' and version>=%lld", id, manifest_version)) { + case -1: + return WHY("database error reading stored manifest version"); + case 1: + if (count) { + /* Okay, we have a stored version which is newer, so update the cache + using a random replacement strategy. */ + long long stored_version; + if (sqlite_exec_int64(&stored_version, "select version from manifests where id='%s'", id) < 1) + return WHY("database error reading stored manifest version"); // database is broken, we can't confirm that it is here + DEBUGF("stored version=%lld, manifest_version=%lld (not fetching; remembering in cache)", + stored_version,manifest_version); + slot=random()%RHIZOME_VERSION_CACHE_ASSOCIATIVITY; + rhizome_manifest_version_cache_slot *entry + =&rhizome_manifest_version_cache[bin][slot]; + entry->version=stored_version; + for(i=0;i<24;i++) + { + int byte=(chartonybl(id[(i*2)])<<4)|chartonybl(id[(i*2)+1]); + entry->idprefix[i]=byte; + } + /* Finally, say that it isn't worth RXing this manifest */ + return stored_version > manifest_version ? -2 : -1; } - /* Finally, say that it isn't worth RXing this manifest */ - return stored_version > manifest_version ? -2 : -1; + break; + default: + return WHY("bad select result"); } /* At best we hold an older version of this manifest, and at worst we don't hold any copy. */ @@ -397,12 +402,12 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, return -1; } else { if (1||debug&DEBUG_RHIZOMESYNC) { - long long stored_version - =sqlite_exec_int64("select version from manifests where id='%s'",id); - DEBUGF("manifest id=%s, version=%lld is new to us (we only have version %lld).", - id, - m->version, - stored_version); + long long stored_version; + if (sqlite_exec_int64(&stored_version, "select version from manifests where id='%s'",id) > 0) + DEBUGF("manifest id=%s, version=%lld is new to us (we only have version %lld).", + id, + m->version, + stored_version); } } @@ -575,9 +580,9 @@ int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peeri if (filesize > 0 && m->fileHexHash[0]) { - int gotfile= sqlite_exec_int64("SELECT COUNT(*) FROM FILES WHERE ID='%s' and datavalid=1;", m->fileHexHash); - WHYF("SELECT COUNT(*) FROM FILES WHERE ID='%s' and datavalid=1; returned %d", m->fileHexHash, - gotfile); + long long gotfile = 0; + if (sqlite_exec_int64(&gotfile, "SELECT COUNT(*) FROM FILES WHERE ID='%s' and datavalid=1;", m->fileHexHash) != 1) + return WHY("select failed"); if (gotfile!=1) { /* We need to get the file */ /* Discard request if the same manifest is already queued for reception. diff --git a/rhizome_http.c b/rhizome_http.c index 0e83bcb6..44582a39 100644 --- a/rhizome_http.c +++ b/rhizome_http.c @@ -328,23 +328,16 @@ int rhizome_server_sql_query_http_response(int rn,rhizome_http_request *r, the body, although encryption is not yet implemented here. */ - char query[1024]; - if (r->buffer) { free(r->buffer); r->buffer=NULL; } r->buffer_size=16384; r->buffer=malloc(r->buffer_size); if (!r->buffer) return WHY("malloc() failed to allocate response buffer"); r->buffer_length=0; r->buffer_offset=0; - - snprintf(query,1024,"SELECT COUNT(*) %s",query_body); - query[1023]=0; - r->source_record_size=bytes_per_row; - r->source_count=sqlite_exec_int64(query); + r->source_count = 0; + sqlite_exec_int64(&r->source_count, "SELECT COUNT(*) %s", query_body); - if (r->source_count<1) r->source_count=0; - /* Work out total response length */ long long response_bytes=256+r->source_count*r->source_record_size; rhizome_server_http_response_header(r,200,"servalproject.org/rhizome-list", @@ -370,15 +363,16 @@ int rhizome_server_sql_query_http_response(int rn,rhizome_http_request *r, WHY("no function yet exists to obtain our public key?"); /* build templated query */ - snprintf(query,1024,"SELECT %s,rowid %s",column,query_body); - query[1023]=0; - bcopy(query,r->source,1024); + strbuf b = strbuf_local(r->source, sizeof r->source); + strbuf_sprintf(b, "SELECT %s,rowid %s", column, query_body); + if (strbuf_overrun(b)) + WHYF("SQL query overrun: %s", strbuf_str(b)); r->source_index=0; r->source_flags=dehexP; r->blob_column=strdup(column); r->blob_table=strdup(table); - WHYF("buffer_length=%d",r->buffer_length); + DEBUGF("buffer_length=%d",r->buffer_length); /* Populate spare space in buffer with rows of data */ return rhizome_server_sql_query_fill_buffer(rn,r); @@ -532,7 +526,8 @@ int rhizome_server_parse_http_request(int rn,rhizome_http_request *r) if (dud) rhizome_server_simple_http_response(r,400,"

That doesn't look like hex to me.

\r\n"); else { str_toupper_inplace(id); - long long rowid = sqlite_exec_int64("select rowid from files where id='%s';",id); + long long rowid = -1; + sqlite_exec_int64(&rowid, "select rowid from files where id='%s';", id); sqlite3_blob *blob; if (rowid>=0) if (sqlite3_blob_open(rhizome_db,"main","files","data",rowid,0,&blob) !=SQLITE_OK) diff --git a/rhizome_packetformats.c b/rhizome_packetformats.c index 49a721ed..53365c0e 100644 --- a/rhizome_packetformats.c +++ b/rhizome_packetformats.c @@ -135,13 +135,14 @@ int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e) and energy asking the database much the same questions possibly many times per second. */ - - if (debug&DEBUG_RHIZOME) { -#warning DEBUG("Group handling not completely thought out here yet."); - } + + // TODO Group handling not completely thought out here yet. /* Get number of bundles available if required */ - bundles_available=sqlite_exec_int64("SELECT COUNT(BAR) FROM MANIFESTS;"); + long long tmp = 0; + if (sqlite_exec_int64(&tmp, "SELECT COUNT(BAR) FROM MANIFESTS;") != 1) + return WHY("Could not count BARs for advertisement"); + bundles_available = (int) tmp; if (bundles_available==-1||(bundle_offset[0]>=bundles_available)) bundle_offset[0]=0; if (bundles_available==-1||(bundle_offset[1]>=bundles_available)) diff --git a/testdefs.sh b/testdefs.sh index b6bcf65d..32184fe0 100644 --- a/testdefs.sh +++ b/testdefs.sh @@ -9,7 +9,7 @@ servald_build_root="$servald_source_root" rexp_sid='[0-9a-fA-F]\{64\}' # Utility function for creating DNA fixtures: -# - Create a temporary directory to contain all servald-related files +# - create a temporary directory to contain all servald-related files # - set $servald variable (executable under test) # - set SERVALINSTANCE_PATH environment variable # - mkdir $SERVALINSTANCE_PATH unless --no-mkdir option given @@ -21,6 +21,14 @@ setup_servald() { fi } +# Utility function for running servald and asserting no errors: +# - executes $servald with the given arguments +# - asserts that standard error contains no error messages +executeOk_servald() { + executeOk --executable="$servald" "$@" + assertStderrGrep --matches=0 '^ERROR:' +} + # Utility function: # - set up environment and normal variables for the given instance name # - if the argument is not an instance name, then use the default instance name diff --git a/testframework.sh b/testframework.sh index a4520274..8a0a6369 100644 --- a/testframework.sh +++ b/testframework.sh @@ -182,6 +182,12 @@ escape_grep_extended() { echo "$re" } +# Executes its arguments as a command: +# - captures the standard output and error in temporary files for later +# examination +# - captures the exit status for later assertions +# - sets the $executed variable to a description of the command that was +# executed execute() { echo -n "# execute "; _tfw_shellarg "$@" _tfw_getopts execute "$@" @@ -245,14 +251,14 @@ tfw_cat() { for file; do case $file in --stdout) - echo "#--- ${header:-stdout of ${_tfw_execute_argv0##*/}} ---" + echo "#--- ${header:-stdout of $executed} ---" cat $show_nonprinting $_tfw_tmp/stdout echo "#---" header= show_nonprinting= ;; --stderr) - echo "#--- ${header:-stderr of ${_tfw_execute_argv0##*/}} ---" + echo "#--- ${header:-stderr of $executed} ---" cat $show_nonprinting $_tfw_tmp/stderr echo "#---" header= @@ -274,7 +280,7 @@ tfw_cat() { assertExitStatus() { _tfw_getopts assertexitstatus "$@" shift $_tfw_getopts_shift - [ -z "$_tfw_message" ] && _tfw_message="exit status of ${_tfw_execute_argv0##*/} ($_tfw_exitStatus) $*" + [ -z "$_tfw_message" ] && _tfw_message="exit status of $executed ($_tfw_exitStatus) $*" _tfw_assertExpr "$_tfw_exitStatus" "$@" || _tfw_failexit echo "# assert $_tfw_message" return 0 @@ -283,7 +289,7 @@ assertExitStatus() { assertRealTime() { _tfw_getopts assertrealtime "$@" shift $_tfw_getopts_shift - [ -z "$_tfw_message" ] && _tfw_message="real execution time of ${_tfw_execute_argv0##*/} ($realtime) $*" + [ -z "$_tfw_message" ] && _tfw_message="real execution time of $executed ($realtime) $*" _tfw_assertExpr "$realtime" "$@" || _tfw_failexit echo "# assert $_tfw_message" return 0 @@ -495,18 +501,19 @@ _tfw_teardown() { rm -rf $_tfw_tmp } +# Executes $_tfw_executable with the given arguments. _tfw_execute() { - _tfw_execute_argv0="$1" - { time -p "$@" >$_tfw_tmp/stdout 2>$_tfw_tmp/stderr ; } 2>$_tfw_tmp/times + executed=$(_tfw_shellarg "${_tfw_executable##*/}" "$@") + { time -p "$_tfw_executable" "$@" >$_tfw_tmp/stdout 2>$_tfw_tmp/stderr ; } 2>$_tfw_tmp/times _tfw_exitStatus=$? # Deal with exit status. if [ -n "$_tfw_opt_exit_status" ]; then - _tfw_message="exit status of ${_tfw_execute_argv0##*/} ($_tfw_exitStatus) is $_tfw_opt_exit_status" + _tfw_message="exit status of $executed ($_tfw_exitStatus) is $_tfw_opt_exit_status" _tfw_dump_stderr_on_fail=true _tfw_assert [ "$_tfw_exitStatus" -eq "$_tfw_opt_exit_status" ] || _tfw_failexit echo "# assert $_tfw_message" else - echo "# exit status of ${_tfw_execute_argv0##*/} = $_tfw_exitStatus" + echo "# exit status of $executed = $_tfw_exitStatus" fi # Parse execution time report. if ! _tfw_parse_times_to_milliseconds real realtime_ms || @@ -570,6 +577,7 @@ _tfw_dump_on_fail() { _tfw_getopts() { local context="$1" shift + _tfw_executable= _tfw_message= _tfw_opt_dump_on_fail=() _tfw_opt_error_on_fail=false @@ -583,6 +591,10 @@ _tfw_getopts() { *:--stderr) _tfw_dump_on_fail --stderr;; assert*:--dump-on-fail=*) _tfw_dump_on_fail "${1#*=}";; execute:--exit-status=*) _tfw_opt_exit_status="${1#*=}";; + execute*:--executable=*) + _tfw_executable="${1#*=}" + [ -z "$_tfw_executable" ] && _tfw_error "missing value: $1" + ;; assert*:--error-on-fail) _tfw_opt_error_on_fail=true;; assert*:--message=*) _tfw_message="${1#*=}";; assertgrep:--matches=*) _tfw_opt_matches="${1#*=}";; @@ -594,6 +606,16 @@ _tfw_getopts() { let _tfw_getopts_shift=_tfw_getopts_shift+1 shift done + case "$context" in + execute*) + if [ -z "$_tfw_executable" ]; then + _tfw_executable="$1" + let _tfw_getopts_shift=_tfw_getopts_shift+1 + shift + fi + [ -z "$_tfw_executable" ] && _tfw_error "missing executable argument" + ;; + esac } _tfw_expr_to_awkexpr() { @@ -659,7 +681,7 @@ _tfw_assert_stdxxx_is() { ;; esac _tfw_shopt_restore - local message="${_tfw_message:-${_tfw_opt_line:+line $_tfw_opt_line of }$qual of ${_tfw_execute_argv0##*/} is $*}" + local message="${_tfw_message:-${_tfw_opt_line:+line $_tfw_opt_line of }$qual of $executed is $*}" echo -n "$@" >$_tfw_tmp/stdxxx_is.tmp if ! cmp --quiet $_tfw_tmp/stdxxx_is.tmp "$_tfw_tmp/content"; then _tfw_failmsg "assertion failed: $message" @@ -695,7 +717,7 @@ _tfw_assert_stdxxx_grep() { _tfw_error "incorrect arguments" return 254 fi - _tfw_assert_grep "$qual of ${_tfw_execute_argv0##*/}" $_tfw_tmp/$qual "$@" + _tfw_assert_grep "$qual of $executed" $_tfw_tmp/$qual "$@" } _tfw_assert_grep() { diff --git a/tests/config b/tests/config index 348c7192..70af014d 100755 --- a/tests/config +++ b/tests/config @@ -32,7 +32,7 @@ setup_GetCreateInstanceDir() { assert [ ! -d "$SERVALINSTANCE_PATH" ] } test_GetCreateInstanceDir() { - executeOk $servald config get + executeOk_servald config get assert [ -d "$SERVALINSTANCE_PATH" ] } @@ -42,29 +42,29 @@ setup_SetCreateInstanceDir() { assert [ ! -d "$SERVALINSTANCE_PATH" ] } test_SetCreateInstanceDir() { - executeOk $servald config set foo bar + executeOk_servald config set foo bar assert [ -d "$SERVALINSTANCE_PATH" ] } doc_GetNull="Get an unset config item" test_GetNull() { - executeOk $servald config get foo + executeOk_servald config get foo assertStdoutLineCount '==' 0 } doc_SetGet="Set and get a single config item" test_SetGet() { - executeOk $servald config set foo bar - executeOk $servald config get foo + executeOk_servald config set foo bar + executeOk_servald config get foo assertStdoutLineCount '==' 1 assertStdoutGrep --stdout --stderr --matches=1 '^foo=bar$' } doc_GetAll="Get all config items" test_GetAll() { - executeOk $servald config set foo bar - executeOk $servald config set hello world - executeOk $servald config get + executeOk_servald config set foo bar + executeOk_servald config set hello world + executeOk_servald config get assertStdoutLineCount '==' 2 assertStdoutGrep --stdout --matches=1 '^foo=bar$' assertStdoutGrep --stdout --matches=1 '^hello=world$' @@ -72,54 +72,54 @@ test_GetAll() { doc_SetTwice="Set a single config item twice" test_SetTwice() { - executeOk $servald config set foo bar - executeOk $servald config get foo + executeOk_servald config set foo bar + executeOk_servald config get foo assertStdoutLineCount '==' 1 assertStdoutGrep --stdout --stderr --matches=1 '^foo=bar$' - executeOk $servald config set foo wah - executeOk $servald config get foo + executeOk_servald config set foo wah + executeOk_servald config get foo assertStdoutLineCount '==' 1 assertStdoutGrep --stdout --stderr --matches=1 '^foo=wah$' } doc_DelNull="Delete an unset config item" test_DelNull() { - executeOk $servald config del foo + executeOk_servald config del foo assertStdoutLineCount '==' 0 } doc_Del="Delete single config item" test_Del() { - executeOk $servald config set foo bar - executeOk $servald config set hello world - executeOk $servald config get + executeOk_servald config set foo bar + executeOk_servald config set hello world + executeOk_servald config get assertStdoutLineCount '==' 2 - executeOk $servald config del foo - executeOk $servald config get + executeOk_servald config del foo + executeOk_servald config get assertStdoutLineCount '==' 1 - executeOk $servald config get foo + executeOk_servald config get foo assertStdoutLineCount '==' 0 } doc_CaseInsensitive="Config item names are case insensitive" test_CaseInsensitive() { - executeOk $servald config set foo bar - executeOk $servald config get foo + executeOk_servald config set foo bar + executeOk_servald config get foo assertStdoutLineCount '==' 1 assertStdoutGrep --stdout --stderr --matches=1 '^foo=bar$' - executeOk $servald config get Foo + executeOk_servald config get Foo assertStdoutLineCount '==' 1 assertStdoutGrep --stdout --stderr --matches=1 '^foo=bar$' - executeOk $servald config set FOO wah - executeOk $servald config get foo + executeOk_servald config set FOO wah + executeOk_servald config get foo assertStdoutLineCount '==' 1 assertStdoutGrep --stdout --stderr --matches=1 '^FOO=wah$' } doc_DotsInNames="Config item names can have internal dots" test_DotsInNames() { - executeOk $servald config set foo.bar yes - executeOk $servald config get foo.bar + executeOk_servald config set foo.bar yes + executeOk_servald config get foo.bar assertStdoutLineCount '==' 1 assertStdoutGrep --stdout --stderr --matches=1 '^foo\.bar=yes$' execute $servald config set foo. yes @@ -128,37 +128,37 @@ test_DotsInNames() { assertExitStatus '!=' 0 execute $servald config set foo..bar yes assertExitStatus '!=' 0 - executeOk $servald config set foo.x.bar yes - executeOk $servald config get foo.x.bar + executeOk_servald config set foo.x.bar yes + executeOk_servald config get foo.x.bar assertStdoutLineCount '==' 1 assertStdoutGrep --stdout --stderr --matches=1 '^foo\.x\.bar=yes$' } doc_DebugFlags="Debug config options affect verbosity" test_DebugFlags() { - executeOk $servald echo one two three + executeOk_servald echo one two three assertStderrGrep --matches=0 '\file1 echo "Another test file" >file2 } test_AddNoAuthorNoManifest() { - executeOk $servald rhizome add file '' '' file1 + executeOk_servald rhizome add file '' '' file1 assert_stdout_add_file file1 } doc_AddNoManifest="Add with no manifest file" setup_AddNoManifest() { setup_servald_rhizome - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list echo "A test file" >file1 echo "Another test file" >file2 } test_AddNoManifest() { - executeOk $servald rhizome add file $sid '' file1 + executeOk_servald rhizome add file $sid '' file1 assert_stdout_add_file file1 } @@ -232,7 +232,7 @@ setup_AddNoAuthor() { echo "A test file" >file1 } test_AddNoAuthor() { - executeOk $servald rhizome add file '' '' file1 file1.manifest + executeOk_servald rhizome add file '' '' file1 file1.manifest assert_stdout_add_file file1 assertGrep --matches=0 file1.manifest '^BK=' } @@ -240,14 +240,14 @@ test_AddNoAuthor() { doc_AddNonExistManifest="Add with non-existent manifest file" setup_AddNonExistManifest() { setup_servald_rhizome - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list echo "A test file" >file1 echo "Another test file" >file2 } test_AddNonExistManifest() { assert --error-on-fail [ ! -e file1.manifest ] - executeOk $servald rhizome add file $sid '' file1 file1.manifest + executeOk_servald rhizome add file $sid '' file1 file1.manifest assert_stdout_add_file file1 assert [ -r file1.manifest ] tfw_cat -v file1.manifest @@ -264,14 +264,14 @@ test_AddNonExistManifest() { doc_AddManifest="Add with minimal manifest file" setup_AddManifest() { setup_servald_rhizome - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list echo "A test file" >file1 echo -e 'name=wah\ndate=12345' >file1.manifest echo "Another test file" >file2 } test_AddManifest() { - executeOk $servald rhizome add file $sid '' file1 file1.manifest + executeOk_servald rhizome add file $sid '' file1 file1.manifest tfw_cat --stdout --stderr -v file1.manifest assert_stdout_add_file file1 wah assertGrep file1.manifest '^service=file$' @@ -287,11 +287,11 @@ test_AddManifest() { doc_AddEmpty="Add with empty payload" setup_AddEmpty() { setup_servald_rhizome - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list } test_AddEmpty() { - executeOk $servald rhizome add file $sid '' '' .manifest + executeOk_servald rhizome add file $sid '' '' .manifest tfw_cat --stdout --stderr -v .manifest assert_stdout_add_file '' assertGrep .manifest '^service=file$' @@ -307,19 +307,19 @@ test_AddEmpty() { doc_AddThenList="List contains one file after one add" setup_AddThenList() { setup_servald_rhizome - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list echo "A test file" >file1 echo "Another test file" >file2 } test_AddThenList() { # Add first file - executeOk $servald rhizome add file $sid '' file1 file1.manifest - executeOk $servald rhizome list + executeOk_servald rhizome add file $sid '' file1 file1.manifest + executeOk_servald rhizome list assert_rhizome_list file1 # Add second file - executeOk $servald rhizome add file $sid '' file2 file2.manifest - executeOk $servald rhizome list + executeOk_servald rhizome add file $sid '' file2 file2.manifest + executeOk_servald rhizome list assert_rhizome_list file1 file2 } @@ -327,15 +327,15 @@ doc_AddThenExtractManifest="Extract manifest after one add" setup_AddThenExtractManifest() { setup_servald_rhizome echo "A test file" >file1 - executeOk $servald rhizome add file $sid '' file1 file1.manifest - executeOk $servald rhizome list + executeOk_servald rhizome add file $sid '' file1 file1.manifest + executeOk_servald rhizome list assert_rhizome_list file1 extract_manifest_id manifestid file1.manifest extract_manifest_version version file1.manifest extract_manifest_filehash filehash file1.manifest } test_AddThenExtractManifest() { - executeOk $servald rhizome extract manifest $manifestid file1x.manifest + executeOk_servald rhizome extract manifest $manifestid file1x.manifest assert cmp file1.manifest file1x.manifest assertStdoutLineCount '==' 6 local size=$(( $(cat file1 | wc -c) + 0 )) @@ -378,14 +378,14 @@ doc_AddThenExtractFile="Extract file after one add" setup_AddThenExtractFile() { setup_servald_rhizome echo "A test file" >file1 - executeOk $servald rhizome add file $sid '' file1 file1.manifest + executeOk_servald rhizome add file $sid '' file1 file1.manifest tfw_cat --stderr - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list file1 extract_manifest_filehash filehash file1.manifest } test_AddThenExtractFile() { - executeOk $servald rhizome extract file $filehash file1x + executeOk_servald rhizome extract file $filehash file1x assert cmp file1 file1x local size=$(( $(cat file1 | wc -c) + 0 )) assertStdoutLineCount '==' 2 @@ -423,19 +423,19 @@ test_ExtractFileInvalidID() { doc_AddDuplicate="Add same manifest detects duplicate" setup_AddDuplicate() { setup_servald_rhizome - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list echo "A test file" >file1 echo "Another test file" >file2 echo "A test file, second version" >file1_2 # Add first file - executeOk $servald rhizome add file $sid '' file1 file1.manifest + executeOk_servald rhizome add file $sid '' file1 file1.manifest extract_stdout_secret file1_secret # Add second file - executeOk $servald rhizome add file $sid '' file2 file2.manifest + executeOk_servald rhizome add file $sid '' file2 file2.manifest extract_stdout_secret file2_secret # Make sure they are both in the list. - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list file1 file2 } test_AddDuplicate() { @@ -445,7 +445,7 @@ test_AddDuplicate() { execute --exit-status=2 $servald rhizome add file $sid '' file1 file1.manifestA assert [ -s file1.manifestA ] assert_stdout_add_file file1 - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list file1 file2 strip_signatures file1.manifest file1.manifestA assert diff file1.manifest file1.manifestA @@ -453,7 +453,7 @@ test_AddDuplicate() { execute --exit-status=2 $servald rhizome add file $sid '' file2 file2.manifestA assert [ -s file2.manifestA ] assert_stdout_add_file file2 - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list file1 file2 strip_signatures file2.manifest file2.manifestA assert diff file2.manifest file2.manifestA @@ -471,7 +471,7 @@ test_AddMismatched() { assertExitStatus '!=' 0 assert cmp file1.manifest file1_2.manifest # And rhizome store should be unchanged. - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list file1 file2 } @@ -494,7 +494,7 @@ test_AddUpdateSameVersion() { tfw_cat -v file1_2.manifest assert cmp file1_2.manifest file1_2.manifest.orig # And rhizome store should be unchanged. - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list file1 file2 } @@ -508,11 +508,11 @@ setup_AddUpdateNewVersion() { } test_AddUpdateNewVersion() { tfw_cat -v file1_2.manifest - executeOk $servald rhizome add file $sid '' file1_2 file1_2.manifest + executeOk_servald rhizome add file $sid '' file1_2 file1_2.manifest assert_stdout_add_file file1_2 file1 assert_manifest_newer file1.manifest file1_2.manifest # Rhizome store contents reflect new payload. - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list file1_2 file2 } @@ -527,7 +527,7 @@ test_AddUpdateNoAuthor() { tfw_cat --stderr assertExitStatus '!=' 0 # Rhizome store contents have old payload. - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list file1 file2 } @@ -537,10 +537,10 @@ setup_AddUpdateNoAuthorWithSecret() { } test_AddUpdateNoAuthorWithSecret() { tfw_cat -v file1_2.manifest - executeOk $servald rhizome add file $sid '' file1_2 file1_2.manifest "$file1_secret" + executeOk_servald rhizome add file $sid '' file1_2 file1_2.manifest "$file1_secret" tfw_cat --stderr # Rhizome store contents have new payload. - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list file1_2 file2 } @@ -553,10 +553,10 @@ setup_AddUpdateAutoVersion() { test_AddUpdateAutoVersion() { tfw_cat -v file1_2.manifest sleep 0.001 # Ensure that at least one millisecond has elapsed - executeOk $servald rhizome add file $sid '' file1_2 file1_2.manifest + executeOk_servald rhizome add file $sid '' file1_2 file1_2.manifest assert_manifest_newer file1.manifest file1_2.manifest # Rhizome store contents reflect new payload. - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list file1_2 file2 } @@ -578,11 +578,11 @@ setup_AddMeshMSCreate() { echo -e "service=MeshMS1\nsender=$sid\nrecipient=$sid1" >file1.manifest } test_AddMeshMSCreate() { - executeOk $servald rhizome add file $sid '' file1 file1.manifest - executeOk $servald rhizome list + executeOk_servald rhizome add file $sid '' file1 file1.manifest + executeOk_servald rhizome list assert_rhizome_list file1 extract_manifest_filehash filehash file1.manifest - executeOk $servald rhizome extract file $filehash file1x + executeOk_servald rhizome extract file $filehash file1x assert diff file1 file1x } @@ -593,8 +593,8 @@ setup_AddMeshMSGrow() { echo -e "service=MeshMS1\nsender=$sid\nrecipient=$sid1" >file1.manifest } test_AddMeshMSGrow() { - executeOk $servald rhizome add file $sid '' file1 file1.manifest - executeOk $servald rhizome list + executeOk_servald rhizome add file $sid '' file1 file1.manifest + executeOk_servald rhizome list assert_rhizome_list file1 extract_manifest_id id file1.manifest extract_manifest_filehash filehash file1.manifest @@ -604,8 +604,8 @@ test_AddMeshMSGrow() { ofilehashes+=("$filehash") echo -e "id=$id\nBK=$bk\nservice=MeshMS1\nsender=$sid\nrecipient=$sid1" >file1.manifest echo "Message$m" >>file1 - executeOk $servald rhizome add file $sid '' file1 file1.manifest - executeOk $servald rhizome list + executeOk_servald rhizome add file $sid '' file1 file1.manifest + executeOk_servald rhizome list assert_rhizome_list file1 extract_manifest_id idx file1.manifest extract_manifest_filehash filehashx file1.manifest @@ -614,7 +614,7 @@ test_AddMeshMSGrow() { assert --message="manifest ID remains the same" [ "$idx" = "$id" ] assert --message="manifest BK remains the same" [ "$bkx" = "$bk" ] assert --message="filehash is for new file" [ "$filehash" = "$filehashx" ] - executeOk $servald rhizome extract file "$filehash" file1x + executeOk_servald rhizome extract file "$filehash" file1x assert --message="extracted payload is correct" diff file1 file1x for ofilehash in "${ofilehashes[@]}"; do execute --exit-status=1 --stderr $servald rhizome extract file "$ofilehash" @@ -636,7 +636,7 @@ test_AddMeshMSMissingSender() { doc_AddMeshMSMissingRecipient="Add MeshMS without recipient fails" setup_AddMeshMSMissingRecipient() { setup_servald_rhizome - executeOk $servald rhizome list + executeOk_servald rhizome list assert_rhizome_list echo "Message1" >file1 echo -e "service=MeshMS1\nsender=$sid" >file1.manifest @@ -653,8 +653,8 @@ setup_AddMeshMSMissingSender() { echo -e "service=MeshMS1\nsender=$sid\nrecipient=$sid1" >file1.manifest } test_AddMeshMSMissingSender() { - executeOk $servald rhizome add file '' '' file1 file1.manifest - executeOk $servald rhizome list + executeOk_servald rhizome add file '' '' file1 file1.manifest + executeOk_servald rhizome list assert_rhizome_list file1 } @@ -669,41 +669,41 @@ setup_ListMeshMSFilter() { echo -e "service=MeshMS1\nsender=$sid\nrecipient=$sid3" >file3.manifest echo "Message3" >file4 echo -e "service=MeshMS1\nsender=$sid1\nrecipient=$sid2" >file4.manifest - executeOk $servald rhizome add file '' '' file1 file1.manifest - executeOk $servald rhizome add file '' '' file2 file2.manifest - executeOk $servald rhizome add file '' '' file3 file3.manifest - executeOk $servald rhizome add file '' '' file4 file4.manifest - executeOk $servald rhizome list + executeOk_servald rhizome add file '' '' file1 file1.manifest + executeOk_servald rhizome add file '' '' file2 file2.manifest + executeOk_servald rhizome add file '' '' file3 file3.manifest + executeOk_servald rhizome add file '' '' file4 file4.manifest + executeOk_servald rhizome list assert_rhizome_list file1 file2 file3 file4 } test_ListMeshMSFilter() { - executeOk $servald rhizome list file + executeOk_servald rhizome list file assert_rhizome_list - executeOk $servald rhizome list MeshMS1 + executeOk_servald rhizome list MeshMS1 assert_rhizome_list file1 file2 file3 file4 - executeOk $servald rhizome list '' $sid + executeOk_servald rhizome list '' $sid assert_rhizome_list file1 file2 file3 - executeOk $servald rhizome list '' $sid1 + executeOk_servald rhizome list '' $sid1 assert_rhizome_list file4 - executeOk $servald rhizome list '' $sid2 + executeOk_servald rhizome list '' $sid2 assert_rhizome_list - executeOk $servald rhizome list '' $sid3 + executeOk_servald rhizome list '' $sid3 assert_rhizome_list - executeOk $servald rhizome list '' '' $sid + executeOk_servald rhizome list '' '' $sid assert_rhizome_list - executeOk $servald rhizome list '' '' $sid1 + executeOk_servald rhizome list '' '' $sid1 assert_rhizome_list file1 - executeOk $servald rhizome list '' '' $sid2 + executeOk_servald rhizome list '' '' $sid2 assert_rhizome_list file2 file4 - executeOk $servald rhizome list file '' $sid2 + executeOk_servald rhizome list file '' $sid2 assert_rhizome_list - executeOk $servald rhizome list '' '' $sid3 + executeOk_servald rhizome list '' '' $sid3 assert_rhizome_list file3 - executeOk $servald rhizome list '' $sid $sid3 + executeOk_servald rhizome list '' $sid $sid3 assert_rhizome_list file3 - executeOk $servald rhizome list '' $sid1 $sid3 + executeOk_servald rhizome list '' $sid1 $sid3 assert_rhizome_list - executeOk $servald rhizome list '' $sid1 $sid2 + executeOk_servald rhizome list '' $sid1 $sid2 assert_rhizome_list file4 }