#!/usr/bin/env python
# Copyright (c) 2001 actzero, inc. All rights reserved.
# This set of clients validates when run against the servers in
# silab.servers.
import copy
import fileinput
import getopt
import re
import string
import sys
import time
import traceback
sys.path.insert (1, '..')
from SOAPpy import SOAP
SOAP.Config.typesNamespace = SOAP.NS.XSD3
SOAP.Config.typesNamespace = SOAP.NS.XSD3
ident = '$Id: silabclient.py,v 1.2 2003/03/08 05:10:01 warnes Exp $'
DEFAULT_SERVERS_FILE = 'silab.servers'
DEFAULT_METHODS = \
(
'actorShouldPass', 'actorShouldFail',
'echoDate', 'echoBase64',
'echoFloat', 'echoFloatArray',
'echoFloatINF', 'echoFloatNaN',
'echoFloatNegINF', 'echoFloatNegZero',
'echoInteger', 'echoIntegerArray',
'echoString', 'echoStringArray',
'echoStruct', 'echoStructArray',
'echoVeryLargeFloat', 'echoVerySmallFloat',
'echoVoid',
'mustUnderstandEqualsOne', 'mustUnderstandEqualsZero',
)
def usage (error = None):
sys.stdout = sys.stderr
if error != None:
print error
print """usage: %s [options] [server ...]
If a long option shows an argument is mandatory, it's mandatory for the
equivalent short option also.
-?, --help display this usage
-d, --debug turn on debugging in the SOAP library
-e, --exit-on-failure exit on the first (unexpected) failure
-h, --harsh turn on harsh testing:
- look for the documented error code from
mustUnderstand failures
- use non-ASCII strings in the string tests
-i, --invert test servers *not* in the list of servers given
-m, --method=METHOD#[,METHOD#...]
call only the given methods, specify a METHOD# of ?
for the list of method numbers
-n, --no-stats, --no-statistics
don't display success and failure statistics
-N, --no-boring-stats, --no-boring-statistics
only display unexpected failures and unimplemented
tests, and only if non-zero
-o, --output=TYPE turn on output, TYPE is one or more of s(uccess),
f(ailure), n(ot implemented), F(ailed (as expected)),
a(ll)
[f]
-s, --servers=FILE use FILE as list of servers to test [%s]
-t, --stacktrace print a stack trace on each unexpected failure
-T, --always-stacktrace
print a stack trace on any failure
""" % (sys.argv[0], DEFAULT_SERVERS_FILE),
sys.exit (0)
def methodUsage ():
sys.stdout = sys.stderr
print "Methods are specified by number. Multiple methods can be " \
"specified using a\ncomma-separated list of numbers or ranges. " \
"For example 1,4-6,8 specifies\nmethods 1, 4, 5, 6, and 8.\n"
print "The available methods are:\n"
half = (len (DEFAULT_METHODS) + 1) / 2
for i in range (half):
print "%4d. %-25s" % (i + 1, DEFAULT_METHODS[i]),
if i + half < len (DEFAULT_METHODS):
print "%4d. %-25s" % (i + 1 + half, DEFAULT_METHODS[i + half]),
print
sys.exit (0)
# as borrowed from jake.soapware.org for float compares.
def nearlyeq (a, b, prec = 1e-7):
return abs (a - b) <= abs (a) * prec
def readServers (file):
servers = []
names = {}
cur = None
f = fileinput.input(file)
for line in f:
if line[0] == '#':
continue
if line == '' or line[0] == '\n':
cur = None
continue
if cur == None:
cur = {'nonfunctional': {}, '_line': f.filelineno(),
'_file': f.filename()}
tag = None
servers.append (cur)
if line[0] in string.whitespace:
if tag == 'nonfunctional':
value = method + ' ' + cur[tag][method]
else:
value = cur[tag]
value += ' ' + line.strip ()
elif line[0] == '_':
raise ValueError, \
"%s, line %d: can't have a tag starting with `_'" % \
(f.filename(), f.filelineno())
else:
tag, value = line.split (':', 1)
tag = tag.strip ().lower ()
value = value.strip ()
if value[0] == '"' and value[-1] == '"':
value = value[1:-1]
if tag == 'typed':
if value.lower() in ('0', 'no', 'false'):
value = 0
elif value.lower() in ('1', 'yes', 'false'):
value = 1
else:
raise ValueError, \
"%s, line %d: unknown typed value `%s'" % \
(f.filename(), f.filelineno(), value)
elif tag == 'name':
if names.has_key(value):
old = names[value]
raise ValueError, \
"%s, line %d: already saw a server named `%s' " \
"(on line %d of %s)" % \
(f.filename(), f.filelineno(), value,
old['_line'], old['_file'])
names[value] = cur
if tag == 'nonfunctional':
value = value.split (' ', 1) + ['']
method = value[0]
cur[tag][method] = value[1]
elif tag == 'functional':
try:
del cur['nonfunctional'][value]
except:
raise ValueError, \
"%s, line %d: `%s' not marked nonfunctional" % \
(f.filename(), f.filelineno(), value)
elif tag == 'like':
try:
new = copy.deepcopy(names[value])
except:
raise ValueError, \
"%s, line %d: don't know about a server named `%s'" % \
(f.filename(), f.filelineno(), value)
# This is so we don't lose the nonfunctional methods in new or
# in cur
new['nonfunctional'].update(cur['nonfunctional'])
del cur['nonfunctional']
new.update(cur)
# This is because servers and possibly names has a reference to
# cur, so we have to keep working with cur so changes are
# reflected in servers and names.
cur.update(new)
else:
cur[tag] = value
return servers
def str2list (s):
l = {}
for i in s.split (','):
if i.find ('-') != -1:
i = i.split ('-')
for i in range (int (i[0]),int (i[1]) + 1):
l[i] = 1
else:
l[int (i)] = 1
l = l.keys ()
l.sort ()
return l
def testActorShouldPass (server, action, harsh):
test = 42
server = server._sa (action % {'methodname': 'echoInteger'})
hd = SOAP.headerType ()
hd.InteropTestHeader = SOAP.stringType ("This shouldn't fault because "
"the mustUnderstand attribute is 0")
hd.InteropTestHeader._setMustUnderstand (0)
hd.InteropTestHeader._setActor (
'http://schemas.xmlsoap.org/soap/actor/next')
server = server._hd (hd)
result = server.echoInteger (inputInteger = test)
if not SOAP.Config.typed:
result = int (result)
if result != test:
raise Exception, "expected %s, got %s" % (test, result)
def testActorShouldFail (server, action, harsh):
test = 42
server = server._sa (action % {'methodname': 'echoInteger'})
hd = SOAP.headerType ()
hd.InteropTestHeader = SOAP.stringType ("This should fault because "
"the mustUnderstand attribute is 1")
hd.InteropTestHeader._setMustUnderstand (1)
hd.InteropTestHeader._setActor (
'http://schemas.xmlsoap.org/soap/actor/next')
server = server._hd (hd)
try:
result = server.echoInteger (inputInteger = test)
except SOAP.faultType, e:
if harsh and e.faultcode != 'SOAP-ENV:MustUnderstand':
raise AttributeError, "unexpected faultcode %s" % e.faultcode
return
raise Exception, "should fail, succeeded with %s" % result
def testEchoFloat (server, action, harsh):
server = server._sa (action % {'methodname': 'echoFloat'})
for test in (0.0, 1.0, -1.0, 3853.33333333):
result = server.echoFloat (inputFloat = test)
if not SOAP.Config.typed:
result = float (result)
if not nearlyeq (result, test):
raise Exception, "expected %.8f, got %.8f" % (test, result)
def testEchoFloatArray (server, action, harsh):
test = [0.0, 1.0, -1.0, 3853.33333333]
server = server._sa (action % {'methodname': 'echoFloatArray'})
result = server.echoFloatArray (inputFloatArray = test)
for i in range (len (test)):
if not SOAP.Config.typed:
result[i] = float (result[i])
if not nearlyeq (result[i], test[i]):
raise Exception, "@ %d expected %s, got %s" % \
(i, repr (test), repr (result))
def testEchoFloatINF (server, action, harsh):
try:
test = float ('INF')
except:
test = float (1e300**2)
server = server._sa (action % {'methodname': 'echoFloat'})
result = server.echoFloat (inputFloat = test)
if not SOAP.Config.typed:
result = float (result)
if result != test:
raise Exception, "expected %.8f, got %.8f" % (test, result)
def testEchoFloatNaN (server, action, harsh):
try:
test = float ('NaN')
except:
test = float (0.0)
server = server._sa (action % {'methodname': 'echoFloat'})
result = server.echoFloat (inputFloat = test)
if not SOAP.Config.typed:
result = float (result)
if result != test:
raise Exception, "expected %.8f, got %.8f" % (test, result)
def testEchoFloatNegINF (server, action, harsh):
try:
test = float ('-INF')
except:
test = float (-1e300**2)
server = server._sa (action % {'methodname': 'echoFloat'})
result = server.echoFloat (inputFloat = test)
if not SOAP.Config.typed:
result = float (result)
if result != test:
raise Exception, "expected %.8f, got %.8f" % (test, result)
def testEchoFloatNegZero (server, action, harsh):
test = float ('-0.0')
server = server._sa (action % {'methodname': 'echoFloat'})
result = server.echoFloat (inputFloat = test)
if not SOAP.Config.typed:
result = float (result)
if result != test:
raise Exception, "expected %.8f, got %.8f" % (test, result)
def testEchoInteger (server, action, harsh):
server = server._sa (action % {'methodname': 'echoInteger'})
for test in (0, 1, -1, 3853):
result = server.echoInteger (inputInteger = test)
if not SOAP.Config.typed:
result = int (result)
if result != test:
raise Exception, "expected %.8f, got %.8f" % (test, result)
def testEchoIntegerArray (server, action, harsh):
test = [0, 1, -1, 3853]
server = server._sa (action % {'methodname': 'echoIntegerArray'})
result = server.echoIntegerArray (inputIntegerArray = test)
for i in range (len (test)):
if not SOAP.Config.typed:
result[i] = int (result[i])
if result[i] != test[i]:
raise Exception, "@ %d expected %s, got %s" % \
(i, repr (test), repr (result))
relaxedStringTests = ['', 'Hello', '\'<&>"',]
relaxedStringTests = ['Hello', '\'<&>"',]
harshStringTests = ['', 'Hello', '\'<&>"',
u'\u0041', u'\u00a2', u'\u0141', u'\u2342',
u'\'<\u0041&>"', u'\'<\u00a2&>"', u'\'<\u0141&>"', u'\'<\u2342&>"',]
def testEchoString (server, action, harsh):
if harsh:
test = harshStringTests
else:
test = relaxedStringTests
server = server._sa (action % {'methodname': 'echoString'})
for test in test:
result = server.echoString (inputString = test)
if result != test:
raise Exception, "expected %s, got %s" % \
(repr (test), repr (result))
def testEchoStringArray (server, action, harsh):
if harsh:
test = harshStringTests
else:
test = relaxedStringTests
server = server._sa (action % {'methodname': 'echoStringArray'})
result = server.echoStringArray (inputStringArray = test)
if result != test:
raise Exception, "expected %s, got %s" % (repr (test), repr (result))
def testEchoStruct (server, action, harsh):
test = {'varFloat': 2.256, 'varInt': 474, 'varString': 'Utah'}
server = server._sa (action % {'methodname': 'echoStruct'})
result = server.echoStruct (inputStruct = test)
if not SOAP.Config.typed:
result.varFloat = float (result.varFloat)
result.varInt = int (result.varInt)
if not nearlyeq (test['varFloat'], result.varFloat):
raise Exception, ".varFloat expected %s, got %s" % \
(i, repr (test['varFloat']), repr (result.varFloat))
for i in test.keys ():
if i == 'varFloat':
continue
if test[i] != getattr (result, i):
raise Exception, ".%s expected %s, got %s" % \
(i, repr (test[i]), repr (getattr (result, i)))
def testEchoStructArray (server, action, harsh):
test = [{'varFloat': -5.398, 'varInt': -546, 'varString': 'West Virginia'},
{'varFloat': -9.351, 'varInt': -641, 'varString': 'New Mexico'},
{'varFloat': 1.495, 'varInt': -819, 'varString': 'Missouri'}]
server = server._sa (action % {'methodname': 'echoStructArray'})
result = server.echoStructArray (inputStructArray = test)
for s in range (len (test)):
if not SOAP.Config.typed:
result[s].varFloat = float (result[s].varFloat)
result[s].varInt = int (result[s].varInt)
if not nearlyeq (test[s]['varFloat'], result[s].varFloat):
raise Exception, \
"@ %d.varFloat expected %s, got %s" % \
(s, repr (test[s]['varFloat']), repr (result[s].varFloat))
for i in test[s].keys ():
if i == 'varFloat':
continue
if test[s][i] != getattr (result[s], i):
raise Exception, "@ %d.%s expected %s, got %s" % \
(s, i, repr (test[s][i]), repr (getattr (result[s], i)))
def testEchoVeryLargeFloat (server, action, harsh):
test = 2.2535e29
server = server._sa (action % {'methodname': 'echoFloat'})
result = server.echoFloat (inputFloat = test)
if not SOAP.Config.typed:
result = float (result)
if not nearlyeq (result, test):
raise Exception, "expected %s, got %s" % (repr (test), repr (result))
def testEchoVerySmallFloat (server, action, harsh):
test = 2.2535e29
server = server._sa (action % {'methodname': 'echoFloat'})
result = server.echoFloat (inputFloat = test)
if not SOAP.Config.typed:
result = float (result)
if not nearlyeq (result, test):
raise Exception, "expected %s, got %s" % (repr (test), repr (result))
def testEchoVoid (server, action, harsh):
server = server._sa (action % {'methodname': 'echoVoid'})
result = server.echoVoid ()
for k in result.__dict__.keys ():
if k[0] != '_':
raise Exception, "expected an empty structType, got %s" % \
repr (result.__dict__)
def testMustUnderstandEqualsOne (server, action, harsh):
test = 42
server = server._sa (action % {'methodname': 'echoInteger'})
hd = SOAP.headerType ()
hd.MustUnderstandThis = SOAP.stringType ("This should fault because "
"the mustUnderstand attribute is 1")
hd.MustUnderstandThis._setMustUnderstand (1)
server = server._hd (hd)
try:
result = server.echoInteger (inputInteger = test)
except SOAP.faultType, e:
if harsh and e.faultcode != 'SOAP-ENV:MustUnderstand':
raise AttributeError, "unexpected faultcode %s" % e.faultcode
return
raise Exception, "should fail, succeeded with %s" % result
def testMustUnderstandEqualsZero (server, action, harsh):
test = 42
server = server._sa (action % {'methodname': 'echoInteger'})
hd = SOAP.headerType ()
hd.MustUnderstandThis = SOAP.stringType ("This shouldn't fault because "
"the mustUnderstand attribute is 0")
hd.MustUnderstandThis._setMustUnderstand (0)
server = server._hd (hd)
result = server.echoInteger (inputInteger = test)
if not SOAP.Config.typed:
result = int (result)
if result != test:
raise Exception, "expected %s, got %s" % (test, result)
def testEchoDate (server, action, harsh):
test = time.gmtime (time.time ())
server = server._sa (action % {'methodname': 'echoDate'})
if SOAP.Config.namespaceStyle == '1999':
result = server.echoDate (inputDate = SOAP.timeInstantType (test))
else:
result = server.echoDate (inputDate = SOAP.dateTimeType (test))
if not SOAP.Config.typed and type (result) in (type (''), type (u'')):
p = SOAP.SOAPParser()
result = p.convertDateTime(result, 'timeInstant')
if result != test[:6]:
raise Exception, "expected %s, got %s" % (repr (test), repr (result))
def testEchoBase64 (server, action, harsh):
test = '\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\xa0\xb0\xc0\xd0\xe0\xf0'
server = server._sa (action % {'methodname': 'echoBase64'})
result = server.echoBase64 (inputBase64 = SOAP.base64Type (test))
if not SOAP.Config.typed:
import base64
result = base64.decodestring(result)
if result != test:
raise Exception, "expected %s, got %s" % (repr (test), repr (result))
def main ():
stats = 1
total = 0
fail = 0
failok = 0
succeed = 0
exitonfailure = 0
harsh = 0
invert = 0
printtrace = 0
methodnums = None
notimp = 0
output = 'f'
servers = DEFAULT_SERVERS_FILE
started = time.time ()
try:
opts, args = getopt.getopt (sys.argv[1:], '?dehim:nNo:s:tT',
['help', 'debug', 'exit-on-failure', 'harsh', 'invert',
'method', 'no-stats', 'no-statistics',
'no-boring-statistics', 'no-boring-stats', 'output',
'servers=', 'stacktrace', 'always-stacktrace'])
for opt, arg in opts:
if opt in ('-?', '--help'):
usage ()
elif opt in ('-d', '--debug'):
SOAP.Config.debug = 1
elif opt in ('-h', '--harsh'):
harsh = 1
elif opt in ('-i', '--invert'):
invert = 1
elif opt in ('-e', '--exit-on-failure'):
exitonfailure = 1
elif opt in ('-m', '--method'):
if arg == '?':
methodUsage ()
methodnums = str2list (arg)
elif opt in ('-n', '--no-stats', '--no-statistics'):
stats = 0
elif opt in ('-N', '--no-boring-stats', '--no-boring-statistics'):
stats = -1
elif opt in ('-o', '--output'):
output = arg
elif opt in ('-s', '--servers'):
servers = arg
elif opt in ('-t', '--stacktrace'):
printtrace = 1
elif opt in ('-T', '--always-stacktrace'):
printtrace = 2
else:
raise AttributeError, \
"Recognized but unimplemented option `%s'" % opt
except SystemExit:
raise
except:
usage (sys.exc_info ()[1])
if 'a' in output:
output = 'fFns'
servers = readServers (servers)
if methodnums == None:
methodnums = range (1, len (DEFAULT_METHODS) + 1)
limitre = re.compile ('|'.join (args), re.IGNORECASE)
for s in servers:
if (not not limitre.match (s['name'])) == invert:
continue
try: typed = s['typed']
except: typed = 1
try: style = s['style']
except: style = 1999
SOAP.Config.typed = typed
SOAP.Config.namespaceStyle = style
server = SOAP.SOAPProxy (s['endpoint'], ("m", s['namespace']))
for num in (methodnums):
if num > len (DEFAULT_METHODS):
break
total += 1
name = DEFAULT_METHODS[num - 1]
title = '%s: %s (#%d)' % (s['name'], name, num)
if SOAP.Config.debug:
print "%s:" % title
try:
fn = globals ()['test' + name[0].upper () + name[1:]]
except KeyboardInterrupt:
raise
except:
if 'n' in output:
print title, "test not yet implemented"
notimp += 1
continue
try:
fn (server, s['soapaction'], harsh)
if s['nonfunctional'].has_key (name):
print title, \
"succeeded despite being marked nonfunctional"
if 's' in output:
print title, "succeeded"
succeed += 1
except KeyboardInterrupt:
raise
except:
fault = str (sys.exc_info ()[1])
if fault[-1] == '\n':
fault = fault[:-1]
if s['nonfunctional'].has_key (name):
if 'F' in output:
t = 'as expected'
if s['nonfunctional'][name] != '':
t += ', ' + s['nonfunctional'][name]
print title, "failed (%s) -" % t, fault
if printtrace > 1:
traceback.print_exc ()
failok += 1
else:
if 'f' in output:
print title, "failed -", fault
if printtrace:
traceback.print_exc ()
fail += 1
if exitonfailure:
return -1
if stats:
print " Tests started at:", time.ctime (started)
if stats > 0:
print " Total tests: %d" % total
print " Successes: %d (%3.2f%%)" % \
(succeed, 100.0 * succeed / total)
if stats > 0 or fail > 0:
print "Failed unexpectedly: %d (%3.2f%%)" % \
(fail, 100.0 * fail / total)
if stats > 0:
print " Failed as expected: %d (%3.2f%%)" % \
(failok, 100.0 * failok / total)
if stats > 0 or notimp > 0:
print " Not implemented: %d (%3.2f%%)" % \
(notimp, 100.0 * notimp / total)
return fail + notimp
if __name__ == '__main__':
try:
sys.exit (main ())
except KeyboardInterrupt:
sys.exit (0)
|