Skip to content

Commit 8509916

Browse files
committed
Project API tests now pass with DRF3.
Moved factories to their own package. DRF3-style test pattern for translations. Fixes #1080, #1078, #1076, #1075
1 parent 0c0a39b commit 8509916

File tree

7 files changed

+71
-61
lines changed

7 files changed

+71
-61
lines changed

readthedocs/restapi/views/model_views.py

+12-11
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414
from projects.filters import ProjectFilter
1515
from restapi.permissions import APIPermission
1616

17-
from restapi.serializers import BuildSerializer, ProjectSerializer, VersionSerializer
17+
from restapi.serializers import BuildSerializer, ProjectSerializer, VersionSerializer,\
18+
SimpleProjectSerializer
1819
from restapi.permissions import RelatedProjectIsOwner
1920
import restapi.utils as api_utils
2021
from docutils.utils.math.math2html import Link
22+
from rest_framework.decorators import detail_route
2123

2224
log = logging.getLogger(__name__)
2325

@@ -31,11 +33,11 @@ class ProjectViewSet(viewsets.ModelViewSet):
3133
paginate_by = 100
3234
paginate_by_param = 'page_size'
3335
max_paginate_by = 1000
34-
36+
3537
def get_queryset(self):
3638
return self.model.objects.api(self.request.user)
3739

38-
@decorators.list_route()
40+
@decorators.detail_route()
3941
def valid_versions(self, request, **kwargs):
4042
"""
4143
Maintain state of versions that are wanted.
@@ -51,15 +53,14 @@ def valid_versions(self, request, **kwargs):
5153
'flat': version_strings,
5254
})
5355

54-
@decorators.list_route()
55-
def translations(self, request, **kwargs):
56-
project = get_object_or_404(Project.objects.api(self.request.user), pk=kwargs['pk'])
57-
queryset = project.translations.all()
56+
@detail_route()
57+
def translations(self, request, pk):
58+
translations = self.get_object().translations.all()
5859
return Response({
59-
'translations': ProjectSerializer(queryset, many=True).data
60+
'translations': ProjectSerializer(translations, many=True).data
6061
})
6162

62-
@decorators.list_route()
63+
@detail_route()
6364
def subprojects(self, request, **kwargs):
6465
project = get_object_or_404(Project.objects.api(self.request.user), pk=kwargs['pk'])
6566
rels = project.subprojects.all()
@@ -68,15 +69,15 @@ def subprojects(self, request, **kwargs):
6869
'subprojects': ProjectSerializer(children, many=True).data
6970
})
7071

71-
@decorators.list_route(permission_classes=[permissions.IsAdminUser])
72+
@decorators.detail_route(permission_classes=[permissions.IsAdminUser])
7273
def token(self, request, **kwargs):
7374
project = get_object_or_404(Project.objects.api(self.request.user), pk=kwargs['pk'])
7475
token = oauth_utils.get_token_for_project(project, force_local=True)
7576
return Response({
7677
'token': token
7778
})
7879

79-
@decorators.detail_route(permission_classes=[permissions.IsAdminUser])
80+
@decorators.detail_route(permission_classes=[permissions.IsAdminUser], methods=['post'])
8081
def sync_versions(self, request, **kwargs):
8182
"""
8283
Sync the version data in the repo (on the build server) with what we have in the database.
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import factory
22
from projects.models import Project
33
from builds.models import Version
4+
from bamboo_boy.materials import Clump
45

56

67
class VersionFactory(factory.DjangoModelFactory):
78

89
FACTORY_FOR = Version
910

1011
verbose_name = factory.Sequence(lambda n: "Project %s" % n)
11-
slug = factory.Sequence(lambda n: "project-%s" % n)
12+
slug = factory.Sequence(lambda n: "project-%s" % n)
1213

1314

1415
class ProjectFactory(factory.DjangoModelFactory):
@@ -19,7 +20,17 @@ class ProjectFactory(factory.DjangoModelFactory):
1920
slug = factory.Sequence(lambda n: "project-%s" % n)
2021
documentation_type = "sphinx"
2122
conf_py_file = "test_conf.py"
22-
23+
2324
version = factory.RelatedFactory(VersionFactory,
2425
'project',
25-
)
26+
)
27+
28+
29+
class OneProjectWithTranslationsOneWithout(Clump):
30+
31+
def build_canopy(self):
32+
self.project_with_translations = self.include_factory(
33+
ProjectFactory, 1)[0]
34+
self.first_translation = ProjectFactory(
35+
main_language_project=self.project_with_translations)
36+
pass
+22-23
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import subprocess
2+
13
from django.test import TestCase
2-
from projects.tasks import build_docs
3-
from rtd_tests.tests.projects_factories import ProjectFactory
44
import mock
5-
import subprocess
5+
6+
from projects.tasks import build_docs
7+
from rtd_tests.factories.projects_factories import ProjectFactory
68

79

810
class MockProcess(object):
@@ -11,7 +13,7 @@ class MockProcess(object):
1113

