Fossil SCM

fossil-scm / test / json.test
Blame History Raw 926 lines
1
#
2
# Copyright (c) 2016 D. Richard Hipp
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the Simplified BSD License (also
6
# known as the "2-Clause License" or "FreeBSD License".)
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but without any warranty; without even the implied warranty of
10
# merchantability or fitness for a particular purpose.
11
#
12
# Author contact information:
13
# [email protected]
14
# http://www.hwaci.com/drh/
15
#
16
############################################################################
17
#
18
# Test JSON Support
19
#
20
21
# Make sure we have a build with the json command at all and that it
22
# is not stubbed out. This assumes the current (as of 2016-01-27)
23
# practice of eliminating all trace of the fossil json command when
24
# not configured. If that changes, these conditions might not prevent
25
# the rest of this file from running.
26
fossil test-th-eval "hasfeature json"
27
28
if {[normalize_result] ne "1"} {
29
puts "Fossil was not compiled with JSON support."
30
test_cleanup_then_return
31
}
32
33
# We need a JSON parser to effectively test the JSON produced by
34
# fossil. It looks like the one from tcllib is exactly what we need.
35
# On ActiveTcl, add it with teacup. On other platforms, YMMV.
36
# teacup install json
37
# teacup install json::write
38
if {[catch {package require json}] != 0} then {
39
puts {
40
The "json" package for Tcl is not available.
41
Please see: https://core.tcl-lang.org/tcllib
42
}
43
test_cleanup_then_return
44
}
45
46
proc json2dict {txt} {
47
set rc [catch {::json::json2dict $txt} result options]
48
if {$rc != 0} {
49
protOut "JSON ERROR: $result"
50
return {}
51
}
52
return $result
53
}
54
55
# and that the json itself smells ok and has the expected API error code in it
56
fossil json -expectError
57
set JR [json2dict $RESULT]
58
if {$JR eq ""} {
59
puts "Fossil was not compiled with JSON support (bad JSON)."
60
test_cleanup_then_return
61
}
62
test json-1 {[dict exists $JR resultCode]
63
&& [dict get $JR resultCode] in "FOSSIL-3002 FOSSIL-4102"}
64
65
# Use the CLI interface to execute a JSON command. Sets the global
66
# RESULT to the response text, and JR to a Tcl dict conversion of the
67
# response body.
68
#
69
# Returns "200" or "500".
70
proc fossil_json {args} {
71
global RESULT JR
72
uplevel 1 fossil json {*}$args
73
set JR [json2dict $RESULT]
74
return "200"
75
}
76
77
# Use the HTTP interface to GET a JSON API URL. Sets the globals
78
# RESULT to the HTTP response body, and JR to a Tcl dict conversion of
79
# the response body.
80
#
81
# Returns the status code from the HTTP header.
82
proc fossil_http_json {url {cookie "Muppet=Monster"} args} {
83
global RESULT JR
84
set request "GET $url HTTP/1.1\r\nHost: localhost\r\nUser-Agent: Fossil-http-json\r\nCookie: $cookie"
85
set RESULT [fossil_maybe_answer $request http {*}$args --ipaddr 127.0.0.1]
86
set head ""; set body ""; set status "--NO_MATCH--"
87
regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body
88
regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg
89
if {$status eq "200"} {
90
set JR [json2dict $body]
91
}
92
return $status
93
}
94
95
96
# Use the HTTP interface to POST a JSON API URL. Sets the globals
97
# RESULT to the HTTP response body, and JR to a Tcl dict conversion of
98
# the response body.
99
#
100
# Returns the status code from the HTTP header.
101
proc fossil_post_json {url data {cookie "Muppet=Monster"} args} {
102
global RESULT JR
103
104
# set up a full GET or POST HTTP request
105
set len [string length $data]
106
if {$len > 0} {
107
set request [subst {POST $url HTTP/1.0\r
108
Host: localhost\r
109
User-Agent: Fossil-Test\r
110
Cookie: $cookie\r
111
Content-Type: application/json
112
Content-Length $len
113
\r
114
$data}]
115
} else {
116
set request [subst {GET $url HTTP/1.0\r
117
Host: localhost\r
118
User-Agent: Fossil-Test\r
119
Cookie: $cookie\r
120
\r
121
}]
122
}
123
124
# handle the actual request
125
flush stdout
126
#exec $fossilexe
127
set RESULT [fossil_maybe_answer $request http {*}$args --ipaddr 127.0.0.1]
128
129
# separate HTTP headers from body
130
set head ""; set body ""; set status "--NO_MATCH--"
131
regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body
132
regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg
133
if {$status eq "200"} {
134
if {[string length $body] > 0} {
135
set JR [json2dict $body]
136
} else {
137
set JR ""
138
}
139
}
140
return $status
141
}
142
143
144
# Inspect a dict for keys it must have and keys it must not have
145
proc test_dict_keys {testname D okfields badfields} {
146
if {$D eq ""} {
147
test $testname-validJSON 0
148
return
149
}
150
set i 1
151
foreach f $okfields {
152
test "$testname-$i" {[dict exists $D $f]}
153
incr i
154
}
155
foreach f $badfields {
156
test "$testname-$i" {![dict exists $D $f]}
157
incr i
158
}
159
}
160
161
# Inspect the envelope part of a returned JSON structure to confirm
162
# that it has specific fields and that it lacks specific fields.
163
proc test_json_envelope {testname okfields badfields} {
164
test_dict_keys $testname $::JR $okfields $badfields
165
}
166
167
# Inspect the envelope of a normal successful result
168
proc test_json_envelope_ok {testname} {
169
test_json_envelope $testname [concat fossil timestamp command procTimeUs \
170
procTimeMs payload] [concat resultCode resultText]
171
}
172
173
# Inspect the payload of a successful result to confirm that it has
174
# specific fields and that it lacks specific fields.
175
proc test_json_payload {testname okfields badfields} {
176
test_dict_keys $testname [dict get $::JR payload] $okfields $badfields
177
}
178
179
#### VERSION AKA HAI
180
181
# The JSON API generally assumes we have a repository, so let it have one.
182
183
# Set FOSSIL_USER to ensure consistent results in "json user list"
184
set _fossil_user ""
185
if [info exists env(FOSSIL_USER)] {
186
set _fossil_user $env(FOSSIL_USER)
187
}
188
set ::env(FOSSIL_USER) "JSON-TEST-USER"
189
190
test_setup
191
192
# Stop backoffice from running during this test as it can cause hangs.
193
fossil settings backoffice-disable 1
194
195
# Check for basic envelope fields in the result with an error
196
fossil_json -expectError
197
test_json_envelope json-enverr [concat resultCode fossil timestamp \
198
resultText command procTimeUs procTimeMs] {}
199
test json-enverr-rc-1 {[dict get $JR resultCode] eq "FOSSIL-3002"}
200
201
202
# Check for basic envelope fields in the result with a successful
203
# command
204
set HAIfields [concat manifestUuid manifestVersion manifestDate \
205
manifestYear releaseVersion releaseVersionNumber \
206
resultCodeParanoiaLevel jsonApiVersion]
207
208
fossil_json HAI
209
test_json_envelope_ok json-HAI
210
test_json_payload json-HAI $HAIfields {}
211
test json-HAI-api {[dict get $JR payload jsonApiVersion] >= 20120713}
212
213
# Check for basic envelope fields in a HTTP result with a successful
214
# command
215
fossil_http_json /json/HAI
216
test_json_envelope_ok json-http-HAI
217
test_json_payload json-http-HAI $HAIfields {}
218
test json-http-HAI-api {[dict get $JR payload jsonApiVersion] >= 20120713}
219
220
fossil_json version
221
test_json_envelope_ok json-version
222
test_json_payload json-version $HAIfields {}
223
test json-version-api {[dict get $JR payload jsonApiVersion] >= 20120713}
224
225
#### ARTIFACT
226
227
# sha1 of 0 bytes and a file to match in a commit
228
set UUID_empty da39a3ee5e6b4b0d3255bfef95601890afd80709
229
# sha3 of 0 bytes and a file to match in a commit
230
set UUID_empty_64 a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a
231
write_file empty ""
232
fossil add empty
233
fossil ci -m "empty file"
234
235
# json artifact (checkin)
236
fossil_json [concat artifact tip]
237
test_json_envelope_ok json-artifact-checkin-env
238
test json-artifact-checkin {[dict get $JR payload type] eq "checkin"}
239
test_json_payload json-artifact \
240
[concat type uuid isLeaf timestamp user comment parents tags files] {}
241
242
# json artifact (file)
243
fossil_json [concat artifact $UUID_empty_64]
244
test_json_envelope_ok json-artifact-file-env
245
test json-artifact-file {[dict get $JR payload type] eq "file"}
246
test_json_payload json-artifact [concat type uuid size checkins] {}
247
248
# json artifact (wiki)
249
fossil wiki create Empty <<"-=BLANK=-"
250
fossil_json wiki get Empty
251
test json-wiki-get {[dict get $JR payload name] eq "Empty"}
252
set uuid [dict get $JR payload uuid]
253
fossil_json artifact $uuid
254
test_json_envelope_ok json-artifact-wiki-env
255
test json-artifact-wiki {[dict get $JR payload type] eq "wiki"}
256
test_json_payload json-artifact-wiki [list type uuid artifact] {}
257
set artifact [dict get $JR payload artifact]
258
test_dict_keys json-artifact-wiki-artifact $artifact \
259
[list name uuid user timestamp size] {}
260
# name, uuid, parent?, user, timestamp, size?, content?
261
262
263
#### AUTHENTICATION
264
fossil_json anonymousPassword
265
test_json_envelope_ok json-anonymousPassword-env
266
test_json_payload json-anonymousPassword {seed password} {}
267
set seed [dict get $JR payload seed]
268
set pass [dict get $JR payload password]
269
270
write_file anon-1 [subst {
271
{
272
"command":"login",
273
"payload":{
274
"name":"anonymous",
275
"anonymousSeed":$seed,
276
"password":"$pass"
277
}
278
}
279
}]
280
fossil_json --json-input anon-1
281
test_json_envelope_ok json-login-a-env
282
test_json_payload json-login-a {authToken name capabilities loginCookieName} {}
283
set AuthAnon [dict get $JR payload]
284
proc test_hascaps {testname need caps} {
285
foreach n [split $need {}] {
286
test $testname-$n {[string first $n $caps] >= 0}
287
}
288
}
289
test_hascaps json-login-c "hz" [dict get $AuthAnon capabilities]
290
291
fossil user new U1 User-1 Uone
292
fossil user capabilities U1 s
293
write_file u1 {
294
{
295
"command":"login",
296
"payload":{
297
"name":"U1",
298
"password":"Uone"
299
}
300
}
301
}
302
fossil_json --json-input u1
303
test_json_envelope_ok json-login-u1-env
304
test_json_payload json-login-u1 {authToken name capabilities loginCookieName} {}
305
set AuthU1 [dict get $JR payload]
306
test_hascaps json-login-c "s" [dict get $AuthU1 capabilities]
307
308
set U1Cookie [dict get $AuthU1 loginCookieName]=[regsub -all {[/]} [dict get $AuthU1 authToken] {%2F} ]
309
set AnonCookie [dict get $AuthAnon loginCookieName]=[regsub -all {[/]} [dict get $AuthAnon authToken] {%2F} ]
310
311
# json cap
312
# The CLI user has all rights, and no auth token affects that. This
313
# is consistent with the rest of the fossil CLI, and with the
314
# pragmatic argument that using the CLI implies physical access to
315
# the repo file itself, which can be taunted with many tools
316
# including raw SQLite which will also ignore authentication.
317
write_file anon-2 [subst {
318
{"command":"cap",
319
"authToken":"[dict get $AuthAnon authToken]"
320
}
321
}]
322
fossil_json --json-input anon-2
323
test_json_envelope_ok json-cap-env
324
test json-cap-CLI {[dict get $JR payload permissionFlags setup]}
325
326
# json cap via POST with authToken in request envelope
327
set anon2 [read_file anon-2]
328
fossil_post_json "/json/cap" $anon2
329
test json-cap-POSTenv-env-0 {[string length $JR] > 0}
330
test_json_envelope_ok json-cap-POSTenv-env
331
if {[catch {test json-cap-POSTenv-name \
332
{[dict get $JR payload name] eq "anonymous"} knownBug} jerr]} then {
333
test json-cap-POSTenv-name-threw 0
334
protOut "CAUGHT: $jerr"
335
}
336
test json-cap-POSTenv-notsetup {![dict get $JR payload permissionFlags setup]}
337
338
339
# json cap via GET with authToken in Cookie header
340
fossil_post_json "/json/cap" {} $AnonCookie
341
test json-cap-GETcookie-env-0 {[string length $JR] > 0}
342
test_json_envelope_ok json-cap-GETcookie-env-0
343
if {[catch {test json-cap-GETcookie-name-0 \
344
{[dict get $JR payload name] eq "anonymous"}} jerr]} then {
345
test json-cap-GETcookie-name-0-threw 0
346
protOut "CAUGHT: $jerr"
347
}
348
test json-cap-GETcookie-notsetup-0 {![dict get $JR payload permissionFlags setup]}
349
350
351
# json cap via GET with authToken in a parameter
352
fossil_post_json "/json/cap?authToken=[dict get $AuthAnon authToken]" {}
353
test json-cap-GETcookie-env-1 {[string length $JR] > 0}
354
test_json_envelope_ok json-cap-GETcookie-env-1
355
if {[catch {test json-cap-GETcookie-name-1 \
356
{[dict get $JR payload name] eq "anonymous"}} jerr]} then {
357
test json-cap-GETcookie-name-1-threw 0
358
protOut "CAUGHT: $jerr"
359
}
360
test json-cap-GETcookie-notsetup-1 {![dict get $JR payload permissionFlags setup]}
361
362
363
# whoami
364
# via CLI with no auth token supplied
365
fossil_json whoami
366
test_json_envelope_ok json-whoami-cli-env
367
test_json_payload json-whoami-cli {name capabilities} {}
368
test json-whoami-cli-name {[dict get $JR payload name] eq "nobody"}
369
test_hascaps json-whoami-cli-cap "gjorz" [dict get $JR payload capabilities]
370
371
#### BRANCHES
372
# json branch list
373
fossil_json branch list
374
test_json_envelope_ok json-branch-list-env
375
test_json_payload json-branch-list {range current branches} {}
376
test json-branch-list-cur {[dict get $JR payload current] eq "trunk"}
377
test json-branch-list-cnt {[llength [dict get $JR payload branches]] == 1}
378
test json-branch-list-val {[dict get $JR payload branches] eq "trunk"}
379
380
# json branch create
381
fossil_json branch create alpha --basis trunk
382
test_json_envelope_ok json-branch-create-env
383
test_json_payload json-branch-create {name basis rid uuid isPrivate} {}
384
385
386
#### CONFIG
387
# json config get AREA
388
# AREAs are skin ticket project all skin-backup
389
foreach a [list skin ticket project all skin-backup] {
390
fossil_json config get $a
391
test_json_envelope_ok json-config-$a-env
392
# payload depends on specific area and may be completely empty
393
}
394
395
#### DIFFS
396
# json diff v1 v2
397
398
write_file fish {
399
ABCD goldfish
400
}
401
fossil add fish
402
fossil ci -m "goldfish"
403
fossil_json finfo fish
404
set fishHist [dict get $JR payload checkins]
405
set fishV1 [dict get [lindex $fishHist 0] uuid]
406
407
write_file fish {
408
ABCD goldfish
409
LMNO goldfish
410
}
411
fossil ci -m "goldfish"
412
fossil_json finfo fish
413
set fishHist [dict get $JR payload checkins]
414
set fishV2 [dict get [lindex $fishHist 0] uuid]
415
416
test fossil-diff-setup {$fishV1 ne $fishV2}
417
fossil_json diff $fishV1 $fishV2
418
test_json_envelope_ok json-diff-env
419
test_json_payload json-diff {from to diff} {}
420
test json-diff-v1 {[dict get $JR payload from] eq $fishV1}
421
test json-diff-v2 {[dict get $JR payload to] eq $fishV2}
422
set diff [dict get $JR payload diff]
423
test json-diff-diff {[string first "+LMNO goldfish" $diff] >= 0}
424
protOut [dict get $JR payload diff]
425
426
427
#### DIRECTORY LISTING
428
# json dir DIRNAME
429
fossil_json dir
430
test_json_envelope_ok json-dir-env
431
test_json_payload json-dir {name entries} {}
432
433
#### FILE INFO
434
# json finfo FILENAME
435
fossil_json finfo empty
436
test_json_envelope_ok json-finfo-env
437
test_json_payload json-finfo {name checkins} {}
438
439
#### QUERY
440
# json query SQLCODE
441
fossil_json query {"SELECT * FROM reportfmt"}
442
test_json_envelope_ok json-query-env
443
test_json_payload json-query {columns rows} {}
444
445
#### STATS
446
# json stat
447
fossil_json stat
448
test_json_envelope_ok json-stat-env
449
test_json_payload json-stat {repositorySize ageDays ageYears projectCode compiler sqlite} \
450
{blobCount deltaCount uncompressedArtifactSize averageArtifactSize maxArtifactSize \
451
compressionRatio checkinCount fileCount wikiPageCount ticketCount}
452
453
fossil_json stat -f
454
test_json_envelope_ok json-stat-env
455
test_json_payload json-stat {repositorySize \
456
blobCount deltaCount uncompressedArtifactSize averageArtifactSize maxArtifactSize \
457
compressionRatio checkinCount fileCount wikiPageCount ticketCount \
458
ageDays ageYears projectCode compiler sqlite} {}
459
460
461
#### STATUS
462
# NOTE: Local checkout required
463
# json status
464
fossil_json status
465
test_json_envelope_ok json-status-env
466
test_json_payload json-status {repository localRoot checkout files errorCount} {}
467
468
#### TAGS
469
470
# json tag add NAME CHECKIN VALUE
471
fossil_json tag add blue trunk green
472
test_json_envelope_ok json-tag-add-env
473
test_json_payload json-tag-add {name value propagate raw appliedTo} {}
474
475
476
# json tag cancel NAME CHECKIN
477
fossil_json tag add cancel alpha
478
test_json_envelope_ok json-tag-cancel-env
479
# DOCBUG? Doc says no payload.
480
test_json_payload json-tag-cancel {name value propagate raw appliedTo} {}
481
482
# json tag find NAME
483
fossil_json tag find alpha
484
test_json_envelope_ok json-tag-find-env
485
test_json_payload json-tag-find {name raw type limit artifacts} {}
486
test json-tag-find-count {[llength [dict get $JR payload artifacts]] >= 1}
487
488
# json tag list CHECKIN
489
fossil_json tag list
490
test_json_envelope_ok json-tag-list-env
491
test_json_payload json-tag-list {raw includeTickets tags} {}
492
test json-tag-list-count {[llength [dict get $JR payload tags]] >= 2}
493
494
495
#### TICKETS
496
# API Docs say not yet defined, so it isn't quite fair to mark this
497
# category as TODO for the test cases...
498
499
#### TICKET REPORTS
500
501
# json report get NUMBER
502
fossil_json report get 1
503
test_json_envelope_ok json-report-get-env
504
test_json_payload json-report-get {report owner title timestamp columns sqlCode} {}
505
506
# json report list
507
fossil_json report list
508
test_json_envelope_ok json-report-list-env
509
#test_json_payload json-report-list {raw includeTickets tags} {}
510
test json-report-list-count {[llength [dict get $JR payload]] >= 1}
511
512
513
# json report run NUMBER
514
fossil_json report run 1
515
test_json_envelope_ok json-report-run-1-env
516
test_json_payload json-report-list {report title sqlcode columnNames tickets} {}
517
test json-report-list-count {[llength [dict get $JR payload columnNames]] >= 7}
518
test json-report-list-count {[llength [dict get $JR payload tickets]] >= 0}
519
520
521
#### TIMELINE
522
523
# json timeline checkin
524
fossil_json timeline checkin
525
test_json_envelope_ok json-timeline-checkin-env
526
test_json_payload json-timeline-checkin {limit timeline} {}
527
set i 0
528
foreach t [dict get $JR payload timeline] {
529
# parents appears only for entries that have a parent
530
# files appears only if requested by the --files parameter
531
test_dict_keys json-timeline-checkin-$i $t {type uuid timestamp comment user isLeaf tags} {}
532
incr i
533
}
534
535
# json timeline ci
536
# removed from documentation
537
#fossil_json timeline ci
538
#test json-timeline-ci {[dict get $JR resultCode] ne "FOSSIL-1102"} knownBug
539
#test_json_payload json-timeline-ci {limit timeline} {}
540
541
# json timeline ticket
542
fossil_json timeline ticket
543
test_json_envelope_ok json-timeline-ticket-env
544
test_json_payload json-timeline-ticket {limit timeline} {}
545
546
# json timeline wiki
547
fossil_json timeline wiki
548
test_json_envelope_ok json-timeline-wiki-env
549
test_json_payload json-timeline-wiki {limit timeline} {}
550
551
552
#### USER MANAGEMENT
553
554
# json user get
555
foreach u [list nobody anonymous reader developer U1] {
556
fossil_json user get $u
557
test_json_envelope_ok json-user-get-$u-env
558
test_json_payload json-user-get-$u {uid name capabilities info timestamp} {}
559
}
560
561
# json user list
562
fossil_json user list
563
test_json_envelope_ok json-user-list-env
564
set i 0
565
foreach u [dict get $JR payload] {
566
test_dict_keys json-user-list-$i $u {uid name capabilities info timestamp} {}
567
incr i
568
}
569
570
# json user save
571
fossil_json user save --uid -1 --name U2 --password Utwo
572
test_json_envelope_ok json-user-save-env
573
test_json_payload json-user-save {uid name capabilities info timestamp} {}
574
575
576
# DOCBUG? Doc says payload is "same as /json/user/get" but actual
577
# result was an array of one user similar to /json/user/list.
578
#set i 0
579
#foreach u [dict get $JR payload] {
580
# test_dict_keys json-user-save-$i $u {uid name capabilities info timestamp} {}
581
# incr i
582
#}
583
#test json-user-save-count {$i == 1}
584
585
586
587
#### WIKI
588
589
# wiki list
590
fossil_json wiki list
591
test_json_envelope_ok json-wiki-list-env
592
set pages [dict get $JR payload]
593
test json-wiki-1 {[llength $pages] == 1}
594
test json-wiki-2 {[lindex $pages 0] eq "Empty"}
595
fossil_json wiki list --verbose
596
set pages [dict get $JR payload]
597
test json-wiki-verbose-1 {[llength $pages] == 1}
598
test_dict_keys json-wiki-verbose-pages [lindex $pages 0] [list name uuid user timestamp size] {}
599
600
# wiki get
601
fossil_json wiki get Empty
602
test_json_envelope_ok json-wiki-get-env
603
# this page has only one version, so no parent should be listed
604
test_json_payload json-wiki-get [list name uuid user timestamp size content] [list parent]
605
606
607
# wiki create
608
# requires an authToken? Not from CLI.
609
610
write_file req.json {
611
{
612
"command":"wiki/create",
613
"payload":{
614
"name":"Page2",
615
"content":"Lorem ipsum dolor sic amet."
616
}
617
}
618
}
619
fossil_json --json-input req.json
620
test_json_envelope_ok json-wiki-create-env
621
fossil_json wiki get Page2
622
test_json_envelope_ok json-wiki-create-get-env
623
test_json_payload json-wiki-save-get [list name uuid user timestamp size content] {parent}
624
set uuid1 [dict get $JR payload uuid]
625
626
# wiki save
627
628
write_file req2.json {
629
{
630
"command":"wiki/save",
631
"payload":{
632
"name":"Page2",
633
"content":"Lorem ipsum dolor sic amet.\nconsectetur adipisicing elit."
634
}
635
}
636
}
637
fossil_json --json-input req2.json
638
test_json_envelope_ok json-wiki-save-env
639
fossil_json wiki get Page2
640
test_json_envelope_ok json-wiki-save-get-env
641
test_json_payload json-wiki-save-get [list name uuid user timestamp size parent content] {}
642
set uuid2 [dict get $JR payload uuid]
643
test json-wiki-save-parent {[dict get $JR payload parent] eq $uuid1}
644
645
# wiki diff
646
647
fossil_json wiki diff $uuid1 $uuid2
648
test_json_envelope_ok json-wiki-diff-env
649
test_json_payload json-wiki-diff [list v1 v2 diff] {}
650
test json-wiki-diff-v1 {[dict get $JR payload v1] eq $uuid1}
651
test json-wiki-diff-v1 {[dict get $JR payload v2] eq $uuid2}
652
set diff [dict get $JR payload diff]
653
test json-wiki-diff-diff {[string first "+consectetur adipisicing elit" $diff] >= 0}
654
#puts [dict get $JR payload diff]
655
656
# wiki preview
657
#
658
# takes a string in fossil wiki markup and return an HTML fragment.
659
# This command does not make use of the actual wiki content (much?)
660
# at all.
661
write_file req3.json {
662
{
663
"command":"wiki/preview",
664
"payload":"Lorem ipsum dolor sic amet.\nconsectetur adipisicing elit."
665
}
666
}
667
fossil_json --json-input req3.json
668
test_json_envelope_ok json-wiki-preview-env
669
set pv [dict get $JR payload]
670
test json-wiki-preview-out-1 {[string first "<p>Lorem ipsum" $pv] == 0}
671
test json-wiki-preview-out-2 {[string last "<p>" $pv] == 0}
672
673
#### UNAVOIDABLE MISC
674
675
# json g
676
fossil_json g
677
test_json_envelope_ok json-g-env
678
#puts [llength [dict keys [dict get $JR payload]]]
679
test json-g-g {[llength [dict keys [dict get $JR payload]]] >= 60};# 64 on my PC
680
681
# json rebuild
682
fossil_json rebuild
683
test_json_envelope json-rebuild-env [concat fossil timestamp command procTimeUs \
684
procTimeMs] [concat payload resultCode resultText]
685
686
# json resultCodes
687
fossil_json resultCodes
688
test_json_envelope_ok json-resultCodes-env
689
set codes [dict get $JR payload]
690
test json-resultCodes-codes-1 {[llength $codes] >= 35} ;# count as of API 20120713
691
# foreach c $codes {
692
# puts [dict values $c]
693
# }
694
foreach r $codes {
695
protOut "# [dict get $r resultCode] [dict get $r cSymbol]\n# [dict get $r description]"
696
}
697
698
699
700
#### From the API Docs
701
702
# Reminder to self: in March 2012 i saw a corner-case which returns
703
# HTML output. To reproduce: chmod 444 REPO, then submit a request
704
# which writes something (timeline creates a temp table). The "repo
705
# is not writable" error comes back as HTML. i don't know if the
706
# error happens before we have made the determination that the app is
707
# in JSON mode or if the error handling is incorrectly not
708
# recognizing JSON mode.
709
#
710
#test_setup x.fossil
711
fossil_http_json /json/query?sql=PRAGMA%20repository.journal_mode%3Dwal $U1Cookie
712
test json-ROrepo-1-1 {$CODE == 0}
713
test json-ROrepo-1-2 {[regexp {\}\s*$} $RESULT]}
714
test json-ROrepo-1-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]}
715
test_json_envelope_ok json-http-timeline1
716
if {$is_windows} then {
717
catch {exec attrib +r .rep.fossil}; # Windows
718
} else {
719
catch {exec chmod 444 .rep.fossil}; # Unix
720
}
721
protOut "chmod 444 repo"
722
fossil_http_json /json/query?sql=PRAGMA%20repository.journal_mode%3Ddelete $U1Cookie -expectError --json-preserve-rc
723
test json-ROrepo-2-1 {$CODE != 0}
724
test json-ROrepo-2-2 {[regexp {\}\s*$} $RESULT]}
725
test json-ROrepo-2-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]}
726
#test_json_envelope_ok json-http-timeline2
727
if {$is_windows} then {
728
catch {exec attrib -r .rep.fossil}; # Windows
729
catch {exec attrib -r .rep.fossil-shm}
730
catch {exec attrib -r .rep.fossil-wal}
731
} else {
732
catch {exec chmod 666 .rep.fossil}; # Unix
733
catch {exec chmod 666 .rep.fossil-shm}
734
catch {exec chmod 666 .rep.fossil-wal}
735
}
736
protOut "chmod 666 repo"
737
738
#### Result Codes
739
# Test cases designed to stimulate each (documented) error code.
740
741
# FOSSIL-0000
742
# Not returned by any command. We generally verify that in the
743
# test_json_envelope_ok command by verifying that the resultCode
744
# field is not present. Should any JSON endpoint begin to use the
745
# range reserved for non-fatal warnings, those tests will fail.
746
#
747
# Notice that code is not included in the list returned from
748
# /json/resultCodes.
749
750
751
# FOSSIL-1000 FSL_JSON_E_GENERIC
752
# Generic error
753
754
# FOSSIL-1101 FSL_JSON_E_INVALID_REQUEST
755
# Invalid request
756
write_file e1101.json {
757
["command","nope"]
758
}
759
fossil_json --json-input e1101.json -expectError
760
test json-RC-1101-array-CLI-exit {$CODE != 0}
761
test_json_envelope json-RC-1101-array-env {fossil timestamp command procTimeUs \
762
procTimeMs resultCode resultText} {payload}
763
test json-RC-1101-array-code {[dict get $JR resultCode] eq "FOSSIL-1101"}
764
765
write_file e1101.json {
766
"Not really a command but more of a suggestion"
767
}
768
fossil_json --json-input e1101.json -expectError
769
test json-RC-1101-string-CLI-exit {$CODE != 0}
770
test_json_envelope json-RC-1101-string-env {fossil timestamp command procTimeUs \
771
procTimeMs resultCode resultText} {payload}
772
test json-RC-1101-string-code {[dict get $JR resultCode] eq "FOSSIL-1101"}
773
774
775
776
777
# FOSSIL-1102 FSL_JSON_E_UNKNOWN_COMMAND
778
# Unknown command or subcommand
779
fossil_json NoSuchEndpoint -expectError
780
test json-RC-1102-CLI-exit {$CODE != 0}
781
test_json_envelope json-RC-1102-env {fossil timestamp command procTimeUs \
782
procTimeMs resultCode resultText} {payload}
783
test json-RC-1102-code {[dict get $JR resultCode] eq "FOSSIL-1102"}
784
785
write_file e1102.json {
786
{
787
"command":"no/such/endpoint"
788
}
789
}
790
fossil_json --json-input e1102.json -expectError
791
test json-env-RC-1102a-CLI-exit {$CODE != 0}
792
test_json_envelope json-env-RC-1102a-env {fossil timestamp command procTimeUs \
793
procTimeMs resultCode resultText} {payload}
794
test json-env-RC-1102a-code {[dict get $JR resultCode] eq "FOSSIL-1102"}
795
796
797
# FOSSIL-1103 FSL_JSON_E_UNKNOWN
798
# Unknown error
799
800
write_file bad.sql {
801
CREATE TABLE spam(a integer, b text);
802
}
803
exec $::fossilexe sqlite3 --no-repository bad.fossil <bad.sql
804
fossil_json HAI -R bad.fossil -expectError
805
test json-env-RC-1103-CLI-exit {$CODE != 0}
806
if { $JR ne "" } {
807
test_json_envelope json-env-RC-1103-env {fossil timestamp command procTimeUs \
808
procTimeMs resultCode resultText} {payload}
809
test json-env-RC-1103-code {[dict exists $JR resultCode]\
810
&& [dict get $JR resultCode] eq "FOSSIL-1103"} knownBug
811
} else {
812
protOut "Want test case for FOSSIL-1103"
813
test json-RC-1103 0 knownBug
814
}
815
816
# FOSSIL-1104 FSL_JSON_E_TIMEOUT
817
# Timeout reached
818
# FOSSIL-1105 FSL_JSON_E_ASSERT
819
# Assertion failed
820
# FOSSIL-1106 FSL_JSON_E_ALLOC
821
# Resource allocation failed
822
# FOSSIL-1107 FSL_JSON_E_NYI
823
# Not yet implemented
824
# FOSSIL-1108 FSL_JSON_E_PANIC
825
# x
826
# FOSSIL-1109 FSL_JSON_E_MANIFEST_READ_FAILED
827
# Reading artifact manifest failed
828
# FOSSIL-1110 FSL_JSON_E_FILE_OPEN_FAILED
829
# Opening file failed
830
831
# FOSSIL-2000 FSL_JSON_E_AUTH
832
# Authentication error
833
# FOSSIL-2001 FSL_JSON_E_MISSING_AUTH
834
# Authentication info missing from request
835
# FOSSIL-2002 FSL_JSON_E_DENIED
836
# Access denied
837
# FOSSIL-2003 FSL_JSON_E_WRONG_MODE
838
# Request not allowed (wrong operation mode)
839
# FOSSIL-2100 FSL_JSON_E_LOGIN_FAILED
840
# Login failed
841
# FOSSIL-2101 FSL_JSON_E_LOGIN_FAILED_NOSEED
842
# Anonymous login attempt was missing password seed
843
# FOSSIL-2102 FSL_JSON_E_LOGIN_FAILED_NONAME
844
# Login failed - name not supplied
845
# FOSSIL-2103 FSL_JSON_E_LOGIN_FAILED_NOPW
846
# Login failed - password not supplied
847
# FOSSIL-2104 FSL_JSON_E_LOGIN_FAILED_NOTFOUND
848
# Login failed - no match found
849
850
# FOSSIL-3000 FSL_JSON_E_USAGE
851
# Usage error
852
# FOSSIL-3001 FSL_JSON_E_INVALID_ARGS
853
# Invalid argument(s)
854
855
# FOSSIL-3002 FSL_JSON_E_MISSING_ARGS
856
# Missing argument(s)
857
write_file e3002.json {
858
{"color":"yellow",
859
"really":"no, blue",
860
"number":42
861
}
862
}
863
fossil_json --json-input e3002.json -expectError
864
test json-RC-3002-strange-CLI-exit {$CODE != 0}
865
test_json_envelope json-RC-3002-strange-env {fossil timestamp command procTimeUs \
866
procTimeMs resultCode resultText} {payload}
867
test json-RC-3002-strange-code {[dict get $JR resultCode] eq "FOSSIL-3002"}
868
869
870
# FOSSIL-3003 FSL_JSON_E_AMBIGUOUS_UUID
871
# Resource identifier is ambiguous
872
# FOSSIL-3004 FSL_JSON_E_UNRESOLVED_UUID
873
# Provided uuid/tag/branch could not be resolved
874
# FOSSIL-3005 FSL_JSON_E_RESOURCE_ALREADY_EXISTS
875
# Resource already exists
876
# FOSSIL-3006 FSL_JSON_E_RESOURCE_NOT_FOUND
877
# Resource not found
878
879
# FOSSIL-4000 FSL_JSON_E_DB
880
# Database error
881
# FOSSIL-4001 FSL_JSON_E_STMT_PREP
882
# Statement preparation failed
883
# FOSSIL-4002 FSL_JSON_E_STMT_BIND
884
# Statement parameter binding failed
885
# FOSSIL-4003 FSL_JSON_E_STMT_EXEC
886
# Statement execution/stepping failed
887
# FOSSIL-4004 FSL_JSON_E_DB_LOCKED
888
# Database is locked
889
# FOSSIL-4101 FSL_JSON_E_DB_NEEDS_REBUILD
890
# Fossil repository needs to be rebuilt
891
892
# FOSSIL-4102 FSL_JSON_E_DB_NOT_FOUND
893
# Fossil repository db file could not be found.
894
fossil close
895
fossil_json HAI -expectError
896
test json-RC-4102-CLI-exit {$CODE != 0}
897
test_json_envelope json-RC-4102-CLI-exit {fossil timestamp command procTimeUs \
898
procTimeMs resultCode resultText} {payload}
899
test json-RC-4102 {[dict get $JR resultCode] eq "FOSSIL-4102"}
900
901
# FOSSIL-4103 FSL_JSON_E_DB_NOT_VALID
902
# Fossil repository db file is not valid.
903
write_file nope.fossil {
904
This is not a fossil repo. It ought to be a SQLite db with a well-known schema,
905
but it is actually just a block of text.
906
}
907
fossil_json HAI -R nope.fossil -expectError
908
test json-RC-4103-CLI-exit {$CODE != 0}
909
if { $JR ne "" } {
910
test_json_envelope json-RC-4103-CLI {fossil timestamp command procTimeUs \
911
procTimeMs resultCode resultText} {payload}
912
test json-RC-4103 {[dict get $JR resultCode] eq "FOSSIL-4103"}
913
} else {
914
test json-RC-4103 0 knownBug
915
}
916
917
###############################################################################
918
919
test_cleanup
920
921
if { $_fossil_user eq "" } {
922
unset ::env(FOSSIL_USER)
923
} else {
924
set ::env(FOSSIL_USER) $_fossil_user
925
}
926

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button