From 1ac8f82abba8aab37ebd4730575b32ac19f64f9e Mon Sep 17 00:00:00 2001 From: Masaki Tsukuda Date: Fri, 20 Feb 2015 14:25:32 +0900 Subject: [PATCH] Draft: Change functional tests to the new structure. I change functional tests to the new structure using nosetests. Existing functional tests has the following problems. - File name becomes the nonsense sequence number. - Large quantity of files will be located in one directory when we add tests because it becomes 1 file every 1 test. - Because the system is such that it is more special than other products of OpenStack, it is hard to develop it. I think that the problem mentioned above are solved by this patch. Change-Id: Ic75858ca1894e19f12c37b25559354f65fb48fa6 --- swift3/test/functional/001 | 12 - swift3/test/functional/001.out | 29 - swift3/test/functional/002 | 14 - swift3/test/functional/002.out | 13 - swift3/test/functional/003 | 16 - swift3/test/functional/003.out | 31 -- swift3/test/functional/__init__.py | 0 swift3/test/functional/check | 508 ------------------ swift3/test/functional/common | 17 - swift3/test/functional/common.config | 111 ---- swift3/test/functional/common.filter | 205 ------- swift3/test/functional/common.rc | 209 ------- swift3/test/functional/group | 16 - swift3/test/functional/run_test.sh | 24 +- swift3/test/functional/s3.rc | 108 ---- swift3/test/functional/s3_test_client.py | 88 +++ swift3/test/functional/s3curl.pl | 326 ----------- swift3/test/functional/setup_keystone | 15 + swift3/test/functional/swift.rc | 112 ---- swift3/test/functional/swift3.config | 42 ++ swift3/test/functional/test_bucket.py | 167 ++++++ swift3/test/functional/test_object.py | 138 +++++ swift3/test/functional/test_service.py | 67 +++ swift3/test/functional/{xpath.py => utils.py} | 20 +- swift3/test/functional/xmlindent.py | 25 - test-requirements.txt | 1 + 26 files changed, 551 insertions(+), 1763 deletions(-) delete mode 100755 swift3/test/functional/001 delete mode 100644 swift3/test/functional/001.out delete mode 100755 swift3/test/functional/002 delete mode 100644 swift3/test/functional/002.out delete mode 100755 swift3/test/functional/003 delete mode 100644 swift3/test/functional/003.out create mode 100644 swift3/test/functional/__init__.py delete mode 100755 swift3/test/functional/check delete mode 100644 swift3/test/functional/common delete mode 100644 swift3/test/functional/common.config delete mode 100644 swift3/test/functional/common.filter delete mode 100644 swift3/test/functional/common.rc delete mode 100644 swift3/test/functional/group delete mode 100644 swift3/test/functional/s3.rc create mode 100644 swift3/test/functional/s3_test_client.py delete mode 100755 swift3/test/functional/s3curl.pl delete mode 100644 swift3/test/functional/swift.rc create mode 100644 swift3/test/functional/swift3.config create mode 100644 swift3/test/functional/test_bucket.py create mode 100644 swift3/test/functional/test_object.py create mode 100644 swift3/test/functional/test_service.py rename swift3/test/functional/{xpath.py => utils.py} (56%) mode change 100755 => 100644 delete mode 100755 swift3/test/functional/xmlindent.py diff --git a/swift3/test/functional/001 b/swift3/test/functional/001 deleted file mode 100755 index f83fc706..00000000 --- a/swift3/test/functional/001 +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -# GET Service - -. ./common - -S3USER=tester - -_s3_put /abcdefghijklmnopqrstuvwxyz_01234 -_s3_put /5ABCDEFGHIJKLMNOPQRSTUVWXYZ.5-6789 - -_s3_get / -D - | _filter_curl xml diff --git a/swift3/test/functional/001.out b/swift3/test/functional/001.out deleted file mode 100644 index 0fd4d32d..00000000 --- a/swift3/test/functional/001.out +++ /dev/null @@ -1,29 +0,0 @@ -QA output created by 001 -> s3curl --id tester -- -X PUT http://SWIFT_HOST/abcdefghijklmnopqrstuvwxyz_01234... 200 -> s3curl --id tester -- -X PUT http://SWIFT_HOST/5ABCDEFGHIJKLMNOPQRSTUVWXYZ.5-6789... 200 -> s3curl --id tester -- -X GET -D - http://SWIFT_HOST/... 200 -HTTP/1.1 200 OK -Content-Length: LENGTH -Content-Type: application/xml -Date: DATE -x-amz-id-2: TXID -x-amz-request-id: TXID -X-Trans-Id: TXID - - - - - TESTER - TESTER - - - - 5ABCDEFGHIJKLMNOPQRSTUVWXYZ.5-6789 - DATE - - - abcdefghijklmnopqrstuvwxyz_01234 - DATE - - - diff --git a/swift3/test/functional/002 b/swift3/test/functional/002 deleted file mode 100755 index 51fe06c3..00000000 --- a/swift3/test/functional/002 +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -# PUT Bucket - -. ./common - -echo ' - -US -' > $tmp.default.xml - -S3USER=tester - -_s3_put /bucket -D - -T $tmp.default.xml | _filter_curl diff --git a/swift3/test/functional/002.out b/swift3/test/functional/002.out deleted file mode 100644 index edf2512d..00000000 --- a/swift3/test/functional/002.out +++ /dev/null @@ -1,13 +0,0 @@ -QA output created by 002 -> s3curl --id tester -- -X PUT -D - -T /TMP.default.xml http://SWIFT_HOST/bucket... 200 -HTTP/1.1 100 Continue - -HTTP/1.1 200 OK -Content-Length: LENGTH -Content-Type: text/html; charset=UTF-8 -Date: DATE -Location: /bucket -x-amz-id-2: TXID -x-amz-request-id: TXID -X-Trans-Id: TXID - diff --git a/swift3/test/functional/003 b/swift3/test/functional/003 deleted file mode 100755 index 3c4aaac5..00000000 --- a/swift3/test/functional/003 +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# GET Bucket - -. ./common - -S3USER=tester - -_s3_put /bucket -_s3_put /bucket/sample.jpg -T /dev/null -_s3_put /bucket/photos/2006/January/sample.jpg -T /dev/null -_s3_put /bucket/photos/2006/February/sample2.jpg -T /dev/null -_s3_put /bucket/photos/2006/February/sample3.jpg -T /dev/null -_s3_put /bucket/pho/2006/February/sample4.jpg -T /dev/null - -_s3_get /bucket?delimiter=/\&prefix=photos/2006/ -D - | _filter_curl xml diff --git a/swift3/test/functional/003.out b/swift3/test/functional/003.out deleted file mode 100644 index 2d33a1c8..00000000 --- a/swift3/test/functional/003.out +++ /dev/null @@ -1,31 +0,0 @@ -QA output created by 003 -> s3curl --id tester -- -X PUT http://SWIFT_HOST/bucket... 200 -> s3curl --id tester -- -X PUT -T /dev/null http://SWIFT_HOST/bucket/sample.jpg... 200 -> s3curl --id tester -- -X PUT -T /dev/null http://SWIFT_HOST/bucket/photos/2006/January/sample.jpg... 200 -> s3curl --id tester -- -X PUT -T /dev/null http://SWIFT_HOST/bucket/photos/2006/February/sample2.jpg... 200 -> s3curl --id tester -- -X PUT -T /dev/null http://SWIFT_HOST/bucket/photos/2006/February/sample3.jpg... 200 -> s3curl --id tester -- -X PUT -T /dev/null http://SWIFT_HOST/bucket/pho/2006/February/sample4.jpg... 200 -> s3curl --id tester -- -X GET -D - http://SWIFT_HOST/bucket?delimiter=/&prefix=photos/2006/... 200 -HTTP/1.1 200 OK -Content-Length: LENGTH -Content-Type: application/xml -Date: DATE -x-amz-id-2: TXID -x-amz-request-id: TXID -X-Trans-Id: TXID - - - - bucket - photos/2006/ - - 1000 - / - false - - photos/2006/February/ - - - photos/2006/January/ - - diff --git a/swift3/test/functional/__init__.py b/swift3/test/functional/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/swift3/test/functional/check b/swift3/test/functional/check deleted file mode 100755 index e24188e0..00000000 --- a/swift3/test/functional/check +++ /dev/null @@ -1,508 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2009 Red Hat, Inc. -# Copyright (c) 2000-2002,2005-2006 Silicon Graphics, Inc. All Rights Reserved. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# -# Control script for QA -# - -tmp=/tmp/$$ -status=0 -needwrap=true -try=0 -n_bad=0 -bad="" -notrun="" -interrupt=true - -# by default don't output timestamps -timestamp=${TIMESTAMP:=false} - -# generic initialization -export iam=check - -cd $(readlink -f $(dirname $0)) - -# we need common.config -if ! . ./common.config -then - echo "$iam: failed to source common.config" - exit 1 -fi - -_setenvironment() -{ - MSGVERB="text:action" - export MSGVERB -} - -here=`pwd` -rm -f $here/$iam.out -_setenvironment - -check=${check-true} - -diff="diff -u" -verbose=false -group=false -xgroup=false -exit_on_err=false -showme=false -sortme=false -expunge=true -have_test_arg=false -randomize=false - -rm -f $tmp.list $tmp.tmp $tmp.sed - -for r -do - - if $group - then - # arg after -g - group_list=`sed -n /dev/null - then - : - else - echo "$t" >>$tmp.list - fi - done - group=false - continue - - elif $xgroup - then - # arg after -x - [ ! -s $tmp.list ] && ls [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] >$tmp.list 2>/dev/null - group_list=`sed -n $tmp.tmp - mv $tmp.tmp $tmp.list - numsed=0 - rm -f $tmp.sed - fi - echo "/^$t\$/d" >>$tmp.sed - numsed=`expr $numsed + 1` - done - sed -f $tmp.sed <$tmp.list >$tmp.tmp - mv $tmp.tmp $tmp.list - xgroup=false - continue - fi - - xpand=true - case "$r" - in - - -\? | -h | --help) # usage - echo "Usage: $0 [options] [testlist]"' - -common options - -v verbose - -check options - -xdiff graphical mode diff - -e exit immediately on test failure - -n show me, do not run tests - -T output timestamps - -r randomize test order - -keep-passed keep directories of passed tests - -testlist options - -g group[,group...] include tests from these groups - -x group[,group...] exclude tests from these groups - NNN include test NNN - NNN-NNN include test range (eg. 012-021) -' - exit 0 - ;; - - -g) # -g group ... pick from group file - group=true - xpand=false - ;; - - -xdiff) # graphical diff mode - xpand=false - - if [ ! -z "$DISPLAY" ] - then - which xdiff >/dev/null 2>&1 && diff=xdiff - which gdiff >/dev/null 2>&1 && diff=gdiff - which tkdiff >/dev/null 2>&1 && diff=tkdiff - which xxdiff >/dev/null 2>&1 && diff=xxdiff - fi - ;; - - -e) # exit immediately on test failure - exit_on_err=true - xpand=false - ;; - -n) # show me, don't do it - showme=true - xpand=false - ;; - -r) # randomize test order - randomize=true - xpand=false - ;; - - -T) # turn on timestamp output - timestamp=true - xpand=false - ;; - - -v) - verbose=true - xpand=false - ;; - -x) # -x group ... exclude from group file - xgroup=true - xpand=false - ;; - '[0-9][0-9][0-9] [0-9][0-9][0-9][0-9]') - echo "No tests?" - status=1 - exit $status - ;; - - [0-9]*-[0-9]*) - eval `echo $r | sed -e 's/^/start=/' -e 's/-/ end=/'` - ;; - - [0-9]*-) - eval `echo $r | sed -e 's/^/start=/' -e 's/-//'` - end=`echo [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] | sed -e 's/\[0-9]//g' -e 's/ *$//' -e 's/.* //'` - if [ -z "$end" ] - then - echo "No tests in range \"$r\"?" - status=1 - exit $status - fi - ;; - - *) - start=$r - end=$r - ;; - - esac - - # get rid of leading 0s as can be interpreted as octal - start=`echo $start | sed 's/^0*//'` - end=`echo $end | sed 's/^0*//'` - - if $xpand - then - have_test_arg=true - $AWK_PROG /dev/null - then - # in group file ... OK - echo $id >>$tmp.list - else - if [ -f expunged ] && $expunge && egrep "^$id([ ]|\$)" expunged >/dev/null - then - # expunged ... will be reported, but not run, later - echo $id >>$tmp.list - else - # oops - echo "$id - unknown test, ignored" - fi - fi - done - fi - -done - -if [ -s $tmp.list ] -then - # found some valid test numbers ... this is good - : -else - if $have_test_arg - then - # had test numbers, but none in group file ... do nothing - touch $tmp.list - else - # no test numbers, do everything from group file - sed -n -e '/^[0-9][0-9][0-9]*/s/[ ].*//p' $tmp.list - fi -fi - -# should be sort -n, but this did not work for Linux when this -# was ported from IRIX -# -list=`sort $tmp.list` -rm -f $tmp.list $tmp.tmp $tmp.sed - -if $randomize -then - list=`echo $list | awk -f randomize.awk` -fi - -# we need common.rc -if ! . ./common.rc -then - echo "check: failed to source common.rc" - exit 1 -fi - -_wallclock() -{ - date "+%H %M %S" | $AWK_PROG '{ print $1*3600 + $2*60 + $3 }' -} - -_timestamp() -{ - now=`date "+%T"` - echo -n " [$now]" -} - -_wrapup() -{ - # for hangcheck ... - # remove files that were used by hangcheck - # - [ -f /tmp/check.pid ] && rm -rf /tmp/check.pid - [ -f /tmp/check.sts ] && rm -rf /tmp/check.sts - - if $showme - then - : - elif $needwrap - then - if [ -f check.time -a -f $tmp.time ] - then - cat check.time $tmp.time \ - | $AWK_PROG ' - { t[$1] = $2 } -END { if (NR > 0) { - for (i in t) print i " " t[i] - } - }' \ - | sort -n >$tmp.out - mv $tmp.out check.time - fi - - if [ -f $tmp.expunged ] - then - notrun=`wc -l <$tmp.expunged | sed -e 's/ *//g'` - try=`expr $try - $notrun` - list=`echo "$list" | sed -f $tmp.expunged` - fi - - echo "" >>check.log - date >>check.log - echo $list | fmt | sed -e 's/^/ /' >>check.log - $interrupt && echo "Interrupted!" >>check.log - - if [ ! -z "$notrun" ] - then - echo "Not run:$notrun" - echo "Not run:$notrun" >>check.log - fi - if [ ! -z "$n_bad" -a $n_bad != 0 ] - then - echo "Failures:$bad" - echo "Failed $n_bad of $try tests" - echo "Failures:$bad" | fmt >>check.log - echo "Failed $n_bad of $try tests" >>check.log - else - echo "Passed all $try tests" - echo "Passed all $try tests" >>check.log - fi - needwrap=false - fi - - rm -f /tmp/*.out /tmp/*.err /tmp/*.time - rm -f /tmp/check.pid /tmp/check.sts - rm -f $tmp.* -} - -trap "_wrapup; exit \$status" 0 1 2 3 15 - -# for hangcheck ... -# Save pid of check in a well known place, so that hangcheck can be sure it -# has the right pid (getting the pid from ps output is not reliable enough). -# -rm -rf /tmp/check.pid -echo $$ >/tmp/check.pid - -# for hangcheck ... -# Save the status of check in a well known place, so that hangcheck can be -# sure to know where check is up to (getting test number from ps output is -# not reliable enough since the trace stuff has been introduced). -# -rm -rf /tmp/check.sts -echo "preamble" >/tmp/check.sts - -# don't leave old full output behind on a clean run -rm -f check.full - -[ -f check.time ] || touch check.time - -FULL_HOST_DETAILS=`_full_platform_details` - -cat < $TESTS_REMAINING_LOG - -for seq in $list -do - STORE="$WD/$seq" - err=false - echo -n "$seq" - if [ -n "$TESTS_REMAINING_LOG" ] ; then - sed -e "s/$seq//" -e 's/ / /' -e 's/^ *//' $TESTS_REMAINING_LOG > $TESTS_REMAINING_LOG.tmp - mv $TESTS_REMAINING_LOG.tmp $TESTS_REMAINING_LOG - sync - fi - - if $showme - then - description=`sed -n '3s/^#//p' $seq` - echo " $description" - continue - elif [ -f expunged ] && $expunge && egrep "^$seq([ ]|\$)" expunged >/dev/null - then - echo " - expunged" - rm -f $seq.out.bad - echo "/^$seq\$/d" >>$tmp.expunged - elif [ ! -f $seq ] - then - echo " - no such test?" - echo "/^$seq\$/d" >>$tmp.expunged - else - # really going to try and run this one - # - rm -f $seq.out.bad - lasttime=`sed -n -e "/^$seq /s/.* //p" /tmp/check.sts - - start=`_wallclock` - $timestamp && echo -n " ["`date "+%T"`"]" - [ ! -x $seq ] && chmod u+x $seq # ensure we can run it - ./$seq >$tmp.out 2>&1 - sts=$? - $timestamp && _timestamp - stop=`_wallclock` - - if [ -f core ] - then - echo -n " [dumped core]" - mv core $seq.core - err=true - fi - - if [ -f $seq.notrun ] - then - $timestamp || echo -n " [not run] " - $timestamp && echo " [not run]" && echo -n " $seq -- " - cat $seq.notrun - notrun="$notrun $seq" - else - if [ $sts -ne 0 ] - then - echo -n " [failed, exit status $sts]" - err=true - fi - if [ ! -f $seq.out ] - then - echo " - no qualified output" - err=true - else - if diff $seq.out $tmp.out >/dev/null 2>&1 - then - echo "" - if $err - then - : - else - echo "$seq `expr $stop - $start`" >>$tmp.time - fi - else - echo " - output mismatch (see $seq.out.bad)" - mv $tmp.out $seq.out.bad - $diff $seq.out $seq.out.bad - err=true - fi - fi - fi - - fi - - # come here for each test, except when $showme is true - # - [ -f $seq.notrun ] || try=`expr $try + 1` - if $err - then - bad="$bad $seq" - n_bad=`expr $n_bad + 1` - quick=false - if $exit_on_err - then - break - fi - fi - - seq="after_$seq" -done - -interrupt=false -status=`expr $n_bad` -exit diff --git a/swift3/test/functional/common b/swift3/test/functional/common deleted file mode 100644 index dd06da24..00000000 --- a/swift3/test/functional/common +++ /dev/null @@ -1,17 +0,0 @@ -set -e -seq=`basename $0` -echo "QA output created by $seq" - -here=`pwd` -tmp=/tmp/$$ -status=1 # failure is the default! - -# get standard environment, filters and checks -. ./common.rc -. ./common.filter - -. ./swift.rc -. ./s3.rc - -_sw_setup -_s3_setup diff --git a/swift3/test/functional/common.config b/swift3/test/functional/common.config deleted file mode 100644 index 2d6c9da1..00000000 --- a/swift3/test/functional/common.config +++ /dev/null @@ -1,111 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2009 Red Hat, Inc. -# Copyright (c) 2000-2003,2006 Silicon Graphics, Inc. All Rights Reserved. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# -# setup and check for config parameters -# - -# all tests should use a common language setting to prevent golden -# output mismatches. -export LANG=C - -PATH=".:$PATH" - -HOST=`hostname -s` -HOSTOS=`uname -s` - -export CHECK_OPTIONS=${CHECK_OPTIONS:="-g auto"} -export PWD=`pwd` - -# $1 = prog to look for, $2* = default pathnames if not found in $PATH -set_prog_path() -{ - p=`which $1 2> /dev/null` - if [ -n "$p" -a -x "$p" ]; then - echo $p - return 0 - fi - p=$1 - - shift - for f; do - if [ -x $f ]; then - echo $f - return 0 - fi - done - - echo "" - return 1 -} - -_fatal() -{ - echo "$*" - status=1 - exit 1 -} - -export PERL_PROG="`set_prog_path perl`" -[ "$PERL_PROG" = "" ] && _fatal "perl not found" - -export AWK_PROG="`set_prog_path awk`" -[ "$AWK_PROG" = "" ] && _fatal "awk not found" - -export SED_PROG="`set_prog_path sed`" -[ "$SED_PROG" = "" ] && _fatal "sed not found" - -export CURL_PROG="`set_prog_path curl`" -[ "$CURL_PROG" = "" ] && _fatal "curl not found" - -if [ -z "$TEST_DIR" ]; then - TEST_DIR=`pwd`/scratch -fi - -if [ ! -e "$TEST_DIR" ]; then - mkdir "$TEST_DIR" -fi - -if [ ! -d "$TEST_DIR" ]; then - echo "common.config: Error: \$TEST_DIR ($TEST_DIR) is not a directory" - exit 1 -fi - -export TEST_DIR - -export SWIFT_HOST=${SWIFT_HOST:-"localhost:8080"} -export KEYSTONE_HOST=${KEYSTONE_HOST:-"localhost:35357"} -export AUTH=${AUTH:-"keystone"} -export TENANT=${TENANT:-"test"} - -export ADMIN_USER=${ADMIN_USER:-"admin"} -export ADMIN_PASS=${ADMIN_PASS:-"admin"} -export ADMIN_ACCESS_KEY=${ADMIN_ACCESS_KEY:-"${TENANT}:${ADMIN_USER}"} -export ADMIN_SECRET_KEY=${ADMIN_SECRET_KEY:-"${ADMIN_PASS}"} - -export TESTER_USER=${TESTER_USER:-"tester"} -export TESTER_PASS=${TESTER_PASS:-"testing"} -export TESTER_ACCESS_KEY=${TESTER_ACCESS_KEY:-"${TENANT}:${TESTER_USER}"} -export TESTER_SECRET_KEY=${TESTER_SECRET_KEY:-"${TESTER_PASS}"} - -export TESTER2_USER=${TESTER2_USER:-"tester2"} -export TESTER2_PASS=${TESTER2_PASS:-"testing2"} -export TESTER2_ACCESS_KEY=${TESTER2_ACCESS_KEY:-"${TENANT}:${TESTER2_USER}"} -export TESTER2_SECRET_KEY=${TESTER2_SECRET_KEY:-"${TESTER2_PASS}"} - -# make sure this script returns success -/bin/true diff --git a/swift3/test/functional/common.filter b/swift3/test/functional/common.filter deleted file mode 100644 index b7e0d37b..00000000 --- a/swift3/test/functional/common.filter +++ /dev/null @@ -1,205 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2009 Red Hat, Inc. -# Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# -# standard filters -# - -# ctime(3) dates -# -_filter_date() -{ - sed -e 's/[A-Z][a-z][a-z] [A-Za-z][a-z][a-z] *[0-9][0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]$/DATE/' -} - -# ISO dates -_filter_iso_date() -{ - sed -e 's/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]/DATE/g' -} - -_filter_short_date() -{ - sed -e 's/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]/DATE/g' -} - -# remove trailing whitespace, some versions of sg3_utils do that -_filter_spaces() -{ - sed -e 's/ *$//' -} - -_filter_eol() -{ - tr -d '\r\n' -} - -_filter_nop() -{ - cat -} - -_filter_user() -{ - - sed "s/${TENANT}:${ADMIN_USER}/ADMIN_USER/g" | \ - sed "s/${TENANT}:${TESTER_USER}/TESTER/g" | \ - sed "s/${TENANT}:${TESTER2_USER}/TESTER2/g" -} - -_filter_tenant() -{ - sed -e 's/AUTH_[a-z0-9]*\>/TENANT/g' -} - -_filter_timestamp() -{ - sed -e 's/[0-9]\{10\}\.[0-9]\{5\}/TIMESTAMP/g' -} - -_filter_host() -{ - sed "s/$SWIFT_HOST/SWIFT_HOST/g" -} - -_filter_s3_iso_date() -{ - sed -e 's/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9][0-9][0-9]Z/DATE/g' -} - -_filter_upload_id() -{ - sed -e 's#[-_0-9a-zA-Z]*UPLOAD_ID[-_0-9a-zA-Z]*UPLOAD_ID[-_0-9a-zA-Z]*VERSION_ID[-_0-9a-zA-Z]*VERSION_ID/TXID/g' -} - -_filter_etag() -{ - sed -e 's/\<[a-z0-9]\{32\}\>/ETAG/g' -} - -_filter_header_date() -{ - sed -e 's/[A-Z][a-z][a-z], [0-9][0-9] [A-Z][a-z][a-z] [0-9]\{4\} [0-9][0-9]:[0-9][0-9]:[0-9][0-9] GMT/DATE/g' -} - -_filter_header_content_length() -{ - sed -e 's/^Content-Length: [0-9]*$/Content-Length: LENGTH/g' -} - -_filter_header() -{ - _filter_header_date | _filter_user | \ - _filter_upload_id | _filter_version_id | _filter_txid | _filter_etag | \ - _filter_timestamp | _filter_header_content_length -} - -_filter_body() -{ - local format=$1 - local fmt_filter="" - - case "$format" - in - xml) - fmt_filter=_xmlindent - ;; - json) - fmt_filter=_jsonindent - ;; - *) - fmt_filter=_filter_nop - ;; - esac - - $fmt_filter | _filter_user | _filter_s3_iso_date | \ - _filter_host | _filter_tenant | _filter_upload_id | \ - _filter_version_id | _filter_txid | _filter_etag | \ - _filter_timestamp -} - -_filter_curl() -{ - local format=$1 - local type=body - local status="" - local header="" - local body="" - - while read line; do - line=$(echo -n $line | _filter_eol) - if [[ "$body" == "" && "$line" == HTTP/1.1* ]]; then - type=status - fi - - case "$type" - in - status) - if [[ "$line" == *:* ]]; then - type=header - header="${header}${line}\n" - else - status="${status}${line}\n" - fi - ;; - header) - if [ "$line" == "" ]; then - type=body - else - header="${header}${line}\n" - fi - ;; - body) - body="${body}${line}\n" - ;; - esac - done - - body="${body}${line}" - - echo -en $status - if [ "$header" != "" ]; then - echo -en $header | _filter_header | sort -f - echo - fi - echo -en $body | _filter_body $format -} - -_filter_curl_command() -{ - sed "s#$tmp#/TMP#g" | _filter_user | _filter_host | _filter_tenant | \ - _filter_upload_id | _filter_version_id | _filter_txid | _filter_etag | \ - _filter_timestamp -} - -# make sure this script returns success -/bin/true diff --git a/swift3/test/functional/common.rc b/swift3/test/functional/common.rc deleted file mode 100644 index e8d9ff2c..00000000 --- a/swift3/test/functional/common.rc +++ /dev/null @@ -1,209 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2009 Red Hat, Inc. -# Copyright (c) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -# we need common.config -if [ "$iam" != "check" ] -then - if ! . ./common.config - then - echo "$iam: failed to source common.config" - exit 1 - fi -fi - -# make sure we have a standard umask -umask 022 - -# check if run as root -# -_need_to_be_root() -{ - local id=`id | $SED_PROG -e 's/(.*//' -e 's/.*=//'` - if [ "$id" -ne 0 ] - then - _notrun "you need to be root (not uid=$id) to run this test" - fi -} - -# To remove directory successfully always, we have to rename it first -# so that new files are not created in the directory while we remove it. -_safe_remove() -{ - local dir=$1 - mv ${dir} ${dir}.tmp - rm -rf ${dir}.tmp -} - -# Do a command, log it to $seq.full, optionally test return status -# and die if command fails. If called with one argument _do executes the -# command, logs it, and returns its exit status. With two arguments _do -# first prints the message passed in the first argument, and then "done" -# or "fail" depending on the return status of the command passed in the -# second argument. If the command fails and the variable _do_die_on_error -# is set to "always" or the two argument form is used and _do_die_on_error -# is set to "message_only" _do will print an error message to -# $seq.out and exit. - -_do() -{ - if [ $# -eq 1 ]; then - _cmd=$1 - elif [ $# -eq 2 ]; then - _note=$1 - _cmd=$2 - echo -n "$_note... " - else - echo "Usage: _do [note] cmd" 1>&2 - status=1; exit - fi - - (eval "echo '---' \"$_cmd\"") >>$here/$seq.full - (eval "$_cmd") >$tmp._out 2>&1; ret=$? - cat $tmp._out >>$here/$seq.full - if [ $# -eq 2 ]; then - if [ $ret -eq 0 ]; then - echo "done" - else - echo "fail" - fi - fi - if [ $ret -ne 0 ] \ - && [ "$_do_die_on_error" = "always" \ - -o \( $# -eq 2 -a "$_do_die_on_error" = "message_only" \) ] - then - [ $# -ne 2 ] && echo - eval "echo \"$_cmd\" failed \(returned $ret\): see $seq.full" - status=1; exit - fi - - return $ret -} - -# bail out, setting up .notrun file -# -_notrun() -{ - echo "$*" >$seq.notrun - echo "$seq not run: $*" - status=0 - exit -} - -# just plain bail out -# -_fail() -{ - echo "$*" | tee -a $here/$seq.full - echo "(see $seq.full for details)" - status=1 - exit 1 -} - -# this test requires that a specified command (executable) exists -# -_require_command() -{ - [ -n "`which $1`" ] || _notrun "$1 utility required, skipped this test" - [ -x "`which $1`" ] || _notrun "$1 utility required, skipped this test" -} - -_full_platform_details() -{ - os=`uname -s` - host=`hostname -s` - kernel=`uname -r` - platform=`uname -m` - echo "$os/$platform $host $kernel" -} - -_die() -{ - echo $@ - exit 1 -} - -_random() -{ - openssl enc -rc4 -pass pass:"$(date)" < /dev/zero 2>/dev/null -} - -_one() -{ - yes $'\xFF' | tr -d "\n" -} - -_hq() -{ - local name=$1 - - egrep -i "^$name: " | $AWK_PROG '{print $2}' | _filter_eol -} - -_xmlindent() -{ - ./xmlindent.py -} - -_xpath() -{ - local path=$1 - - ./xpath.py ${path} -} - -_md5() -{ - local file=$1 - cat $file | openssl md5 -binary | base64 | _filter_eol -} - -_etag() -{ - local file=$1 - - md5sum $file | awk '{print $1}' | _filter_eol -} - -_file_size() -{ - local file=$1 - - wc -c $file | awk '{print $1}' | _filter_eol -} - -_is_http_success() -{ - local status=$1 - - [ $(($status / 100)) == 2 ] -} - -_retry() -{ - for n in `seq 5`; do - "$@" > /dev/null 2>&1 && return - echo "try again" - sleep 1 - done - - _die "FAILED: $@" -} - -# make sure this script returns success -/bin/true diff --git a/swift3/test/functional/group b/swift3/test/functional/group deleted file mode 100644 index a22c47bb..00000000 --- a/swift3/test/functional/group +++ /dev/null @@ -1,16 +0,0 @@ -# -# QA groups control file -# -# Defines test groups -# - do not start group names with a digit -# - test-group association are one line per test -# - each test can be part of multiple groups -# -# auto: tests that are run by defaul -# quick: test that take less than 30 seconds (normally) -# bucket: test bucket operations -# object: test object operations -# -001 auto quick -002 auto quick -003 auto quick diff --git a/swift3/test/functional/run_test.sh b/swift3/test/functional/run_test.sh index 16acc127..c4f05d65 100755 --- a/swift3/test/functional/run_test.sh +++ b/swift3/test/functional/run_test.sh @@ -1,8 +1,22 @@ #!/bin/bash +# Copyright (c) 2014 OpenStack Foundation +# +# 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. cd $(readlink -f $(dirname $0)) -. ./common.config +. ./swift3.config CONF_DIR=$(readlink -f ./conf) @@ -17,7 +31,8 @@ if [ "$AUTH" == 'keystone' ]; then elif [ "$AUTH" == 'tempauth' ]; then MIDDLEWARE="tempauth" else - _fatal "unknown auth: $AUTH" + echo "unknown auth: $AUTH" + exit 1 fi for server in keystone swift proxy-server object-server container-server account-server; do @@ -78,7 +93,8 @@ _start() done cat ${TEST_DIR}/log/${name}.log - _fatal "Cannot start ${name}-server." + echo "Cannot start ${name}-server." + exit 1 } _start account ./run_daemon.py account 6002 conf/account-server.conf -v @@ -90,7 +106,7 @@ _start proxy coverage run --branch --include=../../* --omit=./* \ ./run_daemon.py proxy 8080 conf/proxy-server.conf -v # run tests -./check "$@" +nosetests -v ./ rvalue=$? # cleanup diff --git a/swift3/test/functional/s3.rc b/swift3/test/functional/s3.rc deleted file mode 100644 index c41933b0..00000000 --- a/swift3/test/functional/s3.rc +++ /dev/null @@ -1,108 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2014 OpenStack Foundation. -# -# 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. - -_s3_setup() -{ - echo " -%awsSecretAccessKeys = ( - tester => { - id => '$TESTER_ACCESS_KEY', - key => '$TESTER_SECRET_KEY', - endpoints => '${SWIFT_HOST%:*}', - }, - - tester2 => { - id => '$TESTER2_ACCESS_KEY', - key => '$TESTER2_SECRET_KEY', - endpoints => '${SWIFT_HOST%:*}', - }, - - admin => { - id => '$ADMIN_ACCESS_KEY', - key => '$ADMIN_SECRET_KEY', - endpoints => '${SWIFT_HOST%:*}', - }, -);" > .s3curl - - chmod 600 .s3curl -} - -_s3curl() -{ - local tmp_file=$tmp.$RANDOM - local args="" - - if [ "$S3USER" == "" ]; then - _die "S3USER is not defined." - fi - args="--id $S3USER" - - if [ "$MD5" != "" ]; then - args="$args --contentMd5 $MD5" - fi - - if [ "$CONTENT_TYPE" != "" ]; then - args="$args --contentType $CONTENT_TYPE" - fi - - LANG=C ./s3curl.pl $args -- -s "$@" -w '%{http_code}' > $tmp_file - - status=$(tail -c -3 $tmp_file) - echo "> s3curl $args -- $@... $status" | _filter_curl_command >&2 - - head -c -3 $tmp_file - - _is_http_success $status -} - -_s3_head() -{ - local path=$1; shift - - _s3curl -I -X HEAD "$@" http://${SWIFT_HOST}${path} -} - -_s3_get() -{ - local path=$1; shift - - _s3curl -X GET "$@" http://${SWIFT_HOST}${path} -} - -_s3_put() -{ - local path=$1; shift - - _s3curl -X PUT "$@" http://${SWIFT_HOST}${path} -} - -_s3_post() -{ - local path=$1; shift - - _s3curl -X POST "$@" http://${SWIFT_HOST}${path} -} - -_s3_delete() -{ - local path=$1; shift - - _s3curl -X DELETE "$@" http://${SWIFT_HOST}${path} -} - -# make sure this script returns success -/bin/true diff --git a/swift3/test/functional/s3_test_client.py b/swift3/test/functional/s3_test_client.py new file mode 100644 index 00000000..ecc529b2 --- /dev/null +++ b/swift3/test/functional/s3_test_client.py @@ -0,0 +1,88 @@ +# Copyright (c) 2015 OpenStack Foundation +# +# 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. + +import os +from boto.s3.connection import S3Connection, OrdinaryCallingFormat +from swift3.response import NoSuchKey, NoSuchBucket + +RETRY_COUNT = 3 + + +class Connection(object): + """ + Manage Connection + """ + def __init__(self, aws_access_key=os.environ.get('ADMIN_ACCESS_KEY'), + aws_secret_key=os.environ.get('ADMIN_SECRET_KEY'), + user_id='%s:%s' % (os.environ.get('ADMIN_TENANT'), + os.environ.get('ADMIN_USER'))): + self.aws_access_key = aws_access_key + self.aws_secret_key = aws_secret_key + self.user_id = user_id + swift_host = os.environ.get('SWIFT_HOST').split(':') + self.host = swift_host[0] + self.port = int(swift_host[1]) if len(swift_host) == 2 else 80 + self.conn = \ + S3Connection(aws_access_key, aws_secret_key, is_secure=False, + host=self.host, port=self.port, + calling_format=OrdinaryCallingFormat()) + + def reset(self): + for i in range(RETRY_COUNT): + buckets = self.conn.get_all_buckets() + if not buckets: + break + for bucket in buckets: + for obj in bucket.list(): + try: + bucket.delete_key(obj.name) + except (NoSuchKey): + pass + try: + self.conn.delete_bucket(bucket.name) + except (NoSuchBucket): + pass + + def make_request(self, method, bucket='', obj='', headers=None, body='', + query=None): + response = \ + self.conn.make_request(method, bucket=bucket, key=obj, + headers=headers, data=body, + query_args=query, sender=None, + override_num_retries=RETRY_COUNT, + retry_handler=None) + return response.status, dict(response.getheaders()), response.read() + + +def get_tester_connection(): + """ + Return tester connection + """ + aws_access_key = os.environ.get('TESTER_ACCESS_KEY') + aws_secret_key = os.environ.get('TESTER_SECRET_KEY') + user_id = os.environ.get('TESTER_TENANT') + ':' + \ + os.environ.get('TESTER_USER') + return Connection(aws_access_key, aws_secret_key, user_id) + + +def get_tester2_connection(): + """ + Return tester2 connection + """ + aws_access_key = os.environ.get('TESTER2_ACCESS_KEY') + aws_secret_key = os.environ.get('TESTER2_SECRET_KEY') + user_id = os.environ.get('TESTER2_TENANT') + ':' + \ + os.environ.get('TESTER2_USER') + return Connection(aws_access_key, aws_secret_key, user_id) diff --git a/swift3/test/functional/s3curl.pl b/swift3/test/functional/s3curl.pl deleted file mode 100755 index c65c6bf8..00000000 --- a/swift3/test/functional/s3curl.pl +++ /dev/null @@ -1,326 +0,0 @@ -#!/usr/bin/perl -w - -# Copyright 2006-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this -# file except in compliance with the License. A copy of the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file 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. - -use strict; -use POSIX; - -# you might need to use CPAN to get these modules. -# run perl -MCPAN -e "install " to get them. - -use FindBin; -use Getopt::Long qw(GetOptions); - -use constant STAT_MODE => 2; -use constant STAT_UID => 4; - -# begin customizing here - -my $CURL = "curl"; - -# stop customizing here - -my @endpoints = (); -my $cmdLineSecretKey; -my %awsSecretAccessKeys = (); -my $keyFriendlyName; -my $keyId; -my $secretKey; -my $contentType = ""; -my $acl; -my $contentMD5 = ""; -my $fileToPut; -my $createBucket; -my $doDelete; -my $doHead; -my $help; -my $debug = 0; -my $copySourceObject; -my $copySourceRange; -my $postBody; -my $print; - -my $DOTFILENAME=".s3curl"; -my $EXECFILE=$FindBin::Bin; -my $LOCALDOTFILE = $EXECFILE . "/" . $DOTFILENAME; -my $HOMEDOTFILE = $ENV{HOME} . "/" . $DOTFILENAME; -my $DOTFILE = -f $LOCALDOTFILE? $LOCALDOTFILE : $HOMEDOTFILE; - -if (-f $DOTFILE) { - open(CONFIG, $DOTFILE) || die "can't open $DOTFILE: $!"; - - my @stats = stat(*CONFIG); - - if (($stats[STAT_UID] != $<) || $stats[STAT_MODE] & 066) { - die "I refuse to read your credentials from $DOTFILE as this file is " . - "readable by, writable by or owned by someone else. Try " . - "chmod 600 $DOTFILE"; - } - - my @lines = ; - close CONFIG; - eval("@lines"); - die "Failed to eval() file $DOTFILE:\n$@\n" if ($@); -} - -GetOptions( - 'id=s' => \$keyId, - 'key=s' => \$cmdLineSecretKey, - 'contentType=s' => \$contentType, - 'acl=s' => \$acl, - 'contentMd5=s' => \$contentMD5, - 'put=s' => \$fileToPut, - 'copySrc=s' => \$copySourceObject, - 'copySrcRange=s' => \$copySourceRange, - 'post:s' => \$postBody, - 'delete' => \$doDelete, - 'createBucket:s' => \$createBucket, - 'head' => \$doHead, - 'help' => \$help, - 'debug' => \$debug, - 'print' => \$print, -); - -my $usage = < PUT request (from the provided local file) - --post [] POST request (optional local file) - --copySrc bucket/key Copy from this source key - --copySrcRange {startIndex}-{endIndex} - --createBucket [] create-bucket with optional location constraint - --head HEAD request - --debug enable debug logging - --print print command instead of executing it - common curl options: - -H 'x-amz-acl: public-read' another way of using canned ACLs - -v verbose logging -USAGE -die $usage if $help || !defined $keyId; - -if ($cmdLineSecretKey) { - printCmdlineSecretWarning(); - sleep 5; - - $secretKey = $cmdLineSecretKey; -} else { - my $keyinfo = $awsSecretAccessKeys{$keyId}; - die "I don't know about key with friendly name $keyId. " . - "Do you need to set it up in $DOTFILE?" - unless defined $keyinfo; - - $keyId = $keyinfo->{id}; - $secretKey = $keyinfo->{key}; - @endpoints = split /,/, $keyinfo->{endpoints}; -} - - -my $method = ""; -if (defined $fileToPut or defined $createBucket or defined $copySourceObject) { - $method = "PUT"; -} elsif (defined $doDelete) { - $method = "DELETE"; -} elsif (defined $doHead) { - $method = "HEAD"; -} elsif (defined $postBody) { - $method = "POST"; -} else { - $method = "GET"; -} -my $resource; -my $host; - -my %xamzHeaders; -$xamzHeaders{'x-amz-acl'}=$acl if (defined $acl); -$xamzHeaders{'x-amz-copy-source'}=$copySourceObject if (defined $copySourceObject); -$xamzHeaders{'x-amz-copy-source-range'}="bytes=$copySourceRange" if (defined $copySourceRange); - -# try to understand curl args -for (my $i=0; $i<@ARGV; $i++) { - my $arg = $ARGV[$i]; - # resource name - if ($arg =~ /https?:\/\/([^\/:?]+)(?::(\d+))?([^?]*)(?:\?(\S+))?/) { - $host = $1 if !$host; - my $port = defined $2 ? $2 : ""; - my $requestURI = $3; - my $query = defined $4 ? $4 : ""; - debug("Found the url: host=$host; port=$port; uri=$requestURI; query=$query;"); - if (length $requestURI) { - $resource = $requestURI; - } else { - $resource = "/"; - } - my @attributes = (); - for my $attribute ("acl", "location", "logging", "notification", "lifecycle", - "partNumber", "policy", "requestPayment", "response-cache-control", - "response-content-disposition", "response-content-encoding", "response-content-language", - "response-content-type", "response-expires", "torrent", "delete", "restore", - "uploadId", "uploads", "versionId", "versioning", "versions", "website") { - if ($query =~ /(?:^|&)($attribute(?:=[^&]*)?)(?:&|$)/) { - push @attributes, uri_unescape($1); - } - } - if (@attributes) { - $resource .= "?" . join("&", @attributes); - } - # handle virtual hosted requests - getResourceToSign($host, \$resource); - } - elsif ($arg =~ /\-X/) { - # mainly for DELETE - $method = $ARGV[++$i]; - } - elsif ($arg =~ /\-H/) { - my $header = $ARGV[++$i]; - #check for host: and x-amz* - if ($header =~ /^[Hh][Oo][Ss][Tt]:(.+)$/) { - $host = $1; - } - elsif ($header =~ /^([Xx]-[Aa][Mm][Zz]-.+?): *(.+)$/) { - my $name = lc $1; - my $value = $2; - # merge with existing values - if (exists $xamzHeaders{$name}) { - $value = $xamzHeaders{$name} . "," . $value; - } - $xamzHeaders{$name} = $value; - } - } -} - -die "Couldn't find resource by digging through your curl command line args!" - unless defined $resource; - -my $xamzHeadersToSign = ""; -foreach (sort (keys %xamzHeaders)) { - my $headerValue = $xamzHeaders{$_}; - $xamzHeadersToSign .= "$_:$headerValue\n"; -} - -my $httpDate = POSIX::strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime ); -my $stringToSign = "$method\n$contentMD5\n$contentType\n$httpDate\n$xamzHeadersToSign$resource"; - -debug("StringToSign='" . $stringToSign . "'"); -my $signature = `echo -n "$stringToSign" | openssl dgst -sha1 -hmac "$secretKey" -binary | base64`; -chomp($signature); -debug("signature='" . $signature. "'"); - - -my @args = (); -push @args, ("-H", "Date: $httpDate"); -push @args, ("-H", "Authorization: AWS $keyId:$signature"); -push @args, ("-H", "x-amz-acl: $acl") if (defined $acl); -push @args, ("-L"); -push @args, ("-H", "content-type: $contentType") if (length $contentType); -push @args, ("-H", "Content-MD5: $contentMD5") if (length $contentMD5); -push @args, ("-T", $fileToPut) if (defined $fileToPut); -push @args, ("-X", "DELETE") if (defined $doDelete); -push @args, ("-X", "POST") if(defined $postBody); -push @args, ("-I") if (defined $doHead); - -if (defined $createBucket) { - # createBucket is a special kind of put from stdin. Reason being, curl mangles the Request-URI - # to include the local filename when you use -T and it decides there is no remote filename (bucket PUT) - my $data=""; - if (length($createBucket)>0) { - $data="$createBucket"; - } - push @args, ("--data-binary", $data); - push @args, ("-X", "PUT"); -} elsif (defined $copySourceObject) { - # copy operation is a special kind of PUT operation where the resource to put - # is specified in the header - push @args, ("-X", "PUT"); - push @args, ("-H", "x-amz-copy-source: $copySourceObject"); -} elsif (defined $postBody) { - if (length($postBody)>0) { - push @args, ("-T", $postBody); - } -} - -push @args, @ARGV; - -debug("exec $CURL " . join (" ", @args)); - -if (defined($print)) { - print join(" ", $CURL, @args, "\n"); - exit(0) -} -exec($CURL, @args) or die "can't exec program: $!"; - -sub debug { - my ($str) = @_; - $str =~ s/\n/\\n/g; - print STDERR "s3curl: $str\n" if ($debug); -} - -sub getResourceToSign { - my ($host, $resourceToSignRef) = @_; - for my $ep (@endpoints) { - if ($host =~ /(.*)\.$ep/) { # vanity subdomain case - my $vanityBucket = $1; - $$resourceToSignRef = "/$vanityBucket".$$resourceToSignRef; - debug("vanity endpoint signing case"); - return; - } - elsif ($host eq $ep) { - debug("ordinary endpoint signing case"); - return; - } - } - # cname case - $$resourceToSignRef = "/$host".$$resourceToSignRef; - debug("cname endpoint signing case"); -} - - -sub printCmdlineSecretWarning { - print STDERR < { - id => '1ME55KNV6SBTR7EXG0R2', - key => 'zyMrlZUKeG9UcYpwzlPko/+Ciu0K2co0duRM3fhi', - }, - - # corporate account - company => { - id => '1ATXQ3HHA59CYF1CVS02', - key => 'WQY4SrSS95pJUT95V6zWea01gBKBCL6PI0cdxeH8', - }, -); - -\$ chmod 600 $DOTFILE - -Will sleep and continue despite this problem. -Please set up $DOTFILE for future requests. -END_WARNING -} - -sub uri_unescape { - my ($input) = @_; - $input =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg; - debug("replaced string: " . $input); - return ($input); -} diff --git a/swift3/test/functional/setup_keystone b/swift3/test/functional/setup_keystone index 45aa119f..45444d94 100644 --- a/swift3/test/functional/setup_keystone +++ b/swift3/test/functional/setup_keystone @@ -1,3 +1,18 @@ +# Copyright (c) 2014 OpenStack Foundation +# +# 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. + export OS_AUTH_URL=http://localhost:35357/v2.0 export OS_TENANT_NAME=admin export OS_USERNAME=admin diff --git a/swift3/test/functional/swift.rc b/swift3/test/functional/swift.rc deleted file mode 100644 index dc60a362..00000000 --- a/swift3/test/functional/swift.rc +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2014 OpenStack Foundation. -# -# 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. - -_sw_setup() -{ - case "$AUTH" - in - tempauth) - export TENANT_ID="AUTH_${TENANT}" - export TOKEN_ID=$($CURL_PROG -s -I -X GET \ - -H "x-storage-user: ${TENANT}:${ADMIN_USER}" \ - -H "x-storage-pass: ${ADMIN_PASS}" \ - http://${SWIFT_HOST}/auth/v1.0 | \ - _hq x-storage-token) - ;; - keystone) - local xml=" -" - - local res=$($CURL_PROG -s -d "$xml" \ - -H 'Content-type: application/xml' \ - -H 'Accept: application/xml' \ - http://${KEYSTONE_HOST}/v2.0/tokens) - - export TENANT_ID="AUTH_$(echo $res | _xpath '/access/token/tenant/@id')" - export TOKEN_ID=$(echo $res | _xpath '/access/token/@id') - ;; - *) - _die "unknown auth, $AUTH" - ;; - esac - - local c - local o - - # remove user data - for c in $(_sw_get / 2>/dev/null); do - _retry _sw_post /$c -H "x-versions-location: $c" # disable versioning - for o in $(_sw_get /$c 2>/dev/null); do - _retry _sw_delete /$c/$o - done - _retry _sw_delete /$c - done -} - -_swcurl() -{ - local tmp_file=$tmp.$RANDOM - - $CURL_PROG -s -H "x-storage-token: ${TOKEN_ID}" "$@" -w '%{http_code}' \ - > $tmp_file - - status=$(tail -c -3 $tmp_file) - echo "> curl $@... $status" | _filter_curl_command >&2 - - head -c -3 $tmp_file - - _is_http_success $status -} - -_sw_head() -{ - local path=$1; shift - - _swcurl -I -X HEAD "$@" http://${SWIFT_HOST}/v1/${TENANT_ID}${path} -} - -_sw_get() -{ - local path=$1; shift - - _swcurl -X GET "$@" http://${SWIFT_HOST}/v1/${TENANT_ID}${path} -} - -_sw_put() -{ - local path=$1; shift - - _swcurl -X PUT "$@" http://${SWIFT_HOST}/v1/${TENANT_ID}${path} -} - -_sw_post() -{ - local path=$1; shift - - _swcurl -X POST "$@" http://${SWIFT_HOST}/v1/${TENANT_ID}${path} -} - -_sw_delete() -{ - local path=$1; shift - - _swcurl -X DELETE "$@" http://${SWIFT_HOST}/v1/${TENANT_ID}${path} -} - -# make sure this script returns success -/bin/true diff --git a/swift3/test/functional/swift3.config b/swift3/test/functional/swift3.config new file mode 100644 index 00000000..ad7d7c92 --- /dev/null +++ b/swift3/test/functional/swift3.config @@ -0,0 +1,42 @@ +#!/bin/bash +# Copyright (c) 2015 OpenStack Foundation +# +# 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. + +export LANG=C +export PWD=`pwd` +export TEST_DIR=$PWD/'scratch' + +export SWIFT_HOST=${SWIFT_HOST:-"localhost:8080"} +export KEYSTONE_HOST=${KEYSTONE_HOST:-"localhost:35357"} +export AUTH=${AUTH:-"keystone"} + +export ADMIN_TENANT=${ADMIN_TENANT:-"test"} +export ADMIN_USER=${ADMIN_USER:-"admin"} +export ADMIN_PASS=${ADMIN_PASS:-"admin"} +export ADMIN_ACCESS_KEY=${ADMIN_ACCESS_KEY:-"${ADMIN_TENANT}:${ADMIN_USER}"} +export ADMIN_SECRET_KEY=${ADMIN_SECRET_KEY:-"${ADMIN_PASS}"} + +export TESTER_TENANT=${TESTER_TENANT:-"test"} +export TESTER_USER=${TESTER_USER:-"tester"} +export TESTER_PASS=${TESTER_PASS:-"testing"} +export TESTER_ACCESS_KEY=${TESTER_ACCESS_KEY:-"${TESTER_TENANT}:${TESTER_USER}"} +export TESTER_SECRET_KEY=${TESTER_SECRET_KEY:-"${TESTER_PASS}"} + +export TESTER2_TENANT=${TESTER2_TENANT:-"test"} +export TESTER2_USER=${TESTER2_USER:-"tester2"} +export TESTER2_PASS=${TESTER2_PASS:-"testing2"} +export TESTER2_ACCESS_KEY=${TESTER2_ACCESS_KEY:-"${TESTER2_TENANT}:${TESTER2_USER}"} +export TESTER2_SECRET_KEY=${TESTER2_SECRET_KEY:-"${TESTER2_PASS}"} + diff --git a/swift3/test/functional/test_bucket.py b/swift3/test/functional/test_bucket.py new file mode 100644 index 00000000..82ed5cab --- /dev/null +++ b/swift3/test/functional/test_bucket.py @@ -0,0 +1,167 @@ +# Copyright (c) 2015 OpenStack Foundation +# +# 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. + +import unittest + +from swift3.test.functional.s3_test_client import get_tester_connection,\ + Connection +from swift3.test.functional.utils import get_error_code,\ + assert_common_response_headers +from swift3.etree import fromstring +from swift3.cfg import CONF + + +class TestSwift3Bucket(unittest.TestCase): + def setUp(self): + self.conn = get_tester_connection() + self.conn.reset() + + def test_bucket(self): + bucket = 'bucket' + + # PUT Bucket + status, headers, body = self.conn.make_request('PUT', bucket) + self.assertEquals(status, 200) + + assert_common_response_headers(self, headers) + self.assertEquals(headers['location'], '/' + bucket) + self.assertEquals(headers['content-length'], '0') + + # GET Bucket(Without Object) + status, headers, body = self.conn.make_request('GET', bucket) + self.assertEquals(status, 200) + + assert_common_response_headers(self, headers) + self.assertTrue(headers['content-type'] is not None) + self.assertEquals(headers['content-length'], str(len(body))) + # TODO; requires consideration + # self.assertEquasl(headers['transfer-encoding'], 'chunked') + + elem = fromstring(body, 'ListBucketResult') + self.assertEquals(elem.find('Name').text, bucket) + self.assertEquals(elem.find('Prefix').text, None) + self.assertEquals(elem.find('Marker').text, None) + self.assertEquals(elem.find('MaxKeys').text, + str(CONF.max_bucket_listing)) + self.assertEquals(elem.find('IsTruncated').text, 'false') + objects = elem.findall('./Contents') + self.assertEquals(list(objects), []) + + # GET Bucket(With Object) + req_objects = ('object', 'object2') + for obj in req_objects: + self.conn.make_request('PUT', bucket, obj) + status, headers, body = self.conn.make_request('GET', bucket) + self.assertEquals(status, 200) + + elem = fromstring(body, 'ListBucketResult') + self.assertEquals(elem.find('Name').text, bucket) + self.assertEquals(elem.find('Prefix').text, None) + self.assertEquals(elem.find('Marker').text, None) + self.assertEquals(elem.find('MaxKeys').text, + str(CONF.max_bucket_listing)) + self.assertEquals(elem.find('IsTruncated').text, 'false') + resp_objects = elem.findall('./Contents') + self.assertEquals(len(list(resp_objects)), 2) + for o in resp_objects: + self.assertTrue(o.find('Key').text in req_objects) + self.assertTrue(o.find('LastModified').text is not None) + self.assertTrue(o.find('ETag').text is not None) + self.assertTrue(o.find('Size').text is not None) + self.assertTrue(o.find('StorageClass').text is not None) + self.assertTrue(o.find('Owner/ID').text, self.conn.user_id) + self.assertTrue(o.find('Owner/DisplayName').text, + self.conn.user_id) + + # HEAD Bucket + status, headers, body = self.conn.make_request('HEAD', bucket) + self.assertEquals(status, 200) + + assert_common_response_headers(self, headers) + self.assertTrue(headers['content-type'] is not None) + self.assertEquals(headers['content-length'], str(len(body))) + # TODO; requires consideration + # self.assertEquasl(headers['transfer-encoding'], 'chunked') + + # DELETE Bucket + for obj in req_objects: + self.conn.make_request('DELETE', bucket, obj) + status, headers, body = self.conn.make_request('DELETE', bucket) + self.assertEquals(status, 204) + + assert_common_response_headers(self, headers) + + def test_put_bucket_error(self): + status, headers, body = \ + self.conn.make_request('PUT', 'bucket+invalid') + self.assertEquals(get_error_code(body), 'InvalidBucketName') + + auth_error_conn = Connection(aws_secret_key='invalid') + status, headers, body = auth_error_conn.make_request('PUT', 'bucket') + self.assertEquals(get_error_code(body), 'SignatureDoesNotMatch') + + self.conn.make_request('PUT', 'bucket') + status, headers, body = self.conn.make_request('PUT', 'bucket') + self.assertEquals(get_error_code(body), 'BucketAlreadyExists') + self.conn.make_request('DELETE', 'bucket') + + def test_get_bucket_error(self): + self.conn.make_request('PUT', 'bucket') + + status, headers, body = \ + self.conn.make_request('GET', 'bucket+invalid') + self.assertEquals(get_error_code(body), 'InvalidBucketName') + + auth_error_conn = Connection(aws_secret_key='invalid') + status, headers, body = auth_error_conn.make_request('GET', 'bucket') + self.assertEquals(get_error_code(body), 'SignatureDoesNotMatch') + + status, headers, body = self.conn.make_request('GET', 'nothing') + self.assertEquals(get_error_code(body), 'NoSuchBucket') + + self.conn.make_request('DELETE', 'bucket') + + def test_head_bucket_error(self): + self.conn.make_request('PUT', 'bucket') + + status, headers, body = \ + self.conn.make_request('HEAD', 'bucket+invalid') + self.assertEquals(status, 400) + + auth_error_conn = Connection(aws_secret_key='invalid') + status, headers, body = \ + auth_error_conn.make_request('HEAD', 'bucket') + self.assertEquals(status, 403) + + status, headers, body = self.conn.make_request('HEAD', 'nothing') + self.assertEquals(status, 404) + + self.conn.make_request('DELETE', 'bucket') + + def test_delete_bucket_error(self): + status, headers, body = \ + self.conn.make_request('DELETE', 'bucket+invalid') + self.assertEquals(get_error_code(body), 'InvalidBucketName') + + auth_error_conn = Connection(aws_secret_key='invalid') + status, headers, body = \ + auth_error_conn.make_request('DELETE', 'bucket') + self.assertEquals(get_error_code(body), 'SignatureDoesNotMatch') + + status, headers, body = self.conn.make_request('DELETE', 'bucket') + self.assertEquals(get_error_code(body), 'NoSuchBucket') + +if __name__ == '__main__': + unittest.main() diff --git a/swift3/test/functional/test_object.py b/swift3/test/functional/test_object.py new file mode 100644 index 00000000..2309eea2 --- /dev/null +++ b/swift3/test/functional/test_object.py @@ -0,0 +1,138 @@ +# Copyright (c) 2015 OpenStack Foundation +# +# 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. + +import unittest + +from swift3.test.functional.s3_test_client import get_tester_connection,\ + Connection +from swift3.test.functional.utils import get_error_code,\ + assert_common_response_headers + + +class TestSwift3Object(unittest.TestCase): + def setUp(self): + self.conn = get_tester_connection() + self.conn.reset() + self.bucket = 'bucket' + self.conn.make_request('PUT', self.bucket) + + def test_object(self): + obj = 'object' + contents = 'abc123' + + # PUT Object + status, headers, body = \ + self.conn.make_request('PUT', self.bucket, obj, body=contents) + self.assertEquals(status, 200) + + assert_common_response_headers(self, headers) + self.assertTrue(headers['etag'] is not None) + self.assertEquals(headers['content-length'], '0') + + # GET Object + status, headers, body = \ + self.conn.make_request('GET', self.bucket, obj) + self.assertEquals(status, 200) + + assert_common_response_headers(self, headers) + self.assertTrue(headers['last-modified'] is not None) + self.assertTrue(headers['etag'] is not None) + self.assertTrue(headers['content-type'] is not None) + self.assertEquals(headers['content-length'], str(len(contents))) + + # HEAD Object + status, headers, body = \ + self.conn.make_request('HEAD', self.bucket, obj) + self.assertEquals(status, 200) + + assert_common_response_headers(self, headers) + self.assertTrue(headers['last-modified'] is not None) + self.assertTrue(headers['etag'] is not None) + self.assertTrue(headers['content-type'] is not None) + self.assertEquals(headers['content-length'], str(len(contents))) + + # DELETE Object + status, headers, body = \ + self.conn.make_request('DELETE', self.bucket, obj) + self.assertEquals(status, 204) + + assert_common_response_headers(self, headers) + + def test_put_object_error(self): + auth_error_conn = Connection(aws_secret_key='invalid') + status, headers, body = \ + auth_error_conn.make_request('PUT', self.bucket, 'object') + self.assertEquals(get_error_code(body), 'SignatureDoesNotMatch') + + status, headers, body = \ + self.conn.make_request('PUT', 'bucket2', 'object') + self.assertEquals(get_error_code(body), 'NoSuchBucket') + + def test_get_object_error(self): + obj = 'object' + self.conn.make_request('PUT', self.bucket, obj) + + auth_error_conn = Connection(aws_secret_key='invalid') + status, headers, body = \ + auth_error_conn.make_request('GET', self.bucket, obj) + self.assertEquals(get_error_code(body), 'SignatureDoesNotMatch') + + status, headers, body = \ + self.conn.make_request('GET', self.bucket, 'invalid') + self.assertEquals(get_error_code(body), 'NoSuchKey') + + status, headers, body = self.conn.make_request('GET', 'invalid', obj) + # TODO; requires consideration + # self.assertEquals(get_error_code(body), 'NoSuchBucket') + self.assertEquals(get_error_code(body), 'NoSuchKey') + + def test_head_object_error(self): + obj = 'object' + self.conn.make_request('PUT', self.bucket, obj) + + auth_error_conn = Connection(aws_secret_key='invalid') + status, headers, body = \ + auth_error_conn.make_request('HEAD', self.bucket, obj) + self.assertEquals(status, 403) + + status, headers, body = \ + self.conn.make_request('HEAD', self.bucket, 'invalid') + self.assertEquals(status, 404) + + status, headers, body = \ + self.conn.make_request('HEAD', 'invalid', obj) + self.assertEquals(status, 404) + + def test_delete_object_error(self): + obj = 'object' + self.conn.make_request('PUT', self.bucket, obj) + + auth_error_conn = Connection(aws_secret_key='invalid') + status, headers, body = \ + auth_error_conn.make_request('DELETE', self.bucket, obj) + self.assertEquals(get_error_code(body), 'SignatureDoesNotMatch') + + status, headers, body = \ + self.conn.make_request('DELETE', self.bucket, 'invalid') + self.assertEquals(get_error_code(body), 'NoSuchKey') + + status, headers, body = \ + self.conn.make_request('DELETE', 'invalid', obj) + # TODO; requires consideration + # self.assertEquals(get_error_code(body), 'NoSuchBucket') + self.assertEquals(get_error_code(body), 'NoSuchKey') + +if __name__ == '__main__': + unittest.main() diff --git a/swift3/test/functional/test_service.py b/swift3/test/functional/test_service.py new file mode 100644 index 00000000..9ce1e2ab --- /dev/null +++ b/swift3/test/functional/test_service.py @@ -0,0 +1,67 @@ +# Copyright (c) 2015 OpenStack Foundation +# +# 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. + +import unittest + +from swift3.test.functional.s3_test_client import get_tester_connection,\ + Connection +from swift3.test.functional.utils import get_error_code,\ + assert_common_response_headers +from swift3.etree import fromstring + + +class TestSwift3Service(unittest.TestCase): + def setUp(self): + self.conn = get_tester_connection() + self.conn.reset() + + def test_service(self): + # GET Service(without bucket) + status, headers, body = self.conn.make_request('GET') + self.assertEquals(status, 200) + + assert_common_response_headers(self, headers) + self.assertTrue(headers['content-type'] is not None) + # TODO; requires consideration + # self.assertEquasl(headers['transfer-encoding'], 'chunked') + + elem = fromstring(body, 'ListAllMyBucketsResult') + buckets = elem.findall('./Buckets/Bucket') + self.assertEquals(list(buckets), []) + owner = elem.find('Owner') + self.assertEquals(self.conn.user_id, owner.find('ID').text) + self.assertEquals(self.conn.user_id, owner.find('DisplayName').text) + + # GET Service(with Bucket) + req_buckets = ('bucket', 'bucket2') + for bucket in req_buckets: + self.conn.make_request('PUT', bucket) + status, headers, body = self.conn.make_request('GET') + self.assertEquals(status, 200) + + elem = fromstring(body, 'ListAllMyBucketsResult') + resp_buckets = elem.findall('./Buckets/Bucket') + self.assertEquals(len(list(resp_buckets)), 2) + for b in resp_buckets: + self.assertTrue(b.find('Name').text in req_buckets) + self.assertTrue(b.find('CreationDate') is not None) + + def test_service_error(self): + auth_error_conn = Connection(aws_secret_key='invalid') + status, headers, body = auth_error_conn.make_request('GET') + self.assertEquals(get_error_code(body), 'SignatureDoesNotMatch') + +if __name__ == '__main__': + unittest.main() diff --git a/swift3/test/functional/xpath.py b/swift3/test/functional/utils.py old mode 100755 new mode 100644 similarity index 56% rename from swift3/test/functional/xpath.py rename to swift3/test/functional/utils.py index 5674794f..a4a82cfe --- a/swift3/test/functional/xpath.py +++ b/swift3/test/functional/utils.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python -# Copyright (c) 2014 OpenStack Foundation +# Copyright (c) 2015 OpenStack Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,10 +13,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from swift3.etree import fromstring -if __name__ == '__main__': - elem = fromstring(sys.stdin.read()) - print elem.xpath(sys.argv[1])[0] + +def assert_common_response_headers(self, headers): + self.assertTrue(headers['x-amz-id-2'] is not None) + self.assertTrue(headers['x-amz-request-id'] is not None) + self.assertTrue(headers['date'] is not None) + # TODO; requires consideration + # self.assertTrue(headers['server'] is not None) + + +def get_error_code(body): + elem = fromstring(body, 'Error') + return elem.find('Code').text diff --git a/swift3/test/functional/xmlindent.py b/swift3/test/functional/xmlindent.py deleted file mode 100755 index acfe4d88..00000000 --- a/swift3/test/functional/xmlindent.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2014 OpenStack Foundation -# -# 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. - -import sys - -from lxml.etree import fromstring, tostring - -if __name__ == '__main__': - xml = sys.stdin.read().replace('\n', '') - elem = fromstring(xml) - print tostring(elem, xml_declaration=True, encoding='UTF-8', - pretty_print=True), diff --git a/test-requirements.txt b/test-requirements.txt index 742c56e7..63120fb5 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -6,3 +6,4 @@ coverage mock pylint python-openstackclient +boto