1214
def __init__(self, communicate_result):
1315
self.communicate_result = communicate_result
14-
16+
1517
def communicate(self):
1618
return self.communicate_result
1719

@@ -31,37 +33,34 @@ class BuildTests(TestCase):
3133
@mock.patch('os.chdir')
3234
@mock.patch('projects.models.Project.api_versions')
3335
@mock.patch('subprocess.Popen')
34-
3536
def test_build(self, mock_Popen, mock_api_versions, mock_chdir, mock_apiv2_downloads):
36-
37+
3738
# subprocess mock logic
38-
39+
3940
mock_process = mock.Mock()
4041
process_return_dict = {'communicate.return_value': ('SOMEGITHASH', '')}
4142
mock_process.configure_mock(**process_return_dict)
4243
mock_Popen.return_value = mock_process
4344
mock_Popen.side_effect = build_subprocess_side_effect
44-
45-
45+
4646
project = ProjectFactory(allow_comments=True)
47-
47+
4848
version = project.versions.all()[0]
4949
mock_api_versions.return_value = [version]
50-
50+
5151
mock_apiv2_downloads.get.return_value = {'downloads': "no_url_here"}
52-
52+
5353
with mock.patch('codecs.open', mock.mock_open(), create=True):
5454
built_docs = build_docs(version,
55-
False,
56-
False,
57-
False,
58-
False,
59-
False,
60-
False,
61-
False,
62-
)
63-
55+
False,
56+
False,
57+
False,
58+
False,
59+
False,
60+
False,
61+
False,
62+
)
63+
6464
self.assertIn(project.doc_builder().sphinx_builder,
6565
str(mock_Popen.call_args_list[1])
66-
)
67-
66+
)

readthedocs/rtd_tests/tests/test_comments.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
from comments.views import add_node, get_metadata, update_node
1313
from privacy.backend import AdminNotAuthorized
1414
from projects.views.private import project_comments_moderation
15-
from rtd_tests.tests.coments_factories import DocumentNodeFactory, \
15+
from rtd_tests.factories.comments_factories import DocumentNodeFactory, \
1616
DocumentCommentFactory, ProjectsWithComments
17-
from rtd_tests.tests.general_factories import UserFactory
18-
from rtd_tests.tests.projects_factories import ProjectFactory
17+
from rtd_tests.factories.general_factories import UserFactory
18+
from rtd_tests.factories.projects_factories import ProjectFactory
1919

2020

2121
@with_canopy(ProjectsWithComments)
+20-21
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
from bamboo_boy.utils import with_canopy
12
import json
2-
33
from django.test import TestCase
4-
54
from projects.models import Project
6-
from .projects_factories import ProjectFactory
5+
from rtd_tests.factories.projects_factories import OneProjectWithTranslationsOneWithout,\
6+
ProjectFactory
7+
from rest_framework.reverse import reverse
8+
from restapi.serializers import ProjectSerializer, SimpleProjectSerializer
79

810

11+
@with_canopy(OneProjectWithTranslationsOneWithout)
912
class TestProject(TestCase):
1013
fixtures = ["eric", "test_data"]
1114

@@ -27,27 +30,23 @@ def test_subprojects(self):
2730
self.assertEqual(resp['subprojects'][0]['id'], 23)
2831

2932
def test_translations(self):
30-
r = self.client.get('/api/v2/project/6/translations/', {})
31-
self.assertEqual(r.status_code, 200)
33+
p = self.canopy.project_with_translations
34+
url = reverse('project-translations', [p.id])
35+
response = self.client.get(url)
36+
self.assertEqual(response.status_code, 200)
37+
38+
translation_ids_from_api = [t['id']
39+
for t in response.data['translations']]
40+
translation_ids_from_orm = [t[0]
41+
for t in p.translations.values_list('id')]
42+
43+
self.assertEqual(
44+
set(translation_ids_from_api),
45+
set(translation_ids_from_orm)
46+
)
3247

3348
def test_token(self):
3449
r = self.client.get('/api/v2/project/6/token/', {})
3550
resp = json.loads(r.content)
3651
self.assertEqual(r.status_code, 200)
3752
self.assertEqual(resp['token'], None)
38-
39-
class ProjectCommentTests(TestCase):
40-
41-
def test_commentable_project_uses_builder_with_commentable_versioning_method(self):
42-
'''
43-
Even though we show the user a boolean "commentable" option,
44-
we compose this knowledge as a separate class, WebSupportBuilder.
45-
'''
46-
project = ProjectFactory(allow_comments=True)
47-
builder = project.doc_builder()
48-
self.assertEqual(getattr(builder, 'versioning_method', None), "commentable")
49-
50-
def test_uncommentable_project_uses_builder_without_commentable_verioning_method(self):
51-
project = ProjectFactory(allow_comments=False)
52-
builder = project.doc_builder()
53-
self.assertNotEqual(getattr(builder, 'versioning_method', None), "commentable")

0 commit comments

Comments
 (0)