Fossil SCM
Experimental changes to get JSON tests passing.
Commit
2e4238368ea5093773a0849946d6ce541a16c2d2d0801661026f9b5f7f586a5d
Parent
37806e85d2601bf…
6 files changed
+1
+12
+6
+8
-1
+19
-10
+38
-20
M
src/db.c
+1
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -78,10 +78,11 @@ | ||
| 78 | 78 | va_start(ap, zFormat); |
| 79 | 79 | z = vmprintf(zFormat, ap); |
| 80 | 80 | va_end(ap); |
| 81 | 81 | #ifdef FOSSIL_ENABLE_JSON |
| 82 | 82 | if( g.json.isJsonMode ){ |
| 83 | + if( !json_is_main_boostrapped() ) json_main_bootstrap(); | |
| 83 | 84 | json_err( 0, z, 1 ); |
| 84 | 85 | } |
| 85 | 86 | else |
| 86 | 87 | #endif /* FOSSIL_ENABLE_JSON */ |
| 87 | 88 | if( g.xferPanic && g.cgiOutput==1 ){ |
| 88 | 89 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -78,10 +78,11 @@ | |
| 78 | va_start(ap, zFormat); |
| 79 | z = vmprintf(zFormat, ap); |
| 80 | va_end(ap); |
| 81 | #ifdef FOSSIL_ENABLE_JSON |
| 82 | if( g.json.isJsonMode ){ |
| 83 | json_err( 0, z, 1 ); |
| 84 | } |
| 85 | else |
| 86 | #endif /* FOSSIL_ENABLE_JSON */ |
| 87 | if( g.xferPanic && g.cgiOutput==1 ){ |
| 88 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -78,10 +78,11 @@ | |
| 78 | va_start(ap, zFormat); |
| 79 | z = vmprintf(zFormat, ap); |
| 80 | va_end(ap); |
| 81 | #ifdef FOSSIL_ENABLE_JSON |
| 82 | if( g.json.isJsonMode ){ |
| 83 | if( !json_is_main_boostrapped() ) json_main_bootstrap(); |
| 84 | json_err( 0, z, 1 ); |
| 85 | } |
| 86 | else |
| 87 | #endif /* FOSSIL_ENABLE_JSON */ |
| 88 | if( g.xferPanic && g.cgiOutput==1 ){ |
| 89 |
+12
| --- src/json.c | ||
| +++ src/json.c | ||
| @@ -707,10 +707,21 @@ | ||
| 707 | 707 | cson_value * json_req_payload_get(char const *pKey){ |
| 708 | 708 | return g.json.reqPayload.o |
| 709 | 709 | ? cson_object_get(g.json.reqPayload.o,pKey) |
| 710 | 710 | : NULL; |
| 711 | 711 | } |
| 712 | + | |
| 713 | +/* | |
| 714 | +** Returns non-zero if the json_main_bootstrap() function has already | |
| 715 | +** been called. In general, this function should be used sparingly, | |
| 716 | +** e.g. from low-level support functions like fossil_warning() where | |
| 717 | +** there is genuine uncertainty about whether (or not) the JSON setup | |
| 718 | +** has already been called. | |
| 719 | +*/ | |
| 720 | +int json_is_main_boostrapped(){ | |
| 721 | + return ((g.json.gc.v != NULL) && (g.json.gc.a != NULL)); | |
| 722 | +} | |
| 712 | 723 | |
| 713 | 724 | /* |
| 714 | 725 | ** Initializes some JSON bits which need to be initialized relatively |
| 715 | 726 | ** early on. It should only be called from cgi_init() or |
| 716 | 727 | ** json_cmd_top() (early on in those functions). |
| @@ -1565,10 +1576,11 @@ | ||
| 1565 | 1576 | cson_output( resp, cson_data_dest_cgi, NULL, &g.json.outOpt ); |
| 1566 | 1577 | if( g.json.jsonp ){ |
| 1567 | 1578 | cgi_append_content(")",1); |
| 1568 | 1579 | } |
| 1569 | 1580 | } |
| 1581 | + cgi_reply(); | |
| 1570 | 1582 | }else{ |
| 1571 | 1583 | json_send_response(resp); |
| 1572 | 1584 | } |
| 1573 | 1585 | cson_value_free(resp); |
| 1574 | 1586 | } |
| 1575 | 1587 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -707,10 +707,21 @@ | |
| 707 | cson_value * json_req_payload_get(char const *pKey){ |
| 708 | return g.json.reqPayload.o |
| 709 | ? cson_object_get(g.json.reqPayload.o,pKey) |
| 710 | : NULL; |
| 711 | } |
| 712 | |
| 713 | /* |
| 714 | ** Initializes some JSON bits which need to be initialized relatively |
| 715 | ** early on. It should only be called from cgi_init() or |
| 716 | ** json_cmd_top() (early on in those functions). |
| @@ -1565,10 +1576,11 @@ | |
| 1565 | cson_output( resp, cson_data_dest_cgi, NULL, &g.json.outOpt ); |
| 1566 | if( g.json.jsonp ){ |
| 1567 | cgi_append_content(")",1); |
| 1568 | } |
| 1569 | } |
| 1570 | }else{ |
| 1571 | json_send_response(resp); |
| 1572 | } |
| 1573 | cson_value_free(resp); |
| 1574 | } |
| 1575 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -707,10 +707,21 @@ | |
| 707 | cson_value * json_req_payload_get(char const *pKey){ |
| 708 | return g.json.reqPayload.o |
| 709 | ? cson_object_get(g.json.reqPayload.o,pKey) |
| 710 | : NULL; |
| 711 | } |
| 712 | |
| 713 | /* |
| 714 | ** Returns non-zero if the json_main_bootstrap() function has already |
| 715 | ** been called. In general, this function should be used sparingly, |
| 716 | ** e.g. from low-level support functions like fossil_warning() where |
| 717 | ** there is genuine uncertainty about whether (or not) the JSON setup |
| 718 | ** has already been called. |
| 719 | */ |
| 720 | int json_is_main_boostrapped(){ |
| 721 | return ((g.json.gc.v != NULL) && (g.json.gc.a != NULL)); |
| 722 | } |
| 723 | |
| 724 | /* |
| 725 | ** Initializes some JSON bits which need to be initialized relatively |
| 726 | ** early on. It should only be called from cgi_init() or |
| 727 | ** json_cmd_top() (early on in those functions). |
| @@ -1565,10 +1576,11 @@ | |
| 1576 | cson_output( resp, cson_data_dest_cgi, NULL, &g.json.outOpt ); |
| 1577 | if( g.json.jsonp ){ |
| 1578 | cgi_append_content(")",1); |
| 1579 | } |
| 1580 | } |
| 1581 | cgi_reply(); |
| 1582 | }else{ |
| 1583 | json_send_response(resp); |
| 1584 | } |
| 1585 | cson_value_free(resp); |
| 1586 | } |
| 1587 |
+6
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -274,10 +274,13 @@ | ||
| 274 | 274 | always output JSON-form error |
| 275 | 275 | responses and always (in CGI mode) |
| 276 | 276 | exit() with code 0 to avoid an HTTP |
| 277 | 277 | 500 error. |
| 278 | 278 | */ |
| 279 | + int preserveRc; /* Do not convert error codes into 0. | |
| 280 | + * This is primarily intended for use | |
| 281 | + * by the test suite. */ | |
| 279 | 282 | int resultCode; /* used for passing back specific codes |
| 280 | 283 | ** from /json callbacks. */ |
| 281 | 284 | int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */ |
| 282 | 285 | cson_output_opt outOpt; /* formatting options for JSON mode. */ |
| 283 | 286 | cson_value *authToken; /* authentication token */ |
| @@ -746,10 +749,13 @@ | ||
| 746 | 749 | g.fSshTrace = find_option("sshtrace", 0, 0)!=0; |
| 747 | 750 | g.fCgiTrace = find_option("cgitrace", 0, 0)!=0; |
| 748 | 751 | g.fSshClient = 0; |
| 749 | 752 | g.zSshCmd = 0; |
| 750 | 753 | if( g.fSqlTrace ) g.fSqlStats = 1; |
| 754 | +#ifdef FOSSIL_ENABLE_JSON | |
| 755 | + g.json.preserveRc = find_option("json-preserve-rc", 0, 0)!=0; | |
| 756 | +#endif | |
| 751 | 757 | g.fHttpTrace = find_option("httptrace", 0, 0)!=0; |
| 752 | 758 | #ifdef FOSSIL_ENABLE_TH1_HOOKS |
| 753 | 759 | g.fNoThHook = find_option("no-th-hook", 0, 0)!=0; |
| 754 | 760 | #endif |
| 755 | 761 | g.fAnyTrace = g.fSqlTrace|g.fSystemTrace|g.fSshTrace| |
| 756 | 762 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -274,10 +274,13 @@ | |
| 274 | always output JSON-form error |
| 275 | responses and always (in CGI mode) |
| 276 | exit() with code 0 to avoid an HTTP |
| 277 | 500 error. |
| 278 | */ |
| 279 | int resultCode; /* used for passing back specific codes |
| 280 | ** from /json callbacks. */ |
| 281 | int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */ |
| 282 | cson_output_opt outOpt; /* formatting options for JSON mode. */ |
| 283 | cson_value *authToken; /* authentication token */ |
| @@ -746,10 +749,13 @@ | |
| 746 | g.fSshTrace = find_option("sshtrace", 0, 0)!=0; |
| 747 | g.fCgiTrace = find_option("cgitrace", 0, 0)!=0; |
| 748 | g.fSshClient = 0; |
| 749 | g.zSshCmd = 0; |
| 750 | if( g.fSqlTrace ) g.fSqlStats = 1; |
| 751 | g.fHttpTrace = find_option("httptrace", 0, 0)!=0; |
| 752 | #ifdef FOSSIL_ENABLE_TH1_HOOKS |
| 753 | g.fNoThHook = find_option("no-th-hook", 0, 0)!=0; |
| 754 | #endif |
| 755 | g.fAnyTrace = g.fSqlTrace|g.fSystemTrace|g.fSshTrace| |
| 756 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -274,10 +274,13 @@ | |
| 274 | always output JSON-form error |
| 275 | responses and always (in CGI mode) |
| 276 | exit() with code 0 to avoid an HTTP |
| 277 | 500 error. |
| 278 | */ |
| 279 | int preserveRc; /* Do not convert error codes into 0. |
| 280 | * This is primarily intended for use |
| 281 | * by the test suite. */ |
| 282 | int resultCode; /* used for passing back specific codes |
| 283 | ** from /json callbacks. */ |
| 284 | int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */ |
| 285 | cson_output_opt outOpt; /* formatting options for JSON mode. */ |
| 286 | cson_value *authToken; /* authentication token */ |
| @@ -746,10 +749,13 @@ | |
| 749 | g.fSshTrace = find_option("sshtrace", 0, 0)!=0; |
| 750 | g.fCgiTrace = find_option("cgitrace", 0, 0)!=0; |
| 751 | g.fSshClient = 0; |
| 752 | g.zSshCmd = 0; |
| 753 | if( g.fSqlTrace ) g.fSqlStats = 1; |
| 754 | #ifdef FOSSIL_ENABLE_JSON |
| 755 | g.json.preserveRc = find_option("json-preserve-rc", 0, 0)!=0; |
| 756 | #endif |
| 757 | g.fHttpTrace = find_option("httptrace", 0, 0)!=0; |
| 758 | #ifdef FOSSIL_ENABLE_TH1_HOOKS |
| 759 | g.fNoThHook = find_option("no-th-hook", 0, 0)!=0; |
| 760 | #endif |
| 761 | g.fAnyTrace = g.fSqlTrace|g.fSystemTrace|g.fSshTrace| |
| 762 |
+8
-1
| --- src/printf.c | ||
| +++ src/printf.c | ||
| @@ -1076,12 +1076,13 @@ | ||
| 1076 | 1076 | ** Write error message output |
| 1077 | 1077 | */ |
| 1078 | 1078 | static int fossil_print_error(int rc, const char *z){ |
| 1079 | 1079 | #ifdef FOSSIL_ENABLE_JSON |
| 1080 | 1080 | if( g.json.isJsonMode ){ |
| 1081 | + if( !json_is_main_boostrapped() ) json_main_bootstrap(); | |
| 1081 | 1082 | json_err( 0, z, 1 ); |
| 1082 | - if( g.isHTTP ){ | |
| 1083 | + if( g.isHTTP && !g.json.preserveRc ){ | |
| 1083 | 1084 | rc = 0 /* avoid HTTP 500 */; |
| 1084 | 1085 | } |
| 1085 | 1086 | } |
| 1086 | 1087 | else |
| 1087 | 1088 | #endif |
| @@ -1190,11 +1191,17 @@ | ||
| 1190 | 1191 | va_start(ap, zFormat); |
| 1191 | 1192 | z = vmprintf(zFormat, ap); |
| 1192 | 1193 | va_end(ap); |
| 1193 | 1194 | fossil_errorlog("warning: %s", z); |
| 1194 | 1195 | #ifdef FOSSIL_ENABLE_JSON |
| 1196 | + /* | |
| 1197 | + ** Avoid calling into the JSON support subsystem if it | |
| 1198 | + ** has not yet been initialized, e.g. early SQLite log | |
| 1199 | + ** messages, etc. | |
| 1200 | + */ | |
| 1195 | 1201 | if(g.json.isJsonMode){ |
| 1202 | + if( !json_is_main_boostrapped() ) json_main_bootstrap(); | |
| 1196 | 1203 | json_warn( FSL_JSON_W_UNKNOWN, "%s", z ); |
| 1197 | 1204 | }else |
| 1198 | 1205 | #endif |
| 1199 | 1206 | { |
| 1200 | 1207 | if( g.cgiOutput==1 ){ |
| 1201 | 1208 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -1076,12 +1076,13 @@ | |
| 1076 | ** Write error message output |
| 1077 | */ |
| 1078 | static int fossil_print_error(int rc, const char *z){ |
| 1079 | #ifdef FOSSIL_ENABLE_JSON |
| 1080 | if( g.json.isJsonMode ){ |
| 1081 | json_err( 0, z, 1 ); |
| 1082 | if( g.isHTTP ){ |
| 1083 | rc = 0 /* avoid HTTP 500 */; |
| 1084 | } |
| 1085 | } |
| 1086 | else |
| 1087 | #endif |
| @@ -1190,11 +1191,17 @@ | |
| 1190 | va_start(ap, zFormat); |
| 1191 | z = vmprintf(zFormat, ap); |
| 1192 | va_end(ap); |
| 1193 | fossil_errorlog("warning: %s", z); |
| 1194 | #ifdef FOSSIL_ENABLE_JSON |
| 1195 | if(g.json.isJsonMode){ |
| 1196 | json_warn( FSL_JSON_W_UNKNOWN, "%s", z ); |
| 1197 | }else |
| 1198 | #endif |
| 1199 | { |
| 1200 | if( g.cgiOutput==1 ){ |
| 1201 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -1076,12 +1076,13 @@ | |
| 1076 | ** Write error message output |
| 1077 | */ |
| 1078 | static int fossil_print_error(int rc, const char *z){ |
| 1079 | #ifdef FOSSIL_ENABLE_JSON |
| 1080 | if( g.json.isJsonMode ){ |
| 1081 | if( !json_is_main_boostrapped() ) json_main_bootstrap(); |
| 1082 | json_err( 0, z, 1 ); |
| 1083 | if( g.isHTTP && !g.json.preserveRc ){ |
| 1084 | rc = 0 /* avoid HTTP 500 */; |
| 1085 | } |
| 1086 | } |
| 1087 | else |
| 1088 | #endif |
| @@ -1190,11 +1191,17 @@ | |
| 1191 | va_start(ap, zFormat); |
| 1192 | z = vmprintf(zFormat, ap); |
| 1193 | va_end(ap); |
| 1194 | fossil_errorlog("warning: %s", z); |
| 1195 | #ifdef FOSSIL_ENABLE_JSON |
| 1196 | /* |
| 1197 | ** Avoid calling into the JSON support subsystem if it |
| 1198 | ** has not yet been initialized, e.g. early SQLite log |
| 1199 | ** messages, etc. |
| 1200 | */ |
| 1201 | if(g.json.isJsonMode){ |
| 1202 | if( !json_is_main_boostrapped() ) json_main_bootstrap(); |
| 1203 | json_warn( FSL_JSON_W_UNKNOWN, "%s", z ); |
| 1204 | }else |
| 1205 | #endif |
| 1206 | { |
| 1207 | if( g.cgiOutput==1 ){ |
| 1208 |
+19
-10
| --- test/json.test | ||
| +++ test/json.test | ||
| @@ -75,10 +75,11 @@ | ||
| 75 | 75 | # Returns the status code from the HTTP header. |
| 76 | 76 | proc fossil_http_json {url {cookie "Muppet=Monster"} args} { |
| 77 | 77 | global RESULT JR |
| 78 | 78 | set request "GET $url HTTP/1.1\r\nHost: localhost\r\nUser-Agent: Fossil-http-json\r\nCookie: $cookie" |
| 79 | 79 | set RESULT [fossil_maybe_answer $request http {*}$args] |
| 80 | + set head ""; set status "--NO_MATCH--" | |
| 80 | 81 | regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body |
| 81 | 82 | regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg |
| 82 | 83 | if {$status eq "200"} { |
| 83 | 84 | set JR [json2dict $body] |
| 84 | 85 | } |
| @@ -170,10 +171,13 @@ | ||
| 170 | 171 | |
| 171 | 172 | #### VERSION AKA HAI |
| 172 | 173 | |
| 173 | 174 | # The JSON API generally assumes we have a respository, so let it have one. |
| 174 | 175 | test_setup |
| 176 | + | |
| 177 | +# Stop backoffice from running during this test as it can cause hangs. | |
| 178 | +fossil settings backoffice-disable 1 | |
| 175 | 179 | |
| 176 | 180 | # Check for basic envelope fields in the result with an error |
| 177 | 181 | fossil_json -expectError |
| 178 | 182 | test_json_envelope json-enverr [concat resultCode fossil timestamp \ |
| 179 | 183 | resultText command procTimeUs procTimeMs] {} |
| @@ -675,27 +679,32 @@ | ||
| 675 | 679 | # error happens before we have made the determination that the app is |
| 676 | 680 | # in JSON mode or if the error handling is incorrectly not |
| 677 | 681 | # recognizing JSON mode. |
| 678 | 682 | # |
| 679 | 683 | #test_setup x.fossil |
| 680 | -#catch {exec chmod 444 .rep.fossil}; # Unix. What about Win? | |
| 681 | -fossil_http_json /json/timeline/checkin $U1Cookie | |
| 684 | +fossil_http_json /json/query?sql=PRAGMA%20repository.journal_mode%3Dwal $U1Cookie | |
| 682 | 685 | test json-ROrepo-1-1 {$CODE == 0} |
| 683 | 686 | test json-ROrepo-1-2 {[regexp {\}\s*$} $RESULT]} |
| 684 | 687 | test json-ROrepo-1-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} |
| 685 | 688 | test_json_envelope_ok json-http-timeline1 |
| 689 | +if {$is_windows} then { | |
| 690 | + catch {exec attrib +r .rep.fossil}; # Windows | |
| 691 | +} else { | |
| 692 | + catch {exec chmod 444 .rep.fossil}; # Unix | |
| 693 | +} | |
| 686 | 694 | protOut "chmod 444 repo" |
| 687 | -catch {exec chmod 444 .rep.fossil}; # Unix | |
| 688 | -catch {exec attrib +r .rep.fossil}; # Windows | |
| 689 | -fossil_http_json /json/timeline/checkin $U1Cookie -expectError | |
| 695 | +fossil_http_json /json/query?sql=PRAGMA%20repository.journal_mode%3Ddelete $U1Cookie -expectError --json-preserve-rc | |
| 690 | 696 | test json-ROrepo-2-1 {$CODE != 0} |
| 691 | -test json-ROrepo-2-2 {[regexp {\}\s*$} $RESULT]} knownBug | |
| 692 | -test json-ROrepo-2-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} knownBug | |
| 697 | +test json-ROrepo-2-2 {[regexp {\}\s*$} $RESULT]} | |
| 698 | +test json-ROrepo-2-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} | |
| 693 | 699 | #test_json_envelope_ok json-http-timeline2 |
| 694 | -catch {exec attrib -r .rep.fossil}; # Windows | |
| 695 | -catch {exec chmod 666 .rep.fossil}; # Unix | |
| 696 | - | |
| 700 | +if {$is_windows} then { | |
| 701 | + catch {exec attrib -r .rep.fossil}; # Windows | |
| 702 | +} else { | |
| 703 | + catch {exec chmod 666 .rep.fossil}; # Unix | |
| 704 | +} | |
| 705 | +protOut "chmod 666 repo" | |
| 697 | 706 | |
| 698 | 707 | #### Result Codes |
| 699 | 708 | # Test cases designed to stimulate each (documented) error code. |
| 700 | 709 | |
| 701 | 710 | # FOSSIL-0000 |
| 702 | 711 |
| --- test/json.test | |
| +++ test/json.test | |
| @@ -75,10 +75,11 @@ | |
| 75 | # Returns the status code from the HTTP header. |
| 76 | proc fossil_http_json {url {cookie "Muppet=Monster"} args} { |
| 77 | global RESULT JR |
| 78 | set request "GET $url HTTP/1.1\r\nHost: localhost\r\nUser-Agent: Fossil-http-json\r\nCookie: $cookie" |
| 79 | set RESULT [fossil_maybe_answer $request http {*}$args] |
| 80 | regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body |
| 81 | regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg |
| 82 | if {$status eq "200"} { |
| 83 | set JR [json2dict $body] |
| 84 | } |
| @@ -170,10 +171,13 @@ | |
| 170 | |
| 171 | #### VERSION AKA HAI |
| 172 | |
| 173 | # The JSON API generally assumes we have a respository, so let it have one. |
| 174 | test_setup |
| 175 | |
| 176 | # Check for basic envelope fields in the result with an error |
| 177 | fossil_json -expectError |
| 178 | test_json_envelope json-enverr [concat resultCode fossil timestamp \ |
| 179 | resultText command procTimeUs procTimeMs] {} |
| @@ -675,27 +679,32 @@ | |
| 675 | # error happens before we have made the determination that the app is |
| 676 | # in JSON mode or if the error handling is incorrectly not |
| 677 | # recognizing JSON mode. |
| 678 | # |
| 679 | #test_setup x.fossil |
| 680 | #catch {exec chmod 444 .rep.fossil}; # Unix. What about Win? |
| 681 | fossil_http_json /json/timeline/checkin $U1Cookie |
| 682 | test json-ROrepo-1-1 {$CODE == 0} |
| 683 | test json-ROrepo-1-2 {[regexp {\}\s*$} $RESULT]} |
| 684 | test json-ROrepo-1-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} |
| 685 | test_json_envelope_ok json-http-timeline1 |
| 686 | protOut "chmod 444 repo" |
| 687 | catch {exec chmod 444 .rep.fossil}; # Unix |
| 688 | catch {exec attrib +r .rep.fossil}; # Windows |
| 689 | fossil_http_json /json/timeline/checkin $U1Cookie -expectError |
| 690 | test json-ROrepo-2-1 {$CODE != 0} |
| 691 | test json-ROrepo-2-2 {[regexp {\}\s*$} $RESULT]} knownBug |
| 692 | test json-ROrepo-2-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} knownBug |
| 693 | #test_json_envelope_ok json-http-timeline2 |
| 694 | catch {exec attrib -r .rep.fossil}; # Windows |
| 695 | catch {exec chmod 666 .rep.fossil}; # Unix |
| 696 | |
| 697 | |
| 698 | #### Result Codes |
| 699 | # Test cases designed to stimulate each (documented) error code. |
| 700 | |
| 701 | # FOSSIL-0000 |
| 702 |
| --- test/json.test | |
| +++ test/json.test | |
| @@ -75,10 +75,11 @@ | |
| 75 | # Returns the status code from the HTTP header. |
| 76 | proc fossil_http_json {url {cookie "Muppet=Monster"} args} { |
| 77 | global RESULT JR |
| 78 | set request "GET $url HTTP/1.1\r\nHost: localhost\r\nUser-Agent: Fossil-http-json\r\nCookie: $cookie" |
| 79 | set RESULT [fossil_maybe_answer $request http {*}$args] |
| 80 | set head ""; set status "--NO_MATCH--" |
| 81 | regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body |
| 82 | regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg |
| 83 | if {$status eq "200"} { |
| 84 | set JR [json2dict $body] |
| 85 | } |
| @@ -170,10 +171,13 @@ | |
| 171 | |
| 172 | #### VERSION AKA HAI |
| 173 | |
| 174 | # The JSON API generally assumes we have a respository, so let it have one. |
| 175 | test_setup |
| 176 | |
| 177 | # Stop backoffice from running during this test as it can cause hangs. |
| 178 | fossil settings backoffice-disable 1 |
| 179 | |
| 180 | # Check for basic envelope fields in the result with an error |
| 181 | fossil_json -expectError |
| 182 | test_json_envelope json-enverr [concat resultCode fossil timestamp \ |
| 183 | resultText command procTimeUs procTimeMs] {} |
| @@ -675,27 +679,32 @@ | |
| 679 | # error happens before we have made the determination that the app is |
| 680 | # in JSON mode or if the error handling is incorrectly not |
| 681 | # recognizing JSON mode. |
| 682 | # |
| 683 | #test_setup x.fossil |
| 684 | fossil_http_json /json/query?sql=PRAGMA%20repository.journal_mode%3Dwal $U1Cookie |
| 685 | test json-ROrepo-1-1 {$CODE == 0} |
| 686 | test json-ROrepo-1-2 {[regexp {\}\s*$} $RESULT]} |
| 687 | test json-ROrepo-1-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} |
| 688 | test_json_envelope_ok json-http-timeline1 |
| 689 | if {$is_windows} then { |
| 690 | catch {exec attrib +r .rep.fossil}; # Windows |
| 691 | } else { |
| 692 | catch {exec chmod 444 .rep.fossil}; # Unix |
| 693 | } |
| 694 | protOut "chmod 444 repo" |
| 695 | fossil_http_json /json/query?sql=PRAGMA%20repository.journal_mode%3Ddelete $U1Cookie -expectError --json-preserve-rc |
| 696 | test json-ROrepo-2-1 {$CODE != 0} |
| 697 | test json-ROrepo-2-2 {[regexp {\}\s*$} $RESULT]} |
| 698 | test json-ROrepo-2-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} |
| 699 | #test_json_envelope_ok json-http-timeline2 |
| 700 | if {$is_windows} then { |
| 701 | catch {exec attrib -r .rep.fossil}; # Windows |
| 702 | } else { |
| 703 | catch {exec chmod 666 .rep.fossil}; # Unix |
| 704 | } |
| 705 | protOut "chmod 666 repo" |
| 706 | |
| 707 | #### Result Codes |
| 708 | # Test cases designed to stimulate each (documented) error code. |
| 709 | |
| 710 | # FOSSIL-0000 |
| 711 |
+38
-20
| --- test/tester.tcl | ||
| +++ test/tester.tcl | ||
| @@ -170,39 +170,57 @@ | ||
| 170 | 170 | set index [lsearch -exact $args -keepNewline] |
| 171 | 171 | if {$index != -1} { |
| 172 | 172 | set keepNewline 1 |
| 173 | 173 | set args [lreplace $args $index $index] |
| 174 | 174 | } |
| 175 | + set whatIf 0 | |
| 176 | + set index [lsearch -exact $args -whatIf] | |
| 177 | + if {$index != -1} { | |
| 178 | + set whatIf 1 | |
| 179 | + set args [lreplace $args $index $index] | |
| 180 | + } | |
| 175 | 181 | foreach a $args { |
| 176 | 182 | lappend cmd $a |
| 177 | 183 | } |
| 178 | 184 | protOut $cmd |
| 179 | 185 | |
| 180 | 186 | flush stdout |
| 181 | - if {[string length $answer] > 0} { | |
| 182 | - protOut $answer | |
| 183 | - set prompt_file [file join $::tempPath fossil_prompt_answer] | |
| 184 | - write_file $prompt_file $answer\n | |
| 185 | - if {$keepNewline} { | |
| 186 | - set rc [catch {eval exec -keepnewline $cmd <$prompt_file} result] | |
| 187 | - } else { | |
| 188 | - set rc [catch {eval exec $cmd <$prompt_file} result] | |
| 189 | - } | |
| 190 | - file delete $prompt_file | |
| 191 | - } else { | |
| 192 | - if {$keepNewline} { | |
| 193 | - set rc [catch {eval exec -keepnewline $cmd} result] | |
| 194 | - } else { | |
| 195 | - set rc [catch {eval exec $cmd} result] | |
| 196 | - } | |
| 187 | + if {$whatIf} { | |
| 188 | + protOut [pwd]; protOut $answer | |
| 189 | + set result WHAT-IF-MODE; set rc 42 | |
| 190 | + } else { | |
| 191 | + if {[string length $answer] > 0} { | |
| 192 | + protOut $answer | |
| 193 | + set prompt_file [file join $::tempPath fossil_prompt_answer] | |
| 194 | + write_file $prompt_file $answer\n | |
| 195 | + set execCmd [list eval exec] | |
| 196 | + if {$keepNewline} {lappend execCmd -keepnewline} | |
| 197 | + lappend execCmd $cmd <$prompt_file | |
| 198 | + set rc [catch $execCmd result] | |
| 199 | + file delete $prompt_file | |
| 200 | + } else { | |
| 201 | + set execCmd [list eval exec] | |
| 202 | + if {$keepNewline} {lappend execCmd -keepnewline} | |
| 203 | + lappend execCmd $cmd | |
| 204 | + set rc [catch $execCmd result] | |
| 205 | + } | |
| 206 | + } | |
| 207 | + set ab(str) {child process exited abnormally} | |
| 208 | + set ab(len) [string length $ab(str)] | |
| 209 | + set ab(off) [expr {$ab(len) - 1}] | |
| 210 | + if {$rc && $expectError && \ | |
| 211 | + [string range $result end-$ab(off) end] eq $ab(str)} { | |
| 212 | + set result [string range $result 0 end-$ab(len)] | |
| 197 | 213 | } |
| 198 | 214 | global RESULT CODE |
| 199 | 215 | set CODE $rc |
| 200 | - if {($rc && !$expectError) || (!$rc && $expectError)} { | |
| 201 | - protOut "ERROR: $result" 1 | |
| 202 | - } elseif {$::VERBOSE} { | |
| 203 | - protOut "RESULT: $result" | |
| 216 | + if {!$whatIf} { | |
| 217 | + if {($rc && !$expectError) || (!$rc && $expectError)} { | |
| 218 | + protOut "ERROR ($rc): $result" 1 | |
| 219 | + } elseif {$::VERBOSE} { | |
| 220 | + protOut "RESULT ($rc): $result" | |
| 221 | + } | |
| 204 | 222 | } |
| 205 | 223 | set RESULT $result |
| 206 | 224 | } |
| 207 | 225 | |
| 208 | 226 | # Read a file into memory. |
| 209 | 227 |
| --- test/tester.tcl | |
| +++ test/tester.tcl | |
| @@ -170,39 +170,57 @@ | |
| 170 | set index [lsearch -exact $args -keepNewline] |
| 171 | if {$index != -1} { |
| 172 | set keepNewline 1 |
| 173 | set args [lreplace $args $index $index] |
| 174 | } |
| 175 | foreach a $args { |
| 176 | lappend cmd $a |
| 177 | } |
| 178 | protOut $cmd |
| 179 | |
| 180 | flush stdout |
| 181 | if {[string length $answer] > 0} { |
| 182 | protOut $answer |
| 183 | set prompt_file [file join $::tempPath fossil_prompt_answer] |
| 184 | write_file $prompt_file $answer\n |
| 185 | if {$keepNewline} { |
| 186 | set rc [catch {eval exec -keepnewline $cmd <$prompt_file} result] |
| 187 | } else { |
| 188 | set rc [catch {eval exec $cmd <$prompt_file} result] |
| 189 | } |
| 190 | file delete $prompt_file |
| 191 | } else { |
| 192 | if {$keepNewline} { |
| 193 | set rc [catch {eval exec -keepnewline $cmd} result] |
| 194 | } else { |
| 195 | set rc [catch {eval exec $cmd} result] |
| 196 | } |
| 197 | } |
| 198 | global RESULT CODE |
| 199 | set CODE $rc |
| 200 | if {($rc && !$expectError) || (!$rc && $expectError)} { |
| 201 | protOut "ERROR: $result" 1 |
| 202 | } elseif {$::VERBOSE} { |
| 203 | protOut "RESULT: $result" |
| 204 | } |
| 205 | set RESULT $result |
| 206 | } |
| 207 | |
| 208 | # Read a file into memory. |
| 209 |
| --- test/tester.tcl | |
| +++ test/tester.tcl | |
| @@ -170,39 +170,57 @@ | |
| 170 | set index [lsearch -exact $args -keepNewline] |
| 171 | if {$index != -1} { |
| 172 | set keepNewline 1 |
| 173 | set args [lreplace $args $index $index] |
| 174 | } |
| 175 | set whatIf 0 |
| 176 | set index [lsearch -exact $args -whatIf] |
| 177 | if {$index != -1} { |
| 178 | set whatIf 1 |
| 179 | set args [lreplace $args $index $index] |
| 180 | } |
| 181 | foreach a $args { |
| 182 | lappend cmd $a |
| 183 | } |
| 184 | protOut $cmd |
| 185 | |
| 186 | flush stdout |
| 187 | if {$whatIf} { |
| 188 | protOut [pwd]; protOut $answer |
| 189 | set result WHAT-IF-MODE; set rc 42 |
| 190 | } else { |
| 191 | if {[string length $answer] > 0} { |
| 192 | protOut $answer |
| 193 | set prompt_file [file join $::tempPath fossil_prompt_answer] |
| 194 | write_file $prompt_file $answer\n |
| 195 | set execCmd [list eval exec] |
| 196 | if {$keepNewline} {lappend execCmd -keepnewline} |
| 197 | lappend execCmd $cmd <$prompt_file |
| 198 | set rc [catch $execCmd result] |
| 199 | file delete $prompt_file |
| 200 | } else { |
| 201 | set execCmd [list eval exec] |
| 202 | if {$keepNewline} {lappend execCmd -keepnewline} |
| 203 | lappend execCmd $cmd |
| 204 | set rc [catch $execCmd result] |
| 205 | } |
| 206 | } |
| 207 | set ab(str) {child process exited abnormally} |
| 208 | set ab(len) [string length $ab(str)] |
| 209 | set ab(off) [expr {$ab(len) - 1}] |
| 210 | if {$rc && $expectError && \ |
| 211 | [string range $result end-$ab(off) end] eq $ab(str)} { |
| 212 | set result [string range $result 0 end-$ab(len)] |
| 213 | } |
| 214 | global RESULT CODE |
| 215 | set CODE $rc |
| 216 | if {!$whatIf} { |
| 217 | if {($rc && !$expectError) || (!$rc && $expectError)} { |
| 218 | protOut "ERROR ($rc): $result" 1 |
| 219 | } elseif {$::VERBOSE} { |
| 220 | protOut "RESULT ($rc): $result" |
| 221 | } |
| 222 | } |
| 223 | set RESULT $result |
| 224 | } |
| 225 | |
| 226 | # Read a file into memory. |
| 227 |