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
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
80 """Clears the default test queue out, as created by lamson.testing.queue."""
81 queue(queue_dir).clear()
82
83
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
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
104 return False
105
106
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
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
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 """
160 self.From = From
161 self.Subject = Subject
162
163 - def deliver(self, To, From, Subject, Body):
168
169
170
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