Package madrona :: Package features :: Module tests
[hide private]

Source Code for Module madrona.features.tests

   1  from django.test import TestCase 
   2  from madrona.features import * 
   3  from madrona.features.models import Feature, PointFeature, LineFeature, PolygonFeature, FeatureCollection 
   4  from madrona.features.forms import FeatureForm 
   5  from madrona.common.utils import kml_errors, enable_sharing 
   6  import os 
   7  import shutil 
   8  import json 
   9  from django.test.client import Client 
  10  from django.contrib.auth.models import * 
  11  from django.core.urlresolvers import reverse 
  12  from django.http import HttpResponse, HttpResponseForbidden 
  13  from django.contrib.gis.geos import GEOSGeometry  
  14  from django.conf import settings 
15 16 # used by some of the tests to temporarily create a template file 17 -def create_template(path):
18 d = os.path.dirname(__file__) 19 dpath = os.path.dirname(os.path.join(d, 'templates', path)) 20 os.mkdir(dpath) 21 path = os.path.join(dpath, 'show.html') 22 f = open(path, 'w') 23 f.write('h1 />') 24 f.close()
25
26 -def delete_template(path):
27 d = os.path.dirname(__file__) 28 dpath = os.path.join(d, 'templates') 29 path = os.path.join(dpath, path) 30 path = os.path.dirname(path) 31 if os.path.exists(path): 32 shutil.rmtree(path)
33
34 @register 35 -class TestGetFormClassFeature(Feature):
36 - class Options:
37 form = 'madrona.features.tests.TestFeatureForm'
38
39 -class TestFeatureForm(FeatureForm):
40 - class Meta:
42
43 @register 44 -class TestGetFormClassFailFeature(Feature):
45 - class Options:
46 form = 'madrona.features.tests.TestForm'
47
48 -class TestForm:
49 - class Meta:
51
52 @register 53 -class TestSlugFeature(Feature):
54 - class Options:
55 form = 'madrona.features.form.FeatureForm'
56
57 @register 58 -class TestDefaultVerboseNameFeature(Feature):
59 - class Options:
60 form = 'madrona.features.form.FeatureForm'
61
62 @register 63 -class TestCustomVerboseNameFeature(Feature):
64 - class Options:
65 form = 'madrona.features.form.FeatureForm' 66 verbose_name = 'vb-name'
67
68 @register 69 -class TestDefaultShowTemplateFeature(Feature):
70 - class Options:
71 form = 'madrona.features.form.FeatureForm'
72
73 @register 74 -class TestCustomShowTemplateFeature(Feature):
75 - class Options:
76 form = 'madrona.features.form.FeatureForm' 77 show_template = 'location/show.html'
78
79 @register 80 -class TestMissingDefaultShowFeature(Feature):
81 - class Options:
82 form = 'madrona.features.form.FeatureForm'
83
84 @register 85 -class TestMissingCustomShowFeature(Feature):
86 - class Options:
87 form = 'madrona.features.form.FeatureForm' 88 show_template = 'location/show.html'
89
90 -class FeatureOptionsTest(TestCase):
91
92 - def test_check_for_subclass(self):
93 with self.assertRaisesRegexp(FeatureConfigurationError, 'subclass'): 94 @register 95 class NotAFeature: 96 pass
97 NotAFeature.get_options()
98
99 - def test_check_for_inner_class(self):
100 with self.assertRaisesRegexp(FeatureConfigurationError,'not defined'): 101 @register 102 class TestFeatureFails(Feature): 103 pass
104 TestFeatureFails.get_options() 105
106 - def test_must_have_form_class(self):
107 with self.assertRaisesRegexp(FeatureConfigurationError,'form'): 108 @register 109 class TestFeatureNoForm(Feature): 110 class Options: 111 pass
112 TestFeatureNoForm.get_options() 113
114 - def test_must_specify_form_as_string(self):
115 with self.assertRaisesRegexp(FeatureConfigurationError,'string'): 116 @register 117 class TestFeature(Feature): 118 class Options: 119 form = FeatureForm
120 TestFeature.get_options() 121
122 - def test_slug(self):
123 self.assertEqual(TestSlugFeature.get_options().slug, 'testslugfeature')
124
125 - def test_default_verbose_name(self):
126 self.assertEqual( 127 TestDefaultVerboseNameFeature.get_options().verbose_name, 128 'TestDefaultVerboseNameFeature')
129
130 - def test_custom_verbose_name(self):
131 self.assertEqual( 132 TestCustomVerboseNameFeature.get_options().verbose_name, 133 'vb-name')
134
135 - def test_default_show_template(self):
136 options = TestDefaultShowTemplateFeature.get_options() 137 path = options.slug + '/show.html' 138 delete_template(path) 139 create_template(path) 140 self.assertEqual( 141 options.get_show_template().name, 142 path) 143 delete_template(path)
144
145 - def test_custom_show_template(self):
146 options = TestCustomShowTemplateFeature.get_options() 147 path = TestCustomShowTemplateFeature.Options.show_template 148 delete_template(path) 149 create_template(path) 150 self.assertEqual( 151 options.get_show_template().name, 152 path) 153 delete_template(path)
154
155 - def test_missing_default_show_template(self):
156 options = TestMissingDefaultShowFeature.get_options() 157 path = options.slug + '/show.html' 158 self.assertEqual( 159 options.get_show_template().name, 160 'features/show.html')
161
162 - def test_missing_custom_show_template(self):
163 164 options = TestMissingCustomShowFeature.get_options() 165 self.assertEqual( 166 options.get_show_template().name, 167 'features/show.html')
168
169 - def test_get_form_class(self):
170 self.assertEqual( 171 TestGetFormClassFeature.get_options().get_form_class(), 172 TestFeatureForm)
173
174 - def test_get_form_not_subclass(self):
175 with self.assertRaisesRegexp(FeatureConfigurationError, 'subclass'): 176 TestGetFormClassFailFeature.get_options().get_form_class()
177
178 # Generic view tests 179 180 @register 181 -class TestDeleteFeature(Feature):
182 - class Options:
183 form = 'madrona.features.form.FeatureForm'
184
185 -class DeleteTest(TestCase):
186
187 - def setUp(self):
188 self.client = Client() 189 self.options = TestDeleteFeature.get_options() 190 self.user = User.objects.create_user( 191 'featuretest', 'featuretest@madrona.org', password='pword') 192 self.test_instance = TestDeleteFeature(user=self.user, name="My Name") 193 self.test_instance.save()
194
195 - def test_delete_not_logged_in(self):
196 """ 197 If user not logged in they can't delete anything 198 401 status_code response 199 """ 200 url = self.test_instance.get_absolute_url() 201 response = self.client.delete(url) 202 self.assertEqual(response.status_code, 401)
203
204 - def test_delete_not_owner(self):
205 """ 206 Don't allow just any old user to delete objects. 207 Return 403 Forbidden status code 208 """ 209 other_user = User.objects.create_user( 210 'other', 'other@madrona.org', password='pword') 211 self.client.login(username=other_user.username, password='pword') 212 url = self.test_instance.get_absolute_url() 213 response = self.client.delete(url) 214 self.assertEqual(response.status_code, 403)
215
217 """ 218 Staff users can delete anyone's stuff 219 """ 220 staff_user = User.objects.create_user( 221 'staff', 'staff@madrona.org', password='pword') 222 staff_user.is_staff = True 223 staff_user.save() 224 pk = self.test_instance.pk 225 url = self.test_instance.get_absolute_url() 226 self.assertEqual(TestDeleteFeature.objects.filter(pk=pk).count(), 1) 227 self.client.login(username='staff', password='pword') 228 response = self.client.delete(url) 229 self.assertEqual(response.status_code, 200) 230 self.assertEqual(TestDeleteFeature.objects.filter(pk=pk).count(), 0)
231
232 - def test_delete_authorized(self):
233 """ 234 Users can delete objects that belong to them 235 """ 236 pk = self.test_instance.pk 237 self.assertEqual(TestDeleteFeature.objects.filter(pk=pk).count(), 1) 238 url = self.test_instance.get_absolute_url() 239 self.client.login(username='featuretest', password='pword') 240 response = self.client.delete(url) 241 self.assertEqual(response.status_code, 200) 242 self.assertEqual(TestDeleteFeature.objects.filter(pk=pk).count(), 0)
243
244 - def test_delete_collection(self):
245 """ 246 Users can delete collections that belong to them 247 Any features in the collection will also be deleted 248 """ 249 pk = self.test_instance.pk 250 self.assertEqual(TestDeleteFeature.objects.filter(pk=pk).count(), 1) 251 folder = TestFolder(user=self.user, name="My Folder") 252 folder.save() 253 folder_pk = folder.pk 254 self.test_instance.add_to_collection(folder) 255 self.assertEqual(TestFolder.objects.filter(pk=folder_pk).count(), 1) 256 self.assertTrue(self.test_instance in folder.feature_set()) 257 url = folder.get_absolute_url() 258 self.client.login(username='featuretest', password='pword') 259 response = self.client.delete(url) 260 self.assertEqual(response.status_code, 200) 261 self.assertEqual(TestFolder.objects.filter(pk=folder_pk).count(), 0) 262 self.assertEqual(TestDeleteFeature.objects.filter(pk=pk).count(), 0)
263
264 - def test_multi_delete(self):
265 self.test_instance2 = TestDeleteFeature(user=self.user, name="My Name2") 266 self.test_instance2.save() 267 self.assertEqual(TestDeleteFeature.objects.all().count(), 2) 268 uids = [self.test_instance.uid, self.test_instance2.uid] 269 link = GenericLinksTestFeature.get_options().get_link('Delete') 270 url = link.reverse([self.test_instance, self.test_instance2]) 271 self.client.login(username='featuretest', password='pword') 272 response = self.client.delete(url) 273 self.assertEqual(response.status_code, 200) 274 self.assertEqual(TestDeleteFeature.objects.all().count(), 0)
275
276 @register 277 -class CreateFormTestFeature(Feature):
278 - class Options:
279 form = 'madrona.features.tests.CreateFormTestForm'
280
281 -class CreateFormTestForm(FeatureForm):
282 - class Meta:
284
285 -class CreateFormTest(TestCase):
286
287 - def setUp(self):
288 self.client = Client() 289 self.user = User.objects.create_user( 290 'featuretest', 'featuretest@madrona.org', password='pword') 291 self.options = CreateFormTestFeature.get_options()
292
293 - def test_user_not_logged_in(self):
294 """ 295 Can't create stuff without being logged in. 296 """ 297 response = self.client.get(self.options.get_create_form()) 298 self.assertEqual(response.status_code, 401)
299
300 - def test_get_form(self):
301 """ 302 Returns a form that can be displayed on the client. 303 """ 304 self.client.login(username='featuretest', password='pword') 305 response = self.client.get(self.options.get_create_form()) 306 self.assertEqual(response.status_code, 200)
307
308 @register 309 -class CreateTestFeature(Feature):
310 - class Options:
311 form = 'madrona.features.tests.CreateTestForm'
312
313 -class CreateTestForm(FeatureForm):
314 - class Meta:
316
317 -class CreateTest(TestCase):
318
319 - def setUp(self):
320 self.client = Client() 321 self.user = User.objects.create_user( 322 'featuretest', 'featuretest@madrona.org', password='pword') 323 self.options = CreateTestFeature.get_options() 324 self.create_url = self.options.get_create_form()
325
327 response = self.client.post(self.create_url, 328 {'name': "My Test", 'user': 1}) 329 self.assertEqual(response.status_code, 401)
330
331 - def test_submit_invalid_form(self):
332 old_count = CreateTestFeature.objects.count() 333 self.client.login(username='featuretest', password='pword') 334 response = self.client.post(self.create_url, {'name': ''}) 335 self.assertEqual(response.status_code, 400) 336 self.assertTrue(old_count == CreateTestFeature.objects.count()) 337 self.assertNotEqual( 338 response.content.find('This field is required.'), -1)
339
340 - def test_submit_valid_form(self):
341 old_count = CreateTestFeature.objects.count() 342 self.client.login(username='featuretest', password='pword') 343 response = self.client.post(self.create_url, {'name': "My Test"}) 344 self.assertEqual(response.status_code, 201,response.content) 345 self.assertTrue(old_count < CreateTestFeature.objects.count()) 346 inst = CreateTestFeature.objects.get(name='My Test') 347 self.assertTrue( 348 response._get_content().find(inst.get_absolute_url()) > -1)
349
351 other_user = User.objects.create_user( 352 'other', 'other@madrona.org', password='pword') 353 old_count = CreateTestFeature.objects.count() 354 self.client.login(username='featuretest', password='pword') 355 response = self.client.post(self.create_url, 356 {'name': "My Test Hack Test", 'user': other_user.pk}) 357 self.assertEqual(response.status_code, 201) 358 self.assertTrue(old_count < CreateTestFeature.objects.count()) 359 new_instance = CreateTestFeature.objects.get(name='My Test Hack Test') 360 self.assertNotEqual(new_instance.user, other_user)
361
362 @register 363 -class UpdateFormTestFeature(Feature):
364 - class Options:
365 form = 'madrona.features.tests.UpdateFormTestForm'
366
367 -class UpdateFormTestForm(FeatureForm):
368 - class Meta:
370
371 -class UpdateFormTest(TestCase):
372
373 - def setUp(self):
374 self.options = UpdateFormTestFeature.get_options() 375 self.client = Client() 376 self.user = User.objects.create_user( 377 'featuretest', 'featuretest@madrona.org', password='pword') 378 self.test_instance = UpdateFormTestFeature( 379 user=self.user, name="My Name") 380 self.test_instance.save() 381 self.update_form_url = self.options.get_update_form( 382 self.test_instance.pk)
383
384 - def test_get_form(self):
385 self.client.login(username='featuretest', password='pword') 386 response = self.client.get(self.update_form_url) 387 self.assertEqual(response.status_code, 200) 388 self.assertNotEqual(response.content.find('My Name'), -1)
389
390 - def test_not_logged_in(self):
391 response = self.client.get(self.update_form_url) 392 self.assertEqual(response.status_code, 401)
393
394 - def test_not_owner(self):
395 other_user = User.objects.create_user( 396 'other', 'other@madrona.org', password='pword') 397 self.client.login(username='other', password='pword') 398 response = self.client.get(self.update_form_url) 399 self.assertEqual(response.status_code, 403)
400
401 - def test_not_owner_but_staff(self):
402 staff_user = User.objects.create_user( 403 'staff', 'other@madrona.org', password='pword') 404 staff_user.is_staff = True 405 staff_user.save() 406 self.client.login(username='staff', password='pword') 407 response = self.client.get(self.update_form_url) 408 self.assertEqual(response.status_code, 200)
409
410 - def test_not_found(self):
411 self.client.login(username='featuretest', password='pword') 412 response = self.client.get(self.options.get_update_form(30000000000)) 413 self.assertEqual(response.status_code, 404)
414
415 @register 416 -class UpdateTestFeature(Feature):
417 - class Options:
418 form = 'madrona.features.tests.UpdateTestForm'
419
420 -class UpdateTestForm(FeatureForm):
421 - class Meta:
423
424 -class UpdateTest(TestCase):
425
426 - def setUp(self):
427 self.options = UpdateTestFeature.get_options() 428 self.client = Client() 429 self.user = User.objects.create_user( 430 'featuretest', 'featuretest@madrona.org', password='pword') 431 self.test_instance = UpdateTestFeature(user=self.user, name="My Name") 432 self.test_instance.save() 433 self.update_form_url = self.options.get_update_form( 434 self.test_instance.pk) 435 self.instance_url = self.test_instance.get_absolute_url()
436
437 - def test_post(self):
438 self.client.login(username='featuretest', password='pword') 439 response = self.client.post(self.instance_url, { 440 'name': 'My New Name', 441 }) 442 self.assertEqual(response.status_code, 200)
443
444 - def test_post_validation_error(self):
445 self.client.login(username='featuretest', password='pword') 446 response = self.client.post(self.instance_url, { 447 'name': '', 448 }) 449 self.assertEqual(response.status_code, 400)
450
451 - def test_post_not_logged_in(self):
452 response = self.client.post(self.instance_url, { 453 'name': 'My New Name', 454 }) 455 self.assertEqual(response.status_code, 401)
456
457 - def test_post_not_owner(self):
458 other_user = User.objects.create_user('other', 'other@madrona.org', password='pword') 459 self.client.login(username='other', password='pword') 460 response = self.client.post(self.instance_url, { 461 'name': 'My New Name', 462 }) 463 self.assertEqual(response.status_code, 403)
464
465 - def test_post_not_owner_but_staff(self):
466 other_user = User.objects.create_user('other', 'other@madrona.org', password='pword') 467 other_user.is_staff = True 468 other_user.save() 469 self.client.login(username='other', password='pword') 470 response = self.client.post(self.instance_url, { 471 'name': 'My New Name', 472 }) 473 self.assertEqual(response.status_code, 200)
474
475 - def test_not_found(self):
476 self.client.login(username='featuretest', password='pword') 477 response = self.client.post(self.options.get_resource(10000000), { 478 'name': 'My New Name', 479 }) 480 self.assertEqual(response.status_code, 404)
481
483 other_user = User.objects.create_user('other', 'other@madrona.org', password='pword') 484 self.client.login(username='featuretest', password='pword') 485 response = self.client.post(self.instance_url, { 486 'name': 'My New Name', 487 'user': other_user.pk, 488 }) 489 self.assertEqual(response.status_code, 200) 490 edited_instance = UpdateTestFeature.objects.get(pk=self.test_instance.pk) 491 self.assertNotEqual(edited_instance.user, other_user)
492
493 -def valid_single_select_view(request, instance):
494 return HttpResponse(instance.name)
495
496 -def invalid_single_select_view(request, pk):
497 pass
498
499 -def invalid_multiple_select_view(request, fail):
500 pass
501
502 -def valid_multiple_select_view(request, instances):
503 return HttpResponse(', '.join([i.name for i in instances]))
504
505 -class LinkViewValidationTest(TestCase):
506
508 # Must accept at least a second argument for the instance 509 with self.assertRaises(FeatureConfigurationError): 510 link = alternate( 511 'test title', 512 'madrona.features.tests.invalid_single_select_view') 513 514 # Accepts the instance argument 515 link = alternate('test title', 516 'madrona.features.tests.valid_single_select_view') 517 self.assertIsInstance(link, Link)
518
520 # Must accept at least a second argument for the instances 521 with self.assertRaises(FeatureConfigurationError): 522 link = alternate('test title', 523 'madrona.features.tests.invalid_multiple_select_view', 524 select='multiple') 525 526 # Accepts the instance argument 527 link = alternate('test title', 528 'madrona.features.tests.valid_multiple_select_view', 529 select='multiple') 530 self.assertIsInstance(link, Link)
531
533 pass
534 # TODO: Test that Link validates extra_kwargs option is compatible
535 # with the view 536 537 @register 538 -class LinkTestFeature(Feature):
539 - class Options:
540 form = 'madrona.features.tests.LinkTestFeatureForm' 541 links = ( 542 alternate('Single Select View', 543 'madrona.features.tests.valid_single_select_view', 544 type="application/shapefile"), 545 546 alternate('Spreadsheet of all Features', 547 'madrona.features.tests.valid_multiple_select_view', 548 type="application/xls", 549 select='multiple single'), 550 551 edit('Edit single feature', 552 'madrona.features.tests.valid_single_select_view' 553 ), 554 555 edit_form('Edit multiple features', 556 'madrona.features.tests.valid_multiple_select_view', 557 select='multiple single' 558 ), 559 )
560
561 -class LinkTestFeatureForm(FeatureForm):
562 - class Meta:
564
565 -class LinkTest(TestCase):
566
567 - def setUp(self):
568 self.options = LinkTestFeature.get_options() 569 self.client = Client() 570 self.user = User.objects.create_user( 571 'featuretest', 'featuretest@madrona.org', password='pword') 572 self.other_user = User.objects.create_user( 573 'other', 'other@madrona.org', password='pword') 574 self.test_instance = LinkTestFeature(user=self.user, name="My Name") 575 self.test_instance.save() 576 self.update_form_url = self.options.get_update_form( 577 self.test_instance.pk) 578 self.instance_url = self.test_instance.get_absolute_url() 579 self.i2 = LinkTestFeature(user=self.user, name="I2") 580 self.i2.save()
581 587 588 # TODO ... instead of referencing link by index, use get_link 589 605
606 - def test_401_response(self):
607 """Should not be able to perform editing actions without login. 608 """ 609 link = self.options.get_link('Edit single feature') 610 link2 = self.options.get_link('Edit multiple features') 611 response = self.client.post(link.reverse(self.test_instance)) 612 self.assertEqual(response.status_code, 401,response.content) 613 response = self.client.get(link2.reverse(self.test_instance)) 614 self.assertEqual(response.status_code, 401) 615 self.client.login(username='featuretest', password='pword') 616 response = self.client.get(link2.reverse(self.test_instance)) 617 self.assertEqual(response.status_code, 200)
618 627
628 - def test_403_response(self):
629 """Should not be able to edit shapes a user doesn't own. 630 """ 631 link = self.options.get_link('Edit multiple features') 632 self.client.login(username='other', password='pword') 633 response = self.client.get(link.reverse(self.test_instance)) 634 self.assertEqual(response.status_code, 403)
635
637 """Should not be able to edit shapes a user doesn't own. Test to make 638 sure every feature in a request is checked. 639 """ 640 link = self.options.get_link('Edit multiple features') 641 self.client.login(username='other', password='pword') 642 inst = LinkTestFeature(user=self.other_user, 643 name="Other User's feature") 644 inst.save() 645 response = self.client.get( 646 link.reverse([inst, self.test_instance])) 647 self.assertEqual(response.status_code, 403, response.content)
648
649 - def test_404_response(self):
650 link = self.options.get_link('Edit multiple features') 651 self.client.login(username='featuretest', password='pword') 652 inst = LinkTestFeature(user=self.user, 653 name="feature") 654 inst.save() 655 path = link.reverse([inst, self.test_instance]) 656 inst.delete() 657 response = self.client.get(path) 658 self.assertEqual(response.status_code, 404)
659
660 -def multi_select_view(request, instances):
661 return HttpResponse(', '.join([i.name for i in instances]))
662
663 @register 664 -class GenericLinksTestFeature(Feature):
665 - class Options:
666 form = 'madrona.features.tests.GenericLinksTestForm' 667 links = ( 668 alternate('Generic Link', 669 'madrona.features.tests.multi_select_view', 670 type="application/shapefile", 671 select='multiple single'), 672 alternate('Non-Generic Link', 673 'madrona.features.tests.multi_select_view', 674 type="application/shapefile", 675 select='multiple single'), 676 )
677
678 -class GenericLinksTestForm(FeatureForm):
679 - class Meta:
681
682 @register 683 -class OtherGenericLinksTestFeature(Feature):
684 - class Options:
685 form = 'madrona.features.tests.OtherGenericLinksTestForm' 686 links = ( 687 alternate('Generic Link', 688 'madrona.features.tests.multi_select_view', 689 type="application/shapefile", 690 select='multiple single'), 691 )
692
693 -class OtherGenericLinksTestForm(FeatureForm):
694 - class Meta:
696
697 @register 698 -class LastGenericLinksTestFeature(Feature):
699 - class Options:
700 form = 'madrona.features.tests.GenericLinksTestForm' 701 links = ( 702 alternate('Different Name', 703 'madrona.features.tests.multi_select_view', 704 type="application/shapefile", 705 select='multiple single'), 706 707 )
708
709 -class GenericLinksTest(TestCase):
710
711 - def setUp(self):
712 self.client = Client() 713 self.user = User.objects.create_user( 714 'featuretest', 'featuretest@madrona.org', password='pword') 715 self.generic_instance = GenericLinksTestFeature(user=self.user, 716 name="Generic") 717 self.other_instance = OtherGenericLinksTestFeature(user=self.user, 718 name="Other") 719 self.last_instance = LastGenericLinksTestFeature(user=self.user, 720 name="Last") 721 self.generic_instance.save() 722 self.other_instance.save() 723 self.last_instance.save()
724 733 744
756
757 -def delete_w_contents(request, instances):
758 return HttpResponse('Deleted')
759
760 -def habitat_spreadsheet(request, instance):
761 return HttpReponse('Report Contents')
762
763 -def viewshed_map(request, instance):
764 return HttpResponse('image')
765
766 -def kml(request, instances):
767 return HttpResponse('<kml />')
768 769 # Lets use the following as a canonical example of how to use all the features 770 # of this framework (will be kept up to date as api changes): 771 772 DESIGNATION_CHOICES = ( 773 ('R', 'Reserve'), 774 ('P', 'Park'), 775 ('C', 'Conservation Area') 776 )
777 778 @register 779 -class TestMpa(PolygonFeature):
780 designation = models.CharField(max_length=1, choices=DESIGNATION_CHOICES) 781
782 - class Options:
783 verbose_name = 'Marine Protected Area' 784 form = 'madrona.features.tests.MpaForm' 785 manipulators = ['madrona.manipulators.tests.TestManipulator'] 786 optional_manipulators = ['madrona.manipulators.manipulators.ClipToGraticuleManipulator'] 787 links = ( 788 related('Habitat Spreadsheet', 789 'madrona.features.tests.habitat_spreadsheet', 790 select='single', 791 type='application/xls', 792 limit_to_groups=['SuperSpecialTestGroup'] 793 ), 794 alternate('Export KML for Owner', 795 'madrona.features.tests.kml', 796 select='multiple single', 797 must_own=True 798 ), 799 alternate('Export KML', 800 'madrona.features.tests.kml', 801 select='multiple single' 802 ), 803 alternate('Export Misc for Owner', 804 'madrona.features.tests.kml', 805 select='multiple single', 806 must_own=True 807 ) 808 )
809
810 -class MpaForm(FeatureForm):
811 - class Meta:
812 model = TestMpa
813
814 @register 815 -class TestArray(FeatureCollection):
816 - class Options:
817 form = 'madrona.features.tests.TestArrayForm' 818 valid_children = ( 819 'madrona.features.tests.TestMpa', 820 'madrona.features.tests.Pipeline', 821 'madrona.features.tests.RenewableEnergySite')
822
823 -class TestArrayForm(FeatureForm):
824 - class Meta:
826
827 @register 828 -class TestFolder(FeatureCollection):
829
830 - def copy(self, user):
831 copy = super(TestFolder, self).copy(user) 832 copy.name = copy.name.replace(' (copy)', '-Copy') 833 copy.save() 834 return copy
835
836 - class Options:
837 form = 'madrona.features.tests.TestFolderForm' 838 valid_children = ( 839 'madrona.features.tests.TestMpa', 840 'madrona.features.tests.TestArray', 841 'madrona.features.tests.TestFolder', 842 'madrona.features.tests.TestDeleteFeature', 843 'madrona.features.tests.RenewableEnergySite') 844 links = ( 845 edit('Delete folder and contents', 846 'madrona.features.tests.delete_w_contents', 847 select='single multiple', 848 confirm=""" 849 Are you sure you want to delete this folder and it's contents? 850 This action cannot be undone. 851 """ 852 ), 853 alternate('Export KML for Owner', 854 'madrona.features.tests.kml', 855 select='multiple single', 856 must_own=True 857 ), 858 alternate('Export KML', 859 'madrona.features.tests.kml', 860 select='multiple single' 861 ) 862 )
863
864 -class TestFolderForm(FeatureForm):
865 - class Meta:
867 868 TYPE_CHOICES = ( 869 ('W', 'Wind'), 870 ('H', 'Hydrokinetic'), 871 )
872 873 @register 874 -class RenewableEnergySite(PolygonFeature):
875 type = models.CharField(max_length=1, choices=TYPE_CHOICES) 876
877 - class Options:
878 verbose_name = 'Renewable Energy Site' 879 form = 'madrona.features.tests.RenewableEnergySiteForm' 880 links = ( 881 related('Viewshed Map', 882 'madrona.features.tests.viewshed_map', 883 select='single', 884 type='image/png' 885 ), 886 alternate('Export KML', 887 'madrona.features.tests.kml', 888 select='multiple single' 889 ) 890 )
891
892 -class RenewableEnergySiteForm(FeatureForm):
893 - class Meta:
895
896 @register 897 -class Pipeline(LineFeature):
898 type = models.CharField(max_length=30,default='') 899 diameter = models.FloatField(null=True) 900
901 - class Options:
902 verbose_name = 'Pipeline' 903 form = 'madrona.features.tests.PipelineForm'
904
905 -class PipelineForm(FeatureForm):
906 - class Meta:
907 model = Pipeline
908
909 @register 910 -class Shipwreck(PointFeature):
911 incident = models.CharField(max_length=100,default='') 912
913 - class Options:
914 verbose_name = 'Shipwreck' 915 form = 'madrona.features.tests.ShipwreckForm'
916
917 -class ShipwreckForm(FeatureForm):
918 - class Meta:
920
921 -class JsonSerializationTest(TestCase):
922
923 - def setUp(self):
924 self.user = User.objects.create_user( 925 'featuretest', 'featuretest@madrona.org', password='pword') 926 self.json = workspace_json(user=self.user,is_owner=True) 927 self.json_shared = workspace_json(user=self.user,is_owner=False) 928 self.dict = json.loads(self.json) 929 self.dict_shared = json.loads(self.json_shared)
930
931 - def test_normal_features(self):
932 fcdict = [x for x in self.dict['feature-classes'] if x['title'] == 'Shipwreck'][0] 933 for lr in ['self','create','edit']: 934 self.assertTrue(fcdict['link-relations'][lr]) 935 with self.assertRaises(KeyError): 936 fcdict['link-relations']['alternate'] 937 with self.assertRaises(KeyError): 938 fcdict['link-relations']['related']
939
940 - def test_generic(self):
941 linkdict = [x for x in self.dict['generic-links'] if x['title'] == 'Generic Link'][0] 942 for f in ["features_genericlinkstestfeature", "features_othergenericlinkstestfeature"]: 943 self.assertTrue(f in linkdict['models']) 944 self.assertFalse("features_shipwreck" in linkdict['models'])
945
946 - def test_custom_features(self):
947 fcdict = [x for x in self.dict['feature-classes'] if x['id'] == 'features_testmpa'][0] 948 for lr in ['self','create','edit','alternate']: 949 self.assertTrue(fcdict['link-relations'][lr]) 950 951 fcdict = [x for x in self.dict['feature-classes'] if x['title'] == 'LinkTestFeature'][0] 952 for lr in ['self','create','edit', 'alternate']: 953 self.assertTrue(fcdict['link-relations'][lr]) 954 with self.assertRaises(KeyError): 955 fcdict['link-relations']['related']
956
957 - def test_collections(self):
958 fcdict = [x for x in self.dict['feature-classes'] if x['title'] == 'TestArray'][0] 959 self.assertTrue(fcdict['collection']) 960 self.assertEquals(len(fcdict['collection']['classes']), 3)
961
962 - def test_must_own_builtin(self):
963 """ For "builtin" edit links, 964 they shouldn't show up when using workspace-shared """ 965 fcdict = [x for x in self.dict['feature-classes'] 966 if x['id'] == 'features_testmpa'][0] 967 self.assertEquals(fcdict['link-relations']['edit'][0]['title'], 'Edit') 968 fcdict_shared = [x for x in self.dict_shared['feature-classes'] 969 if x['id'] == 'features_testmpa'][0] 970 with self.assertRaises(KeyError): 971 fcdict_shared['link-relations']['edit']
972
973 - def test_must_own_generic(self):
974 """ For generic links with must_own=True, 975 they shouldn't show up when using workspace-shared """ 976 # Owner dict should have the must_own generic link 977 linkdict = [x for x in self.dict['generic-links'] if x['title'] == 'Export KML for Owner'][0] 978 self.assertTrue('features_testmpa' in linkdict['models']) 979 self.assertTrue('features_testfolder' in linkdict['models']) 980 981 # ... shared dict should NOT have the must_own generic link 982 self.assertEquals(len([x for x in self.dict_shared['generic-links'] 983 if x['title'] == 'Export KML for Owner']),0)
984
985 - def test_must_own_custom(self):
986 """ For custom links with must_own=True, 987 they shouldn't show up when using workspace-shared """ 988 fcdict = [x for x in self.dict['feature-classes'] 989 if x['id'] == 'features_testmpa'][0] 990 self.assertEquals(fcdict['link-relations']['alternate'][0]['title'], 'Export Misc for Owner') 991 fcdict_shared = [x for x in self.dict_shared['feature-classes'] 992 if x['id'] == 'features_testmpa'][0] 993 with self.assertRaises(KeyError): 994 fcdict_shared['link-relations']['alternate'][0]['title']
995
996 - def test_limit_to_groups(self):
997 self.assertEquals(len(self.user.groups.filter(name="SuperSpecialTestGroup")),0) 998 999 dict_pre = json.loads(workspace_json(self.user, True)) 1000 fcdict = [x for x in dict_pre['feature-classes'] 1001 if x['id'] == 'features_testmpa'][0] 1002 with self.assertRaises(KeyError): 1003 fcdict['link-relations']['related'][0]['title'] 1004 1005 special_group, created = Group.objects.get_or_create(name="SuperSpecialTestGroup") 1006 self.user.groups.add(special_group) 1007 self.user.save() 1008 self.assertEquals(len(self.user.groups.filter(name="SuperSpecialTestGroup")),1) 1009 1010 dict_post = json.loads(workspace_json(self.user, True)) 1011 fcdict = [x for x in dict_post['feature-classes'] 1012 if x['id'] == 'features_testmpa'][0] 1013 self.assertEquals(fcdict['link-relations']['related'][0]['title'], 'Habitat Spreadsheet')
1014
1015 - def test_owner_url(self):
1016 client = Client() 1017 client.login(username='featuretest', password='pword') 1018 url = '/features/featuretest/workspace-owner.json' 1019 response = client.get(url) 1020 self.assertEqual(response.status_code, 200) 1021 self.assertEqual(response.content, self.json)
1022
1023 - def test_shared_url(self):
1024 client = Client() 1025 client.login(username='featuretest', password='pword') 1026 url = '/features/featuretest/workspace-shared.json' 1027 response = client.get(url) 1028 self.assertEqual(response.status_code, 200) 1029 self.assertEqual(response.content, self.json_shared)
1030
1031 -class CopyTest(TestCase):
1032
1033 - def setUp(self):
1034 self.client = Client() 1035 1036 self.user = User.objects.create_user( 1037 'featuretest', 'featuretest@madrona.org', password='pword') 1038 self.other_user = User.objects.create_user( 1039 'othertest', 'othertest@madrona.org', password='pword') 1040 self.group1 = Group.objects.create(name="Test Group 1") 1041 self.group1.save() 1042 self.user.groups.add(self.group1) 1043 self.other_user.groups.add(self.group1) 1044 enable_sharing(self.group1) 1045 1046 self.mpa = TestMpa(user=self.user, name="My Mpa") 1047 self.folder = TestFolder(user=self.user, name="My Folder") 1048 self.folder.save() 1049 self.mpa.save()
1050
1051 - def test_login_required(self):
1052 self.client.logout() 1053 link = self.mpa.options.get_link("Copy") 1054 self.assertEqual(Link, getattr(link, '__class__', None)) 1055 response = self.client.post(link.reverse([self.mpa])) 1056 self.assertEqual(response.status_code, 401, response)
1057
1058 - def test_copy(self):
1059 self.client.login(username='featuretest', password='pword') 1060 link = self.mpa.options.get_link("Copy") 1061 self.assertEqual(Link, getattr(link, '__class__', None)) 1062 response = self.client.post(link.reverse([self.mpa])) 1063 # TODO reponse changed; test for copy? 1064 #self.assertRegexpMatches(response.content, r'(copy)') 1065 self.assertRegexpMatches(response['X-Madrona-Select'], 1066 r'features_testmpa_\d+')
1067
1069 self.client.login(username='featuretest', password='pword') 1070 link = self.mpa.options.get_link("Copy") 1071 self.assertEqual(Link, getattr(link, '__class__', None)) 1072 path = link.reverse([self.mpa, self.folder]) 1073 response = self.client.post(path) 1074 # TODO reponse changed; test for copy? 1075 #self.assertRegexpMatches(response.content, r'(copy)') 1076 #self.assertRegexpMatches(response.content, r'Folder-Copy') 1077 self.assertRegexpMatches(response['X-Madrona-Select'], 1078 r'features_testmpa_\d+ features_testfolder_\d+')
1079
1081 self.mpa.share_with(self.group1) 1082 self.client.login(username='othertest', password='pword') 1083 link = self.mpa.options.get_link("Copy") 1084 self.assertEqual(Link, getattr(link, '__class__', None)) 1085 response = self.client.post(link.reverse([self.mpa])) 1086 # TODO reponse changed; test for copy? 1087 #self.assertRegexpMatches(response.content, r'(copy)') 1088 self.assertRegexpMatches(response['X-Madrona-Select'], 1089 r'features_testmpa_\d')
1090
1091 -class SpatialTest(TestCase):
1092
1093 - def setUp(self):
1094 self.client = Client() 1095 self.user = User.objects.create_user( 1096 'featuretest', 'featuretest@madrona.org', password='pword') 1097 self.client.login(username='featuretest', password='pword') 1098 1099 g3 = GEOSGeometry('SRID=4326;POINT(-120.45 34.32)') 1100 g3.transform(settings.GEOMETRY_DB_SRID) 1101 self.wreck = Shipwreck(user=self.user, name="Nearby Wreck", geometry_final=g3) 1102 self.wreck.save() 1103 1104 g2 = GEOSGeometry('SRID=4326;LINESTRING(-120.42 34.37, -121.42 33.37)') 1105 g2.transform(settings.GEOMETRY_DB_SRID) 1106 self.pipeline = Pipeline(user=self.user, name="My Pipeline", geometry_final=g2) 1107 self.pipeline.save() 1108 1109 g1 = GEOSGeometry('SRID=4326;POLYGON((-120.42 34.37, -119.64 34.32, -119.63 34.12, -120.44 34.15, -120.42 34.37))') 1110 g1.transform(settings.GEOMETRY_DB_SRID) 1111 self.mpa = TestMpa(user=self.user, name="My Mpa", geometry_orig=g1) 1112 # geometry_final will be set with manipulator 1113 self.mpa.save()
1114
1115 - def test_feature_types(self):
1116 self.assertTrue(isinstance(self.wreck, PointFeature)) 1117 self.assertEqual(self.wreck.geometry_final.geom_type,'Point') 1118 1119 self.assertTrue(isinstance(self.pipeline, LineFeature)) 1120 self.assertEqual(self.pipeline.geometry_final.geom_type,'LineString') 1121 1122 self.assertTrue(isinstance(self.mpa, PolygonFeature)) 1123 self.assertEqual(self.mpa.geometry_final.geom_type,'Polygon')
1124
1125 - def test_point_defaultkml_url(self):
1126 link = self.wreck.options.get_link('KML') 1127 url = link.reverse(self.wreck) 1128 response = self.client.get(url) 1129 errors = kml_errors(response.content) 1130 self.assertFalse(errors,"invalid KML %s" % str(errors))
1131
1132 - def test_line_defaultkml_url(self):
1133 link = self.pipeline.options.get_link('KML') 1134 url = link.reverse(self.pipeline) 1135 response = self.client.get(url) 1136 errors = kml_errors(response.content) 1137 self.assertFalse(errors,"invalid KML %s" % str(errors))
1138
1140 link = self.mpa.options.get_link('KML') 1141 url = link.reverse(self.mpa) 1142 response = self.client.get(url) 1143 errors = kml_errors(response.content) 1144 self.assertFalse(errors,"invalid KML %s" % str(errors))
1145
1146 -class CollectionTest(TestCase):
1147
1148 - def setUp(self):
1149 self.client = Client() 1150 1151 self.user1 = User.objects.create_user( 1152 'user1', 'featuretest@madrona.org', password='pword') 1153 self.user2 = User.objects.create_user( 1154 'user2', 'othertest@madrona.org', password='pword') 1155 1156 self.mpa1 = TestMpa(user=self.user1, name="My Mpa") 1157 self.mpa1.save() 1158 self.mpa2 = TestMpa(user=self.user1, name="My Mpa 2") 1159 self.mpa2.save() 1160 self.folder1 = TestFolder(user=self.user1, name="My Folder") 1161 self.folder1.save() 1162 self.folder2 = TestFolder(user=self.user1, name="My Folder2") 1163 self.folder2.save() 1164 self.pipeline = Pipeline(user=self.user1, name="My Pipeline") 1165 self.pipeline.save() 1166 self.mpa3 = TestMpa(user=self.user2, name="User2s MPA") 1167 self.mpa3.save()
1168
1170 self.mpa1.add_to_collection(self.folder1) 1171 self.assertEqual(self.mpa1.collection, self.folder1) 1172 self.assertTrue(self.mpa1 in self.folder1.feature_set()) 1173 1174 self.mpa1.remove_from_collection() 1175 self.assertEqual(self.mpa1.collection, None) 1176 self.assertTrue(self.mpa1 not in self.folder1.feature_set()) 1177 1178 self.assertRaises(AssertionError, self.mpa3.add_to_collection, self.folder1)
1179
1181 self.folder1.add(self.mpa1) 1182 self.assertEqual(self.mpa1.collection, self.folder1) 1183 self.assertTrue(self.mpa1 in self.folder1.feature_set()) 1184 1185 self.folder1.remove(self.mpa1) 1186 self.assertEqual(self.mpa1.collection, None) 1187 self.assertTrue(self.mpa1 not in self.folder1.feature_set()) 1188 1189 self.assertRaises(AssertionError, self.folder1.add, self.mpa3)
1190
1191 - def test_feature_set(self):
1192 """ 1193 When checking which mpas belong to folder1 we can: 1194 * look only at immediate children 1195 * look for children of a given feature class 1196 * look recursively through all containers 1197 1198 folder1 1199 |- mpa1 1200 |- folder2 1201 | - mpa2 1202 """ 1203 self.folder1.add(self.mpa1) 1204 self.folder2.add(self.mpa2) 1205 self.folder1.add(self.folder2) 1206 1207 direct_children = self.folder1.feature_set(recurse=False) 1208 self.assertEqual(len(direct_children), 2) 1209 self.assertTrue(self.mpa1 in direct_children) 1210 self.assertTrue(self.folder2 in direct_children) 1211 self.assertTrue(self.mpa2 not in direct_children) 1212 1213 direct_mpa_children = self.folder1.feature_set(recurse=False,feature_classes=[TestMpa]) 1214 self.assertEqual(len(direct_mpa_children), 1) 1215 self.assertTrue(self.mpa1 in direct_mpa_children) 1216 self.assertTrue(self.folder2 not in direct_mpa_children) 1217 self.assertTrue(self.mpa2 not in direct_mpa_children) 1218 1219 recursive_mpa_children = self.folder1.feature_set(recurse=True,feature_classes=[TestMpa]) 1220 self.assertEqual(len(recursive_mpa_children), 2) 1221 self.assertTrue(self.mpa1 in recursive_mpa_children) 1222 self.assertTrue(self.folder2 not in recursive_mpa_children) 1223 self.assertTrue(self.mpa2 in recursive_mpa_children)
1224
1225 - def test_deep_recursion(self):
1226 """ 1227 folder1 1228 |- mpa1 1229 |- folder2 1230 | - mpa2 1231 | - folder3 1232 |- mpa3 1233 |- folder4 1234 |- mpa4 1235 |- mpa5 1236 """ 1237 mpa3 = TestMpa(user=self.user1, name="My Mpa") 1238 mpa3.save() 1239 mpa4 = TestMpa(user=self.user1, name="My Mpa 2") 1240 mpa4.save() 1241 mpa5 = TestMpa(user=self.user1, name="My Mpa 2") 1242 mpa5.save() 1243 folder3 = TestFolder(user=self.user1, name="My Folder") 1244 folder3.save() 1245 folder4 = TestFolder(user=self.user1, name="My Folder2") 1246 folder4.save() 1247 1248 self.folder1.add(self.mpa1) 1249 self.folder2.add(self.mpa2) 1250 self.folder1.add(self.folder2) 1251 self.folder2.add(folder3) 1252 folder3.add(folder4) 1253 folder3.add(mpa3) 1254 folder4.add(mpa4) 1255 folder4.add(mpa5) 1256 1257 recursive_mpa_children = self.folder1.feature_set(recurse=True,feature_classes=[TestMpa]) 1258 self.assertEqual(len(recursive_mpa_children), 5) 1259 self.assertTrue(self.mpa1 in recursive_mpa_children) 1260 self.assertTrue(mpa5 in recursive_mpa_children) 1261 self.assertTrue(folder4 not in recursive_mpa_children) 1262 1263 recursive_children = self.folder1.feature_set(recurse=True) 1264 self.assertEqual(len(recursive_children), 8) 1265 self.assertTrue(self.mpa1 in recursive_children) 1266 self.assertTrue(mpa5 in recursive_children) 1267 self.assertTrue(folder4 in recursive_children)
1268
1269 - def test_potential_parents(self):
1270 """ 1271 Folder (of which TestArray is a valid child but Pipeline is NOT) 1272 TestArray (of which Pipeline is a valid child) 1273 Therefore, Folder is also a potential parent of Pipeline 1274 1275 folder1 1276 |-my_array 1277 |-self.pipeline 1278 |-self.mpa1 1279 """ 1280 pipeline_parents = Pipeline.get_options().get_potential_parents() 1281 self.assertTrue(TestArray in pipeline_parents) 1282 self.assertTrue(self.folder1.__class__ in pipeline_parents) 1283 1284 my_array = TestArray(user=self.user1, name="My TestArray") 1285 my_array.save() 1286 my_array.add(self.pipeline) 1287 my_array.add(self.mpa1) 1288 self.assertTrue(self.pipeline in my_array.feature_set()) 1289 1290 self.folder1.add(my_array) 1291 self.assertTrue(my_array in self.folder1.feature_set()) 1292 self.assertTrue(self.pipeline in self.folder1.feature_set(recurse=True))
1293
1294 - def test_no_potential_parents(self):
1295 shipwreck_parents = Shipwreck.get_options().get_potential_parents() 1296 self.assertFalse(TestArray in shipwreck_parents) 1297 self.assertFalse(TestFolder in shipwreck_parents) 1298 self.assertEqual(len(shipwreck_parents), 0)
1299
1301 """ 1302 Try to add a Pipeline to Folder; feature.add has a runtime assertion so 1303 this should raise an AssertionError 1304 """ 1305 self.assertRaises(AssertionError, self.folder1.add, self.pipeline)
1306
1308 """ 1309 folder1 copied to folder1-copy 1310 make sure it contains mpa1-copy, mpa2-copy and folder2-copy 1311 """ 1312 self.folder1.add(self.mpa1) 1313 self.folder2.add(self.mpa2) 1314 self.folder1.add(self.folder2) 1315 folder1_copy = self.folder1.copy(self.user1) 1316 folder1_copy.save() 1317 children = folder1_copy.feature_set(recurse=True) 1318 self.assertEqual(len(children),3, 1319 "Folder1_copy should contain copies folder2, mpa1, mpa2 but doesn't")
1320
1321 -class SharingTestCase(TestCase):
1322
1323 - def setUp(self):
1324 self.client = Client() 1325 1326 # Create 3 users 1327 self.password = 'iluvsharing' 1328 self.user1 = User.objects.create_user('user1', 'test@madrona.org', password=self.password) 1329 self.user2 = User.objects.create_user('user2', 'test@madrona.org', password=self.password) 1330 self.user3 = User.objects.create_user('user3', 'test@madrona.org', password=self.password) 1331 1332 # Create some groups 1333 # Group 1 has user1 and user2 and can share 1334 # Group 2 has user2 and user3 and has no sharing permissions 1335 # Group 3 has user1 only and no sharing permissions 1336 self.group1 = Group.objects.create(name="Test Group 1") 1337 self.group1.save() 1338 self.user1.groups.add(self.group1) 1339 self.user2.groups.add(self.group1) 1340 1341 self.group2 = Group.objects.create(name="Test Group 2") 1342 self.group2.save() 1343 self.user2.groups.add(self.group2) 1344 self.user3.groups.add(self.group2) 1345 1346 self.group3 = Group.objects.create(name="Test Group 3") 1347 self.group3.save() 1348 self.user1.groups.add(self.group3) 1349 1350 enable_sharing(self.group1) 1351 1352 # Create some necessary objects 1353 g1 = GEOSGeometry('SRID=4326;POLYGON ((-120.42 34.37, -119.64 34.32, -119.63 34.12, -120.44 34.15, -120.42 34.37))') 1354 g1.transform(settings.GEOMETRY_DB_SRID) 1355 1356 # Create three Mpas by different users 1357 self.mpa1 = TestMpa.objects.create(name='Test_MPA_1', designation='R', user=self.user1, geometry_final=g1) 1358 self.mpa1.save() 1359 1360 self.mpa2 = TestMpa.objects.create(name='Test_MPA_2', designation='R', user=self.user2, geometry_final=g1) 1361 self.mpa2.save() 1362 1363 self.mpa3 = TestMpa.objects.create(name='Test_MPA_3', designation='R', user=self.user3, geometry_final=g1) 1364 self.mpa3.save() 1365 1366 # Create a pipeline 1367 self.pipeline1 = Pipeline(user=self.user1, name="My Pipeline") 1368 self.pipeline1.save() 1369 1370 # folder1 1371 # |-array1 1372 # |-pipeline1 1373 # |-mpa1 1374 1375 self.array1 = TestArray.objects.create(name='Test_Array_1', user=self.user1) 1376 self.array1.save() 1377 self.array1.add(self.mpa1) 1378 self.array1.add(self.pipeline1) 1379 1380 self.folder1 = TestFolder.objects.create(user=self.user1, name="My Folder") 1381 self.folder1.save() 1382 self.folder1.add(self.array1) 1383 1384 self.folder1_share_url = self.folder1.get_options().get_share_form(self.folder1.pk) 1385 self.folder1_resource_url = self.folder1.get_options().get_resource(self.folder1.pk)
1386
1387 - def test_nested_folder_sharing(self):
1388 # Not shared yet 1389 viewable, response = self.pipeline1.is_viewable(self.user2) 1390 self.assertEquals(viewable, False) 1391 viewable, response = self.pipeline1.is_viewable(self.user3) 1392 self.assertEquals(viewable, False) 1393 1394 # Share folder1 with group1; now group1 should be able to see array1 1395 self.folder1.share_with(self.group1) 1396 viewable, response = self.array1.is_viewable(self.user2) 1397 self.assertEquals(viewable, True, str(response.status_code) + str(response)) 1398 viewable, response = self.array1.is_viewable(self.user3) 1399 self.assertEquals(viewable, False) 1400 # ... and group1 should be able to see pipeline 1401 viewable, response = self.pipeline1.is_viewable(self.user2) 1402 self.assertEquals(viewable, True, str(response.status_code) + str(response)) 1403 viewable, response = self.pipeline1.is_viewable(self.user3) 1404 self.assertEquals(viewable, False)
1405
1406 - def test_user_sharing_groups(self):
1407 sgs = user_sharing_groups(self.user1) 1408 self.assertEquals(len(sgs),1) 1409 1410 sgs = user_sharing_groups(self.user2) 1411 self.assertEquals(len(sgs),1) 1412 1413 sgs = user_sharing_groups(self.user3) 1414 self.assertEquals(len(sgs),0)
1415
1416 - def test_nothing_shared(self):
1417 """ 1418 Make sure nothing is shared yet 1419 """ 1420 shared_mpas = TestMpa.objects.shared_with_user(self.user1) 1421 self.assertEquals(len(shared_mpas),0)
1422
1423 - def test_share_mpa_manager(self):
1424 """ 1425 Make sure the basic sharing of mpas works 1426 via the object manager (for returning querysets) 1427 """ 1428 # User2 shares their MPA2 with Group1 1429 self.mpa2.share_with(self.group1) 1430 # User1 should see it (since they're part of Group1) 1431 shared_mpas = TestMpa.objects.shared_with_user(self.user1) 1432 self.assertEquals(len(shared_mpas),1) 1433 # User3 should not see it since they're not part of Group1 1434 shared_mpas = TestMpa.objects.shared_with_user(self.user3) 1435 self.assertEquals(len(shared_mpas),0)
1436
1437 - def test_share_mpa_method(self):
1438 """ 1439 Make sure the basic sharing of mpas works 1440 via the feature method (check viewability of particular instance) 1441 """ 1442 # User2 shares their MPA2 with Group1 1443 self.mpa2.share_with(self.group1) 1444 # User 2 should be able to view it since they own it 1445 viewable, response = self.mpa2.is_viewable(self.user2) 1446 self.assertEquals(viewable, True) 1447 # User1 should see it (since they're part of Group1) 1448 viewable, response = self.mpa2.is_viewable(self.user1) 1449 self.assertEquals(viewable, True) 1450 # User3 should not see it since they're not part of Group1 1451 viewable, response = self.mpa2.is_viewable(self.user3) 1452 self.assertEquals(response.status_code, 403) 1453 self.assertEquals(viewable, False)
1454
1455 - def test_share_with_bad_group(self):
1456 """ 1457 Make sure we can't share with a group which does not have permissions 1458 """ 1459 # Would use assertRaises here but can't figure how to pass args to callable 1460 # see http://www.mail-archive.com/django-users@googlegroups.com/msg46609.html 1461 error_occured = False 1462 try: 1463 self.mpa2.share_with(self.group2) 1464 except: 1465 error_occured = True 1466 self.assertTrue(error_occured)
1467
1468 - def test_share_by_bad_user(self):
1469 """ 1470 Make sure user not belonging to the group can't share their objects 1471 """ 1472 # User3 trys to share their MPA3 with Group1 1473 error_occured = False 1474 try: 1475 self.mpa3.share_with(self.group1) 1476 except: 1477 error_occured = True 1478 self.assertTrue(error_occured)
1479
1481 """ 1482 Arrays are containers of MPAs so their child objects should also appear to be shared 1483 Uses the class object manager 1484 """ 1485 # User1 shares their array1 (which contains MPA1) with Group1 1486 self.array1.share_with(self.group1) 1487 # User2 should see the mpa contained in array1 (since they're part of Group1) 1488 shared_mpas = TestMpa.objects.shared_with_user(self.user2) 1489 self.assertEquals(len(shared_mpas),1) 1490 # User3 should not see it (since they're not part of Group1) 1491 shared_mpas = TestMpa.objects.shared_with_user(self.user3) 1492 self.assertEquals(len(shared_mpas),0)
1493
1495 """ 1496 Arrays are containers of MPAs so their child objects should also appear to be shared 1497 Uses the feature's is_viewable() method 1498 """ 1499 # User1 shares their array1 (which contains MPA1) with Group1 1500 self.array1.share_with(self.group1) 1501 # User 1 should see it since they own it 1502 viewable, response = self.mpa1.is_viewable(self.user1) 1503 self.assertEquals(viewable, True) 1504 # User2 should see the mpa contained in array1 (since they're part of Group1) 1505 viewable, response = self.mpa1.is_viewable(self.user2) 1506 self.assertEquals(viewable, True) 1507 # User3 should not see it (since they're not part of Group1) 1508 viewable, response = self.mpa1.is_viewable(self.user3) 1509 self.assertEquals(viewable, False)
1510
1512 """ 1513 Test if we can get a list of groups and users who are sharing with a given user 1514 """ 1515 # User1 shares their Mpa1 with Group1 1516 self.mpa1.share_with(self.group1) 1517 # User1 should NOT see himself 1518 sw = groups_users_sharing_with(self.user1) 1519 self.assertEquals(sw,None) 1520 # User2 should see group1:user1 as a sharer 1521 sw = groups_users_sharing_with(self.user2) 1522 self.assertNotEquals(sw,None) 1523 usernames = [x.username for x in sw['Test Group 1']['users']] 1524 self.assertEquals(usernames, ['user1']) 1525 # User3 should see nothing 1526 sw = groups_users_sharing_with(self.user3) 1527 self.assertEquals(sw, None)
1528
1529 - def test_get_share_form_401(self):
1530 # Need to log in 1531 response = self.client.get(self.folder1_share_url) 1532 self.assertEqual(response.status_code, 401)
1533
1534 - def test_get_share_form_403(self):
1535 # Need to own the feature in order to share it 1536 self.client.login(username=self.user3.username, password=self.password) 1537 response = self.client.get(self.folder1_share_url) 1538 self.assertEqual(response.status_code, 403)
1539
1540 - def test_get_share_form(self):
1541 self.client.login(username=self.user1.username, password=self.password) 1542 1543 # user1 should be able to share with Group 1 only 1544 response = self.client.get(self.folder1_share_url) 1545 self.assertEqual(response.status_code, 200, response.content) 1546 self.assertRegexpMatches(response.content, r'Test Group 1') 1547 self.assertNotRegexpMatches(response.content, r'Test Group 2') 1548 self.assertNotRegexpMatches(response.content, r'Test Group 3') 1549 1550 enable_sharing(self.group3) 1551 # Now user1 should be able to share with Group 1 & 3 1552 response = self.client.get(self.folder1_share_url) 1553 self.assertEqual(response.status_code, 200) 1554 self.assertRegexpMatches(response.content, r'Test Group 1') 1555 self.assertNotRegexpMatches(response.content, r'Test Group 2') 1556 self.assertRegexpMatches(response.content, r'Test Group 3')
1557
1558 - def test_post_share_form(self):
1559 # user 2 tries to get resource for folder1, not shared yet 1560 self.client.login(username=self.user2.username, password=self.password) 1561 response = self.client.get(self.folder1_resource_url) 1562 self.assertEqual(response.status_code, 403) 1563 1564 # user 1 shares it 1565 self.client.logout() 1566 self.client.login(username=self.user1.username, password=self.password) 1567 response = self.client.post(self.folder1_share_url, {'sharing_groups': [self.group1.pk]}) 1568 self.assertEqual(response.status_code, 200, response.content) 1569 1570 # user2 tries again 1571 self.client.logout() 1572 self.client.login(username=self.user2.username, password=self.password) 1573 response = self.client.get(self.folder1_resource_url) 1574 self.assertEqual(response.status_code, 200)
1575
1576 @register 1577 -class TestForGeoJSON(PolygonFeature):
1578 designation = models.CharField(max_length=1, choices=DESIGNATION_CHOICES)
1579 - class Options:
1580 form = 'madrona.features.tests.GJForm'
1581
1582 - def geojson(self, srid):
1583 import json 1584 from madrona.common.jsonutils import get_properties_json, get_feature_json 1585 props = get_properties_json(self) 1586 props['absolute_url'] = self.get_absolute_url() 1587 jsongeom = self.geometry_final.transform(srid, clone=True).json 1588 return get_feature_json(jsongeom, json.dumps(props))
1589
1590 -class GJForm(FeatureForm):
1591 - class Meta:
1593
1594 @register 1595 -class TestNoGeomFinal(Feature):
1596 designation = models.CharField(max_length=1, choices=DESIGNATION_CHOICES) 1597 # just a base feature so no geometry_final attribute
1598 - class Options:
1599 form = 'madrona.features.tests.GJFormNoGeom'
1600
1601 -class GJFormNoGeom(FeatureForm):
1602 - class Meta:
1604
1605 @register 1606 -class TestNoGeoJSON(PolygonFeature):
1607 designation = models.CharField(max_length=1, choices=DESIGNATION_CHOICES)
1608 - class Options:
1609 form = 'madrona.features.tests.TestNoGeoJSONForm' 1610 export_geojson = False
1611
1612 -class TestNoGeoJSONForm(FeatureForm):
1613 - class Meta:
1615
1616 -class GeoJSONTest(TestCase):
1617
1618 - def setUp(self):
1619 self.client = Client() 1620 self.user = User.objects.create_user( 1621 'featuretest', 'featuretest@madrona.org', password='pword') 1622 self.user2 = User.objects.create_user( 1623 'joerando', 'featuretest@madrona.org', password='pword') 1624 self.group1 = Group.objects.create(name="Test Group 1") 1625 self.user.groups.add(self.group1) 1626 self.user2.groups.add(self.group1) 1627 enable_sharing(self.group1) 1628 self.client.login(username='featuretest', password='pword') 1629 1630 g1 = GEOSGeometry('SRID=4326;POLYGON((-120.42 34.37, -119.64 34.32, -119.63 34.12, -120.44 34.15, -120.42 34.37))') 1631 g1.transform(settings.GEOMETRY_DB_SRID) 1632 1633 ''' 1634 mpa3 1635 folder1 1636 |- mpa1 1637 |- folder2 1638 | - mpa2 1639 ''' 1640 self.mpa1 = TestMpa.objects.create(user=self.user, name="Mpa1", geometry_orig=g1) 1641 self.mpa2 = TestMpa.objects.create(user=self.user, name="Mpa2", geometry_orig=g1) 1642 self.mpa3 = TestMpa.objects.create(user=self.user, name="Mpa3", geometry_orig=g1) 1643 self.mpa4 = TestMpa.objects.create(user=self.user2, name="Mpa4", geometry_orig=g1) 1644 self.mpa5 = TestForGeoJSON.objects.create(user=self.user, name="Mpa5", geometry_orig=g1) 1645 self.mpa6 = TestNoGeomFinal.objects.create(user=self.user, name="Mpa6") 1646 self.mpa7 = TestNoGeoJSON.objects.create(user=self.user, name="Mpa7", geometry_orig=g1) 1647 self.folder1 = TestFolder.objects.create(user=self.user, name="Folder1") 1648 self.folder2 = TestFolder.objects.create(user=self.user, name="Folder2") 1649 self.folder1.add(self.mpa1) 1650 self.folder2.add(self.mpa2) 1651 self.folder1.add(self.folder2)
1652 1653
1654 - def test_geojson_single(self):
1655 link = self.mpa3.options.get_link('GeoJSON') 1656 url = link.reverse(self.mpa3) 1657 response = self.client.get(url) 1658 self.assertEqual(response.status_code, 200) 1659 self.assertTrue('application/json' in response['Content-Type']) 1660 fc = json.loads(response.content) 1661 self.assertEquals(fc['features'][0]['properties']['name'], 'Mpa3') 1662 self.assertEquals(len(fc['features']), 1)
1663
1664 - def test_geojson_byproperty(self):
1665 """ 1666 Mpa5 has a custom geojson @property that should 1667 return a GeoJSON Feature with an extra `absolute_url` property 1668 """ 1669 link = self.mpa5.options.get_link('GeoJSON') 1670 url = link.reverse(self.mpa5) 1671 response = self.client.get(url) 1672 self.assertEqual(response.status_code, 200) 1673 self.assertTrue('application/json' in response['Content-Type']) 1674 fc = json.loads(response.content) 1675 self.assertEquals(fc['features'][0]['properties']['absolute_url'], self.mpa5.get_absolute_url()) 1676 self.assertEquals(len(fc['features']), 1)
1677
1678 - def test_geojson_nogeomfinal(self):
1679 """ 1680 Mpa6 has no geometry_final attr 1681 should fail gracefully with null geometry 1682 """ 1683 link = self.mpa6.options.get_link('GeoJSON') 1684 url = link.reverse(self.mpa6) 1685 response = self.client.get(url) 1686 self.assertEqual(response.status_code, 200) 1687 fc = json.loads(response.content) 1688 self.assertEquals(fc['features'][0]['geometry'], None)
1689
1690 - def test_no_geojson(self):
1691 """ 1692 This one has export_geojson = False 1693 so no link should be available 1694 """ 1695 with self.assertRaisesRegexp(Exception, 'has no link named GeoJSON'): 1696 link = self.mpa7.options.get_link('GeoJSON')
1697
1698 - def test_geojson_flat(self):
1699 """ 1700 We expect default 'flat' behavior 1701 1702 FeatureCollection: 1703 mpa1 1704 mpa2 1705 """ 1706 link = self.folder1.options.get_link('GeoJSON') 1707 url = link.reverse(self.folder1) 1708 response = self.client.get(url) 1709 self.assertEqual(response.status_code, 200) 1710 self.assertTrue('application/json' in response['Content-Type']) 1711 fc = json.loads(response.content) 1712 self.assertTrue(fc['features'][0]['properties']['name'] in ['Mpa1','Mpa2']) 1713 self.assertTrue(fc['features'][1]['properties']['name'] in ['Mpa1','Mpa2']) 1714 self.assertEquals(len(fc['features']), 2, fc)
1715
1716 - def test_geojson_nest_url(self):
1717 """ 1718 We expect custom 'nest_feature_set' behavior 1719 1720 FeatureCollection: 1721 folder1 (with a `feature_set` property listing uids and null geom) 1722 """ 1723 link = self.folder1.options.get_link('GeoJSON') 1724 url = link.reverse(self.folder1) + "?strategy=nest_feature_set" 1725 response = self.client.get(url) 1726 self.assertEqual(response.status_code, 200) 1727 self.assertTrue('application/json' in response['Content-Type']) 1728 fc = json.loads(response.content) 1729 self.assertEquals(fc['features'][0]['properties']['feature_set'], [x.uid for x in [self.mpa1, self.folder2]]) 1730 self.assertEquals(len(fc['features']), 1)
1731
1732 - def test_geojson_nest_multi(self):
1733 """ 1734 We expect custom 'nest_feature_set' behavior 1735 1736 FeatureCollection: 1737 mpa1 1738 folder2 (with a `feature_set` property listing uids and null geom) 1739 """ 1740 link = self.folder1.options.get_link('GeoJSON') 1741 url = link.reverse([self.mpa1, self.folder2]) + "?strategy=nest_feature_set" 1742 response = self.client.get(url) 1743 self.assertEqual(response.status_code, 200) 1744 self.assertTrue('application/json' in response['Content-Type']) 1745 fc = json.loads(response.content) 1746 self.assertEquals(fc['features'][0]['properties']['name'], 'Mpa1') 1747 self.assertEquals(fc['features'][1]['properties']['feature_set'], [self.mpa2.uid]) 1748 self.assertEquals(len(fc['features']), 2)
1749
1750 - def test_geojson_forbidden(self):
1751 self.client.logout() 1752 self.client.login(username='joerando', password='pword') 1753 link = self.folder1.options.get_link('GeoJSON') 1754 # joerando user may own mpa4 but not folder2 so boot him 1755 url = link.reverse([self.mpa4, self.folder2]) 1756 response = self.client.get(url) 1757 self.assertEqual(response.status_code, 403) 1758 self.folder2.share_with(self.group1) 1759 response = self.client.get(url) 1760 self.assertEqual(response.status_code, 200) 1761 fc = json.loads(response.content) 1762 self.assertEquals(len(fc['features']), 2)
1763
1764 - def test_geojson_transform(self):
1765 from madrona.common.jsonutils import srid_to_urn 1766 link = self.mpa3.options.get_link('GeoJSON') 1767 # this one should be in db srs 1768 url = link.reverse(self.mpa3) 1769 response = self.client.get(url) 1770 fc = json.loads(response.content) 1771 self.assertEquals(fc['crs']['properties']['name'], srid_to_urn(settings.GEOMETRY_DB_SRID)) 1772 self.assertEquals(int(fc['features'][0]['geometry']['coordinates'][0][0][0]), -38619) 1773 # and this one should be in latlon 1774 url = url + "?srid=4326" 1775 response = self.client.get(url) 1776 fc = json.loads(response.content) 1777 self.assertEquals(fc['crs']['properties']['name'], srid_to_urn(4326)) 1778 self.assertEquals(int(fc['features'][0]['geometry']['coordinates'][0][0][0]), -120) 1779 # and this one should be in latlon as well 1780 settings.GEOJSON_SRID = 4326 1781 url = link.reverse(self.mpa3) # no need to specify parameter, setting should work 1782 response = self.client.get(url) 1783 fc = json.loads(response.content) 1784 self.assertEquals(fc['crs']['properties']['name'], srid_to_urn(4326)) 1785 self.assertEquals(int(fc['features'][0]['geometry']['coordinates'][0][0][0]), -120)
1786
1787 - def test_geojson_download(self):
1788 link = self.mpa3.options.get_link('GeoJSON') 1789 # default download 1790 url = link.reverse(self.mpa3) 1791 response = self.client.get(url) 1792 self.assertEqual(response.status_code, 200) 1793 self.assertTrue('Content-Disposition' in response) 1794 self.assertTrue('attachment; filename=mpa3.geojson' in response['Content-Disposition']) 1795 # no attach 1796 url = link.reverse(self.mpa3) + "?noattach" 1797 response = self.client.get(url) 1798 self.assertEqual(response.status_code, 200) 1799 self.assertFalse('Content-Disposition' in response) 1800 # setting default to no download 1801 settings.GEOJSON_DOWNLOAD = False 1802 url = link.reverse(self.mpa3) 1803 response = self.client.get(url) 1804 self.assertEqual(response.status_code, 200) 1805 self.assertFalse('Content-Disposition' in response) 1806 # attach 1807 url = link.reverse(self.mpa3) + "?attach" 1808 response = self.client.get(url) 1809 self.assertEqual(response.status_code, 200) 1810 self.assertTrue('Content-Disposition' in response) 1811 self.assertTrue('attachment; filename=mpa3.geojson' in response['Content-Disposition']) 1812 # cleanup 1813 settings.GEOJSON_DOWNLOAD = True
1814
1815 - def test_srid_util(self):
1816 from madrona.common.jsonutils import srid_to_urn, srid_to_proj 1817 ogc_wgs84 = "urn:ogc:def:crs:OGC:1.3:CRS84" 1818 proj4_wgs84 = "+proj=longlat +datum=WGS84 +no_defs" 1819 self.assertEqual(ogc_wgs84, srid_to_urn(4326)) 1820 self.assertEqual(proj4_wgs84, srid_to_proj(4326))
1821