Fossil

Check-in [09a46c28]
Login

Check-in [09a46c28]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Use the 'hasfeature' TH1 command to test if JSON was included at compile-time.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 09a46c287359f04f74170571ea739d9d271e4b88
User & Date: mistachkin 2016-02-07 22:55:32.433
Context
2016-02-07
23:22
Make the read-only json test work on Windows. ... (check-in: 938122da user: mistachkin tags: trunk)
22:55
Use the 'hasfeature' TH1 command to test if JSON was included at compile-time. ... (check-in: 09a46c28 user: mistachkin tags: trunk)
04:15
Defer requiring json loading until after it is determined that fossil json works. ... (check-in: 5d700c7d user: andybradford tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to test/json.test.
19
20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#

# Make sure we have a build with the json command at all and that it
# is not stubbed out. This assumes the current (as of 2016-01-27)
# practice of eliminating all trace of the fossil json command when
# not configured. If that changes, these conditions might not prevent
# the rest of this file from running.
fossil help -a
if {[string first json $RESULT] < 0} {

  puts "Fossil was not compiled with JSON support (fossil help -a)."; return
}

# We need a JSON parser to effectively test the JSON produced by
# fossil. It looks like the one from tcllib is exactly what we need.
# On ActiveTcl, add it with teacup. On other platforms, YMMV.
# teacup install json
# teacup install json::write
package require json

proc json2dict {txt} {
  set rc [catch {::json::json2dict $txt} result options]
  if {$rc != 0} {
    protOut "JSON ERROR: $result" 
    return {}
  }
  return $result
}

# and that the json itself smells ok and has the expected API error code in it
fossil json -expectError 
set JR [json2dict $RESULT]
if {$JR eq ""} {
  puts "Fossil was not compiled with JSON support (bad JSON)."; return
}
test json-1 {[dict exists $JR resultCode]
             && [dict get $JR resultCode] eq "FOSSIL-4102"}








|
|
>
|












|






|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#

# Make sure we have a build with the json command at all and that it
# is not stubbed out. This assumes the current (as of 2016-01-27)
# practice of eliminating all trace of the fossil json command when
# not configured. If that changes, these conditions might not prevent
# the rest of this file from running.
fossil test-th-eval "hasfeature json"

if {$::RESULT ne "1"} then {
  puts "Fossil was not compiled with JSON support."; return
}

# We need a JSON parser to effectively test the JSON produced by
# fossil. It looks like the one from tcllib is exactly what we need.
# On ActiveTcl, add it with teacup. On other platforms, YMMV.
# teacup install json
# teacup install json::write
package require json

proc json2dict {txt} {
  set rc [catch {::json::json2dict $txt} result options]
  if {$rc != 0} {
    protOut "JSON ERROR: $result"
    return {}
  }
  return $result
}

# and that the json itself smells ok and has the expected API error code in it
fossil json -expectError
set JR [json2dict $RESULT]
if {$JR eq ""} {
  puts "Fossil was not compiled with JSON support (bad JSON)."; return
}
test json-1 {[dict exists $JR resultCode]
             && [dict get $JR resultCode] eq "FOSSIL-4102"}

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  set JR [json2dict $RESULT]
  return "200"
}

# Use the HTTP interface to GET a JSON API URL. Sets the globals
# RESULT to the HTTP response body, and JR to a Tcl dict conversion of
# the response body.
# 
# Returns the status code from the HTTP header.
proc fossil_http_json {url {cookie "Muppet=Monster"} args} {
  global RESULT JR
  set request "GET $url HTTP/1.1\r\nHost: localhost\r\nUser-Agent: Fossil-http-json\r\nCookie: $cookie"
  set RESULT [fossil_maybe_answer $request http {*}$args]
  regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body
  regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg
  if {$status eq "200"} {
    set JR [json2dict $body]
  }
  return $status
}


