RESTCONF PUT/POST -d {} media is enforced
This commit is contained in:
parent
aa653d0831
commit
aa14f8ac2c
35 changed files with 933 additions and 640 deletions
269
test/jukebox.sh
Executable file
269
test/jukebox.sh
Executable file
|
|
@ -0,0 +1,269 @@
|
|||
#!/bin/bash
|
||||
# Jukebox example from rfc 8040 Appendix A.1
|
||||
# ASsumes fjukebox is set to name of yang file
|
||||
|
||||
cat <<EOF > $fjukebox
|
||||
module example-jukebox {
|
||||
|
||||
namespace "http://example.com/ns/example-jukebox";
|
||||
prefix "jbox";
|
||||
|
||||
organization "Example, Inc.";
|
||||
contact "support at example.com";
|
||||
description "Example Jukebox Data Model Module.";
|
||||
revision "2016-08-15" {
|
||||
description "Initial version.";
|
||||
reference "example.com document 1-4673.";
|
||||
}
|
||||
|
||||
identity genre {
|
||||
description
|
||||
"Base for all genre types.";
|
||||
}
|
||||
|
||||
// abbreviated list of genre classifications
|
||||
identity alternative {
|
||||
base genre;
|
||||
description
|
||||
"Alternative music.";
|
||||
}
|
||||
identity blues {
|
||||
base genre;
|
||||
description
|
||||
"Blues music.";
|
||||
}
|
||||
identity country {
|
||||
base genre;
|
||||
description
|
||||
"Country music.";
|
||||
}
|
||||
identity jazz {
|
||||
base genre;
|
||||
description
|
||||
"Jazz music.";
|
||||
}
|
||||
identity pop {
|
||||
base genre;
|
||||
description
|
||||
"Pop music.";
|
||||
}
|
||||
identity rock {
|
||||
base genre;
|
||||
description
|
||||
"Rock music.";
|
||||
}
|
||||
|
||||
container jukebox {
|
||||
presence
|
||||
"An empty container indicates that the jukebox
|
||||
service is available.";
|
||||
|
||||
description
|
||||
"Represents a 'jukebox' resource, with a library, playlists,
|
||||
and a 'play' operation.";
|
||||
|
||||
container library {
|
||||
|
||||
description
|
||||
"Represents the 'jukebox' library resource.";
|
||||
|
||||
list artist {
|
||||
key name;
|
||||
description
|
||||
"Represents one 'artist' resource within the
|
||||
'jukebox' library resource.";
|
||||
|
||||
leaf name {
|
||||
type string {
|
||||
length "1 .. max";
|
||||
}
|
||||
description
|
||||
"The name of the artist.";
|
||||
}
|
||||
|
||||
list album {
|
||||
key name;
|
||||
description
|
||||
"Represents one 'album' resource within one
|
||||
'artist' resource, within the jukebox library.";
|
||||
|
||||
leaf name {
|
||||
type string {
|
||||
length "1 .. max";
|
||||
}
|
||||
description
|
||||
"The name of the album.";
|
||||
}
|
||||
|
||||
leaf genre {
|
||||
type identityref { base genre; }
|
||||
description
|
||||
"The genre identifying the type of music on
|
||||
the album.";
|
||||
}
|
||||
|
||||
leaf year {
|
||||
type uint16 {
|
||||
range "1900 .. max";
|
||||
}
|
||||
description
|
||||
"The year the album was released.";
|
||||
}
|
||||
|
||||
container admin {
|
||||
description
|
||||
"Administrative information for the album.";
|
||||
|
||||
leaf label {
|
||||
type string;
|
||||
description
|
||||
"The label that released the album.";
|
||||
}
|
||||
leaf catalogue-number {
|
||||
type string;
|
||||
description
|
||||
"The album's catalogue number.";
|
||||
}
|
||||
}
|
||||
|
||||
list song {
|
||||
key name;
|
||||
description
|
||||
"Represents one 'song' resource within one
|
||||
'album' resource, within the jukebox library.";
|
||||
|
||||
leaf name {
|
||||
type string {
|
||||
length "1 .. max";
|
||||
}
|
||||
description
|
||||
"The name of the song.";
|
||||
}
|
||||
|
||||
leaf location {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"The file location string of the
|
||||
media file for the song.";
|
||||
}
|
||||
leaf format {
|
||||
type string;
|
||||
description
|
||||
"An identifier string for the media type
|
||||
for the file associated with the
|
||||
'location' leaf for this entry.";
|
||||
}
|
||||
leaf length {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
description
|
||||
"The duration of this song in seconds.";
|
||||
}
|
||||
} // end list 'song'
|
||||
} // end list 'album'
|
||||
} // end list 'artist'
|
||||
|
||||
leaf artist-count {
|
||||
type uint32;
|
||||
units "artists";
|
||||
config false;
|
||||
description
|
||||
"Number of artists in the library.";
|
||||
}
|
||||
leaf album-count {
|
||||
type uint32;
|
||||
units "albums";
|
||||
config false;
|
||||
description
|
||||
"Number of albums in the library.";
|
||||
}
|
||||
leaf song-count {
|
||||
type uint32;
|
||||
units "songs";
|
||||
config false;
|
||||
description
|
||||
"Number of songs in the library.";
|
||||
}
|
||||
} // end library
|
||||
|
||||
list playlist {
|
||||
key name;
|
||||
description
|
||||
"Example configuration data resource.";
|
||||
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"The name of the playlist.";
|
||||
}
|
||||
leaf description {
|
||||
type string;
|
||||
description
|
||||
"A comment describing the playlist.";
|
||||
}
|
||||
list song {
|
||||
key index;
|
||||
ordered-by user;
|
||||
|
||||
description
|
||||
"Example nested configuration data resource.";
|
||||
|
||||
leaf index { // not really needed
|
||||
type uint32;
|
||||
description
|
||||
"An arbitrary integer index for this playlist song.";
|
||||
}
|
||||
leaf id {
|
||||
type instance-identifier;
|
||||
mandatory true;
|
||||
description
|
||||
"Song identifier. Must identify an instance of
|
||||
/jukebox/library/artist/album/song/name.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container player {
|
||||
description
|
||||
"Represents the jukebox player resource.";
|
||||
|
||||
leaf gap {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
range "0.0 .. 2.0";
|
||||
}
|
||||
units "tenths of seconds";
|
||||
description
|
||||
"Time gap between each song.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc play {
|
||||
description
|
||||
"Control function for the jukebox player.";
|
||||
input {
|
||||
leaf playlist {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"The playlist name.";
|
||||
}
|
||||
leaf song-number {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description
|
||||
"Song number in playlist to play.";
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf-list extra{
|
||||
type string;
|
||||
ordered-by user;
|
||||
description "Extra added to test ordered-by user inserts on leaf-lists";
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
|
||||
|
|
@ -170,17 +170,17 @@ new "restconf DELETE whole datastore"
|
|||
expectfn 'curl -s -X DELETE http://localhost/restconf/data' 0 ""
|
||||
|
||||
new "restconf set protocol tcp+udp fail"
|
||||
expecteq "$(curl -s -X PUT http://localhost/restconf/data/system:system/protocol -d '{"system:protocol":{"tcp": [null], "udp": [null]}}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"udp"},"error-severity":"error","error-message":"Element in choice statement already exists"}}}
'
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/system:system/protocol -d '{"system:protocol":{"tcp": [null], "udp": [null]}}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"udp"},"error-severity":"error","error-message":"Element in choice statement already exists"}}}
'
|
||||
|
||||
new "restconf set protocol tcp"
|
||||
expecteq "$(curl -s -X PUT http://localhost/restconf/data/system:system/protocol -d {\"system:protocol\":{\"tcp\":[null]}})" 0 ""
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/system:system/protocol -d {\"system:protocol\":{\"tcp\":[null]}})" 0 ""
|
||||
|
||||
new "restconf get protocol tcp"
|
||||
expecteq "$(curl -s -X GET http://localhost/restconf/data/system:system)" 0 '{"system:system":{"protocol":{"tcp":[null]}}}
|
||||
'
|
||||
|
||||
new "restconf set protocol tcp+udp fail"
|
||||
expecteq "$(curl -s -X PUT http://localhost/restconf/data/system:system/protocol -d '{"system:protocol":{"tcp": [null], "udp": [null]}}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"udp"},"error-severity":"error","error-message":"Element in choice statement already exists"}}}
'
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/system:system/protocol -d '{"system:protocol":{"tcp": [null], "udp": [null]}}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"udp"},"error-severity":"error","error-message":"Element in choice statement already exists"}}}
'
|
||||
|
||||
new "cli set protocol udp"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o set system protocol udp" 0 "^$"
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<
|
|||
# 2. set identity in other module with restconf , read it with restconf and netconf
|
||||
# 3. set identity in other module with netconf, read it with restconf and netconf
|
||||
new "restconf add own identity"
|
||||
expectpart "$(curl -s -i -X PUT http://localhost/restconf/data/example:crypto -d '{"example:crypto":"example:aes"}')" 0 'HTTP/1.1 201 Created'
|
||||
expectpart "$(curl -s -i -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/example:crypto -d '{"example:crypto":"example:aes"}')" 0 'HTTP/1.1 201 Created'
|
||||
|
||||
new "restconf get own identity"
|
||||
expectpart "$(curl -s -i -X GET http://localhost/restconf/data/example:crypto)" 0 'HTTP/1.1 200 OK' '{"example:crypto":"aes"}'
|
||||
|
|
@ -280,10 +280,10 @@ expectpart "$(curl -s -i -X DELETE http://localhost/restconf/data/example:crypt
|
|||
|
||||
# 2. set identity in other module with restconf , read it with restconf and netconf
|
||||
new "restconf add POST instead of PUT (should fail)"
|
||||
expectpart "$(curl -s -i -X POST http://localhost/restconf/data/example:crypto -d '{"example:crypto":"example-des:des3"}')" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"crypto"},"error-severity":"error","error-message":"Leaf contains sub-element"}}}'
|
||||
expectpart "$(curl -s -i -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/example:crypto -d '{"example:crypto":"example-des:des3"}')" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"crypto"},"error-severity":"error","error-message":"Leaf contains sub-element"}}}'
|
||||
|
||||
new "restconf add other (des) identity using POST"
|
||||
expectpart "$(curl -s -i -X POST http://localhost/restconf/data -d '{"example:crypto":"example-des:des3"}')" 0 'HTTP/1.1 201 Created' 'Location: http://localhost/restconf/data/example:crypto'
|
||||
expectpart "$(curl -s -i -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data -d '{"example:crypto":"example-des:des3"}')" 0 'HTTP/1.1 201 Created' 'Location: http://localhost/restconf/data/example:crypto'
|
||||
|
||||
new "restconf get other identity"
|
||||
expectpart "$(curl -s -i -X GET http://localhost/restconf/data/example:crypto)" 0 'HTTP/1.1 200 OK' '{"example:crypto":"example-des:des3"}'
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/nacm-exam
|
|||
|
||||
# explicitly disable nacm (regression on netgate bug)
|
||||
new "disable nacm"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": false}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-netconf-acm:enable-nacm": false}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||
|
||||
new "auth set authentication config"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><edit-config><target><candidate/></target><config>$RULES</config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
|
@ -157,7 +157,7 @@ expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/nacm-exam
|
|||
#----------------Enable NACM
|
||||
|
||||
new "enable nacm"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||
|
||||
new "admin get nacm"
|
||||
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" 0 '{"nacm-example:x":0}
|
||||
|
|
@ -171,13 +171,13 @@ new "guest get nacm"
|
|||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}
'
|
||||
|
||||
new "admin edit nacm"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"nacm-example:x":1}' http://localhost/restconf/data/nacm-example:x)" 0 ""
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"nacm-example:x":1}' http://localhost/restconf/data/nacm-example:x)" 0 ""
|
||||
|
||||
new "limited edit nacm"
|
||||
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"nacm-example:x": 2}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}
'
|
||||
expecteq "$(curl -u wilma:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"nacm-example:x": 2}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}
'
|
||||
|
||||
new "guest edit nacm"
|
||||
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"nacm-example:x": 3}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}
'
|
||||
expecteq "$(curl -u guest:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"nacm-example:x": 3}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}
'
|
||||
|
||||
new "Kill restconf daemon"
|
||||
stop_restconf
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ EOF
|
|||
;;
|
||||
esac
|
||||
new "edit new 99"
|
||||
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"nacm-example:x": 99}' http://localhost/restconf/data/nacm-example:x)" 0 "$ret"
|
||||
expecteq "$(curl -u guest:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"nacm-example:x": 99}' http://localhost/restconf/data/nacm-example:x)" 0 "$ret"
|
||||
|
||||
#----------- Then second get
|
||||
case "$ret3" in
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data)" 0 '{"da
|
|||
'
|
||||
|
||||
new "Set x to 0"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"nacm-example:x": 0}' http://localhost/restconf/data/nacm-example:x)" 0 ""
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"nacm-example:x": 0}' http://localhost/restconf/data/nacm-example:x)" 0 ""
|
||||
|
||||
new "auth get (no user: access denied)"
|
||||
expecteq "$(curl -sS -X GET -H \"Accept:\ application/yang-data+json\" http://localhost/restconf/data)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"access-denied","error-severity":"error","error-message":"The requested URL was unauthorized"}}}
'
|
||||
|
|
@ -181,13 +181,13 @@ new "guest get nacm"
|
|||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}
'
|
||||
|
||||
new "admin edit nacm"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"nacm-example:x": 1}' http://localhost/restconf/data/nacm-example:x)" 0 ""
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"nacm-example:x": 1}' http://localhost/restconf/data/nacm-example:x)" 0 ""
|
||||
|
||||
new "limited edit nacm"
|
||||
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"nacm-example:x": 2}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}
'
|
||||
expecteq "$(curl -u wilma:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"nacm-example:x": 2}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}
'
|
||||
|
||||
new "guest edit nacm"
|
||||
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"nacm-example:x": 3}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}
'
|
||||
expecteq "$(curl -u guest:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"nacm-example:x": 3}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}
'
|
||||
|
||||
new "cli show conf as admin"
|
||||
expectfn "$clixon_cli -1 -U andy -l o -f $cfg show conf" 0 "^x 1;$"
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ new "commit it"
|
|||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "enable nacm"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||
|
||||
#--------------- nacm enabled
|
||||
|
||||
|
|
@ -233,21 +233,21 @@ expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data)" 0 '{"i
|
|||
#------- RPC operation
|
||||
|
||||
new "admin rpc ok"
|
||||
expecteq "$(curl -u andy:bar -s -X POST -d '{"clixon-example:input":{"x":"78"}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"clixon-example:output":{"x":"78","y":"42"}}
|
||||
expecteq "$(curl -u andy:bar -s -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"78"}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"clixon-example:output":{"x":"78","y":"42"}}
|
||||
'
|
||||
|
||||
new "admin rpc netconf ok"
|
||||
expecteof "$clixon_netconf -U andy -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example xmlns="urn:example:clixon"><x>0</x></example></rpc>]]>]]>' 0 '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><x xmlns="urn:example:clixon">0</x><y xmlns="urn:example:clixon">42</y></rpc-reply>]]>]]>$'
|
||||
|
||||
new "limit rpc ok"
|
||||
expecteq "$(curl -u wilma:bar -s -X POST http://localhost/restconf/operations/clixon-example:example -d '{"clixon-example:input":{"x":42}}' )" 0 '{"clixon-example:output":{"x":"42","y":"42"}}
|
||||
expecteq "$(curl -u wilma:bar -s -X POST http://localhost/restconf/operations/clixon-example:example -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":42}}' )" 0 '{"clixon-example:output":{"x":"42","y":"42"}}
|
||||
'
|
||||
|
||||
new "limit rpc netconf ok"
|
||||
expecteof "$clixon_netconf -U wilma -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example xmlns="urn:example:clixon"><x>0</x></example></rpc>]]>]]>' 0 '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><x xmlns="urn:example:clixon">0</x><y xmlns="urn:example:clixon">42</y></rpc-reply>]]>]]>$'
|
||||
|
||||
new "guest rpc fail"
|
||||
expecteq "$(curl -u guest:bar -s -X POST http://localhost/restconf/operations/clixon-example:example -d '{"clixon-example:input":{"x":42}}' )" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}
'
|
||||
expecteq "$(curl -u guest:bar -s -X POST http://localhost/restconf/operations/clixon-example:example -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":42}}' )" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}
'
|
||||
|
||||
new "guest rpc netconf fail"
|
||||
expecteof "$clixon_netconf -U guest -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example xmlns="urn:example:clixon"><x>0</x></example></rpc>]]>]]>' 0 '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><rpc-error><error-type>application</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||
|
|
@ -255,7 +255,7 @@ expecteof "$clixon_netconf -U guest -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml
|
|||
#------------------ Set read-default permit
|
||||
|
||||
new "admin set read-default permit"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:read-default":"permit"}' http://localhost/restconf/data/ietf-netconf-acm:nacm/read-default)" 0 ""
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-netconf-acm:read-default":"permit"}' http://localhost/restconf/data/ietf-netconf-acm:nacm/read-default)" 0 ""
|
||||
|
||||
new "limit read ok"
|
||||
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate)" 0 '{"clixon-example:translate":[{"k":"key42","value":"val42"},{"k":"key43","value":"val43"}]}
|
||||
|
|
|
|||
|
|
@ -164,7 +164,8 @@ nacm(){
|
|||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "enable nacm"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||
expectpart "$(curl -u andy:bar -sS -X PUT -H 'Content-Type: application/yang-data+json' -d '{"ietf-netconf-acm:enable-nacm":true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||
# -H 'Content-Type: application/yang-data+json'
|
||||
}
|
||||
|
||||
#--------------- enable nacm
|
||||
|
|
@ -179,7 +180,7 @@ nacm
|
|||
# replace all, then must include NACM rules as well
|
||||
MSG="<data>$RULES</data>"
|
||||
new "update root list permit"
|
||||
expecteq "$(curl -u andy:bar -sS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data -d "$MSG")" 0 ''
|
||||
expectpart "$(curl -u andy:bar -sS -H 'Content-Type: application/yang-data+xml' -X PUT http://localhost/restconf/data -d "$MSG")" 0 ''
|
||||
|
||||
new "delete root list deny"
|
||||
expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}
'
|
||||
|
|
@ -238,13 +239,13 @@ expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data/nacm-
|
|||
|
||||
#----- default deny (clixon-example limit and guest have default access)
|
||||
new "default create list deny"
|
||||
expecteq "$(curl -u wilma:bar -sS -X PUT http://localhost/restconf/data/clixon-example:translate=key42 -d '{"clixon-example:translate": [{"k":"key42","value":"val42"}]}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}
'
|
||||
expecteq "$(curl -u wilma:bar -sS -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/clixon-example:translate=key42 -d '{"clixon-example:translate": [{"k":"key42","value":"val42"}]}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}
'
|
||||
|
||||
new "create list permit"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT http://localhost/restconf/data/clixon-example:translate=key42 -d '{"clixon-example:translate": [{"k":"key42","value":"val42"}]}')" 0 ''
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/clixon-example:translate=key42 -d '{"clixon-example:translate": [{"k":"key42","value":"val42"}]}')" 0 ''
|
||||
|
||||
new "default update list deny"
|
||||
expecteq "$(curl -u wilma:bar -sS -X PUT http://localhost/restconf/data/clixon-example:translate=key42 -d '{"clixon-example:translate": [{"k":"key42","value":"val99"}]}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}
'
|
||||
expecteq "$(curl -u wilma:bar -sS -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/clixon-example:translate=key42 -d '{"clixon-example:translate": [{"k":"key42","value":"val99"}]}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}
'
|
||||
|
||||
new "default delete list deny"
|
||||
expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data/clixon-example:translate=key42)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}
'
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ new "commit it"
|
|||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "enable nacm"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||
|
||||
#--------------- nacm enabled
|
||||
|
||||
|
|
@ -205,14 +205,14 @@ new "commit it"
|
|||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "enable nacm"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
|
||||
|
||||
# Rule 3: permit-edit-config
|
||||
new "permit-edit-config: limited ok restconf"
|
||||
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"nacm-example:x":2}' http://localhost/restconf/data/nacm-example:x)" 0 ''
|
||||
expecteq "$(curl -u wilma:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"nacm-example:x":2}' http://localhost/restconf/data/nacm-example:x)" 0 ''
|
||||
|
||||
new "permit-edit-config: guest fail restconf"
|
||||
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"nacm-example:x":2}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}
'
|
||||
expecteq "$(curl -u guest:bar -sS -X PUT -H "Content-Type: application/yang-data+json" -d '{"nacm-example:x":2}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}
'
|
||||
|
||||
new "Kill restconf daemon"
|
||||
stop_restconf
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ expecteq "$(curl -s -X GET http://localhost/.well-known/host-meta)" 0 "<XRD xmln
|
|||
</XRD>
"
|
||||
|
||||
new "restconf get restconf resource. RFC 8040 3.3 (json)"
|
||||
expecteq "$(curl -sG http://localhost/restconf)" 0 '{"ietf-restconf:restconf":{"data":{},"operations":{},"yang-library-version":"2016-06-21"}}
|
||||
expecteq "$(curl -sG -H "Accept: application/yang-data+json" http://localhost/restconf)" 0 '{"ietf-restconf:restconf":{"data":{},"operations":{},"yang-library-version":"2016-06-21"}}
|
||||
'
|
||||
|
||||
new "restconf get restconf resource. RFC 8040 3.3 (xml)"
|
||||
|
|
@ -108,10 +108,16 @@ expectfn "curl -s -I http://localhost/restconf/data" 0 "HTTP/1.1 200 OK"
|
|||
#Content-Type: application/yang-data+json"
|
||||
|
||||
new "restconf empty rpc"
|
||||
expecteq "$(curl -s -X POST -d {\"clixon-example:input\":null} http://localhost/restconf/operations/clixon-example:empty)" 0 ""
|
||||
expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-example:input\":null} http://localhost/restconf/operations/clixon-example:empty)" 0 "HTTP/1.1 204 No Content"
|
||||
|
||||
new "restconf empty rpc, default media type should fail"
|
||||
expectpart "$(curl -si -X POST -d {\"clixon-example:input\":null} http://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 415 Unsupported Media Type'
|
||||
|
||||
new "restconf empty rpc, default media type should fail (JSON)"
|
||||
expectpart "$(curl -si -X POST -H "Accept: application/yang-data+json" -d {\"clixon-example:input\":null} http://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 415 Unsupported Media Type'
|
||||
|
||||
new "restconf empty rpc with extra args (should fail)"
|
||||
expecteq "$(curl -s -X POST -d {\"clixon-example:input\":{\"extra\":null}} http://localhost/restconf/operations/clixon-example:empty)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"extra"},"error-severity":"error"}}}
'
|
||||
expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-example:input\":{\"extra\":null}} http://localhost/restconf/operations/clixon-example:empty)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"extra"},"error-severity":"error"}}}
'
|
||||
|
||||
new "restconf get empty config + state json"
|
||||
expecteq "$(curl -sS -X GET http://localhost/restconf/data/clixon-example:state)" 0 '{"clixon-example:state":{"op":["42","41","43"]}}
|
||||
|
|
@ -160,10 +166,10 @@ expecteq "$(curl -s -X GET http://localhost/restconf/data/clixon-example:state)"
|
|||
|
||||
# Exact match
|
||||
new "restconf Add subtree eth/0/0 to datastore using POST"
|
||||
expectfn 'curl -s -i -X POST -H "Accept: application/yang-data+json" -d {"ietf-interfaces:interfaces":{"interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}} http://localhost/restconf/data' 0 'HTTP/1.1 201 Created'
|
||||
expectpart "$(curl -s -i -X POST -H "Accept: application/yang-data+json" -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interfaces":{"interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}}' http://localhost/restconf/data)" 0 'HTTP/1.1 201 Created' 'Location: http://localhost/restconf/data/ietf-interfaces:interfaces'
|
||||
|
||||
new "restconf Re-add subtree eth/0/0 which should give error"
|
||||
expectfn 'curl -s -X POST -d {"ietf-interfaces:interfaces":{"interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}} http://localhost/restconf/data' 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}'
|
||||
expectpart "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interfaces":{"interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}}' http://localhost/restconf/data)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}'
|
||||
|
||||
# XXX Cant get this to work
|
||||
#expecteq "$(curl -s -X POST -d {\"interfaces\":{\"interface\":{\"name\":\"eth/0/0\",\"type\":\"clixon-example:eth\",\"enabled\":true}}} http://localhost/restconf/data)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}'
|
||||
|
|
@ -180,22 +186,21 @@ expectfn "curl -sG http://localhost/restconf/data/clixon-example:state" 0 "$stat
|
|||
"
|
||||
|
||||
new "restconf Add interfaces subtree eth/0/0 using POST"
|
||||
expectpart "$(curl -s -X POST http://localhost/restconf/data/ietf-interfaces:interfaces -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}')" 0 ""
|
||||
#expectfn 'curl -s -X POST http://localhost/restconf/data/ietf-interfaces:interfaces -d {"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' 0 ""
|
||||
expectpart "$(curl -s -X POST http://localhost/restconf/data/ietf-interfaces:interfaces -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}')" 0 ""
|
||||
|
||||
new "restconf Check eth/0/0 added config"
|
||||
expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up"}]}}
|
||||
expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up"}\]}}
|
||||
'
|
||||
|
||||
new "restconf Check eth/0/0 added state"
|
||||
expecteq "$(curl -s -G http://localhost/restconf/data/clixon-example:state)" 0 '{"clixon-example:state":{"op":["42","41","43"]}}
|
||||
expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/clixon-example:state)" 0 '{"clixon-example:state":{"op":\["42","41","43"\]}}
|
||||
'
|
||||
|
||||
new "restconf Re-post eth/0/0 which should generate error"
|
||||
expecteq "$(curl -s -X POST -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}
'
|
||||
expectpart "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}
'
|
||||
|
||||
new "Add leaf description using POST"
|
||||
expecteq "$(curl -s -X POST -d '{"ietf-interfaces:description":"The-first-interface"}' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 ""
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:description":"The-first-interface"}' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 ""
|
||||
|
||||
new "Add nothing using POST"
|
||||
expectfn 'curl -s -X POST http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0' 0 '"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":" on line 1: syntax error at or before:'
|
||||
|
|
@ -214,33 +219,33 @@ new "restconf Re-Delete eth/0/0 using none should generate error"
|
|||
expecteq "$(curl -s -X DELETE http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-missing","error-severity":"error","error-message":"Data does not exist; cannot delete resource"}}}
'
|
||||
|
||||
new "restconf Add subtree eth/0/0 using PUT"
|
||||
expecteq "$(curl -s -X PUT -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 ""
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 ""
|
||||
|
||||
new "restconf get subtree"
|
||||
expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up"}]}}
|
||||
'
|
||||
|
||||
new "restconf rpc using POST json"
|
||||
expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"x":42}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"clixon-example:output":{"x":"42","y":"42"}}
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":42}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"clixon-example:output":{"x":"42","y":"42"}}
|
||||
'
|
||||
|
||||
new "restconf rpc using POST json wrong"
|
||||
expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"wrongelement"},"error-severity":"error"}}}
'
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"wrongelement"},"error-severity":"error"}}}
'
|
||||
|
||||
new "restconf rpc non-existing rpc without namespace"
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/kalle)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}}
'
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/kalle)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}}
'
|
||||
|
||||
new "restconf rpc non-existing rpc"
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/clixon-example:kalle)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}}
'
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/clixon-example:kalle)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}}
'
|
||||
|
||||
new "restconf rpc missing name"
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"Operation name expected"}}}
'
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"Operation name expected"}}}
'
|
||||
|
||||
new "restconf rpc missing input"
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"restconf RPC does not have input statement"}}}
'
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"restconf RPC does not have input statement"}}}
'
|
||||
|
||||
new "restconf rpc using POST xml"
|
||||
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":42}}' http://localhost/restconf/operations/clixon-example:example)
|
||||
ret=$(curl -s -X POST -H "Content-Type: application/yang-data+json" -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":42}}' http://localhost/restconf/operations/clixon-example:example)
|
||||
expect='<output xmlns="urn:example:clixon"><x>42</x><y>42</y></output>'
|
||||
match=`echo $ret | grep -EZo "$expect"`
|
||||
if [ -z "$match" ]; then
|
||||
|
|
@ -248,10 +253,10 @@ if [ -z "$match" ]; then
|
|||
fi
|
||||
|
||||
new "restconf rpc using wrong prefix"
|
||||
expecteq "$(curl -s -X POST -d '{"wrong:input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/wrong:example)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"yang module not found"}}}
'
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"wrong:input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/wrong:example)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"yang module not found"}}}
'
|
||||
|
||||
new "restconf local client rpc using POST xml"
|
||||
ret=$(curl -s -i -X POST -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":"example"}}' http://localhost/restconf/operations/clixon-example:client-rpc)
|
||||
ret=$(curl -s -i -X POST -H "Content-Type: application/yang-data+json" -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":"example"}}' http://localhost/restconf/operations/clixon-example:client-rpc)
|
||||
expect='<output xmlns="urn:example:clixon"><x>example</x></output>'
|
||||
match=`echo $ret | grep -EZo "$expect"`
|
||||
if [ -z "$match" ]; then
|
||||
|
|
@ -259,10 +264,10 @@ if [ -z "$match" ]; then
|
|||
fi
|
||||
|
||||
new "restconf Add subtree without key (expected error)"
|
||||
expecteq "$(curl -s -X PUT -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces/interface)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"malformed key, expected '"'"'=restval'"'"'"}}}
'
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces/interface)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"malformed key, expected '"'"'=restval'"'"'"}}}
'
|
||||
|
||||
new "restconf Add subtree with too many keys (expected error)"
|
||||
expecteq "$(curl -s -X PUT -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=a,b)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"List key interface length mismatch"}}}
'
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=a,b)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"List key interface length mismatch"}}}
'
|
||||
|
||||
new "Kill restconf daemon"
|
||||
stop_restconf
|
||||
|
|
|
|||
|
|
@ -90,13 +90,13 @@ wait_backend
|
|||
wait_restconf
|
||||
|
||||
new "restconf POST tree without key"
|
||||
expectfn 'curl -s -X POST -d {"example:cont1":{"interface":{"type":"regular"}}} http://localhost/restconf/data' 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"name"},"error-severity":"error","error-message":"Mandatory key"}}}
'
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"example:cont1":{"interface":{"type":"regular"}}}' http://localhost/restconf/data)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"name"},"error-severity":"error","error-message":"Mandatory key"}}}
'
|
||||
|
||||
new "restconf POST initial tree"
|
||||
expectfn 'curl -s -X POST -d {"example:cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 ""
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}' http://localhost/restconf/data)" 0 ""
|
||||
|
||||
new "restconf POST top without namespace"
|
||||
expectfn 'curl -s -X POST -d {"cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"cont1"},"error-severity":"error","error-message":"Unassigned yang spec"}}}'
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"cont1":{"interface":{"name":"local0","type":"regular"}}}' http://localhost/restconf/data)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"cont1"},"error-severity":"error","error-message":"Unassigned yang spec"}}}
'
|
||||
|
||||
new "restconf GET datastore initial"
|
||||
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1":{"interface":\[{"name":"local0","type":"regular"}\]}}'
|
||||
|
|
@ -116,22 +116,22 @@ new "restconf GET if-type"
|
|||
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1/interface=local0/type" 0 '{"example:type":"regular"}'
|
||||
|
||||
new "restconf POST interface without mandatory type"
|
||||
expectfn 'curl -s -X POST http://localhost/restconf/data/example:cont1 -d {"example:interface":{"name":"TEST"}}' 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"type"},"error-severity":"error","error-message":"Mandatory variable"}}}
'
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/example:cont1 -d '{"example:interface":{"name":"TEST"}}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"type"},"error-severity":"error","error-message":"Mandatory variable"}}}
'
|
||||
|
||||
new "restconf POST interface without mandatory key"
|
||||
expectfn 'curl -s -X POST http://localhost/restconf/data/example:cont1 -d {"example:interface":{"type":"regular"}}' 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"name"},"error-severity":"error","error-message":"Mandatory key"}}}
'
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/example:cont1 -d '{"example:interface":{"type":"regular"}}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"name"},"error-severity":"error","error-message":"Mandatory key"}}}
'
|
||||
|
||||
new "restconf POST interface"
|
||||
expectfn 'curl -s -X POST -d {"example:interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/example:cont1' 0 ""
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"example:interface":{"name":"TEST","type":"eth0"}}' http://localhost/restconf/data/example:cont1)" 0 ""
|
||||
|
||||
new "restconf POST interface without namespace"
|
||||
expectfn 'curl -s -X POST -d {"interface":{"name":"TEST2","type":"eth0"}} http://localhost/restconf/data/example:cont1' 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"Data is not prefixed with matching namespace"}}}'
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"interface":{"name":"TEST2","type":"eth0"}}' http://localhost/restconf/data/example:cont1)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"Data is not prefixed with matching namespace"}}}
'
|
||||
|
||||
new "restconf POST again"
|
||||
expecteq "$(curl -s -X POST -d '{"example:interface":{"name":"TEST","type":"eth0"}}' http://localhost/restconf/data/example:cont1)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}
'
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"example:interface":{"name":"TEST","type":"eth0"}}' http://localhost/restconf/data/example:cont1)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}
'
|
||||
|
||||
new "restconf POST from top"
|
||||
expecteq "$(curl -s -X POST -d '{"example:cont1":{"interface":{"name":"TEST","type":"eth0"}}}' http://localhost/restconf/data)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}
'
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"example:cont1":{"interface":{"name":"TEST","type":"eth0"}}}' http://localhost/restconf/data)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}
'
|
||||
|
||||
new "restconf DELETE"
|
||||
expectfn 'curl -s -X DELETE http://localhost/restconf/data/example:cont1' 0 ""
|
||||
|
|
@ -140,7 +140,7 @@ new "restconf GET null datastore"
|
|||
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"ietf-restconf:errors":{"error":{"rpc-error":{"error-type":"application","error-tag":"invalid-value","error-severity":"error","error-message":"Instance does not exist"}}}}'
|
||||
|
||||
new "restconf POST initial tree"
|
||||
expectfn 'curl -s -X POST -d {"example:cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 ""
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}' http://localhost/restconf/data)" 0 ""
|
||||
|
||||
new "restconf GET initial tree"
|
||||
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1":{"interface":\[{"name":"local0","type":"regular"}\]}}'
|
||||
|
|
@ -152,41 +152,41 @@ new "restconf GET null datastore"
|
|||
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"ietf-restconf:errors":{"error":{"rpc-error":{"error-type":"application","error-tag":"invalid-value","error-severity":"error","error-message":"Instance does not exist"}}}}'
|
||||
|
||||
new "restconf PUT initial datastore"
|
||||
expectfn 'curl -s -X PUT -d {"data":{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' 0 ""
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" -d '{"data":{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}}' http://localhost/restconf/data)" 0 ""
|
||||
|
||||
new "restconf GET datastore"
|
||||
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1":{"interface":\[{"name":"local0","type":"regular"}\]}}'
|
||||
|
||||
new "restconf PUT replace datastore"
|
||||
expectfn 'curl -s -X PUT -d {"data":{"example:cont2":{"name":"foo"}}} http://localhost/restconf/data' 0 ""
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" -d '{"data":{"example:cont2":{"name":"foo"}}}' http://localhost/restconf/data)" 0 ""
|
||||
|
||||
new "restconf GET replaced datastore"
|
||||
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont2" 0 '{"example:cont2":{"name":"foo"}}'
|
||||
|
||||
new "restconf PUT initial datastore again"
|
||||
expectfn 'curl -s -X PUT -d {"data":{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' 0 ""
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" -d '{"data":{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}}' http://localhost/restconf/data)" 0 ""
|
||||
|
||||
new "restconf PUT change interface"
|
||||
expectfn 'curl -s -X PUT -d {"example:interface":{"name":"local0","type":"atm0"}} http://localhost/restconf/data/example:cont1/interface=local0' 0 ""
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" -d '{"example:interface":{"name":"local0","type":"atm0"}}' http://localhost/restconf/data/example:cont1/interface=local0)" 0 ""
|
||||
|
||||
new "restconf GET datastore atm"
|
||||
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1":{"interface":\[{"name":"local0","type":"atm0"}\]}}'
|
||||
|
||||
new "restconf PUT add interface"
|
||||
expectfn 'curl -s -X PUT -d {"example:interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 ""
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" -d '{"example:interface":{"name":"TEST","type":"eth0"}}' http://localhost/restconf/data/example:cont1/interface=TEST)" 0 ""
|
||||
|
||||
new "restconf PUT change key error"
|
||||
expectfn 'curl -is -X PUT -d {"example:interface":{"name":"ALPHA","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"api-path keys do not match data keys"}}}'
|
||||
expectpart "$(curl -is -X PUT -H "Content-Type: application/yang-data+json" -d '{"example:interface":{"name":"ALPHA","type":"eth0"}}' http://localhost/restconf/data/example:cont1/interface=TEST)" 0 'HTTP/1.1 412 Precondition Failed' '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"api-path keys do not match data keys"}}}
'
|
||||
|
||||
new "restconf PUT change type to eth0 (non-key sub-element to list)"
|
||||
expectfn 'curl -s -X PUT -d {"example:type":"eth0"} http://localhost/restconf/data/example:cont1/interface=local0/type' 0 ""
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" -d '{"example:type":"eth0"}' http://localhost/restconf/data/example:cont1/interface=local0/type)" 0 ""
|
||||
|
||||
new "restconf GET datastore eth"
|
||||
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1/interface=local0" 0 '{"example:interface":\[{"name":"local0","type":"eth0"}\]}'
|
||||
|
||||
#--------------- json type tests
|
||||
new "restconf POST type x3"
|
||||
expectfn 'curl -s -X POST -d {"example:types":{"tint":42,"tdec64":42.123,"tbool":false,"tstr":"str"}} http://localhost/restconf/data' 0 ''
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"example:types":{"tint":42,"tdec64":42.123,"tbool":false,"tstr":"str"}}' http://localhost/restconf/data)" 0 ''
|
||||
|
||||
new "restconf POST type x3"
|
||||
expectfn 'curl -s -X GET http://localhost/restconf/data/example:types' 0 '{"example:types":{"tint":42,"tdec64":42.123,"tbool":false,"tstr":"str"}}'
|
||||
|
|
|
|||
|
|
@ -6,6 +6,12 @@
|
|||
# instance that does not exist, then an error response containing a "404 Not
|
||||
# Found" status-line MUST be returned by the server. The error-tag
|
||||
# value "invalid-value" is used in this case.
|
||||
# RFC 7231:
|
||||
# Response messages with an error status code
|
||||
# usually contain a payload that represents the error condition, such
|
||||
# that it describes the error state and what next steps are suggested
|
||||
# for resolving it.
|
||||
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@ s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
|||
APPNAME=example
|
||||
|
||||
cfg=$dir/conf.xml
|
||||
fyang=$dir/example-jukebox.yang
|
||||
fxml=$dir/initial.xml
|
||||
fjukebox=$dir/example-jukebox.yang
|
||||
|
||||
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
|
||||
cat <<EOF > $cfg
|
||||
|
|
@ -16,7 +15,7 @@ cat <<EOF > $cfg
|
|||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
|
||||
<CLICON_YANG_MAIN_FILE>$fjukebox</CLICON_YANG_MAIN_FILE>
|
||||
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
||||
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||
|
|
@ -26,269 +25,8 @@ cat <<EOF > $cfg
|
|||
</clixon-config>
|
||||
EOF
|
||||
|
||||
cat <<EOF > $fyang
|
||||
module example-jukebox {
|
||||
|
||||
namespace "http://example.com/ns/example-jukebox";
|
||||
prefix "jbox";
|
||||
|
||||
organization "Example, Inc.";
|
||||
contact "support at example.com";
|
||||
description "Example Jukebox Data Model Module.";
|
||||
revision "2016-08-15" {
|
||||
description "Initial version.";
|
||||
reference "example.com document 1-4673.";
|
||||
}
|
||||
|
||||
identity genre {
|
||||
description
|
||||
"Base for all genre types.";
|
||||
}
|
||||
|
||||
// abbreviated list of genre classifications
|
||||
identity alternative {
|
||||
base genre;
|
||||
description
|
||||
"Alternative music.";
|
||||
}
|
||||
identity blues {
|
||||
base genre;
|
||||
description
|
||||
"Blues music.";
|
||||
}
|
||||
identity country {
|
||||
base genre;
|
||||
description
|
||||
"Country music.";
|
||||
}
|
||||
identity jazz {
|
||||
base genre;
|
||||
description
|
||||
"Jazz music.";
|
||||
}
|
||||
identity pop {
|
||||
base genre;
|
||||
description
|
||||
"Pop music.";
|
||||
}
|
||||
identity rock {
|
||||
base genre;
|
||||
description
|
||||
"Rock music.";
|
||||
}
|
||||
|
||||
container jukebox {
|
||||
presence
|
||||
"An empty container indicates that the jukebox
|
||||
service is available.";
|
||||
|
||||
description
|
||||
"Represents a 'jukebox' resource, with a library, playlists,
|
||||
and a 'play' operation.";
|
||||
|
||||
container library {
|
||||
|
||||
description
|
||||
"Represents the 'jukebox' library resource.";
|
||||
|
||||
list artist {
|
||||
key name;
|
||||
description
|
||||
"Represents one 'artist' resource within the
|
||||
'jukebox' library resource.";
|
||||
|
||||
leaf name {
|
||||
type string {
|
||||
length "1 .. max";
|
||||
}
|
||||
description
|
||||
"The name of the artist.";
|
||||
}
|
||||
|
||||
list album {
|
||||
key name;
|
||||
description
|
||||
"Represents one 'album' resource within one
|
||||
'artist' resource, within the jukebox library.";
|
||||
|
||||
leaf name {
|
||||
type string {
|
||||
length "1 .. max";
|
||||
}
|
||||
description
|
||||
"The name of the album.";
|
||||
}
|
||||
|
||||
leaf genre {
|
||||
type identityref { base genre; }
|
||||
description
|
||||
"The genre identifying the type of music on
|
||||
the album.";
|
||||
}
|
||||
|
||||
leaf year {
|
||||
type uint16 {
|
||||
range "1900 .. max";
|
||||
}
|
||||
description
|
||||
"The year the album was released.";
|
||||
}
|
||||
|
||||
container admin {
|
||||
description
|
||||
"Administrative information for the album.";
|
||||
|
||||
leaf label {
|
||||
type string;
|
||||
description
|
||||
"The label that released the album.";
|
||||
}
|
||||
leaf catalogue-number {
|
||||
type string;
|
||||
description
|
||||
"The album's catalogue number.";
|
||||
}
|
||||
}
|
||||
|
||||
list song {
|
||||
key name;
|
||||
description
|
||||
"Represents one 'song' resource within one
|
||||
'album' resource, within the jukebox library.";
|
||||
|
||||
leaf name {
|
||||
type string {
|
||||
length "1 .. max";
|
||||
}
|
||||
description
|
||||
"The name of the song.";
|
||||
}
|
||||
|
||||
leaf location {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"The file location string of the
|
||||
media file for the song.";
|
||||
}
|
||||
leaf format {
|
||||
type string;
|
||||
description
|
||||
"An identifier string for the media type
|
||||
for the file associated with the
|
||||
'location' leaf for this entry.";
|
||||
}
|
||||
leaf length {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
description
|
||||
"The duration of this song in seconds.";
|
||||
}
|
||||
} // end list 'song'
|
||||
} // end list 'album'
|
||||
} // end list 'artist'
|
||||
|
||||
leaf artist-count {
|
||||
type uint32;
|
||||
units "artists";
|
||||
config false;
|
||||
description
|
||||
"Number of artists in the library.";
|
||||
}
|
||||
leaf album-count {
|
||||
type uint32;
|
||||
units "albums";
|
||||
config false;
|
||||
description
|
||||
"Number of albums in the library.";
|
||||
}
|
||||
leaf song-count {
|
||||
type uint32;
|
||||
units "songs";
|
||||
config false;
|
||||
description
|
||||
"Number of songs in the library.";
|
||||
}
|
||||
} // end library
|
||||
|
||||
list playlist {
|
||||
key name;
|
||||
description
|
||||
"Example configuration data resource.";
|
||||
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"The name of the playlist.";
|
||||
}
|
||||
leaf description {
|
||||
type string;
|
||||
description
|
||||
"A comment describing the playlist.";
|
||||
}
|
||||
list song {
|
||||
key index;
|
||||
ordered-by user;
|
||||
|
||||
description
|
||||
"Example nested configuration data resource.";
|
||||
|
||||
leaf index { // not really needed
|
||||
type uint32;
|
||||
description
|
||||
"An arbitrary integer index for this playlist song.";
|
||||
}
|
||||
leaf id {
|
||||
type instance-identifier;
|
||||
mandatory true;
|
||||
description
|
||||
"Song identifier. Must identify an instance of
|
||||
/jukebox/library/artist/album/song/name.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container player {
|
||||
description
|
||||
"Represents the jukebox player resource.";
|
||||
|
||||
leaf gap {
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
range "0.0 .. 2.0";
|
||||
}
|
||||
units "tenths of seconds";
|
||||
description
|
||||
"Time gap between each song.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc play {
|
||||
description
|
||||
"Control function for the jukebox player.";
|
||||
input {
|
||||
leaf playlist {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"The playlist name.";
|
||||
}
|
||||
leaf song-number {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description
|
||||
"Song number in playlist to play.";
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf-list extra{
|
||||
type string;
|
||||
ordered-by user;
|
||||
description "Extra added to test ordered-by user inserts on leaf-lists";
|
||||
}
|
||||
}
|
||||
EOF
|
||||
# Common Jukebox spec (fjukebox must be set)
|
||||
. ./jukebox.sh
|
||||
|
||||
new "test params: -f $cfg"
|
||||
|
||||
|
|
|
|||
|
|
@ -88,65 +88,64 @@ wait_backend
|
|||
wait_restconf
|
||||
|
||||
new "restconf PUT add whole list entry"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"list:a":{"b":"x","c":"y","nonkey":"0"}}' 0 ''
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x,y -d '{"list:a":{"b":"x","c":"y","nonkey":"0"}}')" 0 ''
|
||||
|
||||
new "restconf PUT add whole list entry XML"
|
||||
expecteq "$(curl -s -X PUT -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '<a xmlns="urn:example:clixon"><b>xx</b><c>xy</c><nonkey>0</nonkey></a>' http://localhost/restconf/data/list:c/a=xx,xy)" 0 ''
|
||||
|
||||
|
||||
new "restconf PUT change whole list entry (same keys)"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"list:a":{"b":"x","c":"y","nonkey":"z"}}' 0 ''
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x,y -d '{"list:a":{"b":"x","c":"y","nonkey":"z"}}')" 0 ''
|
||||
|
||||
new "restconf PUT change whole list entry (no namespace)(expect fail)"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"a":{"b":"x","c":"y","nonkey":"z"}}' 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"Data is not prefixed with matching namespace"}}}'
|
||||
expectpart "$(curl -is -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x,y -d '{"a":{"b":"x","c":"y","nonkey":"z"}}')" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"Data is not prefixed with matching namespace"}}}
'
|
||||
|
||||
new "restconf PUT change list entry (wrong keys)(expect fail)"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"list:a":{"b":"y","c":"x"}}' 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"api-path keys do not match data keys"}}}'
|
||||
expectpart "$(curl -is -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x,y -d '{"list:a":{"b":"y","c":"x"}}')" 0 '412 Precondition Failed' '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"api-path keys do not match data keys"}}}
'
|
||||
|
||||
new "restconf PUT change list entry (wrong keys)(expect fail) XML"
|
||||
expecteq "$(curl -s -X PUT -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '<a xmlns="urn:example:clixon"><b>xy</b><c>xz</c><nonkey>0</nonkey></a>' http://localhost/restconf/data/list:c/a=xx,xy)" 0 '<errors xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf"><error><error-type>protocol</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>api-path keys do not match data keys</error-message></error></errors>
'
|
||||
|
||||
new "restconf PUT change list entry (just one key)(expect fail)"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x -d {"list:a":{"b":"x"}}' 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"List key a length mismatch"}}}
'
|
||||
expectpart "$(curl -is -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x -d '{"list:a":{"b":"x"}}')" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"List key a length mismatch"}}}
'
|
||||
|
||||
new "restconf PUT sub non-key"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/nonkey -d {"list:nonkey":"u"}' 0 ''
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x,y/nonkey -d '{"list:nonkey":"u"}')" 0 ''
|
||||
|
||||
new "restconf PUT sub key same value"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/b -d {"list:b":"x"}' 0 ''
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x,y/b -d '{"list:b":"x"}')" 0 ''
|
||||
|
||||
new "restconf PUT just key other value (should fail)ZX"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x/b -d {"b":"y"}' 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"List key a length mismatch"}}}'
|
||||
new "restconf PUT just key other value (should fail)"
|
||||
expectpart "$(curl -is -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x/b -d '{"b":"y"}')" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"List key a length mismatch"}}}'
|
||||
|
||||
new "restconf PUT add leaf-list entry"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/d=x -d {"list:d":"x"}' 0 ''
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/d=x -d '{"list:d":"x"}')" 0 ''
|
||||
|
||||
new "restconf PUT change leaf-list entry (expect fail)"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/d=x -d {"list:d":"y"}' 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"api-path keys do not match data keys"}}}'
|
||||
expectpart "$(curl -is -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/d=x -d '{"list:d":"y"}')" 0 'HTTP/1.1 412 Precondition Failed' '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"api-path keys do not match data keys"}}}'
|
||||
|
||||
new "restconf PUT list-list"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/e=z -d {"list:e":{"f":"z","nonkey":"0"}}' 0 ''
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x,y/e=z -d '{"list:e":{"f":"z","nonkey":"0"}}')" 0 ''
|
||||
|
||||
new "restconf PUT change list-lst entry (wrong keys)(expect fail)"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/e=z -d {"list:e":{"f":"wrong","nonley":"0"}}' 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"api-path keys do not match data keys"}}}'
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x,y/e=z -d '{"list:e":{"f":"wrong","nonley":"0"}}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"api-path keys do not match data keys"}}}
'
|
||||
|
||||
new "restconf PUT list-list sub non-key"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/e=z/nonkey -d {"list:nonkey":"u"}' 0 ''
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x,y/e=z/nonkey -d '{"list:nonkey":"u"}')" 0 ''
|
||||
|
||||
new "restconf PUT list-list single first key"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x/e=z/f -d {"f":"z"}' 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"List key a length mismatch"}}}'
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x/e=z/f -d '{"f":"z"}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"List key a length mismatch"}}}
'
|
||||
|
||||
new "restconf PUT list-list just key ok"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/e=z/f -d {"list:f":"z"}' 0 ''
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x,y/e=z/f -d '{"list:f":"z"}')" 0 ''
|
||||
|
||||
new "restconf PUT list-list just key just key wrong value (should fail)"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/e=z/f -d {"list:f":"wrong"}' 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"api-path keys do not match data keys"}}}'
|
||||
expectpart "$(curl -is -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x,y/e=z/f -d '{"list:f":"wrong"}')" 0 'HTTP/1.1 412 Precondition Failed' '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"api-path keys do not match data keys"}}}
'
|
||||
|
||||
new "restconf PUT add list+leaf-list entry"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/f=u -d {"list:f":"u"}' 0 ''
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x,y/f=u -d '{"list:f":"u"}')" 0 ''
|
||||
|
||||
new "restconf PUT change list+leaf-list entry (expect fail)"
|
||||
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/f=u -d {"list:f":"w"}' 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"api-path keys do not match data keys"}}}'
|
||||
expectpart "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/list:c/a=x,y/f=u -d '{"list:f":"w"}')" 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"api-path keys do not match data keys"}}}'
|
||||
|
||||
|
||||
new "Kill restconf daemon"
|
||||
|
|
|
|||
69
test/test_restconf_patch.sh
Executable file
69
test/test_restconf_patch.sh
Executable file
|
|
@ -0,0 +1,69 @@
|
|||
#!/bin/bash
|
||||
# Restconf RFC8040 plain patch
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
||||
APPNAME=example
|
||||
|
||||
cfg=$dir/conf.xml
|
||||
fjukebox=$dir/example-jukebox.yang
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MAIN_FILE>$fjukebox</CLICON_YANG_MAIN_FILE>
|
||||
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
||||
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||
<CLICON_BACKEND_PIDFILE>$dir/restconf.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||
</clixon-config>
|
||||
EOF
|
||||
|
||||
# Common Jukebox spec (fjukebox must be set)
|
||||
. ./jukebox.sh
|
||||
|
||||
new "test params: -f $cfg"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
sudo pkill clixon_backend # to be sure
|
||||
new "start backend -s init -f $cfg"
|
||||
start_backend -s init -f $cfg
|
||||
fi
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||
|
||||
new "start restconf daemon"
|
||||
start_restconf -f $cfg
|
||||
|
||||
new "waiting"
|
||||
wait_backend
|
||||
wait_restconf
|
||||
|
||||
|
||||
new "Kill restconf daemon"
|
||||
stop_restconf
|
||||
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
new "Kill backend"
|
||||
# Check if premature kill
|
||||
pid=`pgrep -u root -f clixon_backend`
|
||||
if [ -z "$pid" ]; then
|
||||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
stop_backend -f $cfg
|
||||
|
||||
rm -rf $dir
|
||||
|
|
@ -72,13 +72,13 @@ testrun(){
|
|||
wait_restconf
|
||||
|
||||
new "restconf put 42"
|
||||
expecteq "$(curl -s -X PUT http://localhost/restconf/data/example:x/y=42 -d '{"example:y":{"a":"42","b":"42"}}')" 0 ""
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/example:x/y=42 -d '{"example:y":{"a":"42","b":"42"}}')" 0 ""
|
||||
|
||||
new "restconf put 99"
|
||||
expecteq "$(curl -s -X PUT http://localhost/restconf/data/example:x/y=99 -d '{"example:y":{"a":"99","b":"99"}}')" 0 ""
|
||||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/example:x/y=99 -d '{"example:y":{"a":"99","b":"99"}}')" 0 ""
|
||||
|
||||
new "restconf post 123"
|
||||
expecteq "$(curl -s -X POST http://localhost/restconf/data/example:x -d '{"example:y":{"a":"123","b":"123"}}')" 0 ""
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/example:x -d '{"example:y":{"a":"123","b":"123"}}')" 0 ""
|
||||
|
||||
new "restconf delete 42"
|
||||
expecteq "$(curl -s -X DELETE http://localhost/restconf/data/example:x/y=42)" 0 ""
|
||||
|
|
|
|||
|
|
@ -70,36 +70,35 @@ new "netconf empty rpc"
|
|||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><empty xmlns="urn:example:clixon"/></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><ok/></rpc-reply>]]>]]>$'
|
||||
|
||||
new "restconf example rpc json/json default - no http media headers"
|
||||
expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"x":0}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"clixon-example:output":{"x":"0","y":"42"}}
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":0}}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 200 OK' 'Content-Type: application/yang-data+json' '{"clixon-example:output":{"x":"0","y":"42"}}
|
||||
'
|
||||
|
||||
new "restconf example rpc json/json change y default"
|
||||
expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"x":"0","y":"99"}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"clixon-example:output":{"x":"0","y":"99"}}
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"0","y":"99"}}' http://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+json' '{"clixon-example:output":{"x":"0","y":"99"}}
|
||||
'
|
||||
|
||||
new "restconf example rpc json/json"
|
||||
# XXX example:input example:output
|
||||
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+json' -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"clixon-example:output":{"x":"0","y":"42"}}
|
||||
expectpart "$(curl -is -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+json' -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+json' '{"clixon-example:output":{"x":"0","y":"42"}}
|
||||
'
|
||||
|
||||
new "restconf example rpc xml/json"
|
||||
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+json' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/clixon-example:example)" 0 '{"clixon-example:output":{"x":"0","y":"42"}}
|
||||
expectpart "$(curl -is -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+json' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+json' '{"clixon-example:output":{"x":"0","y":"42"}}
|
||||
'
|
||||
|
||||
new "restconf example rpc json/xml"
|
||||
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:example)" 0 '<output xmlns="urn:example:clixon"><x>0</x><y>42</y></output>
|
||||
expectpart "$(curl -is -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+xml' '<output xmlns="urn:example:clixon"><x>0</x><y>42</y></output>
|
||||
'
|
||||
|
||||
new "restconf example rpc xml/xml"
|
||||
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/clixon-example:example)" 0 '<output xmlns="urn:example:clixon"><x>0</x><y>42</y></output>
|
||||
expectpart "$(curl -is -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+xml' '<output xmlns="urn:example:clixon"><x>0</x><y>42</y></output>
|
||||
'
|
||||
|
||||
new "restconf example rpc xml in w json encoding (expect fail)"
|
||||
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/clixon-example:example)" 0 "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>rpc</error-type><error-tag>malformed-message</error-tag><error-severity>error</error-severity><error-message> on line 1: syntax error at or before: '<'</error-message></error></errors>
"
|
||||
|
||||
expectpart "$(curl -is -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Reques' "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>rpc</error-type><error-tag>malformed-message</error-tag><error-severity>error</error-severity><error-message> on line 1: syntax error at or before: '<'</error-message></error></errors>
"
|
||||
|
||||
new "restconf example rpc json in xml encoding (expect fail)"
|
||||
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:example)" 0 '<errors xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf"><error><error-type>rpc</error-type><error-tag>malformed-message</error-tag><error-severity>error</error-severity><error-message>xml_parse: line 0: syntax error: at or before: "</error-message></error></errors>
'
|
||||
expectpart "$(curl -is -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Reques' '<errors xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf"><error><error-type>rpc</error-type><error-tag>malformed-message</error-tag><error-severity>error</error-severity><error-message>xml_parse: line 0: syntax error: at or before: "</error-message></error></errors>
'
|
||||
|
||||
new "netconf example rpc"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example xmlns="urn:example:clixon"><x>0</x></example></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><x xmlns="urn:example:clixon">0</x><y xmlns="urn:example:clixon">42</y></rpc-reply>]]>]]>$'
|
||||
|
|
@ -107,7 +106,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netco
|
|||
# 2. Then error cases
|
||||
#
|
||||
new "restconf empty rpc with null input"
|
||||
ret=$(curl -is -X POST -d '{"clixon-example:input":null}' http://localhost/restconf/operations/clixon-example:empty)
|
||||
ret=$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":null}' http://localhost/restconf/operations/clixon-example:empty)
|
||||
expect="204 No Content"
|
||||
match=`echo $ret | grep -EZo "$expect"`
|
||||
if [ -z "$match" ]; then
|
||||
|
|
@ -115,11 +114,11 @@ if [ -z "$match" ]; then
|
|||
fi
|
||||
|
||||
new "restconf empty rpc with input x"
|
||||
expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"x":0}}' http://localhost/restconf/operations/clixon-example:empty)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"x"},"error-severity":"error"}}}
'
|
||||
expectpart "$(curl -iss -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":0}}' http://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"x"},"error-severity":"error"}}}
'
|
||||
|
||||
# cornercase: optional has yang input/output sections but test without body
|
||||
new "restconf optional rpc with null input and output"
|
||||
ret=$(curl -is -X POST -d '{"clixon-example:input":null}' http://localhost/restconf/operations/clixon-example:optional)
|
||||
ret=$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":null}' http://localhost/restconf/operations/clixon-example:optional)
|
||||
expect="204 No Content"
|
||||
match=`echo $ret | grep -EZo "$expect"`
|
||||
if [ -z "$match" ]; then
|
||||
|
|
@ -127,16 +126,16 @@ if [ -z "$match" ]; then
|
|||
fi
|
||||
|
||||
new "restconf omit mandatory"
|
||||
expecteq "$(curl -s -X POST -d '{"clixon-example:input":null}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"x"},"error-severity":"error","error-message":"Mandatory variable"}}}
'
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":null}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"x"},"error-severity":"error","error-message":"Mandatory variable"}}}
'
|
||||
|
||||
new "restconf add extra"
|
||||
expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"x":"0","extra":"0"}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"extra"},"error-severity":"error"}}}
'
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"0","extra":"0"}}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"extra"},"error-severity":"error"}}}
'
|
||||
|
||||
new "restconf wrong method"
|
||||
expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:wrong)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"wrong"},"error-severity":"error","error-message":"RPC not defined"}}}
'
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:wrong)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"wrong"},"error-severity":"error","error-message":"RPC not defined"}}}
'
|
||||
|
||||
new "restconf example missing input"
|
||||
expecteq "$(curl -s -X POST -d '{"clixon-example:input":null}' http://localhost/restconf/operations/ietf-netconf:edit-config)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"target"},"error-severity":"error","error-message":"Mandatory variable"}}}
'
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":null}' http://localhost/restconf/operations/ietf-netconf:edit-config)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"target"},"error-severity":"error","error-message":"Mandatory variable"}}}
'
|
||||
|
||||
new "netconf kill-session missing session-id mandatory"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><kill-session/></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>missing-element</error-tag><error-info><bad-element>session-id</bad-element></error-info><error-severity>error</error-severity><error-message>Mandatory variable</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||
|
|
|
|||
|
|
@ -204,16 +204,16 @@ expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<
|
|||
|
||||
# Now same with restconf
|
||||
new "restconf edit main"
|
||||
expectfn 'curl -s -i -X POST http://localhost/restconf/data -d {"main:main":{"x":"foo","ext":"foo"}}' 0 'HTTP/1.1 201 Created'
|
||||
expectpart "$(curl -s -i -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data -d '{"main:main":{"x":"foo","ext":"foo"}}')" 0 'HTTP/1.1 201 Created'
|
||||
|
||||
new "restconf edit sub1"
|
||||
expectfn 'curl -s -i -X POST http://localhost/restconf/data -d {"main:sub1":{"x":"foo","ext1":"foo"}}' 0 'HTTP/1.1 201 Created'
|
||||
expectpart "$(curl -s -i -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data -d '{"main:sub1":{"x":"foo","ext1":"foo"}}')" 0 'HTTP/1.1 201 Created'
|
||||
|
||||
new "restconf edit sub2"
|
||||
expectfn 'curl -s -i -X POST http://localhost/restconf/data -d {"main:sub2":{"x":"foo","ext2":"foo"}}' 0 'HTTP/1.1 201 Created'
|
||||
expectpart "$(curl -s -i -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data -d '{"main:sub2":{"x":"foo","ext2":"foo"}}')" 0 'HTTP/1.1 201 Created'
|
||||
|
||||
new "restconf check main/sub1/sub2 contents"
|
||||
expectfn "curl -s -X GET http://localhost/restconf/data" 0 '{"data":{"main:main":{"ext":"foo","x":"foo"},"main:sub1":{"ext1":"foo","x":"foo"},"main:sub2":{"ext2":"foo","x":"foo"}}}'
|
||||
expectpart "$(curl -s -X GET http://localhost/restconf/data)" 0 '{"data":{"main:main":{"ext":"foo","x":"foo"},"main:sub1":{"ext1":"foo","x":"foo"},"main:sub2":{"ext2":"foo","x":"foo"}}}'
|
||||
|
||||
new "Kill restconf daemon"
|
||||
stop_restconf
|
||||
|
|
|
|||
|
|
@ -102,14 +102,14 @@ new "netconf discard-changes"
|
|||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "restconf set x in example1"
|
||||
expecteq "$(curl -s -X POST -d '{"example1:x":42}' http://localhost/restconf/data)" 0 ''
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"example1:x":42}' http://localhost/restconf/data)" 0 ''
|
||||
|
||||
new "restconf get config example1"
|
||||
expecteq "$(curl -s -X GET http://localhost/restconf/data/example1:x)" 0 '{"example1:x":42}
|
||||
'
|
||||
|
||||
new "restconf set x in example2"
|
||||
expecteq "$(curl -s -X POST -d '{"example2:x":{"y":99}}' http://localhost/restconf/data)" 0 ''
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"example2:x":{"y":99}}' http://localhost/restconf/data)" 0 ''
|
||||
|
||||
# XXX GET ../example1:x is translated to select=/x which gets both example1&2
|
||||
#new "restconf get config example1"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue