Package lamson :: Module testing
[hide private]
[frames] | no frames]

Source Code for Module lamson.testing

  1  """ 
  2  A bag of generally useful things when writing unit tests for your Lamson server. 
  3  The most important things are the spelling function and using the 
  4  TestConversation vs. RouterConversation to talk to your server. 
  5   
  6  The TestConversation will use the lamson.server.Relay you have configured to 
  7  talk to your actual running Lamson server.  Since by default Lamson reloads each 
  8  file you change it will work to run your tests. 
  9   
 10  However, this isn't that fast, doesn't give you coverage analysis, and doesn't 
 11  let you test the results.  For that you use RouterConversation to do the exact 
 12  same API (they should be interchangeable) but rather than talk to a running 
 13  server through the relay, it just runs all the messages through the router 
 14  directly.  
 15   
 16  This is faster and will give you code coverage as well as make sure that all the 
 17  modules (not just your handlers) will get reloaded. 
 18   
 19  The spelling function will use PyEnchant to spell check a string.  If it finds 
 20  any errors it prints them out, and returns False. 
 21  """ 
 22   
 23   
 24  from lamson import server, utils, routing, mail 
 25  from lamson.queue import Queue 
 26  from nose.tools import assert_equal 
 27  import re 
 28  import logging 
 29   
 30  TEST_QUEUE = "run/queue" 
 31   
 32   
33 -def spelling(file_name, contents, language="en_US"):
34 """ 35 You give it a file_name and the contents of that file and it tells you 36 if it's spelled correctly. The reason you give it contents is that you 37 will typically run a template through the render process, so spelling 38 can't just load a file and check it. 39 40 It assumes you have PyEnchant installed correctly and configured 41 in your config/testing.py file. Use "lamson spell" to make sure it 42 works right. 43 """ 44 try: 45 from enchant.checker import SpellChecker 46 from enchant.tokenize import EmailFilter, URLFilter 47 except: 48 print "Failed to load PyEnchant. Make sure it's installed and lamson spell works." 49 return True 50 51 failures = 0 52 chkr = SpellChecker(language, filters=[EmailFilter, URLFilter]) 53 chkr.set_text(contents) 54 for err in chkr: 55 print "%s: %s \t %r" % (file_name, err.word, contents[err.wordpos-20:err.wordpos+20]) 56 failures += 1 57 58 if failures: 59 print "You have %d spelling errors in %s. Run lamson spell.." % (failures, file_name) 60 return False 61 else: 62 return True
63 64 65 66
67 -def relay(hostname="127.0.0.1", port=8824):
68 """Wires up a default relay on port 8824 (the default lamson log port).""" 69 return server.Relay(hostname, port, debug=0)
70 71
72 -def queue(queue_dir=TEST_QUEUE):
73 """Creates a queue for you to analyze the results of a send, uses the 74 TEST_QUEUE setting in settings.py if that exists, otherwise defaults to 75 run/queue.""" 76 return Queue(queue_dir)
77 78
79 -def clear_queue(queue_dir=TEST_QUEUE):
80 """Clears the default test queue out, as created by lamson.testing.queue.""" 81 queue(queue_dir).clear()
82 83
84 -def delivered(pattern, to_queue=None):
85 """ 86 Checks that a message with that patter is delivered, and then returns it. 87 88 It does this by searching through the queue directory and finding anything that 89 matches the pattern regex. 90 """ 91 inq = to_queue or queue() 92 for key in inq.keys(): 93 msg = inq.get(key) 94 if not msg: 95 # no messages in the queue 96 return False 97 98 regp = re.compile(pattern) 99 if regp.search(str(msg)): 100 msg = inq.get(key) 101 return msg 102 103 # didn't find anything 104 return False
105 106
107 -class TestConversation(object):
108 """ 109 Used to easily do conversations with an email server such that you 110 send a message and then expect certain responses. 111 """ 112
113 - def __init__(self, relay_to_use, From, Subject):
114 """ 115 This creates a set of default values for the conversation so that you 116 can easily send most basic message. Each method lets you override the 117 Subject and Body when you send. 118 """ 119 self.relay = relay_to_use 120 self.From = From 121 self.Subject = Subject
122
123 - def begin(self):
124 """Clears out the queue and Router states so that you have a fresh start.""" 125 clear_queue() 126 routing.Router.clear_states()
127
128 - def deliver(self, To, From, Subject, Body):
129 """Delivers it to the relay.""" 130 self.relay.send(To, From, Subject, Body)
131
132 - def say(self, To, Body, expect=None, Subject=None):
133 """ 134 Say something to To and expect a reply with a certain address. 135 It returns the message expected or None. 136 """ 137 msg = None 138 139 self.deliver(To, self.From, Subject or self.Subject, Body) 140 if expect: 141 msg = delivered(expect) 142 if not msg: 143 print "MESSAGE IN QUEUE:" 144 inq = queue() 145 for key in inq.keys(): 146 print "-----" 147 print inq.get(key) 148 149 assert msg, "Expected %r when sending to %r with '%s:%s' message." % (expect, 150 To, self.Subject or Subject, Body) 151 return msg
152
153 -class RouterConversation(TestConversation):
154 """ 155 An implementation of TestConversation that routes the messages 156 internally to the Router, rather than connecting with a relay. 157 Use it in tests that are not integration tests. 158 """
159 - def __init__(self, From, Subject):
160 self.From = From 161 self.Subject = Subject
162
163 - def deliver(self, To, From, Subject, Body):
164 """Overrides TestConversation.deliver to do it internally.""" 165 sample = mail.MailResponse(From=From, To=To, Subject=Subject, Body=Body) 166 msg = mail.MailRequest('localhost', sample['From'], sample['To'], str(sample)) 167 routing.Router.deliver(msg)
168 169 170
171 -def assert_in_state(module, To, From, state):
172 """ 173 Makes sure a user is in a certain state for a certain user. 174 Use these sparingly, since every time you change your handler you'll 175 have to change up your tests. It's better to focus on the interaction 176 with your handler and expected outputs. 177 """ 178 fake = {'to': To} 179 state_key = routing.Router.state_key(module, fake) 180 assert_equal(routing.Router.STATE_STORE.get(state_key, From), state)
181