A fork of https://github.com/Synerty/SOAPpy-py3 This is a working tree till fixes get imported upstream.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

700 lines
22 KiB

  1. #!/usr/bin/env python
  2. # Copyright (c) 2001 actzero, inc. All rights reserved.
  3. # This set of clients validates when run against the servers in
  4. # silab.servers.
  5. import copy
  6. import fileinput
  7. import getopt
  8. import re
  9. import string
  10. import sys
  11. import time
  12. import traceback
  13. sys.path.insert (1, '..')
  14. from SOAPpy import SOAP
  15. SOAP.Config.typesNamespace = SOAP.NS.XSD3
  16. SOAP.Config.typesNamespace = SOAP.NS.XSD3
  17. ident = '$Id: silabclient.py 98 2003-03-08 05:10:01Z warnes $'
  18. DEFAULT_SERVERS_FILE = 'silab.servers'
  19. DEFAULT_METHODS = \
  20. (
  21. 'actorShouldPass', 'actorShouldFail',
  22. 'echoDate', 'echoBase64',
  23. 'echoFloat', 'echoFloatArray',
  24. 'echoFloatINF', 'echoFloatNaN',
  25. 'echoFloatNegINF', 'echoFloatNegZero',
  26. 'echoInteger', 'echoIntegerArray',
  27. 'echoString', 'echoStringArray',
  28. 'echoStruct', 'echoStructArray',
  29. 'echoVeryLargeFloat', 'echoVerySmallFloat',
  30. 'echoVoid',
  31. 'mustUnderstandEqualsOne', 'mustUnderstandEqualsZero',
  32. )
  33. def usage (error = None):
  34. sys.stdout = sys.stderr
  35. if error != None:
  36. print error
  37. print """usage: %s [options] [server ...]
  38. If a long option shows an argument is mandatory, it's mandatory for the
  39. equivalent short option also.
  40. -?, --help display this usage
  41. -d, --debug turn on debugging in the SOAP library
  42. -e, --exit-on-failure exit on the first (unexpected) failure
  43. -h, --harsh turn on harsh testing:
  44. - look for the documented error code from
  45. mustUnderstand failures
  46. - use non-ASCII strings in the string tests
  47. -i, --invert test servers *not* in the list of servers given
  48. -m, --method=METHOD#[,METHOD#...]
  49. call only the given methods, specify a METHOD# of ?
  50. for the list of method numbers
  51. -n, --no-stats, --no-statistics
  52. don't display success and failure statistics
  53. -N, --no-boring-stats, --no-boring-statistics
  54. only display unexpected failures and unimplemented
  55. tests, and only if non-zero
  56. -o, --output=TYPE turn on output, TYPE is one or more of s(uccess),
  57. f(ailure), n(ot implemented), F(ailed (as expected)),
  58. a(ll)
  59. [f]
  60. -s, --servers=FILE use FILE as list of servers to test [%s]
  61. -t, --stacktrace print a stack trace on each unexpected failure
  62. -T, --always-stacktrace
  63. print a stack trace on any failure
  64. """ % (sys.argv[0], DEFAULT_SERVERS_FILE),
  65. sys.exit (0)
  66. def methodUsage ():
  67. sys.stdout = sys.stderr
  68. print "Methods are specified by number. Multiple methods can be " \
  69. "specified using a\ncomma-separated list of numbers or ranges. " \
  70. "For example 1,4-6,8 specifies\nmethods 1, 4, 5, 6, and 8.\n"
  71. print "The available methods are:\n"
  72. half = (len (DEFAULT_METHODS) + 1) / 2
  73. for i in range (half):
  74. print "%4d. %-25s" % (i + 1, DEFAULT_METHODS[i]),
  75. if i + half < len (DEFAULT_METHODS):
  76. print "%4d. %-25s" % (i + 1 + half, DEFAULT_METHODS[i + half]),
  77. print
  78. sys.exit (0)
  79. # as borrowed from jake.soapware.org for float compares.
  80. def nearlyeq (a, b, prec = 1e-7):
  81. return abs (a - b) <= abs (a) * prec
  82. def readServers (file):
  83. servers = []
  84. names = {}
  85. cur = None
  86. f = fileinput.input(file)
  87. for line in f:
  88. if line[0] == '#':
  89. continue
  90. if line == '' or line[0] == '\n':
  91. cur = None
  92. continue
  93. if cur == None:
  94. cur = {'nonfunctional': {}, '_line': f.filelineno(),
  95. '_file': f.filename()}
  96. tag = None
  97. servers.append (cur)
  98. if line[0] in string.whitespace:
  99. if tag == 'nonfunctional':
  100. value = method + ' ' + cur[tag][method]
  101. else:
  102. value = cur[tag]
  103. value += ' ' + line.strip ()
  104. elif line[0] == '_':
  105. raise ValueError, \
  106. "%s, line %d: can't have a tag starting with `_'" % \
  107. (f.filename(), f.filelineno())
  108. else:
  109. tag, value = line.split (':', 1)
  110. tag = tag.strip ().lower ()
  111. value = value.strip ()
  112. if value[0] == '"' and value[-1] == '"':
  113. value = value[1:-1]
  114. if tag == 'typed':
  115. if value.lower() in ('0', 'no', 'false'):
  116. value = 0
  117. elif value.lower() in ('1', 'yes', 'false'):
  118. value = 1
  119. else:
  120. raise ValueError, \
  121. "%s, line %d: unknown typed value `%s'" % \
  122. (f.filename(), f.filelineno(), value)
  123. elif tag == 'name':
  124. if names.has_key(value):
  125. old = names[value]
  126. raise ValueError, \
  127. "%s, line %d: already saw a server named `%s' " \
  128. "(on line %d of %s)" % \
  129. (f.filename(), f.filelineno(), value,
  130. old['_line'], old['_file'])
  131. names[value] = cur
  132. if tag == 'nonfunctional':
  133. value = value.split (' ', 1) + ['']
  134. method = value[0]
  135. cur[tag][method] = value[1]
  136. elif tag == 'functional':
  137. try:
  138. del cur['nonfunctional'][value]
  139. except:
  140. raise ValueError, \
  141. "%s, line %d: `%s' not marked nonfunctional" % \
  142. (f.filename(), f.filelineno(), value)
  143. elif tag == 'like':
  144. try:
  145. new = copy.deepcopy(names[value])
  146. except:
  147. raise ValueError, \
  148. "%s, line %d: don't know about a server named `%s'" % \
  149. (f.filename(), f.filelineno(), value)
  150. # This is so we don't lose the nonfunctional methods in new or
  151. # in cur
  152. new['nonfunctional'].update(cur['nonfunctional'])
  153. del cur['nonfunctional']
  154. new.update(cur)
  155. # This is because servers and possibly names has a reference to
  156. # cur, so we have to keep working with cur so changes are
  157. # reflected in servers and names.
  158. cur.update(new)
  159. else:
  160. cur[tag] = value
  161. return servers
  162. def str2list (s):
  163. l = {}
  164. for i in s.split (','):
  165. if i.find ('-') != -1:
  166. i = i.split ('-')
  167. for i in range (int (i[0]),int (i[1]) + 1):
  168. l[i] = 1
  169. else:
  170. l[int (i)] = 1
  171. l = l.keys ()
  172. l.sort ()
  173. return l
  174. def testActorShouldPass (server, action, harsh):
  175. test = 42
  176. server = server._sa (action % {'methodname': 'echoInteger'})
  177. hd = SOAP.headerType ()
  178. hd.InteropTestHeader = SOAP.stringType ("This shouldn't fault because "
  179. "the mustUnderstand attribute is 0")
  180. hd.InteropTestHeader._setMustUnderstand (0)
  181. hd.InteropTestHeader._setActor (
  182. 'http://schemas.xmlsoap.org/soap/actor/next')
  183. server = server._hd (hd)
  184. result = server.echoInteger (inputInteger = test)
  185. if not SOAP.Config.typed:
  186. result = int (result)
  187. if result != test:
  188. raise Exception, "expected %s, got %s" % (test, result)
  189. def testActorShouldFail (server, action, harsh):
  190. test = 42
  191. server = server._sa (action % {'methodname': 'echoInteger'})
  192. hd = SOAP.headerType ()
  193. hd.InteropTestHeader = SOAP.stringType ("This should fault because "
  194. "the mustUnderstand attribute is 1")
  195. hd.InteropTestHeader._setMustUnderstand (1)
  196. hd.InteropTestHeader._setActor (
  197. 'http://schemas.xmlsoap.org/soap/actor/next')
  198. server = server._hd (hd)
  199. try:
  200. result = server.echoInteger (inputInteger = test)
  201. except SOAP.faultType, e:
  202. if harsh and e.faultcode != 'SOAP-ENV:MustUnderstand':
  203. raise AttributeError, "unexpected faultcode %s" % e.faultcode
  204. return
  205. raise Exception, "should fail, succeeded with %s" % result
  206. def testEchoFloat (server, action, harsh):
  207. server = server._sa (action % {'methodname': 'echoFloat'})
  208. for test in (0.0, 1.0, -1.0, 3853.33333333):
  209. result = server.echoFloat (inputFloat = test)
  210. if not SOAP.Config.typed:
  211. result = float (result)
  212. if not nearlyeq (result, test):
  213. raise Exception, "expected %.8f, got %.8f" % (test, result)
  214. def testEchoFloatArray (server, action, harsh):
  215. test = [0.0, 1.0, -1.0, 3853.33333333]
  216. server = server._sa (action % {'methodname': 'echoFloatArray'})
  217. result = server.echoFloatArray (inputFloatArray = test)
  218. for i in range (len (test)):
  219. if not SOAP.Config.typed:
  220. result[i] = float (result[i])
  221. if not nearlyeq (result[i], test[i]):
  222. raise Exception, "@ %d expected %s, got %s" % \
  223. (i, repr (test), repr (result))
  224. def testEchoFloatINF (server, action, harsh):
  225. try:
  226. test = float ('INF')
  227. except:
  228. test = float (1e300**2)
  229. server = server._sa (action % {'methodname': 'echoFloat'})
  230. result = server.echoFloat (inputFloat = test)
  231. if not SOAP.Config.typed:
  232. result = float (result)
  233. if result != test:
  234. raise Exception, "expected %.8f, got %.8f" % (test, result)
  235. def testEchoFloatNaN (server, action, harsh):
  236. try:
  237. test = float ('NaN')
  238. except:
  239. test = float (0.0)
  240. server = server._sa (action % {'methodname': 'echoFloat'})
  241. result = server.echoFloat (inputFloat = test)
  242. if not SOAP.Config.typed:
  243. result = float (result)
  244. if result != test:
  245. raise Exception, "expected %.8f, got %.8f" % (test, result)
  246. def testEchoFloatNegINF (server, action, harsh):
  247. try:
  248. test = float ('-INF')
  249. except:
  250. test = float (-1e300**2)
  251. server = server._sa (action % {'methodname': 'echoFloat'})
  252. result = server.echoFloat (inputFloat = test)
  253. if not SOAP.Config.typed:
  254. result = float (result)
  255. if result != test:
  256. raise Exception, "expected %.8f, got %.8f" % (test, result)
  257. def testEchoFloatNegZero (server, action, harsh):
  258. test = float ('-0.0')
  259. server = server._sa (action % {'methodname': 'echoFloat'})
  260. result = server.echoFloat (inputFloat = test)
  261. if not SOAP.Config.typed:
  262. result = float (result)
  263. if result != test:
  264. raise Exception, "expected %.8f, got %.8f" % (test, result)
  265. def testEchoInteger (server, action, harsh):
  266. server = server._sa (action % {'methodname': 'echoInteger'})
  267. for test in (0, 1, -1, 3853):
  268. result = server.echoInteger (inputInteger = test)
  269. if not SOAP.Config.typed:
  270. result = int (result)
  271. if result != test:
  272. raise Exception, "expected %.8f, got %.8f" % (test, result)
  273. def testEchoIntegerArray (server, action, harsh):
  274. test = [0, 1, -1, 3853]
  275. server = server._sa (action % {'methodname': 'echoIntegerArray'})
  276. result = server.echoIntegerArray (inputIntegerArray = test)
  277. for i in range (len (test)):
  278. if not SOAP.Config.typed:
  279. result[i] = int (result[i])
  280. if result[i] != test[i]:
  281. raise Exception, "@ %d expected %s, got %s" % \
  282. (i, repr (test), repr (result))
  283. relaxedStringTests = ['', 'Hello', '\'<&>"',]
  284. relaxedStringTests = ['Hello', '\'<&>"',]
  285. harshStringTests = ['', 'Hello', '\'<&>"',
  286. u'\u0041', u'\u00a2', u'\u0141', u'\u2342',
  287. u'\'<\u0041&>"', u'\'<\u00a2&>"', u'\'<\u0141&>"', u'\'<\u2342&>"',]
  288. def testEchoString (server, action, harsh):
  289. if harsh:
  290. test = harshStringTests
  291. else:
  292. test = relaxedStringTests
  293. server = server._sa (action % {'methodname': 'echoString'})
  294. for test in test:
  295. result = server.echoString (inputString = test)
  296. if result != test:
  297. raise Exception, "expected %s, got %s" % \
  298. (repr (test), repr (result))
  299. def testEchoStringArray (server, action, harsh):
  300. if harsh:
  301. test = harshStringTests
  302. else:
  303. test = relaxedStringTests
  304. server = server._sa (action % {'methodname': 'echoStringArray'})
  305. result = server.echoStringArray (inputStringArray = test)
  306. if result != test:
  307. raise Exception, "expected %s, got %s" % (repr (test), repr (result))
  308. def testEchoStruct (server, action, harsh):
  309. test = {'varFloat': 2.256, 'varInt': 474, 'varString': 'Utah'}
  310. server = server._sa (action % {'methodname': 'echoStruct'})
  311. result = server.echoStruct (inputStruct = test)
  312. if not SOAP.Config.typed:
  313. result.varFloat = float (result.varFloat)
  314. result.varInt = int (result.varInt)
  315. if not nearlyeq (test['varFloat'], result.varFloat):
  316. raise Exception, ".varFloat expected %s, got %s" % \
  317. (i, repr (test['varFloat']), repr (result.varFloat))
  318. for i in test.keys ():
  319. if i == 'varFloat':
  320. continue
  321. if test[i] != getattr (result, i):
  322. raise Exception, ".%s expected %s, got %s" % \
  323. (i, repr (test[i]), repr (getattr (result, i)))
  324. def testEchoStructArray (server, action, harsh):
  325. test = [{'varFloat': -5.398, 'varInt': -546, 'varString': 'West Virginia'},
  326. {'varFloat': -9.351, 'varInt': -641, 'varString': 'New Mexico'},
  327. {'varFloat': 1.495, 'varInt': -819, 'varString': 'Missouri'}]
  328. server = server._sa (action % {'methodname': 'echoStructArray'})
  329. result = server.echoStructArray (inputStructArray = test)
  330. for s in range (len (test)):
  331. if not SOAP.Config.typed:
  332. result[s].varFloat = float (result[s].varFloat)
  333. result[s].varInt = int (result[s].varInt)
  334. if not nearlyeq (test[s]['varFloat'], result[s].varFloat):
  335. raise Exception, \
  336. "@ %d.varFloat expected %s, got %s" % \
  337. (s, repr (test[s]['varFloat']), repr (result[s].varFloat))
  338. for i in test[s].keys ():
  339. if i == 'varFloat':
  340. continue
  341. if test[s][i] != getattr (result[s], i):
  342. raise Exception, "@ %d.%s expected %s, got %s" % \
  343. (s, i, repr (test[s][i]), repr (getattr (result[s], i)))
  344. def testEchoVeryLargeFloat (server, action, harsh):
  345. test = 2.2535e29
  346. server = server._sa (action % {'methodname': 'echoFloat'})
  347. result = server.echoFloat (inputFloat = test)
  348. if not SOAP.Config.typed:
  349. result = float (result)
  350. if not nearlyeq (result, test):
  351. raise Exception, "expected %s, got %s" % (repr (test), repr (result))
  352. def testEchoVerySmallFloat (server, action, harsh):
  353. test = 2.2535e29
  354. server = server._sa (action % {'methodname': 'echoFloat'})
  355. result = server.echoFloat (inputFloat = test)
  356. if not SOAP.Config.typed:
  357. result = float (result)
  358. if not nearlyeq (result, test):
  359. raise Exception, "expected %s, got %s" % (repr (test), repr (result))
  360. def testEchoVoid (server, action, harsh):
  361. server = server._sa (action % {'methodname': 'echoVoid'})
  362. result = server.echoVoid ()
  363. for k in result.__dict__.keys ():
  364. if k[0] != '_':
  365. raise Exception, "expected an empty structType, got %s" % \
  366. repr (result.__dict__)
  367. def testMustUnderstandEqualsOne (server, action, harsh):
  368. test = 42
  369. server = server._sa (action % {'methodname': 'echoInteger'})
  370. hd = SOAP.headerType ()
  371. hd.MustUnderstandThis = SOAP.stringType ("This should fault because "
  372. "the mustUnderstand attribute is 1")
  373. hd.MustUnderstandThis._setMustUnderstand (1)
  374. server = server._hd (hd)
  375. try:
  376. result = server.echoInteger (inputInteger = test)
  377. except SOAP.faultType, e:
  378. if harsh and e.faultcode != 'SOAP-ENV:MustUnderstand':
  379. raise AttributeError, "unexpected faultcode %s" % e.faultcode
  380. return
  381. raise Exception, "should fail, succeeded with %s" % result
  382. def testMustUnderstandEqualsZero (server, action, harsh):
  383. test = 42
  384. server = server._sa (action % {'methodname': 'echoInteger'})
  385. hd = SOAP.headerType ()
  386. hd.MustUnderstandThis = SOAP.stringType ("This shouldn't fault because "
  387. "the mustUnderstand attribute is 0")
  388. hd.MustUnderstandThis._setMustUnderstand (0)
  389. server = server._hd (hd)
  390. result = server.echoInteger (inputInteger = test)
  391. if not SOAP.Config.typed:
  392. result = int (result)
  393. if result != test:
  394. raise Exception, "expected %s, got %s" % (test, result)
  395. def testEchoDate (server, action, harsh):
  396. test = time.gmtime (time.time ())
  397. server = server._sa (action % {'methodname': 'echoDate'})
  398. if SOAP.Config.namespaceStyle == '1999':
  399. result = server.echoDate (inputDate = SOAP.timeInstantType (test))
  400. else:
  401. result = server.echoDate (inputDate = SOAP.dateTimeType (test))
  402. if not SOAP.Config.typed and type (result) in (type (''), type (u'')):
  403. p = SOAP.SOAPParser()
  404. result = p.convertDateTime(result, 'timeInstant')
  405. if result != test[:6]:
  406. raise Exception, "expected %s, got %s" % (repr (test), repr (result))
  407. def testEchoBase64 (server, action, harsh):
  408. test = '\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\xa0\xb0\xc0\xd0\xe0\xf0'
  409. server = server._sa (action % {'methodname': 'echoBase64'})
  410. result = server.echoBase64 (inputBase64 = SOAP.base64Type (test))
  411. if not SOAP.Config.typed:
  412. import base64
  413. result = base64.decodestring(result)
  414. if result != test:
  415. raise Exception, "expected %s, got %s" % (repr (test), repr (result))
  416. def main ():
  417. stats = 1
  418. total = 0
  419. fail = 0
  420. failok = 0
  421. succeed = 0
  422. exitonfailure = 0
  423. harsh = 0
  424. invert = 0
  425. printtrace = 0
  426. methodnums = None
  427. notimp = 0
  428. output = 'f'
  429. servers = DEFAULT_SERVERS_FILE
  430. started = time.time ()
  431. try:
  432. opts, args = getopt.getopt (sys.argv[1:], '?dehim:nNo:s:tT',
  433. ['help', 'debug', 'exit-on-failure', 'harsh', 'invert',
  434. 'method', 'no-stats', 'no-statistics',
  435. 'no-boring-statistics', 'no-boring-stats', 'output',
  436. 'servers=', 'stacktrace', 'always-stacktrace'])
  437. for opt, arg in opts:
  438. if opt in ('-?', '--help'):
  439. usage ()
  440. elif opt in ('-d', '--debug'):
  441. SOAP.Config.debug = 1
  442. elif opt in ('-h', '--harsh'):
  443. harsh = 1
  444. elif opt in ('-i', '--invert'):
  445. invert = 1
  446. elif opt in ('-e', '--exit-on-failure'):
  447. exitonfailure = 1
  448. elif opt in ('-m', '--method'):
  449. if arg == '?':
  450. methodUsage ()
  451. methodnums = str2list (arg)
  452. elif opt in ('-n', '--no-stats', '--no-statistics'):
  453. stats = 0
  454. elif opt in ('-N', '--no-boring-stats', '--no-boring-statistics'):
  455. stats = -1
  456. elif opt in ('-o', '--output'):
  457. output = arg
  458. elif opt in ('-s', '--servers'):
  459. servers = arg
  460. elif opt in ('-t', '--stacktrace'):
  461. printtrace = 1
  462. elif opt in ('-T', '--always-stacktrace'):
  463. printtrace = 2
  464. else:
  465. raise AttributeError, \
  466. "Recognized but unimplemented option `%s'" % opt
  467. except SystemExit:
  468. raise
  469. except:
  470. usage (sys.exc_info ()[1])
  471. if 'a' in output:
  472. output = 'fFns'
  473. servers = readServers (servers)
  474. if methodnums == None:
  475. methodnums = range (1, len (DEFAULT_METHODS) + 1)
  476. limitre = re.compile ('|'.join (args), re.IGNORECASE)
  477. for s in servers:
  478. if (not not limitre.match (s['name'])) == invert:
  479. continue
  480. try: typed = s['typed']
  481. except: typed = 1
  482. try: style = s['style']
  483. except: style = 1999
  484. SOAP.Config.typed = typed
  485. SOAP.Config.namespaceStyle = style
  486. server = SOAP.SOAPProxy (s['endpoint'], ("m", s['namespace']))
  487. for num in (methodnums):
  488. if num > len (DEFAULT_METHODS):
  489. break
  490. total += 1
  491. name = DEFAULT_METHODS[num - 1]
  492. title = '%s: %s (#%d)' % (s['name'], name, num)
  493. if SOAP.Config.debug:
  494. print "%s:" % title
  495. try:
  496. fn = globals ()['test' + name[0].upper () + name[1:]]
  497. except KeyboardInterrupt:
  498. raise
  499. except:
  500. if 'n' in output:
  501. print title, "test not yet implemented"
  502. notimp += 1
  503. continue
  504. try:
  505. fn (server, s['soapaction'], harsh)
  506. if s['nonfunctional'].has_key (name):
  507. print title, \
  508. "succeeded despite being marked nonfunctional"
  509. if 's' in output:
  510. print title, "succeeded"
  511. succeed += 1
  512. except KeyboardInterrupt:
  513. raise
  514. except:
  515. fault = str (sys.exc_info ()[1])
  516. if fault[-1] == '\n':
  517. fault = fault[:-1]
  518. if s['nonfunctional'].has_key (name):
  519. if 'F' in output:
  520. t = 'as expected'
  521. if s['nonfunctional'][name] != '':
  522. t += ', ' + s['nonfunctional'][name]
  523. print title, "failed (%s) -" % t, fault
  524. if printtrace > 1:
  525. traceback.print_exc ()
  526. failok += 1
  527. else:
  528. if 'f' in output:
  529. print title, "failed -", fault
  530. if printtrace:
  531. traceback.print_exc ()
  532. fail += 1
  533. if exitonfailure:
  534. return -1
  535. if stats:
  536. print " Tests started at:", time.ctime (started)
  537. if stats > 0:
  538. print " Total tests: %d" % total
  539. print " Successes: %d (%3.2f%%)" % \
  540. (succeed, 100.0 * succeed / total)
  541. if stats > 0 or fail > 0:
  542. print "Failed unexpectedly: %d (%3.2f%%)" % \
  543. (fail, 100.0 * fail / total)
  544. if stats > 0:
  545. print " Failed as expected: %d (%3.2f%%)" % \
  546. (failok, 100.0 * failok / total)
  547. if stats > 0 or notimp > 0:
  548. print " Not implemented: %d (%3.2f%%)" % \
  549. (notimp, 100.0 * notimp / total)
  550. return fail + notimp
  551. if __name__ == '__main__':
  552. try:
  553. sys.exit (main ())
  554. except KeyboardInterrupt:
  555. sys.exit (0)