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.
 
 
 
 

693 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), end=' ')
  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]), end=' ')
  75. if i + half < len (DEFAULT_METHODS):
  76. print("%4d. %-25s" % (i + 1 + half, DEFAULT_METHODS[i + half]), end=' ')
  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("%s, line %d: can't have a tag starting with `_'" % \
  106. (f.filename(), f.filelineno()))
  107. else:
  108. tag, value = line.split (':', 1)
  109. tag = tag.strip ().lower ()
  110. value = value.strip ()
  111. if value[0] == '"' and value[-1] == '"':
  112. value = value[1:-1]
  113. if tag == 'typed':
  114. if value.lower() in ('0', 'no', 'false'):
  115. value = 0
  116. elif value.lower() in ('1', 'yes', 'false'):
  117. value = 1
  118. else:
  119. raise ValueError("%s, line %d: unknown typed value `%s'" % \
  120. (f.filename(), f.filelineno(), value))
  121. elif tag == 'name':
  122. if value in names:
  123. old = names[value]
  124. raise ValueError("%s, line %d: already saw a server named `%s' " \
  125. "(on line %d of %s)" % \
  126. (f.filename(), f.filelineno(), value,
  127. old['_line'], old['_file']))
  128. names[value] = cur
  129. if tag == 'nonfunctional':
  130. value = value.split (' ', 1) + ['']
  131. method = value[0]
  132. cur[tag][method] = value[1]
  133. elif tag == 'functional':
  134. try:
  135. del cur['nonfunctional'][value]
  136. except:
  137. raise ValueError("%s, line %d: `%s' not marked nonfunctional" % \
  138. (f.filename(), f.filelineno(), value))
  139. elif tag == 'like':
  140. try:
  141. new = copy.deepcopy(names[value])
  142. except:
  143. raise ValueError("%s, line %d: don't know about a server named `%s'" % \
  144. (f.filename(), f.filelineno(), value))
  145. # This is so we don't lose the nonfunctional methods in new or
  146. # in cur
  147. new['nonfunctional'].update(cur['nonfunctional'])
  148. del cur['nonfunctional']
  149. new.update(cur)
  150. # This is because servers and possibly names has a reference to
  151. # cur, so we have to keep working with cur so changes are
  152. # reflected in servers and names.
  153. cur.update(new)
  154. else:
  155. cur[tag] = value
  156. return servers
  157. def str2list (s):
  158. l = {}
  159. for i in s.split (','):
  160. if i.find ('-') != -1:
  161. i = i.split ('-')
  162. for i in range (int (i[0]),int (i[1]) + 1):
  163. l[i] = 1
  164. else:
  165. l[int (i)] = 1
  166. l = list(l.keys ())
  167. l.sort ()
  168. return l
  169. def testActorShouldPass (server, action, harsh):
  170. test = 42
  171. server = server._sa (action % {'methodname': 'echoInteger'})
  172. hd = SOAP.headerType ()
  173. hd.InteropTestHeader = SOAP.stringType ("This shouldn't fault because "
  174. "the mustUnderstand attribute is 0")
  175. hd.InteropTestHeader._setMustUnderstand (0)
  176. hd.InteropTestHeader._setActor (
  177. 'http://schemas.xmlsoap.org/soap/actor/next')
  178. server = server._hd (hd)
  179. result = server.echoInteger (inputInteger = test)
  180. if not SOAP.Config.typed:
  181. result = int (result)
  182. if result != test:
  183. raise Exception("expected %s, got %s" % (test, result))
  184. def testActorShouldFail (server, action, harsh):
  185. test = 42
  186. server = server._sa (action % {'methodname': 'echoInteger'})
  187. hd = SOAP.headerType ()
  188. hd.InteropTestHeader = SOAP.stringType ("This should fault because "
  189. "the mustUnderstand attribute is 1")
  190. hd.InteropTestHeader._setMustUnderstand (1)
  191. hd.InteropTestHeader._setActor (
  192. 'http://schemas.xmlsoap.org/soap/actor/next')
  193. server = server._hd (hd)
  194. try:
  195. result = server.echoInteger (inputInteger = test)
  196. except SOAP.faultType as e:
  197. if harsh and e.faultcode != 'SOAP-ENV:MustUnderstand':
  198. raise AttributeError("unexpected faultcode %s" % e.faultcode)
  199. return
  200. raise Exception("should fail, succeeded with %s" % result)
  201. def testEchoFloat (server, action, harsh):
  202. server = server._sa (action % {'methodname': 'echoFloat'})
  203. for test in (0.0, 1.0, -1.0, 3853.33333333):
  204. result = server.echoFloat (inputFloat = test)
  205. if not SOAP.Config.typed:
  206. result = float (result)
  207. if not nearlyeq (result, test):
  208. raise Exception("expected %.8f, got %.8f" % (test, result))
  209. def testEchoFloatArray (server, action, harsh):
  210. test = [0.0, 1.0, -1.0, 3853.33333333]
  211. server = server._sa (action % {'methodname': 'echoFloatArray'})
  212. result = server.echoFloatArray (inputFloatArray = test)
  213. for i in range (len (test)):
  214. if not SOAP.Config.typed:
  215. result[i] = float (result[i])
  216. if not nearlyeq (result[i], test[i]):
  217. raise Exception("@ %d expected %s, got %s" % \
  218. (i, repr (test), repr (result)))
  219. def testEchoFloatINF (server, action, harsh):
  220. try:
  221. test = float ('INF')
  222. except:
  223. test = float (1e300**2)
  224. server = server._sa (action % {'methodname': 'echoFloat'})
  225. result = server.echoFloat (inputFloat = test)
  226. if not SOAP.Config.typed:
  227. result = float (result)
  228. if result != test:
  229. raise Exception("expected %.8f, got %.8f" % (test, result))
  230. def testEchoFloatNaN (server, action, harsh):
  231. try:
  232. test = float ('NaN')
  233. except:
  234. test = float (0.0)
  235. server = server._sa (action % {'methodname': 'echoFloat'})
  236. result = server.echoFloat (inputFloat = test)
  237. if not SOAP.Config.typed:
  238. result = float (result)
  239. if result != test:
  240. raise Exception("expected %.8f, got %.8f" % (test, result))
  241. def testEchoFloatNegINF (server, action, harsh):
  242. try:
  243. test = float ('-INF')
  244. except:
  245. test = float (-1e300**2)
  246. server = server._sa (action % {'methodname': 'echoFloat'})
  247. result = server.echoFloat (inputFloat = test)
  248. if not SOAP.Config.typed:
  249. result = float (result)
  250. if result != test:
  251. raise Exception("expected %.8f, got %.8f" % (test, result))
  252. def testEchoFloatNegZero (server, action, harsh):
  253. test = float ('-0.0')
  254. server = server._sa (action % {'methodname': 'echoFloat'})
  255. result = server.echoFloat (inputFloat = test)
  256. if not SOAP.Config.typed:
  257. result = float (result)
  258. if result != test:
  259. raise Exception("expected %.8f, got %.8f" % (test, result))
  260. def testEchoInteger (server, action, harsh):
  261. server = server._sa (action % {'methodname': 'echoInteger'})
  262. for test in (0, 1, -1, 3853):
  263. result = server.echoInteger (inputInteger = test)
  264. if not SOAP.Config.typed:
  265. result = int (result)
  266. if result != test:
  267. raise Exception("expected %.8f, got %.8f" % (test, result))
  268. def testEchoIntegerArray (server, action, harsh):
  269. test = [0, 1, -1, 3853]
  270. server = server._sa (action % {'methodname': 'echoIntegerArray'})
  271. result = server.echoIntegerArray (inputIntegerArray = test)
  272. for i in range (len (test)):
  273. if not SOAP.Config.typed:
  274. result[i] = int (result[i])
  275. if result[i] != test[i]:
  276. raise Exception("@ %d expected %s, got %s" % \
  277. (i, repr (test), repr (result)))
  278. relaxedStringTests = ['', 'Hello', '\'<&>"',]
  279. relaxedStringTests = ['Hello', '\'<&>"',]
  280. harshStringTests = ['', 'Hello', '\'<&>"',
  281. '\u0041', '\u00a2', '\u0141', '\u2342',
  282. '\'<\u0041&>"', '\'<\u00a2&>"', '\'<\u0141&>"', '\'<\u2342&>"',]
  283. def testEchoString (server, action, harsh):
  284. if harsh:
  285. test = harshStringTests
  286. else:
  287. test = relaxedStringTests
  288. server = server._sa (action % {'methodname': 'echoString'})
  289. for test in test:
  290. result = server.echoString (inputString = test)
  291. if result != test:
  292. raise Exception("expected %s, got %s" % \
  293. (repr (test), repr (result)))
  294. def testEchoStringArray (server, action, harsh):
  295. if harsh:
  296. test = harshStringTests
  297. else:
  298. test = relaxedStringTests
  299. server = server._sa (action % {'methodname': 'echoStringArray'})
  300. result = server.echoStringArray (inputStringArray = test)
  301. if result != test:
  302. raise Exception("expected %s, got %s" % (repr (test), repr (result)))
  303. def testEchoStruct (server, action, harsh):
  304. test = {'varFloat': 2.256, 'varInt': 474, 'varString': 'Utah'}
  305. server = server._sa (action % {'methodname': 'echoStruct'})
  306. result = server.echoStruct (inputStruct = test)
  307. if not SOAP.Config.typed:
  308. result.varFloat = float (result.varFloat)
  309. result.varInt = int (result.varInt)
  310. if not nearlyeq (test['varFloat'], result.varFloat):
  311. raise Exception(".varFloat expected %s, got %s" % \
  312. (i, repr (test['varFloat']), repr (result.varFloat)))
  313. for i in list(test.keys ()):
  314. if i == 'varFloat':
  315. continue
  316. if test[i] != getattr (result, i):
  317. raise Exception(".%s expected %s, got %s" % \
  318. (i, repr (test[i]), repr (getattr (result, i))))
  319. def testEchoStructArray (server, action, harsh):
  320. test = [{'varFloat': -5.398, 'varInt': -546, 'varString': 'West Virginia'},
  321. {'varFloat': -9.351, 'varInt': -641, 'varString': 'New Mexico'},
  322. {'varFloat': 1.495, 'varInt': -819, 'varString': 'Missouri'}]
  323. server = server._sa (action % {'methodname': 'echoStructArray'})
  324. result = server.echoStructArray (inputStructArray = test)
  325. for s in range (len (test)):
  326. if not SOAP.Config.typed:
  327. result[s].varFloat = float (result[s].varFloat)
  328. result[s].varInt = int (result[s].varInt)
  329. if not nearlyeq (test[s]['varFloat'], result[s].varFloat):
  330. raise Exception("@ %d.varFloat expected %s, got %s" % \
  331. (s, repr (test[s]['varFloat']), repr (result[s].varFloat)))
  332. for i in list(test[s].keys ()):
  333. if i == 'varFloat':
  334. continue
  335. if test[s][i] != getattr (result[s], i):
  336. raise Exception("@ %d.%s expected %s, got %s" % \
  337. (s, i, repr (test[s][i]), repr (getattr (result[s], i))))
  338. def testEchoVeryLargeFloat (server, action, harsh):
  339. test = 2.2535e29
  340. server = server._sa (action % {'methodname': 'echoFloat'})
  341. result = server.echoFloat (inputFloat = test)
  342. if not SOAP.Config.typed:
  343. result = float (result)
  344. if not nearlyeq (result, test):
  345. raise Exception("expected %s, got %s" % (repr (test), repr (result)))
  346. def testEchoVerySmallFloat (server, action, harsh):
  347. test = 2.2535e29
  348. server = server._sa (action % {'methodname': 'echoFloat'})
  349. result = server.echoFloat (inputFloat = test)
  350. if not SOAP.Config.typed:
  351. result = float (result)
  352. if not nearlyeq (result, test):
  353. raise Exception("expected %s, got %s" % (repr (test), repr (result)))
  354. def testEchoVoid (server, action, harsh):
  355. server = server._sa (action % {'methodname': 'echoVoid'})
  356. result = server.echoVoid ()
  357. for k in list(result.__dict__.keys ()):
  358. if k[0] != '_':
  359. raise Exception("expected an empty structType, got %s" % \
  360. repr (result.__dict__))
  361. def testMustUnderstandEqualsOne (server, action, harsh):
  362. test = 42
  363. server = server._sa (action % {'methodname': 'echoInteger'})
  364. hd = SOAP.headerType ()
  365. hd.MustUnderstandThis = SOAP.stringType ("This should fault because "
  366. "the mustUnderstand attribute is 1")
  367. hd.MustUnderstandThis._setMustUnderstand (1)
  368. server = server._hd (hd)
  369. try:
  370. result = server.echoInteger (inputInteger = test)
  371. except SOAP.faultType as e:
  372. if harsh and e.faultcode != 'SOAP-ENV:MustUnderstand':
  373. raise AttributeError("unexpected faultcode %s" % e.faultcode)
  374. return
  375. raise Exception("should fail, succeeded with %s" % result)
  376. def testMustUnderstandEqualsZero (server, action, harsh):
  377. test = 42
  378. server = server._sa (action % {'methodname': 'echoInteger'})
  379. hd = SOAP.headerType ()
  380. hd.MustUnderstandThis = SOAP.stringType ("This shouldn't fault because "
  381. "the mustUnderstand attribute is 0")
  382. hd.MustUnderstandThis._setMustUnderstand (0)
  383. server = server._hd (hd)
  384. result = server.echoInteger (inputInteger = test)
  385. if not SOAP.Config.typed:
  386. result = int (result)
  387. if result != test:
  388. raise Exception("expected %s, got %s" % (test, result))
  389. def testEchoDate (server, action, harsh):
  390. test = time.gmtime (time.time ())
  391. server = server._sa (action % {'methodname': 'echoDate'})
  392. if SOAP.Config.namespaceStyle == '1999':
  393. result = server.echoDate (inputDate = SOAP.timeInstantType (test))
  394. else:
  395. result = server.echoDate (inputDate = SOAP.dateTimeType (test))
  396. if not SOAP.Config.typed and type (result) in (type (''), type ('')):
  397. p = SOAP.SOAPParser()
  398. result = p.convertDateTime(result, 'timeInstant')
  399. if result != test[:6]:
  400. raise Exception("expected %s, got %s" % (repr (test), repr (result)))
  401. def testEchoBase64 (server, action, harsh):
  402. test = '\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\xa0\xb0\xc0\xd0\xe0\xf0'
  403. server = server._sa (action % {'methodname': 'echoBase64'})
  404. result = server.echoBase64 (inputBase64 = SOAP.base64Type (test))
  405. if not SOAP.Config.typed:
  406. import base64
  407. result = base64.decodestring(result)
  408. if result != test:
  409. raise Exception("expected %s, got %s" % (repr (test), repr (result)))
  410. def main ():
  411. stats = 1
  412. total = 0
  413. fail = 0
  414. failok = 0
  415. succeed = 0
  416. exitonfailure = 0
  417. harsh = 0
  418. invert = 0
  419. printtrace = 0
  420. methodnums = None
  421. notimp = 0
  422. output = 'f'
  423. servers = DEFAULT_SERVERS_FILE
  424. started = time.time ()
  425. try:
  426. opts, args = getopt.getopt (sys.argv[1:], '?dehim:nNo:s:tT',
  427. ['help', 'debug', 'exit-on-failure', 'harsh', 'invert',
  428. 'method', 'no-stats', 'no-statistics',
  429. 'no-boring-statistics', 'no-boring-stats', 'output',
  430. 'servers=', 'stacktrace', 'always-stacktrace'])
  431. for opt, arg in opts:
  432. if opt in ('-?', '--help'):
  433. usage ()
  434. elif opt in ('-d', '--debug'):
  435. SOAP.Config.debug = 1
  436. elif opt in ('-h', '--harsh'):
  437. harsh = 1
  438. elif opt in ('-i', '--invert'):
  439. invert = 1
  440. elif opt in ('-e', '--exit-on-failure'):
  441. exitonfailure = 1
  442. elif opt in ('-m', '--method'):
  443. if arg == '?':
  444. methodUsage ()
  445. methodnums = str2list (arg)
  446. elif opt in ('-n', '--no-stats', '--no-statistics'):
  447. stats = 0
  448. elif opt in ('-N', '--no-boring-stats', '--no-boring-statistics'):
  449. stats = -1
  450. elif opt in ('-o', '--output'):
  451. output = arg
  452. elif opt in ('-s', '--servers'):
  453. servers = arg
  454. elif opt in ('-t', '--stacktrace'):
  455. printtrace = 1
  456. elif opt in ('-T', '--always-stacktrace'):
  457. printtrace = 2
  458. else:
  459. raise AttributeError("Recognized but unimplemented option `%s'" % opt)
  460. except SystemExit:
  461. raise
  462. except:
  463. usage (sys.exc_info ()[1])
  464. if 'a' in output:
  465. output = 'fFns'
  466. servers = readServers (servers)
  467. if methodnums == None:
  468. methodnums = list(range(1, len (DEFAULT_METHODS) + 1))
  469. limitre = re.compile ('|'.join (args), re.IGNORECASE)
  470. for s in servers:
  471. if (not not limitre.match (s['name'])) == invert:
  472. continue
  473. try: typed = s['typed']
  474. except: typed = 1
  475. try: style = s['style']
  476. except: style = 1999
  477. SOAP.Config.typed = typed
  478. SOAP.Config.namespaceStyle = style
  479. server = SOAP.SOAPProxy (s['endpoint'], ("m", s['namespace']))
  480. for num in (methodnums):
  481. if num > len (DEFAULT_METHODS):
  482. break
  483. total += 1
  484. name = DEFAULT_METHODS[num - 1]
  485. title = '%s: %s (#%d)' % (s['name'], name, num)
  486. if SOAP.Config.debug:
  487. print("%s:" % title)
  488. try:
  489. fn = globals ()['test' + name[0].upper () + name[1:]]
  490. except KeyboardInterrupt:
  491. raise
  492. except:
  493. if 'n' in output:
  494. print(title, "test not yet implemented")
  495. notimp += 1
  496. continue
  497. try:
  498. fn (server, s['soapaction'], harsh)
  499. if name in s['nonfunctional']:
  500. print(title, \
  501. "succeeded despite being marked nonfunctional")
  502. if 's' in output:
  503. print(title, "succeeded")
  504. succeed += 1
  505. except KeyboardInterrupt:
  506. raise
  507. except:
  508. fault = str (sys.exc_info ()[1])
  509. if fault[-1] == '\n':
  510. fault = fault[:-1]
  511. if name in s['nonfunctional']:
  512. if 'F' in output:
  513. t = 'as expected'
  514. if s['nonfunctional'][name] != '':
  515. t += ', ' + s['nonfunctional'][name]
  516. print(title, "failed (%s) -" % t, fault)
  517. if printtrace > 1:
  518. traceback.print_exc ()
  519. failok += 1
  520. else:
  521. if 'f' in output:
  522. print(title, "failed -", fault)
  523. if printtrace:
  524. traceback.print_exc ()
  525. fail += 1
  526. if exitonfailure:
  527. return -1
  528. if stats:
  529. print(" Tests started at:", time.ctime (started))
  530. if stats > 0:
  531. print(" Total tests: %d" % total)
  532. print(" Successes: %d (%3.2f%%)" % \
  533. (succeed, 100.0 * succeed / total))
  534. if stats > 0 or fail > 0:
  535. print("Failed unexpectedly: %d (%3.2f%%)" % \
  536. (fail, 100.0 * fail / total))
  537. if stats > 0:
  538. print(" Failed as expected: %d (%3.2f%%)" % \
  539. (failok, 100.0 * failok / total))
  540. if stats > 0 or notimp > 0:
  541. print(" Not implemented: %d (%3.2f%%)" % \
  542. (notimp, 100.0 * notimp / total))
  543. return fail + notimp
  544. if __name__ == '__main__':
  545. try:
  546. sys.exit (main ())
  547. except KeyboardInterrupt:
  548. sys.exit (0)