Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests to asset deployments #3126

Merged
merged 13 commits into from
Jun 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions kpi/deployment_backends/base_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ def __init__(self, asset):
self.current_submissions_count = 0
self.__stored_data_key = None

@property
def backend_response(self):
return self.get_data('backend_response', {})

def get_data(self,
dotted_path: str = None,
default=None) -> Union[None, int, str, dict]:
Expand Down Expand Up @@ -267,6 +271,9 @@ def get_submission(self, pk, requesting_user_id,
pass
return None

def set_asset_uid(self, **kwargs) -> bool:
raise AbstractMethodError

def set_status(self, status):
self.save_to_db({'status': status})

Expand Down Expand Up @@ -296,3 +303,6 @@ def status(self):
@property
def stored_data_key(self):
return self.__stored_data_key

def sync_media_files(self):
raise AbstractMethodError
4 changes: 0 additions & 4 deletions kpi/deployment_backends/kobocat_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,6 @@ def internal_to_external_url(url):
string=url
)

@property
def backend_response(self):
return self.get_data('backend_response', {})

def _kobocat_request(self, method, url, expect_formid=True, **kwargs):
"""
Make a POST or PATCH request and return parsed JSON. Keyword arguments,
Expand Down
3 changes: 3 additions & 0 deletions kpi/deployment_backends/mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ def deployment(self):
def can_be_deployed(self):
return self.asset_type and self.asset_type == ASSET_TYPE_SURVEY

def set_deployment(self, deployment: BaseDeploymentBackend):
setattr(self, '__deployment_backend', deployment)

def __get_deployment_backend(self, backend: str) -> BaseDeploymentBackend:
try:
return getattr(self, '__deployment_backend')
Expand Down
35 changes: 29 additions & 6 deletions kpi/deployment_backends/mock_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ def bulk_assign_mapped_perms(self):

def connect(self, active=False):
self.store_data({
'backend': 'mock',
'identifier': 'mock://%s' % self.asset.uid,
'active': active,
})
'backend': 'mock',
'identifier': 'mock://%s' % self.asset.uid,
'active': active,
'backend_response': {
'downloadable': active,
'has_kpi_hook': self.asset.has_active_hooks,
'kpi_asset_uid': self.asset.uid
}
})

def redeploy(self, active=None):
"""
Expand All @@ -34,10 +39,25 @@ def redeploy(self, active=None):
"""
if active is None:
active = self.active
self.set_active(active)

def set_active(self, active):
self.store_data({
'active': active,
'version': self.asset.version_id,
})

self.set_asset_uid()

def set_asset_uid(self, **kwargs) -> bool:
backend_response = self.backend_response
backend_response.update({
'kpi_asset_uid': self.asset.uid,
})
self.store_data({
'backend_response': backend_response
})

def set_active(self, active):
self.save_to_db({
'active': bool(active),
})

Expand Down Expand Up @@ -296,6 +316,9 @@ def set_has_kpi_hooks(self):
'has_kpi_hooks': has_active_hooks,
})

def sync_media_files(self):
pass

def calculated_submission_count(self, requesting_user_id, **kwargs):
params = self.validate_submission_list_params(requesting_user_id,
validate_count=True,
Expand Down
7 changes: 4 additions & 3 deletions kpi/management/commands/sync_kobocat_xforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ def _sync_form_metadata(asset, xform, changes):
'version': asset.version_id
})
changes.append('CREATE METADATA')
asset.set_deployment(kc_deployment)
# `_sync_permissions()` will save `asset` if it has no `pk`
affected_users = _sync_permissions(asset, xform)
if affected_users:
Expand All @@ -281,7 +282,7 @@ def _sync_form_metadata(asset, xform, changes):

if (asset.deployment.active != xform.downloadable or
backend_response['downloadable'] != xform.downloadable):
asset.store_data({'active': xform.downloadable})
asset.deployment.store_data({'active': xform.downloadable})
modified = True
fetch_backend_response = True
changes.append('ACTIVE')
Expand Down Expand Up @@ -500,9 +501,9 @@ def handle(self, *args, **options):
# form uuid stored in its deployment data
xform_uuids_to_asset_pks = {}
for existing_survey in existing_surveys:
backend_response = existing_survey.deployment.backend_response
if not backend_response:
if not existing_survey.has_deployment:
continue
backend_response = existing_survey.deployment.backend_response
xform_uuids_to_asset_pks[backend_response['uuid']] = \
existing_survey.pk

Expand Down
6 changes: 3 additions & 3 deletions kpi/tests/api/v1/test_api_assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
EMPTY_SURVEY = {'survey': [], 'schema': SCHEMA_VERSION, 'settings': {}}


class AssetsListApiTests(test_api_assets.AssetsListApiTests):
class AssetListApiTests(test_api_assets.AssetListApiTests):
URL_NAMESPACE = None

def test_asset_list_matches_detail(self):
Expand All @@ -49,7 +49,7 @@ class AssetVersionApiTests(test_api_assets.AssetVersionApiTests):
URL_NAMESPACE = None


class AssetsDetailApiTests(test_api_assets.AssetsDetailApiTests):
class AssetDetailApiTests(test_api_assets.AssetDetailApiTests):
URL_NAMESPACE = None

@unittest.skip(reason='`assignable_permissions` property only exists in '
Expand Down Expand Up @@ -246,7 +246,7 @@ def test_move_asset_between_collections(self):
self.assertIn('/assets/%s' % (other_coll.uid), req.data['parent'])


class AssetsSettingsFieldTest(test_api_assets.AssetsSettingsFieldTest):
class AssetSettingsFieldTest(test_api_assets.AssetSettingsFieldTest):
URL_NAMESPACE = None


Expand Down
119 changes: 86 additions & 33 deletions kpi/tests/api/v2/test_api_assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@
from kpi.models import AssetFile
from kpi.models import AssetVersion
from kpi.serializers.v2.asset import AssetListSerializer
from kpi.tests.base_test_case import BaseAssetTestCase, BaseTestCase
from kpi.tests.base_test_case import (
BaseAssetDetailTestCase,
BaseAssetTestCase,
BaseTestCase,
)
from kpi.tests.kpi_test_case import KpiTestCase
from kpi.urls.router_api_v2 import URL_NAMESPACE as ROUTER_URL_NAMESPACE
from kpi.utils.hash import get_hash


class AssetsListApiTests(BaseAssetTestCase):
class AssetListApiTests(BaseAssetTestCase):
fixtures = ['test_data']

URL_NAMESPACE = ROUTER_URL_NAMESPACE
Expand Down Expand Up @@ -297,20 +301,7 @@ def test_restricted_access_to_version(self):
self.assertEqual(resp2.data['detail'], 'Not found.')


class AssetsDetailApiTests(BaseAssetTestCase):
fixtures = ['test_data']

URL_NAMESPACE = ROUTER_URL_NAMESPACE

def setUp(self):
self.client.login(username='someuser', password='someuser')
url = reverse(self._get_endpoint('asset-list'))
data = {'content': '{}', 'asset_type': 'survey'}
self.r = self.client.post(url, data, format='json')
self.asset = Asset.objects.get(uid=self.r.data.get('uid'))
self.asset_url = self.r.data['url']
self.assertEqual(self.r.status_code, status.HTTP_201_CREATED)
self.asset_uid = self.r.data['uid']
class AssetDetailApiTests(BaseAssetDetailTestCase):

def test_asset_exists(self):
resp = self.client.get(self.asset_url, format='json')
Expand All @@ -331,22 +322,6 @@ def test_asset_has_deployment_data(self):
self.assertEqual(response.data.get('deployment__active'), False)
self.assertEqual(response.data.get('has_deployment'), False)

def test_asset_deployment_data_updates(self):
deployment_url = reverse(self._get_endpoint('asset-deployment'),
kwargs={'uid': self.asset_uid})

response1 = self.client.post(deployment_url, {
'backend': 'mock',
'active': True,
})

self.assertEqual(response1.data.get("asset").get('deployment__active'), True)
self.assertEqual(response1.data.get("asset").get('has_deployment'), True)

response2 = self.client.get(self.asset_url, format='json')
self.assertEqual(response2.data.get('deployment__active'), True)
self.assertEqual(response2.data['has_deployment'], True)

def test_can_clone_asset(self):
response = self.client.post(reverse(self._get_endpoint('asset-list')),
format='json',
Expand Down Expand Up @@ -632,7 +607,7 @@ class ObjectRelationshipsTests(BaseTestCase):
pass


class AssetsSettingsFieldTest(KpiTestCase):
class AssetSettingsFieldTest(KpiTestCase):
fixtures = ['test_data']

URL_NAMESPACE = ROUTER_URL_NAMESPACE
Expand Down Expand Up @@ -1055,3 +1030,81 @@ def test_form_media_do_not_show_up_with_date_deleted_not_null(self):
self.assertEqual(list_response.data['count'], asset_files_count - 1)
detail_response = self.client.get(detail_url)
self.assertEqual(detail_response.status_code, status.HTTP_404_NOT_FOUND)


class AssetDeploymentTest(BaseAssetDetailTestCase):

def test_asset_deployment(self):
deployment_url = reverse(self._get_endpoint('asset-deployment'),
kwargs={'uid': self.asset_uid})

response1 = self.client.post(deployment_url, {
'backend': 'mock',
'active': True,
})

self.assertEqual(response1.data['asset']['deployment__active'], True)
self.assertEqual(response1.data['asset']['has_deployment'], True)

response2 = self.client.get(self.asset_url, format='json')

self.assertEqual(response2.data['deployment__active'], True)
self.assertEqual(response2.data['has_deployment'], True)

def test_asset_redeployment(self):
self.test_asset_deployment()

# Update asset to redeploy it
data = {
'name': f'{self.asset.name} v2'
}
asset_response = self.client.patch(self.asset_url,
data=data,
format='json')
self.assertEqual(asset_response.status_code,
status.HTTP_200_OK)
self.asset.refresh_from_db()
version_id = asset_response.data['version_id']

deployment_url = reverse(self._get_endpoint('asset-deployment'),
kwargs={'uid': self.asset_uid})

# We cannot `POST` to redeploy...
redeploy_response = self.client.post(deployment_url, {
'backend': 'mock',
'active': True,
'version_id': version_id,
})
self.assertEqual(redeploy_response.status_code,
status.HTTP_405_METHOD_NOT_ALLOWED)

# ... but we can with `PATCH`
redeploy_response = self.client.patch(deployment_url, {
'backend': 'mock',
'active': True,
'version_id': version_id,
})
self.assertEqual(redeploy_response.status_code,
status.HTTP_200_OK)
# Validate version id
self.asset.refresh_from_db()
self.assertEqual(self.asset.deployment.version_id,
redeploy_response.data['version_id'])
self.assertEqual(self.asset.deployment.version_id,
version_id)

def test_archive_asset(self):
self.test_asset_deployment()

deployment_url = reverse(self._get_endpoint('asset-deployment'),
kwargs={'uid': self.asset_uid})

response1 = self.client.patch(deployment_url, {
'backend': 'mock',
'active': False,
})

self.assertEqual(response1.data['asset']['deployment__active'], False)

response2 = self.client.get(self.asset_url, format='json')
self.assertEqual(response2.data['deployment__active'], False)
18 changes: 18 additions & 0 deletions kpi/tests/base_test_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from rest_framework.test import APITestCase

from kpi.models import Asset
from kpi.urls.router_api_v2 import URL_NAMESPACE as ROUTER_URL_NAMESPACE


class BaseTestCase(APITestCase):
Expand Down Expand Up @@ -43,3 +44,20 @@ def create_asset(self, asset_type='survey'):
sa = Asset.objects.order_by('date_created').last()
self.assertEqual(sa.content, self.EMPTY_SURVEY)
return response


class BaseAssetDetailTestCase(BaseAssetTestCase):

fixtures = ['test_data']

URL_NAMESPACE = ROUTER_URL_NAMESPACE

def setUp(self):
self.client.login(username='someuser', password='someuser')
url = reverse(self._get_endpoint('asset-list'))
data = {'content': '{}', 'asset_type': 'survey'}
self.r = self.client.post(url, data, format='json')
self.asset = Asset.objects.get(uid=self.r.data.get('uid'))
self.asset_url = self.r.data['url']
self.assertEqual(self.r.status_code, status.HTTP_201_CREATED)
self.asset_uid = self.r.data['uid']
24 changes: 22 additions & 2 deletions kpi/tests/test_deployment_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,28 @@ def test_delete(self):
self.asset.deployment.delete()
self.assertFalse(self.asset.has_deployment)

def test_get_not_mutable_deployment_data(self):
deployment_data = self.asset.deployment.get_data()
original_identifier = deployment_data['identifier']
deployment_data['identifier'] = 'mock://test'
# self.asset._deployment_data should have been touched

# Check that original identifier still the same
self.assertEqual(self.asset.deployment.identifier,
original_identifier)

# Check that identifier has not been altered in deployment data
other_deployment_data = self.asset.deployment.get_data()
self.assertEqual(other_deployment_data['identifier'],
original_identifier)

def test_save_to_db_with_quote(self):
new_key = 'dummy'
new_value = "I'm in love with Apostrophe"
self.asset.deployment.save_to_db({new_key: new_value})
self.asset.refresh_from_db()
self.assertEqual(self.asset.deployment.get_data(new_key), new_value)

def test_save_data(self):

deployment_data = self.asset.deployment.get_data()
Expand Down Expand Up @@ -129,5 +151,3 @@ def test_save_data_with_deferred_fields(self):
# altered directly
with self.assertRaises(DeploymentDataException) as e:
asset.save()


1 change: 0 additions & 1 deletion kpi/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,3 @@ def test_query_parser_default_search_too_short(self):
with self.assertRaises(SearchQueryTooShortException) as e:
parse(query_string, default_field_lookups)
assert 'Your query is too short' in str(e.exception)