##// END OF EJS Templates
Added a generator for the 'get' request for sync
neko259 -
r810:6bdf5d6a decentral
parent child Browse files
Show More
@@ -0,0 +1,56 b''
1 import xml.etree.ElementTree as et
2
3 TAG_MODEL = 'model'
4 TAG_REQUEST = 'request'
5 TAG_ID = 'id'
6
7 TYPE_GET = 'get'
8
9 ATTR_VERSION = 'version'
10 ATTR_TYPE = 'type'
11 ATTR_NAME = 'name'
12 ATTR_KEY = 'key'
13 ATTR_KEY_TYPE = 'type'
14 ATTR_LOCAL_ID = 'local-id'
15
16
17 class ModelId:
18 """
19 Model ID describes a global ID that consists of sender's key (with the key
20 type) and local ID on the sender node.
21 """
22
23 def __init__(self, key, key_type, local_id):
24 self.key = key
25 self.key_type = key_type
26 self.local_id = local_id
27
28
29 def respond_pull(request):
30 pass
31
32
33 def respond_get(request):
34 pass
35
36
37 def generate_request_get(id_list: list):
38 """
39 Form a get request from a list of ModelId objects.
40 """
41
42 request = et.Element(TAG_REQUEST)
43 request.set(ATTR_TYPE, TYPE_GET)
44 request.set(ATTR_VERSION, '1.0')
45
46 model = et.SubElement(request, TAG_MODEL)
47 model.set(ATTR_VERSION, '1.0')
48 model.set(ATTR_NAME, 'post')
49
50 for model_id in id_list:
51 tag_id = et.SubElement(model, TAG_ID)
52 tag_id.set(ATTR_KEY, model_id.key)
53 tag_id.set(ATTR_KEY_TYPE, model_id.key_type)
54 tag_id.set(ATTR_LOCAL_ID, model_id.local_id)
55
56 return et.tostring(request, 'unicode') No newline at end of file
@@ -1,338 +1,347 b''
1 1 # coding=utf-8
2 2 import time
3 3 import logging
4 4 import simplejson
5 5 from django.core.paginator import Paginator
6 6
7 7 from django.test import TestCase
8 8 from django.test.client import Client
9 9 from django.core.urlresolvers import reverse, NoReverseMatch
10 10 from boards.abstracts.settingsmanager import get_settings_manager
11 11
12 12 from boards.models import Post, Tag, Thread, KeyPair
13 13 from boards import urls
14 14 from boards import settings
15 15 from boards.views.api import api_get_threaddiff
16 16 from boards.utils import datetime_to_epoch
17 from boards.views.sync import ModelId, generate_request_get
17 18 import neboard
18 19
19 20 TEST_TAG = 'test_tag'
20 21
21 22 PAGE_404 = 'boards/404.html'
22 23
23 24 TEST_TEXT = 'test text'
24 25
25 26 NEW_THREAD_PAGE = '/'
26 27 THREAD_PAGE_ONE = '/thread/1/'
27 28 THREAD_PAGE = '/thread/'
28 29 TAG_PAGE = '/tag/'
29 30 HTTP_CODE_REDIRECT = 302
30 31 HTTP_CODE_OK = 200
31 32 HTTP_CODE_NOT_FOUND = 404
32 33
33 34 logger = logging.getLogger(__name__)
34 35
35 36
36 37 class PostTests(TestCase):
37 38
38 39 def _create_post(self):
39 40 tag = Tag.objects.create(name=TEST_TAG)
40 41 return Post.objects.create_post(title='title', text='text',
41 42 tags=[tag])
42 43
43 44 def test_post_add(self):
44 45 """Test adding post"""
45 46
46 47 post = self._create_post()
47 48
48 49 self.assertIsNotNone(post, 'No post was created.')
49 50 self.assertEqual(TEST_TAG, post.get_thread().tags.all()[0].name,
50 51 'No tags were added to the post.')
51 52
52 53 def test_delete_post(self):
53 54 """Test post deletion"""
54 55
55 56 post = self._create_post()
56 57 post_id = post.id
57 58
58 59 Post.objects.delete_post(post)
59 60
60 61 self.assertFalse(Post.objects.filter(id=post_id).exists())
61 62
62 63 def test_delete_thread(self):
63 64 """Test thread deletion"""
64 65
65 66 opening_post = self._create_post()
66 67 thread = opening_post.get_thread()
67 68 reply = Post.objects.create_post("", "", thread=thread)
68 69
69 70 thread.delete()
70 71
71 72 self.assertFalse(Post.objects.filter(id=reply.id).exists())
72 73
73 74 def test_post_to_thread(self):
74 75 """Test adding post to a thread"""
75 76
76 77 op = self._create_post()
77 78 post = Post.objects.create_post("", "", thread=op.get_thread())
78 79
79 80 self.assertIsNotNone(post, 'Reply to thread wasn\'t created')
80 81 self.assertEqual(op.get_thread().last_edit_time, post.pub_time,
81 82 'Post\'s create time doesn\'t match thread last edit'
82 83 ' time')
83 84
84 85 def test_delete_posts_by_ip(self):
85 86 """Test deleting posts with the given ip"""
86 87
87 88 post = self._create_post()
88 89 post_id = post.id
89 90
90 91 Post.objects.delete_posts_by_ip('0.0.0.0')
91 92
92 93 self.assertFalse(Post.objects.filter(id=post_id).exists())
93 94
94 95 def test_get_thread(self):
95 96 """Test getting all posts of a thread"""
96 97
97 98 opening_post = self._create_post()
98 99
99 100 for i in range(0, 2):
100 101 Post.objects.create_post('title', 'text',
101 102 thread=opening_post.get_thread())
102 103
103 104 thread = opening_post.get_thread()
104 105
105 106 self.assertEqual(3, thread.replies.count())
106 107
107 108 def test_create_post_with_tag(self):
108 109 """Test adding tag to post"""
109 110
110 111 tag = Tag.objects.create(name='test_tag')
111 112 post = Post.objects.create_post(title='title', text='text', tags=[tag])
112 113
113 114 thread = post.get_thread()
114 115 self.assertIsNotNone(post, 'Post not created')
115 116 self.assertTrue(tag in thread.tags.all(), 'Tag not added to thread')
116 117 self.assertTrue(thread in tag.threads.all(), 'Thread not added to tag')
117 118
118 119 def test_thread_max_count(self):
119 120 """Test deletion of old posts when the max thread count is reached"""
120 121
121 122 for i in range(settings.MAX_THREAD_COUNT + 1):
122 123 self._create_post()
123 124
124 125 self.assertEqual(settings.MAX_THREAD_COUNT,
125 126 len(Thread.objects.filter(archived=False)))
126 127
127 128 def test_pages(self):
128 129 """Test that the thread list is properly split into pages"""
129 130
130 131 for i in range(settings.MAX_THREAD_COUNT):
131 132 self._create_post()
132 133
133 134 all_threads = Thread.objects.filter(archived=False)
134 135
135 136 paginator = Paginator(Thread.objects.filter(archived=False),
136 137 settings.THREADS_PER_PAGE)
137 138 posts_in_second_page = paginator.page(2).object_list
138 139 first_post = posts_in_second_page[0]
139 140
140 141 self.assertEqual(all_threads[settings.THREADS_PER_PAGE].id,
141 142 first_post.id)
142 143
143 144
144 145 class PagesTest(TestCase):
145 146
146 147 def test_404(self):
147 148 """Test receiving error 404 when opening a non-existent page"""
148 149
149 tag_name = u'test_tag'
150 tag_name = 'test_tag'
150 151 tag = Tag.objects.create(name=tag_name)
151 152 client = Client()
152 153
153 154 Post.objects.create_post('title', TEST_TEXT, tags=[tag])
154 155
155 156 existing_post_id = Post.objects.all()[0].id
156 157 response_existing = client.get(THREAD_PAGE + str(existing_post_id) +
157 158 '/')
158 159 self.assertEqual(HTTP_CODE_OK, response_existing.status_code,
159 u'Cannot open existing thread')
160 'Cannot open existing thread')
160 161
161 162 response_not_existing = client.get(THREAD_PAGE + str(
162 163 existing_post_id + 1) + '/')
163 164 self.assertEqual(PAGE_404, response_not_existing.templates[0].name,
164 u'Not existing thread is opened')
165 'Not existing thread is opened')
165 166
166 167 response_existing = client.get(TAG_PAGE + tag_name + '/')
167 168 self.assertEqual(HTTP_CODE_OK,
168 169 response_existing.status_code,
169 u'Cannot open existing tag')
170 'Cannot open existing tag')
170 171
171 response_not_existing = client.get(TAG_PAGE + u'not_tag' + '/')
172 response_not_existing = client.get(TAG_PAGE + 'not_tag' + '/')
172 173 self.assertEqual(PAGE_404,
173 174 response_not_existing.templates[0].name,
174 u'Not existing tag is opened')
175 'Not existing tag is opened')
175 176
176 177 reply_id = Post.objects.create_post('', TEST_TEXT,
177 178 thread=Post.objects.all()[0]
178 179 .get_thread())
179 180 response_not_existing = client.get(THREAD_PAGE + str(
180 181 reply_id) + '/')
181 182 self.assertEqual(PAGE_404,
182 183 response_not_existing.templates[0].name,
183 u'Reply is opened as a thread')
184 'Reply is opened as a thread')
184 185
185 186
186 187 class FormTest(TestCase):
187 188 def test_post_validation(self):
188 189 client = Client()
189 190
190 valid_tags = u'tag1 tag_2 тег_3'
191 invalid_tags = u'$%_356 ---'
191 valid_tags = 'tag1 tag_2 тег_3'
192 invalid_tags = '$%_356 ---'
192 193
193 194 response = client.post(NEW_THREAD_PAGE, {'title': 'test title',
194 195 'text': TEST_TEXT,
195 196 'tags': valid_tags})
196 197 self.assertEqual(response.status_code, HTTP_CODE_REDIRECT,
197 198 msg='Posting new message failed: got code ' +
198 199 str(response.status_code))
199 200
200 201 self.assertEqual(1, Post.objects.count(),
201 202 msg='No posts were created')
202 203
203 204 client.post(NEW_THREAD_PAGE, {'text': TEST_TEXT,
204 205 'tags': invalid_tags})
205 206 self.assertEqual(1, Post.objects.count(), msg='The validation passed '
206 207 'where it should fail')
207 208
208 209 # Change posting delay so we don't have to wait for 30 seconds or more
209 210 old_posting_delay = neboard.settings.POSTING_DELAY
210 211 # Wait for the posting delay or we won't be able to post
211 212 neboard.settings.POSTING_DELAY = 1
212 213 time.sleep(neboard.settings.POSTING_DELAY + 1)
213 214 response = client.post(THREAD_PAGE_ONE, {'text': TEST_TEXT,
214 215 'tags': valid_tags})
215 216 self.assertEqual(HTTP_CODE_REDIRECT, response.status_code,
216 msg=u'Posting new message failed: got code ' +
217 msg='Posting new message failed: got code ' +
217 218 str(response.status_code))
218 219 # Restore posting delay
219 220 neboard.settings.POSTING_DELAY = old_posting_delay
220 221
221 222 self.assertEqual(2, Post.objects.count(),
222 msg=u'No posts were created')
223 msg='No posts were created')
223 224
224 225
225 226 class ViewTest(TestCase):
226 227
227 228 def test_all_views(self):
228 229 """
229 230 Try opening all views defined in ulrs.py that don't need additional
230 231 parameters
231 232 """
232 233
233 234 client = Client()
234 235 for url in urls.urlpatterns:
235 236 try:
236 237 view_name = url.name
237 238 logger.debug('Testing view %s' % view_name)
238 239
239 240 try:
240 241 response = client.get(reverse(view_name))
241 242
242 243 self.assertEqual(HTTP_CODE_OK, response.status_code,
243 244 '%s view not opened' % view_name)
244 245 except NoReverseMatch:
245 246 # This view just needs additional arguments
246 247 pass
247 248 except Exception as e:
248 249 self.fail('Got exception %s at %s view' % (e, view_name))
249 250 except AttributeError:
250 251 # This is normal, some views do not have names
251 252 pass
252 253
253 254
254 255 class AbstractTest(TestCase):
255 256 def test_settings_manager(self):
256 257 request = MockRequest()
257 258 settings_manager = get_settings_manager(request)
258 259
259 260 settings_manager.set_setting('test_setting', 'test_value')
260 261 self.assertEqual('test_value', settings_manager.get_setting(
261 'test_setting'), u'Setting update failed.')
262 'test_setting'), 'Setting update failed.')
262 263
263 264
264 265 class MockRequest:
265 266 def __init__(self):
266 267 self.session = dict()
267 268 self.GET = dict()
268 269 self.POST = dict()
269 270
270 271
271 272 class KeyTest(TestCase):
272 273 def test_create_key(self):
273 274 key = KeyPair.objects.generate_key('ecdsa')
274 275
275 276 self.assertIsNotNone(key, 'The key was not created.')
276 277
277 278 def test_validation(self):
278 279 key = KeyPair.objects.generate_key(key_type='ecdsa')
279 280 message = 'msg'
280 281 signature = key.sign(message)
281 282 valid = KeyPair.objects.verify(key.public_key, message, signature,
282 283 key_type='ecdsa')
283 284
284 285 self.assertTrue(valid, 'Message verification failed.')
285 286
286 287 def test_primary_constraint(self):
287 288 KeyPair.objects.generate_key(key_type='ecdsa', primary=True)
288 289
289 290 try:
290 291 KeyPair.objects.generate_key(key_type='ecdsa', primary=True)
291 292 self.fail('Exception should be thrown indicating there can be only'
292 293 ' one primary key.')
293 294 except Exception:
294 295 pass
295
296
297 def test_request_get(self):
298 model_id = ModelId('111', '222', '333')
299 self.assertTrue('<request type="get" version="1.0"><model '
300 'name="post" version="1.0"><id key="111" '
301 'local-id="333" type="222" /></model></request>' in
302 generate_request_get([model_id]),
303 'Wrong XML generated for the GET request.')
304
296 305
297 306 class ApiTest(TestCase):
298 307 def test_thread_diff(self):
299 308 tag = Tag.objects.create(name=TEST_TAG)
300 309 opening_post = Post.objects.create_post(title='title', text='text',
301 310 tags=[tag])
302 311
303 312 last_edit_time = datetime_to_epoch(opening_post.last_edit_time)
304 313
305 314 # Check the exact timestamp post was added
306 315 empty_response = api_get_threaddiff(MockRequest(),
307 316 str(opening_post.thread_new.id),
308 317 str(last_edit_time))
309 318 diff = simplejson.loads(empty_response.content)
310 319 self.assertEqual(0, len(diff['added']),
311 320 'There must be no added posts in the diff.')
312 321 self.assertEqual(0, len(diff['updated']),
313 322 'There must be no updated posts in the diff.')
314 323
315 324 reply = Post.objects.create_post(title='',
316 325 text='[post]%d[/post]\ntext' % opening_post.id,
317 326 thread=opening_post.thread_new)
318 327
319 328 # Check the timestamp before post was added
320 329 response = api_get_threaddiff(MockRequest(),
321 330 str(opening_post.thread_new.id),
322 331 str(last_edit_time))
323 332 diff = simplejson.loads(response.content)
324 333 self.assertEqual(1, len(diff['added']),
325 334 'There must be 1 added posts in the diff.')
326 335 self.assertEqual(1, len(diff['updated']),
327 336 'There must be 1 updated posts in the diff.')
328 337
329 338 empty_response = api_get_threaddiff(MockRequest(),
330 339 str(opening_post.thread_new.id),
331 340 str(datetime_to_epoch(
332 341 reply.last_edit_time)))
333 342 diff = simplejson.loads(empty_response.content)
334 343 self.assertEqual(0, len(diff['added']),
335 344 'There must be no added posts in the diff.')
336 345 self.assertEqual(0, len(diff['updated']),
337 346 'There must be no updated posts in the diff.')
338 347
@@ -1,7 +1,7 b''
1 1 <?xml version="1.1" encoding="UTF-8" ?>
2 2 <request version="1.0" type="get">
3 3 <model version="1.0" name="post">
4 <id key="id1" local-id="1" />
5 <id key="id1" local-id="2" />
4 <id key="id1" type="ecdsa" local-id="1" />
5 <id key="id1" type="ecdsa" local-id="2" />
6 6 </model>
7 7 </request>
@@ -1,10 +1,10 b''
1 1 <?xml version="1.1" encoding="UTF-8" ?>
2 2 <response>
3 3 <status>success</status>
4 4 <models>
5 <id key="id1" local-id="1" />
6 <id key="id1" local-id="2" />
7 <id key="id2" local-id="1" />
8 <id key="id2" local-id="5" />
5 <id key="id1" type="ecdsa" local-id="1" />
6 <id key="id1" type="ecdsa" local-id="2" />
7 <id key="id2" type="ecdsa" local-id="1" />
8 <id key="id2" type="ecdsa" local-id="5" />
9 9 </models>
10 10 </response>
@@ -1,8 +1,9 b''
1 simplejson
1 2 south>=0.8.4
2 3 haystack
3 4 pillow
4 5 django>=1.6
5 6 django_cleanup
6 7 django-markupfield
7 8 bbcode
8 9 ecdsa
General Comments 0
You need to be logged in to leave comments. Login now