diff --git a/tests/commands/head_object.sh b/tests/commands/head_object.sh
index ea44da41..4ea9a355 100644
--- a/tests/commands/head_object.sh
+++ b/tests/commands/head_object.sh
@@ -44,7 +44,7 @@ head_object() {
}
head_object_rest_expect_success() {
- if ! check_param_count_v2 "bucket, object, env vars" 4 $#; then
+ if ! check_param_count_v2 "bucket, object, env vars" 3 $#; then
return 1
fi
env_vars="BUCKET_NAME=$1 OBJECT_KEY=$2 $3"
diff --git a/tests/drivers/get_bucket_cors/get_bucket_cors_rest.sh b/tests/drivers/get_bucket_cors/get_bucket_cors_rest.sh
new file mode 100644
index 00000000..9a639734
--- /dev/null
+++ b/tests/drivers/get_bucket_cors/get_bucket_cors_rest.sh
@@ -0,0 +1,89 @@
+#!/usr/bin/env bats
+
+# Copyright 2026 Versity Software
+# This file is licensed under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+source ./tests/drivers/rest.sh
+
+check_cors_404_content_type_header_and_bucket_name() {
+ if ! check_param_count_v2 "data file" 1 $#; then
+ return 1
+ fi
+ if ! check_for_header_key_and_value "$1" "Content-Type" "application/xml"; then
+ log 2 "error checking Content-Type header and value"
+ return 1
+ fi
+ if ! check_specific_argument_name_and_value "$1"; then
+ log 2 "error checking BucketName"
+ return 1
+ fi
+ return 0
+}
+
+get_bucket_cors_check_404_header_and_bucket_name() {
+ if ! check_param_count_v2 "bucket name" 1 $#; then
+ return 1
+ fi
+ argument_name="BucketName"
+ argument_value="$1"
+ if ! send_rest_go_command_expect_error_callback "404" "NoSuchCORSConfiguration" "The CORS configuration does not exist" \
+ "check_cors_404_content_type_header_and_bucket_name" "-bucketName" "$1" "-query" "cors"; then
+ log 2 "error sending get cors command and checking result"
+ return 1
+ fi
+ return 0
+}
+
+check_cors_response_data() {
+ if ! check_param_count_v2 "data file, allowed origin, allowed method one, allowed method two" 4 $#; then
+ return 1
+ fi
+ local data_file="$1"
+ local allowed_origin="$2"
+ local allowed_method_one="$3"
+ local allowed_method_two="$4"
+
+ if ! check_xml_element "$data_file" "$allowed_origin" "CORSConfiguration" "CORSRule" "AllowedOrigin"; then
+ log 2 "error checking for allowed origin value of '$allowed_origin'"
+ return 1
+ fi
+ if ! check_if_element_exists "$data_file" "$allowed_method_one" "CORSConfiguration" "CORSRule" "AllowedMethod"; then
+ log 2 "error checking if allowed method '$allowed_method_one' exists"
+ return 1
+ fi
+ if ! check_if_element_exists "$data_file" "$allowed_method_two" "CORSConfiguration" "CORSRule" "AllowedMethod"; then
+ log 2 "error checking if allowed method '$allowed_method_two' exists"
+ return 1
+ fi
+ return 0
+}
+
+get_bucket_cors_check_valid_data() {
+ if ! check_param_count_v2 "bucket name" 1 $#; then
+ return 1
+ fi
+ allowed_origin="http://example.com"
+ allowed_method_one="GET"
+ allowed_method_two="PUT"
+ payload="$allowed_origin$allowed_method_one$allowed_method_two"
+ if ! send_openssl_go_command "200" "-bucketName" "$1" "-query" "cors" "-method" "PUT" "-payload" "$payload" "-contentMD5"; then
+ log 2 "error sending PutBucketCors go command"
+ return 1
+ fi
+ if ! send_rest_go_command_callback "200" "check_cors_response_data" "-query" "cors" "-bucketName" "$1" -- "$allowed_origin" "$allowed_method_one" "$allowed_method_two"; then
+ log 2 "error sending GetCors command or checking response"
+ return 1
+ fi
+ return 0
+}
\ No newline at end of file
diff --git a/tests/drivers/head_object/head_object_rest.sh b/tests/drivers/head_object/head_object_rest.sh
index e15ba275..34793d27 100644
--- a/tests/drivers/head_object/head_object_rest.sh
+++ b/tests/drivers/head_object/head_object_rest.sh
@@ -48,7 +48,7 @@ verify_object_exists() {
if ! check_param_count_v2 "bucket name, key" 2 $#; then
return 1
fi
- if ! head_object_rest_expect_success "$1" "$2" "" "200"; then
+ if ! head_object_rest_expect_success "$1" "$2" ""; then
log 2 "error sending HeadObject command and verifying existence"
return 1
fi
diff --git a/tests/drivers/rest.sh b/tests/drivers/rest.sh
index 249696d3..957ecb65 100644
--- a/tests/drivers/rest.sh
+++ b/tests/drivers/rest.sh
@@ -103,7 +103,7 @@ check_rest_expected_header_error() {
status_message=$(echo "$status_line" | cut -d' ' -f3- | tr -d '\r')
log 5 "status code: $status_code, status message: $status_message"
if [ "$2" != "$status_code" ]; then
- log 2 "expected curl response '$2', was '$status_code'"
+ log 2 "expected curl response '$2', was '$status_code' ($(echo -n "$result"))"
return 1
fi
if [ "$status_message" != "$3" ]; then
@@ -253,11 +253,49 @@ send_rest_go_command() {
return 0
}
+# return 0 for callback params, 1 for only go params
+get_go_params() {
+ for param in "$@"; do
+ if [[ "$param" == "--" ]]; then
+ return 1
+ fi
+ log 5 "param: $param"
+ echo "$param"
+ done
+ return 0
+}
+
+get_callback_params() {
+ delimiter_found=false
+ for param in "$@"; do
+ if [ "$delimiter_found" == "true" ]; then
+ echo "$param"
+ continue
+ fi
+ if [ "$param" == "--" ]; then
+ delimiter_found=true
+ fi
+ done
+ return 0
+}
+
send_rest_go_command_callback() {
if ! check_param_count_gt "response code, callback, params" 2 $#; then
return 1
fi
- if ! rest_go_command_perform_send "${@:3}"; then
+
+ local all_params=("${@:3}") no_callback_params=0 go_params go_param_array=() callback_params=()
+ go_params=$(get_go_params "${all_params[@]}") || no_callback_params=$?
+ while IFS= read -r line; do
+ go_param_array+=("$line")
+ done <<< "$go_params"
+ if [ "$no_callback_params" -eq 1 ]; then
+ while IFS= read -r line; do
+ callback_params+=("$line")
+ done <<< "$(get_callback_params "${all_params[@]}")"
+ fi
+
+ if ! rest_go_command_perform_send "${go_param_array[@]}"; then
log 2 "error sending rest go command"
return 1
fi
@@ -274,7 +312,7 @@ send_rest_go_command_callback() {
return 1
fi
echo -n "$result" > "$TEST_FILE_FOLDER/$output_file_name"
- if [ "$2" != "" ] && ! "$2" "$TEST_FILE_FOLDER/$output_file_name"; then
+ if [ "$2" != "" ] && ! "$2" "$TEST_FILE_FOLDER/$output_file_name" "${callback_params[@]}"; then
log 2 "error in callback"
return 1
fi
diff --git a/tests/drivers/xml.sh b/tests/drivers/xml.sh
index 380f2bb7..a24cf8a8 100644
--- a/tests/drivers/xml.sh
+++ b/tests/drivers/xml.sh
@@ -1,5 +1,19 @@
#!/usr/bin/env bash
+# Copyright 2026 Versity Software
+# This file is licensed under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
build_xpath_string() {
if ! check_param_count_gt "XML tree" 1 $#; then
return 1
@@ -14,13 +28,23 @@ build_xpath_string_for_element() {
if ! check_param_count_gt "XML tree" 1 $#; then
return 1
fi
- xpath='//'
+ local xpath='//'
for ((idx=1;idx<=$#;idx++)); do
+ if [ "${!idx}" == "" ]; then
+ log 2 "param number $idx is empty"
+ return 1
+ fi
+ if [[ "${!idx}" =~ [[:space:]] ]]; then
+ log 2 "param '${!idx}' contains a space"
+ return 1
+ fi
xpath+='*[local-name()="'${!idx}'"]'
if [ "$idx" != $# ]; then
xpath+='/'
fi
done
+ echo "$xpath"
+ return 0
}
check_for_empty_element() {
@@ -29,8 +53,8 @@ check_for_empty_element() {
fi
# shellcheck disable=SC2068
- if ! build_xpath_string_for_element ${@:2}; then
- log 2 "error building XPath search string"
+ if ! xpath=$(build_xpath_string_for_element ${@:2} 2>&1); then
+ log 2 "error building XPath search string: $xpath"
return 1
fi
if ! get_xml_data "$1" "$1.xml"; then
@@ -50,7 +74,7 @@ get_element() {
return 1
fi
- if ! build_xpath_string_for_element "${@:2}"; then
+ if ! xpath=$(build_xpath_string_for_element "${@:2}" 2>&1); then
log 2 "error building XPath search string"
return 1
fi
@@ -62,13 +86,12 @@ get_element() {
}
get_element_text() {
- if [ $# -lt 2 ]; then
- log 2 "'get_element_text' requires data file, XML tree"
+ if ! check_param_count_gt "data file, XML tree" 2 $#; then
return 1
fi
- if ! build_xpath_string_for_element "${@:2}"; then
- log 2 "error building XPath search string"
+ if ! xpath=$(build_xpath_string_for_element "${@:2}" 2>&1); then
+ log 2 "error building XPath search string: $xpath"
return 1
fi
@@ -166,8 +189,8 @@ check_if_element_exists() {
if ! check_param_count_gt "data file, element, XML tree" 3 $#; then
return 1
fi
- if ! build_xpath_string_for_element "${@:3}"; then
- log 2 "error building XPath search string"
+ if ! xpath=$(build_xpath_string_for_element "${@:3}" 2>&1); then
+ log 2 "error building XPath search string: $xpath"
return 1
fi
@@ -191,6 +214,11 @@ get_xml_data() {
if ! check_param_count_v2 "data file, output file" 2 $#; then
return 1
fi
+
+ if [ ! -e "$1" ]; then
+ log 2 "file '$1' does not exist"
+ return 1
+ fi
log 5 "data: $(cat "$1")"
# Find first line with "&1); then
+ log 2 "error getting output file file name: $output_file"
+ return 1
+ fi
+ if ! expected_data=$(get_file_name 2>&1); then
+ log 2 "error getting expected data file name: $expected_data"
+ return 1
+ fi
+ if ! get_xml_data "$1" "$TEST_FILE_FOLDER/$output_file"; then
+ log 2 "error getting xml data"
+ return 1
+ fi
+ echo -en "$2" > "$TEST_FILE_FOLDER/$expected_data"
+ if ! diff "$TEST_FILE_FOLDER/$expected_data" "$TEST_FILE_FOLDER/$output_file"; then
+ return 1
+ fi
+ return 0
+}
diff --git a/tests/logger.sh b/tests/logger.sh
index 380ae517..df3d93cb 100644
--- a/tests/logger.sh
+++ b/tests/logger.sh
@@ -22,7 +22,7 @@ check_log_params() {
return 1
fi
if [ "$3" -ne "$4" ]; then
- echo "function $1 requires $2" 2
+ echo "function $1 requires $2" >&2
return 1
fi
return 0
diff --git a/tests/rest_scripts/command/wholePayload.go b/tests/rest_scripts/command/wholePayload.go
index 1657b5e2..185117f1 100644
--- a/tests/rest_scripts/command/wholePayload.go
+++ b/tests/rest_scripts/command/wholePayload.go
@@ -2,6 +2,7 @@ package command
import (
"fmt"
+ "io"
"os"
)
@@ -46,6 +47,9 @@ func (w *WholePayload) WritePayload(filePath string) error {
var bytesRead int
bytesRead, err = sourceFile.Read(buffer)
if err != nil {
+ if err == io.EOF {
+ break
+ }
return fmt.Errorf("error reading data bytes: %w", err)
}
if bytesRead == 0 {
@@ -55,5 +59,8 @@ func (w *WholePayload) WritePayload(filePath string) error {
return fmt.Errorf("error writing bytes to file: %w", err)
}
}
+ if err := outFile.Close(); err != nil {
+ return fmt.Errorf("error closing output file: %w", err)
+ }
return nil
}
diff --git a/tests/test_rest_cors.sh b/tests/test_rest_cors.sh
new file mode 100755
index 00000000..00817c7a
--- /dev/null
+++ b/tests/test_rest_cors.sh
@@ -0,0 +1,147 @@
+#!/usr/bin/env bats
+
+# Copyright 2026 Versity Software
+# This file is licensed under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+load ./bats-support/load
+load ./bats-assert/load
+
+source ./tests/drivers/create_bucket/create_bucket_rest.sh
+source ./tests/drivers/get_bucket_cors/get_bucket_cors_rest.sh
+source ./tests/setup.sh
+
+@test "REST - GetCors - correct content-type, and returns bucket name" {
+ if [ "$DIRECT" != "true" ]; then
+ skip "https://github.com/versity/versitygw/issues/1842"
+ fi
+ run get_bucket_name "$BUCKET_ONE_NAME"
+ assert_success
+ bucket_name=$output
+
+ run setup_bucket_v2 "$bucket_name"
+ assert_success
+
+ run get_bucket_cors_check_404_header_and_bucket_name "$bucket_name"
+ assert_success
+}
+
+@test "REST - PutBucketCors and GetBucketCors - valid configuration" {
+ run get_bucket_name "$BUCKET_ONE_NAME"
+ assert_success
+ bucket_name=$output
+
+ run setup_bucket_v2 "$bucket_name"
+ assert_success
+
+ run get_bucket_cors_check_valid_data "$bucket_name"
+ assert_success
+}
+
+@test "REST - CORS - empty CORS rule" {
+ if [ "$DIRECT" != "true" ]; then
+ skip "https://github.com/versity/versitygw/issues/1863"
+ fi
+ run get_bucket_name "$BUCKET_ONE_NAME"
+ assert_success
+ bucket_name=$output
+
+ run setup_bucket_v2 "$bucket_name"
+ assert_success
+
+ run send_rest_go_command_expect_error "400" "MalformedXML" "did not validate" "-bucketName" "$bucket_name" "-query" "cors" "-method" "PUT" \
+ "-payload" "" "-contentMD5"
+ assert_success
+}
+
+@test "REST - CORS - missing allowed origin" {
+ if [ "$DIRECT" != "true" ]; then
+ skip "https://github.com/versity/versitygw/issues/1863"
+ fi
+ run get_bucket_name "$BUCKET_ONE_NAME"
+ assert_success
+ bucket_name=$output
+
+ run setup_bucket_v2 "$bucket_name"
+ assert_success
+
+ run send_rest_go_command_expect_error "400" "MalformedXML" "did not validate" "-bucketName" "$bucket_name" "-query" "cors" "-method" "PUT" \
+ "-payload" "GET" "-contentMD5"
+ assert_success
+}
+
+@test "REST - CORS - missing allowed method" {
+ if [ "$DIRECT" != "true" ]; then
+ skip "https://github.com/versity/versitygw/issues/1863"
+ fi
+ run get_bucket_name "$BUCKET_ONE_NAME"
+ assert_success
+ bucket_name=$output
+
+ run setup_bucket_v2 "$bucket_name"
+ assert_success
+
+ run send_rest_go_command_expect_error "400" "MalformedXML" "did not validate" "-bucketName" "$bucket_name" "-query" "cors" "-method" "PUT" \
+ "-payload" "example.com" "-contentMD5"
+ assert_success
+}
+
+@test "REST - CORS - empty allowed method" {
+ if [ "$DIRECT" != "true" ]; then
+ skip "https://github.com/versity/versitygw/issues/1863"
+ fi
+ run get_bucket_name "$BUCKET_ONE_NAME"
+ assert_success
+ bucket_name=$output
+
+ run setup_bucket_v2 "$bucket_name"
+ assert_success
+
+ run send_rest_go_command_expect_error "400" "InvalidRequest" "unsupported HTTP method in CORS config" "-bucketName" "$bucket_name" "-query" "cors" "-method" "PUT" \
+ "-payload" "example.com" "-contentMD5"
+ assert_success
+}
+
+@test "REST - CORS - invalid origin" {
+ if [ "$DIRECT" != "true" ]; then
+ skip "https://github.com/versity/versitygw/issues/1870"
+ fi
+ run get_bucket_name "$BUCKET_ONE_NAME"
+ assert_success
+ bucket_name=$output
+
+ run setup_bucket_v2 "$bucket_name"
+ assert_success
+
+ run send_rest_go_command_expect_error "400" "InvalidRequest" "can not have more than one wildcard" "-bucketName" "$bucket_name" "-query" "cors" "-method" "PUT" \
+ "-payload" "*example*.comGET" "-contentMD5"
+ assert_success
+}
+
+@test "REST - CORS - delete" {
+ run get_bucket_name "$BUCKET_ONE_NAME"
+ assert_success
+ bucket_name=$output
+
+ run setup_bucket_v2 "$bucket_name"
+ assert_success
+
+ run get_bucket_cors_check_valid_data "$bucket_name"
+ assert_success
+
+ run send_rest_go_command "204" "-bucketName" "$bucket_name" "-query" "cors" "-method" "DELETE"
+ assert_success
+
+ run send_rest_go_command_expect_error "404" "NoSuchCORSConfiguration" "does not exist" "-query" "cors" "-bucketName" "$bucket_name"
+ assert_success
+}
diff --git a/tests/test_rest_head_object.sh b/tests/test_rest_head_object.sh
index fc37374f..2cbd6d47 100755
--- a/tests/test_rest_head_object.sh
+++ b/tests/test_rest_head_object.sh
@@ -43,3 +43,25 @@ source ./tests/drivers/get_object_attributes/get_object_attributes_rest.sh
run get_etag_attribute_rest "$bucket_name" "$test_file" "$expected_etag"
assert_success
}
+
+@test "REST - HeadObject - default Content-Type is binary/octet-stream" {
+ if [ "$DIRECT" != "true" ]; then
+ skip "https://github.com/versity/versitygw/issues/1849"
+ fi
+ run get_bucket_name "$BUCKET_ONE_NAME"
+ assert_success
+ bucket_name="$output"
+
+ run get_file_name
+ assert_success
+ test_file="$output"
+
+ run setup_bucket_and_file_v2 "$bucket_name" "$test_file"
+ assert_success
+
+ run put_object_rest "$TEST_FILE_FOLDER/$test_file" "$bucket_name" "$test_file"
+ assert_success
+
+ run head_object_check_header_key_and_value "$bucket_name" "$test_file" "Content-Type" "binary/octet-stream"
+ assert_success
+}
diff --git a/tests/test_rest_list_buckets.sh b/tests/test_rest_list_buckets.sh
index 8ec90d8c..6efe90c2 100755
--- a/tests/test_rest_list_buckets.sh
+++ b/tests/test_rest_list_buckets.sh
@@ -222,3 +222,19 @@ export RUN_USERS=true
run send_rest_go_command_expect_error_with_specific_arg_names_values "405" "MethodNotAllowed" "is not allowed" 4 "Method" "POST" "ResourceType" "SERVICE" "-method" "POST"
assert_success
}
+
+@test "REST - ListBuckets - invalid method" {
+ if [ "$DIRECT" != "true" ]; then
+ skip "https://github.com/versity/versitygw/issues/1846"
+ fi
+ run send_rest_go_command_expect_error "400" "BadRequest" "An error occurred when parsing the HTTP request" "-method" "GETS"
+ assert_success
+}
+
+@test "REST - ListBuckets - error Content-Type is application/xml" {
+ if [ "$DIRECT" != "true" ]; then
+ skip "https://github.com/versity/versitygw/issues/1852"
+ fi
+ run send_rest_go_command_check_header_key_and_value "400" "Content-Type" "application/xml" "-method" "GETS"
+ assert_success
+}
\ No newline at end of file
diff --git a/tests/test_rest_put_object.sh b/tests/test_rest_put_object.sh
index ce3a6830..5b32d190 100755
--- a/tests/test_rest_put_object.sh
+++ b/tests/test_rest_put_object.sh
@@ -25,6 +25,7 @@ source ./tests/drivers/list_object_versions/list_object_versions_rest.sh
source ./tests/drivers/put_object/put_object_rest.sh
source ./tests/util/util_public_access_block.sh
source ./tests/util/util_time.sh
+source ./tests/drivers/get_object/get_object_rest.sh
test_file="test_file"
export RUN_USERS=true
@@ -517,3 +518,29 @@ export RUN_USERS=true
run rest_check_legal_hold "$bucket_name" "$test_file"
assert_success
}
+
+@test "REST - PutObject - openssl go non-file payload" {
+ run get_bucket_name "$BUCKET_ONE_NAME"
+ assert_success
+ bucket_name="$output"
+
+ run get_file_name
+ assert_success
+ test_file=$output
+
+ run setup_bucket_v2 "$bucket_name"
+ assert_success
+
+ run bash -c "tr -dc 'a-zA-Z0-9 ' < /dev/urandom | head -c 100"
+ assert_success
+ payload_content=$output
+
+ run bash -c "echo -n \"$payload_content\" > $TEST_FILE_FOLDER/$test_file"
+ assert_success
+
+ run send_openssl_go_command "200" "-method" "PUT" "-payload" "$payload_content" "-bucketName" "$bucket_name" "-objectKey" "$test_file"
+ assert_success
+
+ run download_and_compare_file "$TEST_FILE_FOLDER/$test_file" "$bucket_name" "$test_file" "$TEST_FILE_FOLDER/${test_file}_downloaded"
+ assert_success
+}
diff --git a/tests/test_xml.sh b/tests/test_xml.sh
new file mode 100755
index 00000000..0e363ee0
--- /dev/null
+++ b/tests/test_xml.sh
@@ -0,0 +1,87 @@
+#!/usr/bin/env bats
+
+# Copyright 2026 Versity Software
+# This file is licensed under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+load ./bats-support/load
+load ./bats-assert/load
+
+source ./tests/drivers/file.sh
+source ./tests/drivers/xml.sh
+source ./tests/drivers/params.sh
+source ./tests/logger.sh
+source ./tests/setup_unit.sh
+
+@test "build_xpath_string_for_element" {
+ run build_xpath_string_for_element
+ assert_failure
+ assert_output -p "requires"
+
+ run build_xpath_string_for_element "Error"
+ assert_success
+ assert_output '//*[local-name()="Error"]'
+
+ run build_xpath_string_for_element "Error" "Code"
+ assert_success
+ assert_output '//*[local-name()="Error"]/*[local-name()="Code"]'
+
+ run build_xpath_string_for_element "dontcare" ""
+ assert_failure
+ assert_output -p 'param number 2 is empty'
+
+ run build_xpath_string_for_element "XML With Space"
+ assert_failure
+ assert_output -p "param 'XML With Space' contains a space"
+}
+
+@test "get_xml_data - missing params" {
+ run get_xml_data "oneparam"
+ assert_failure
+ assert_output -p "requires data file, output file"
+}
+
+@test "get_xml_data - file doesn't exist" {
+ run get_xml_data "/nonexistent_$$" "/tmp/out"
+ assert_failure
+ assert_output -p "does not exist"
+}
+
+@test "get_xml_data - no XML content" {
+ input=$(get_file_name)
+ printf 'HTTP/1.1 500\r\n\r\nNo XML here' > "$TEST_FILE_FOLDER/$input"
+ run get_xml_data "$TEST_FILE_FOLDER/$input" "dontcare"
+ assert_failure
+ assert_output -p "No XML declaration found"
+}
+
+@test "get_xml_data - valid XML with declaration" {
+ input=$(get_file_name)
+ printf 'HTTP/1.1 200\r\n\r\nOK' > "$TEST_FILE_FOLDER/$input"
+ run compare_data_with_xml_file "$TEST_FILE_FOLDER/$input" "\nOK"
+ assert_success
+}
+
+@test "get_xml_data - valid XML without declaration" {
+ input=$(get_file_name)
+ printf 'HTTP/1.1 200\r\n\r\nAlsoOK' > "$TEST_FILE_FOLDER/$input"
+ run compare_data_with_xml_file "$TEST_FILE_FOLDER/$input" "\nAlsoOK"
+ assert_success
+}
+
+@test "get_xml_data - XML with extra content after root" {
+ input=$(get_file_name)
+ printf 'HTTP/1.1 200\r\n\r\nAgainOKextra' > "$TEST_FILE_FOLDER/$input"
+ run compare_data_with_xml_file "$TEST_FILE_FOLDER/$input" "\nAgainOK"
+ assert_success
+}