@@ -85,7 +85,7 @@ def tearDown(self):
8585 def get_header (self , header , not_found = None ):
8686 try :
8787 return self .headers [header .lower ()]
88- except (AttributeError , KeyError ):
88+ except (AttributeError , KeyError , TypeError ):
8989 return not_found
9090
9191 def testGet (self ):
@@ -352,7 +352,7 @@ def testEtagProcessing(self):
352352
353353 Run over header only, etag in form only, both,
354354 each one broke and no etag. Use the put command
355- to triger the etag checking code.
355+ to trigger the etag checking code.
356356 '''
357357 for mode in ('header' , 'etag' , 'both' ,
358358 'brokenheader' , 'brokenetag' , 'none' ):
@@ -399,14 +399,27 @@ def testEtagProcessing(self):
399399 else :
400400 self .assertEqual (self .dummy_client .response_code , 412 )
401401
402+ def make_file (self , arg = None ):
403+ ''' work around https://bugs.python.org/issue27777 '''
404+ import tempfile
405+ return tempfile .TemporaryFile ("wb+" )
406+
402407 def testDispatch (self ):
403408 """
404409 run changes through rest dispatch(). This also tests
405410 sending json payload through code as dispatch is the
406411 code that changes json payload into something we can
407412 process.
408413 """
409- # Set joe's 'realname' using json data.
414+
415+ # Override the make_file so it is always set to binary
416+ # read mode. This is needed so we can send a json
417+ # body.
418+ saved_make_file = cgi .FieldStorage .make_file
419+ cgi .FieldStorage .make_file = self .make_file
420+
421+ # TEST #1
422+ # PUT: joe's 'realname' using json data.
410423 # simulate: /rest/data/user/<id>/realname
411424 # use etag in header
412425 etag = calculate_etag (self .db .user .getnode (self .joeid ))
@@ -417,6 +430,7 @@ def testDispatch(self):
417430 }
418431 headers = {"accept" : "application/json" ,
419432 "content-type" : env ['CONTENT_TYPE' ],
433+ "content-length" : env ['CONTENT_LENGTH' ],
420434 "etag" : etag
421435 }
422436 self .headers = headers
@@ -439,24 +453,29 @@ def testDispatch(self):
439453 'Joe Doe 1' )
440454 del (self .headers )
441455
456+ # TEST #2
442457 # Set joe's 'realname' using json data.
443458 # simulate: /rest/data/user/<id>/realname
444459 # use etag in payload
445460 etag = calculate_etag (self .db .user .getnode (self .joeid ))
446461 body = s2b ('{ "@etag": "%s", "data": "Joe Doe 2" }' % etag )
447462 env = { "CONTENT_TYPE" : "application/json" ,
448463 "CONTENT_LENGTH" : len (body ),
449- "REQUEST_METHOD" : "PUT"
464+ "REQUEST_METHOD" : "PUT" ,
450465 }
451- headers = {"accept" : "application/json" ,
452- "content-type" : env ['CONTENT_TYPE' ]
453- }
454- self .headers = headers
466+ self .headers = None # have FieldStorage get len from env.
455467 body_file = BytesIO (body ) # FieldStorage needs a file
456468 form = cgi .FieldStorage (body_file ,
457- headers = headers ,
469+ headers = None ,
458470 environ = env )
459471 self .server .client .request .headers .get = self .get_header
472+
473+ headers = {"accept" : "application/json" ,
474+ "content-type" : env ['CONTENT_TYPE' ],
475+ "etag" : etag
476+ }
477+ self .headers = headers # set for dispatch
478+
460479 results = self .server .dispatch ('PUT' ,
461480 "/rest/data/user/%s/realname" % self .joeid ,
462481 form )
@@ -468,12 +487,13 @@ def testDispatch(self):
468487 'Joe Doe 2' )
469488 del (self .headers )
470489
490+ # TEST #3
471491 # change Joe's realname via a normal web form
472492 # This generates a FieldStorage that looks like:
473493 # FieldStorage(None, None, [])
474494 # use etag from header
475495 #
476- # also use a GET on the uri via the dispatch to get
496+ # Also use GET on the uri via the dispatch to retrieve
477497 # the results from the db.
478498 etag = calculate_etag (self .db .user .getnode (self .joeid ))
479499 headers = {"etag" : etag ,
@@ -499,12 +519,14 @@ def testDispatch(self):
499519 self .assertEqual (json_dict ['data' ]['link' ],
500520 "http://tracker.example/cgi-bin/"
501521 "roundup.cgi/bugs/rest/data/user/3/realname" )
502- self .assertEqual (json_dict ['data' ]['type' ], "<type 'str'>" )
522+ self .assertIn (json_dict ['data' ]['type' ], ("<class 'str'>" ,
523+ "<type 'str'>" ))
503524 self .assertEqual (json_dict ['data' ]["id" ], "3" )
504525 del (self .headers )
505526
506527
507- # PATCH joe's email address with json
528+ # TEST #4
529+ # PATCH: joe's email address with json
508530 # save address so we can use it later
509531 stored_results = self .server .get_element ('user' , self .joeid ,
510532 self .empty_form )
@@ -517,7 +539,8 @@ def testDispatch(self):
517539 "REQUEST_METHOD" : "PATCH"
518540 }
519541 headers = {"accept" : "application/json" ,
520- "content-type" : env ['CONTENT_TYPE' ]
542+ "content-type" : env ['CONTENT_TYPE' ],
543+ "content-length" : len (body )
521544 }
522545 self .headers = headers
523546 body_file = BytesIO (body ) # FieldStorage needs a file
@@ -535,7 +558,7 @@ def testDispatch(self):
535558 self .assertEqual (results ['data' ]['attributes' ]['address' ],
536559537560
538- # and set it back
561+ # and set it back reusing env and headers from last test
539562 etag = calculate_etag (self .db .user .getnode (self .joeid ))
540563 body = s2b ('{ "address": "%s", "@etag": "%s"}' % (
541564 stored_results ['data' ]['attributes' ]['address' ],
@@ -557,15 +580,21 @@ def testDispatch(self):
557580558581 del (self .headers )
559582
560- # POST to create new issue
583+ # TEST #5
584+ # POST: create new issue
585+ # no etag needed
586+ # FIXME at some point we probably want to implement
587+ # Post Once Only, so we need to add a Post Once Exactly
588+ # test and a resubmit as well.
589+ etag = "not needed"
561590 body = b'{ "title": "foo bar", "priority": "critical" }'
562-
563591 env = { "CONTENT_TYPE" : "application/json" ,
564592 "CONTENT_LENGTH" : len (body ),
565593 "REQUEST_METHOD" : "POST"
566594 }
567595 headers = {"accept" : "application/json" ,
568- "content-type" : env ['CONTENT_TYPE' ]
596+ "content-type" : env ['CONTENT_TYPE' ],
597+ "content-length" : len (body )
569598 }
570599 self .headers = headers
571600 body_file = BytesIO (body ) # FieldStorage needs a file
@@ -588,6 +617,9 @@ def testDispatch(self):
588617 'foo bar' )
589618 del (self .headers )
590619
620+ # reset the make_file method in the class
621+ cgi .FieldStorage .make_file = saved_make_file
622+
591623 def testPut (self ):
592624 """
593625 Change joe's 'realname'
0 commit comments