Package expedient :: Package common :: Package tests :: Module client
[hide private]
[frames] | no frames]

Source Code for Module expedient.common.tests.client

  1  ''' 
  2  Created on May 21, 2010 
  3   
  4  Contains functions to login and manage forms. 
  5   
  6  @author: jnaous 
  7  ''' 
  8  import urllib, urllib2, cookielib 
  9  import logging 
 10  from pprint import pformat 
 11  logger = logging.getLogger("expedient.common.tests.client") 
 12   
13 -def fake_login(client, user):
14 """Setup the client to appear logged in even if it isn't. 15 16 @param client: The client to setup 17 @type client: C{django.test.Client} 18 @param user: The user to log the client in as. 19 @type user: C{django.contrib.auth.models.User} 20 """ 21 22 from django.conf import settings 23 from django.utils.importlib import import_module 24 from django.http import HttpRequest 25 from django.contrib.auth import login 26 27 engine = import_module(settings.SESSION_ENGINE) 28 29 # Create a fake request to store login details. 30 request = HttpRequest() 31 if client.session: 32 request.session = client.session 33 else: 34 request.session = engine.SessionStore() 35 login(request, user) 36 37 # Save the session values. 38 request.session.save() 39 40 # Set the cookie to represent the session. 41 session_cookie = settings.SESSION_COOKIE_NAME 42 client.cookies[session_cookie] = request.session.session_key 43 cookie_data = { 44 'max-age': None, 45 'path': '/', 46 'domain': settings.SESSION_COOKIE_DOMAIN, 47 'secure': settings.SESSION_COOKIE_SECURE or None, 48 'expires': None, 49 } 50 client.cookies[session_cookie].update(cookie_data)
51
52 -def parse_form(doc):
53 """ 54 parse the doc (a string), and return a dictionary of 55 name->value. 56 """ 57 from pyquery import PyQuery as pq 58 59 d = pq(doc, parser="html") 60 inputs = d("input") 61 62 # filter the ones that have a name 63 inputs = [i for i in inputs if i.name] 64 65 return dict([(i.name, i.value) for i in inputs])
66
67 -def test_get_and_post_form( 68 client, url, params, del_params=[], post_url=None):
69 """ 70 Get the form at C{url}, modify named parameters by those in C{params}, 71 then submit at C{post_url} or C{url} if C{post_url} is unspecified. 72 Return response. This function uses the Django TestClient C{client}. 73 74 @param client: client to use to make requests. 75 @type client: Django C{TestClient}. 76 @param url: URL to get the form from. 77 @type url: string 78 @param params: parameters to update the form with. 79 @type params: dict 80 @keyword del_params: list of parameter names to delete from form. These 81 parameters are not submitted. 82 @type del_params: list of strings 83 @keyword post_url: (optional) URL to post the form to. If None then port to 84 C{url} instead. 85 @type post_url: str or None 86 @return: response from client.post() 87 @rtype: Test Response instance. 88 """ 89 post_url = post_url or url 90 resp = client.get(url) 91 logger.debug("Response received using get: \n%s" % resp) 92 if resp.status_code != 405 and resp.status_code != 302: 93 form_params = parse_form(resp.content) 94 logger.debug("Form params received: \n%s" % pformat(form_params)) 95 form_params.update(params) 96 else: 97 form_params = params 98 for k in del_params: 99 if k in form_params: 100 del form_params[k] 101 for k, v in form_params.items(): 102 if v == None: 103 del form_params[k] 104 resp = client.post(post_url, form_params) 105 logger.debug("Posting back using params \n%s" % pformat(form_params)) 106 logger.debug("Response after post:\n%s" % resp) 107 return resp
108
109 -class Browser(object):
110
111 - def __init__(self):
112 self.cookiejar = cookielib.CookieJar()
113
114 - def get_form_inputs(self, doc):
115 return parse_form(doc)
116
117 - def get_select_choices(self, doc, select_name):
118 """ 119 parse the doc (a string), and return a dictionary of all 120 options and their values 121 """ 122 from pyquery import PyQuery as pq 123 124 result={} 125 126 d = pq(doc, parser="html") 127 128 selects = d("select") 129 130 for i in range(0,len(selects)): 131 if selects.eq(i).attr.name == select_name: 132 options = selects.find('option') 133 for j in range(0,len(options)): 134 result[options.eq(j).text()] = options.eq(j).attr.value 135 136 return result
137
138 - def get_checkbox_choices(self, doc):
139 """ 140 parse the doc (a string), and return a dictionary of 141 name->text. The checkboxes should be of the following format: 142 <input type="checkbox" name="something">text</input> 143 """ 144 from pyquery import PyQuery as pq 145 146 d = pq(doc, parser="html") 147 inputs = d("input") 148 result = {} 149 150 for i in range(0,len(inputs)): 151 if inputs.eq(i).attr.type=="checkbox": 152 choice = str(inputs.eq(i)).split(">")[1].lstrip() 153 result[choice] = inputs.eq(i).attr.name 154 155 return result
156
157 - def get_form(self,url):
158 """ 159 Get the form at 'url' 160 161 @param url: URL to get the form from. 162 @type url: string 163 164 @return: response from urllib2.urlopen 165 @rtype: file-like object (see L{urllib2.urlopen}) 166 """ 167 168 opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookiejar)) 169 urllib2.install_opener(opener) 170 f = urllib2.urlopen(url) 171 return f
172
173 - def get_and_post_form(self, url, params, del_params=[], post_url=None):
174 """ 175 Get the form at 'url', modify named parameters by those in 'params', 176 then submit at 'post_url' or 'url' if 'post_url' is unspecified. 177 Return response. 178 179 @param url: URL to get the form from. 180 @type url: string 181 @param params: parameters to update the form with. 182 @type params: dict 183 @param post_url: (optional) URL to post the form to. If None then port to 184 C{url} instead. 185 @keyword del_params: list of parameter names to delete from form. These 186 parameters are not submitted. 187 @type del_params: C{list} of C{str} 188 @type post_url: str or None 189 @return: response from urllib2.urlopen 190 @rtype: file-like object (see L{urllib2.urlopen}) 191 """ 192 193 post_url = post_url or url 194 opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookiejar)) 195 urllib2.install_opener(opener) 196 f = urllib2.urlopen(url) 197 form_params = self.get_form_inputs(f.read()) 198 form_params.update(params) 199 200 for k in del_params: 201 if k in form_params: 202 del form_params[k] 203 204 data = urllib.urlencode(form_params) 205 req = urllib2.Request(url=post_url, data=data) 206 req.add_header('Referer', url) 207 f = urllib2.urlopen(req) 208 return f
209
210 - def login(self, url, username, password):
211 """ 212 Log in at the given URL. 213 214 @param url: url of the login page. 215 @type url: str 216 @param username: username to use for login. 217 @type username: str 218 @param password: password to use for login 219 @type password: str 220 @return: True on success, False otherwise. 221 """ 222 223 try: 224 f = self.get_and_post_form( 225 url, dict( 226 username=username, 227 password=password, 228 ) 229 ) 230 except Exception: 231 return False 232 233 if f.geturl() != url: 234 # redirected (hopefully) to the success page 235 return True 236 else: 237 return False
238