# Use the HTTP interface to POST a JSON API URL. Sets the globals
# RESULT to the HTTP response body, and JR to a Tcl dict conversion of
# the response body.
#
# Returns the status code from the HTTP header.
proc fossil_post_json {url data {cookie "Muppet=Monster"} args} {
  global RESULT JR 

  # set up a full GET or POST HTTP request
  set len [string length $data]
  if {$len > 0} {
    set request [subst {POST $url HTTP/1.0\r
Host: localhost\r
User-Agent: Fossil-Test\r







|




















|







65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  set JR [json2dict $RESULT]
  return "200"
}

# Use the HTTP interface to GET a JSON API URL. Sets the globals
# RESULT to the HTTP response body, and JR to a Tcl dict conversion of
# the response body.
#
# Returns the status code from the HTTP header.
proc fossil_http_json {url {cookie "Muppet=Monster"} args} {
  global RESULT JR
  set request "GET $url HTTP/1.1\r\nHost: localhost\r\nUser-Agent: Fossil-http-json\r\nCookie: $cookie"
  set RESULT [fossil_maybe_answer $request http {*}$args]
  regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body
  regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg
  if {$status eq "200"} {
    set JR [json2dict $body]
  }
  return $status
}


# Use the HTTP interface to POST a JSON API URL. Sets the globals
# RESULT to the HTTP response body, and JR to a Tcl dict conversion of
# the response body.
#
# Returns the status code from the HTTP header.
proc fossil_post_json {url data {cookie "Muppet=Monster"} args} {
  global RESULT JR

  # set up a full GET or POST HTTP request
  set len [string length $data]
  if {$len > 0} {
    set request [subst {POST $url HTTP/1.0\r
Host: localhost\r
User-Agent: Fossil-Test\r
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
test_json_payload json-branch-create {name basis rid uuid isPrivate} {}


#### CONFIG
# json config get AREA
# AREAs are skin ticket project all skin-backup
foreach a [list skin ticket project all skin-backup] {
  fossil_json config get $a 
  test_json_envelope_ok json-config-$a-env
  # payload depends on specific area and may be completely empty
}

#### DIFFS
# json diff v1 v2








|







344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
test_json_payload json-branch-create {name basis rid uuid isPrivate} {}


#### CONFIG
# json config get AREA
# AREAs are skin ticket project all skin-backup
foreach a [list skin ticket project all skin-backup] {
  fossil_json config get $a
  test_json_envelope_ok json-config-$a-env
  # payload depends on specific area and may be completely empty
}

#### DIFFS
# json diff v1 v2

382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
set diff [dict get $JR payload diff]
test json-diff-diff {[string first "+LMNO goldfish" $diff] >= 0}
protOut [dict get $JR payload diff]


#### DIRECTORY LISTING
# json dir DIRNAME
fossil_json dir 
test_json_envelope_ok json-dir-env
test_json_payload json-dir {name entries} {}

#### FILE INFO
# json finfo FILENAME
fossil_json finfo empty
test_json_envelope_ok json-finfo-env







|







383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
set diff [dict get $JR payload diff]
test json-diff-diff {[string first "+LMNO goldfish" $diff] >= 0}
protOut [dict get $JR payload diff]


#### DIRECTORY LISTING
# json dir DIRNAME
fossil_json dir
test_json_envelope_ok json-dir-env
test_json_payload json-dir {name entries} {}

#### FILE INFO
# json finfo FILENAME
fossil_json finfo empty
test_json_envelope_ok json-finfo-env
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
set i 0
foreach u [dict get $JR payload] {
  test_dict_keys json-user-list-$i $u {uid name capabilities info timestamp} {}
  incr i
}

# json user save
fossil_json user save --uid -1 --name U2 --password Utwo 
test_json_envelope_ok json-user-save-env
test_json_payload json-user-save {uid name capabilities info timestamp} {}


# DOCBUG? Doc says payload is "same as /json/user/get" but actual
# result was an array of one user similar to /json/user/list.
#set i 0
#foreach u [dict get $JR payload] {
#  test_dict_keys json-user-save-$i $u {uid name capabilities info timestamp} {}
#  incr i
#}
#test json-user-save-count {$i == 1}



#### WIKI

# wiki list
fossil_json wiki list
test_json_envelope_ok json-wiki-list-env 
set pages  [dict get $JR payload]
test json-wiki-1 {[llength $pages] == 1}
test json-wiki-2 {[lindex  $pages 0] eq "Empty"}
fossil_json wiki list --verbose
set pages  [dict get $JR payload]
test json-wiki-verbose-1 {[llength $pages] == 1}
test_dict_keys json-wiki-verbose-pages [lindex $pages 0] [list name uuid user timestamp size] {}

# wiki get
fossil_json wiki get Empty
test_json_envelope_ok json-wiki-get-env 
# this page has only one version, so no parent should be listed
test_json_payload json-wiki-get [list name uuid user timestamp size content] [list parent]


# wiki create
# requires an authToken? Not from CLI.








|



















|










|







525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
set i 0
foreach u [dict get $JR payload] {
  test_dict_keys json-user-list-$i $u {uid name capabilities info timestamp} {}
  incr i
}

# json user save
fossil_json user save --uid -1 --name U2 --password Utwo
test_json_envelope_ok json-user-save-env
test_json_payload json-user-save {uid name capabilities info timestamp} {}


# DOCBUG? Doc says payload is "same as /json/user/get" but actual
# result was an array of one user similar to /json/user/list.
#set i 0
#foreach u [dict get $JR payload] {
#  test_dict_keys json-user-save-$i $u {uid name capabilities info timestamp} {}
#  incr i
#}
#test json-user-save-count {$i == 1}



#### WIKI

# wiki list
fossil_json wiki list
test_json_envelope_ok json-wiki-list-env
set pages  [dict get $JR payload]
test json-wiki-1 {[llength $pages] == 1}
test json-wiki-2 {[lindex  $pages 0] eq "Empty"}
fossil_json wiki list --verbose
set pages  [dict get $JR payload]
test json-wiki-verbose-1 {[llength $pages] == 1}
test_dict_keys json-wiki-verbose-pages [lindex $pages 0] [list name uuid user timestamp size] {}

# wiki get
fossil_json wiki get Empty
test_json_envelope_ok json-wiki-get-env
# this page has only one version, so no parent should be listed
test_json_payload json-wiki-get [list name uuid user timestamp size content] [list parent]


# wiki create
# requires an authToken? Not from CLI.

661
662
663
664
665
666
667
668
669
670
671
672
673
674
675

# Reminder to self: in March 2012 i saw a corner-case which returns
# HTML output. To reproduce: chmod 444 REPO, then submit a request
# which writes something (timeline creates a temp table). The "repo
# is not writable" error comes back as HTML. i don't know if the
# error happens before we have made the determination that the app is
# in JSON mode or if the error handling is incorrectly not
# recognizing JSON mode. 
#
#repo_init x.fossil
#catch {exec chmod 444 .rep.fossil}; # Unix. What about Win?
fossil_http_json /json/timeline/checkin $U1Cookie
test json-ROrepo-1-1 {$CODE == 0}
test json-ROrepo-1-2 {[regexp {\}\s*$} $RESULT]}
test json-ROrepo-1-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]}







|







662
663
664
665
666
667
668
669
670
671
672
673
674
675
676

# Reminder to self: in March 2012 i saw a corner-case which returns
# HTML output. To reproduce: chmod 444 REPO, then submit a request
# which writes something (timeline creates a temp table). The "repo
# is not writable" error comes back as HTML. i don't know if the
# error happens before we have made the determination that the app is
# in JSON mode or if the error handling is incorrectly not
# recognizing JSON mode.
#
#repo_init x.fossil
#catch {exec chmod 444 .rep.fossil}; # Unix. What about Win?
fossil_http_json /json/timeline/checkin $U1Cookie
test json-ROrepo-1-1 {$CODE == 0}
test json-ROrepo-1-2 {[regexp {\}\s*$} $RESULT]}
test json-ROrepo-1-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]}
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
#test_json_envelope_ok json-http-timeline2
catch {exec chmod 666 .rep.fossil}; # Unix. What about Win?


#### Result Codes
# Test cases designed to stimulate each (documented) error code.

# FOSSIL-0000 
# Not returned by any command. We generally verify that in the
# test_json_envelope_ok command by verifying that the resultCode
# field is not present. Should any JSON endpoint begin to use the
# range reserved for non-fatal warnings, those tests will fail.
#
# Notice that code is not included in the list returned from
# /json/resultCodes.







|







684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
#test_json_envelope_ok json-http-timeline2
catch {exec chmod 666 .rep.fossil}; # Unix. What about Win?


#### Result Codes
# Test cases designed to stimulate each (documented) error code.

# FOSSIL-0000
# Not returned by any command. We generally verify that in the
# test_json_envelope_ok command by verifying that the resultCode
# field is not present. Should any JSON endpoint begin to use the
# range reserved for non-fatal warnings, those tests will fail.
#
# Notice that code is not included in the list returned from
# /json/resultCodes.
841
842
843
844
845
846
847
848

# FOSSIL-4103 FSL_JSON_E_DB_NOT_VALID
#     Fossil repository db file is not valid.
write_file nope.fossil {
This is not a fossil repo. It ought to be a SQLite db with a well-known schema,
but it is actually just a block of text.
}








<
842
843
844
845
846
847
848


# FOSSIL-4103 FSL_JSON_E_DB_NOT_VALID
#     Fossil repository db file is not valid.
write_file nope.fossil {
This is not a fossil repo. It ought to be a SQLite db with a well-known schema,
but it is actually just a block of text.
}