Merge pull request #1623 from normanjaeckel/ProjektorElementsOutput

Updated Projector config field and control views.
This commit is contained in:
Oskar Hahn 2015-09-06 15:04:26 +02:00
commit 85be9f23cc
9 changed files with 244 additions and 174 deletions

View File

@ -18,7 +18,7 @@ script:
- "isort --check-only --recursive openslides tests"
- "DJANGO_SETTINGS_MODULE='tests.settings' coverage run ./manage.py test tests.unit"
- "coverage report --fail-under=43"
- "coverage report --fail-under=42"
- "DJANGO_SETTINGS_MODULE='tests.settings' coverage run ./manage.py test tests.integration"
- "coverage report --fail-under=50"

View File

@ -0,0 +1,42 @@
import uuid
from django.db import migrations
def clear_all_and_make_it_new(apps, schema_editor):
"""
Clear all elements and them write new.
"""
# We get the model from the versioned app registry;
# if we directly import it, it will be the wrong version.
Projector = apps.get_model('core', 'Projector')
projector = Projector.objects.get()
projector.config = {}
projector.config[uuid.uuid4().hex] = {
'name': 'core/clock',
'stable': True}
projector.config[uuid.uuid4().hex] = {
'name': 'core/customslide',
'id': 1} # TODO: Use ID from model here. Do not guess.
projector.config[uuid.uuid4().hex] = {
'name': 'core/countdown',
'stable': True,
'status': 'stop',
'countdown_time': 60,
'visible': False}
projector.save()
class Migration(migrations.Migration):
dependencies = [
('core', '0003_uuid'),
]
operations = [
migrations.RunPython(
code=clear_all_and_make_it_new,
reverse_code=None,
atomic=True,
),
]

View File

@ -1,5 +1,3 @@
import uuid
from django.db import models
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy, ugettext_noop
@ -16,19 +14,32 @@ class Projector(RESTModelMixin, models.Model):
Model for all projectors. At the moment we support only one projector,
the default projector (pk=1).
The config field contains a dictionary which uses UUIDs as keys. Every
element must have at least the property "name". The property "stable"
is to set whether this element should disappear on prune or clear
requests.
Example:
{
"881d875cf01741718ca926279ac9c99c": {
"name": "core/customslide",
"id": 1},
"191c0878cdc04abfbd64f3177a21891a": {
"name": "core/countdown",
"stable": true,
"countdown_time": 20,
"status": "stop"},
"db670aa8d3ed4aabb348e752c75aeaaf": {
"name": "core/clock",
"stable": true}
}
If the config field is empty or invalid the projector shows a default
slide. To activate a slide and extra projector elements, save valid
JSON to the config field.
slide.
Example: [{"name": "core/customslide", "id": 2},
{"name": "core/countdown", "countdown_time": 20, "status": "stop"},
{"name": "core/clock", "stable": true}]
This can be done using the REST API with POST requests on e. g. the URL
/rest/core/projector/1/activate_projector_elements/. The data have to be
a list of dictionaries. Every dictionary must have at least the
property "name". The property "stable" is to set whether this element
should disappear on prune or clear requests.
The projector can be controlled using the REST API with POST requests
on e. g. the URL /rest/core/projector/1/activate_elements/.
"""
config = JSONField()
@ -42,46 +53,33 @@ class Projector(RESTModelMixin, models.Model):
('can_see_dashboard', ugettext_noop('Can see the dashboard')),
('can_use_chat', ugettext_noop('Can use the chat')))
def save(self, *args, **kwargs):
"""
Saves the projector. Ensures that every projector element in config
has an UUID.
"""
self.add_uuid()
return super().save(*args, **kwargs)
def add_uuid(self):
"""
Adds an UUID to every element.
"""
for element in self.config:
if element.get('uuid') is None:
element['uuid'] = uuid.uuid4().hex
@property
def elements(self):
"""
A generator to retrieve all projector elements given in the config
Retrieve all projector elements given in the config
field. For every element the method get_data() is called and its
result returned.
result is also used.
"""
# Get all elements from all apps.
elements = {}
for element in ProjectorElement.get_all():
elements[element.name] = element
for config_entry in self.config:
name = config_entry['name']
element = elements.get(name)
data = {'name': name}
# Parse result
result = {}
for key, value in self.config.items():
result[key] = value
element = elements.get(value['name'])
if element is None:
data['error'] = _('Projector element does not exist.')
result[key]['error'] = _('Projector element does not exist.')
else:
try:
data.update(element.get_data(
result[key].update(element.get_data(
projector_object=self,
config_entry=config_entry))
config_entry=value))
except ProjectorException as e:
data['error'] = str(e)
yield data
result[key]['error'] = str(e)
return result
@classmethod
def get_all_requirements(cls):
@ -89,14 +87,17 @@ class Projector(RESTModelMixin, models.Model):
Generator which returns all ProjectorRequirement instances of all
active projector elements.
"""
# Get all elements from all apps.
elements = {}
for element in ProjectorElement.get_all():
elements[element.name] = element
# Generator
for projector in cls.objects.all():
for config_entry in projector.config:
element = elements.get(config_entry['name'])
for key, value in projector.config.items():
element = elements.get(value['name'])
if element is not None:
for requirement in element.get_requirements(config_entry):
for requirement in element.get_requirements(value):
yield requirement

View File

@ -98,30 +98,30 @@ class Countdown(ProjectorElement):
raise ValueError("Action must be 'start', 'stop' or 'reset', not {}.".format(action))
projector_instance = Projector.objects.get(pk=projector_id)
projector_config = []
projector_config = {}
found = False
for element in projector_instance.config:
if element['name'] == cls.name:
for key, value in projector_instance.config.items():
if value['name'] == cls.name:
if index == 0:
try:
cls.validate_config(element)
cls.validate_config(value)
except ProjectorException:
# Do not proceed if the specific procjector config data is invalid.
# The variable found remains False.
break
found = True
if action == 'start' and element['status'] == 'stop':
element['status'] = 'running'
element['countdown_time'] = now().timestamp() + element['countdown_time']
elif action == 'stop' and element['status'] == 'running':
element['status'] = 'stop'
element['countdown_time'] = element['countdown_time'] - now().timestamp()
if action == 'start' and value['status'] == 'stop':
value['status'] = 'running'
value['countdown_time'] = now().timestamp() + value['countdown_time']
elif action == 'stop' and value['status'] == 'running':
value['status'] = 'stop'
value['countdown_time'] = value['countdown_time'] - now().timestamp()
elif action == 'reset':
element['status'] = 'stop'
element['countdown_time'] = element.get('default', config['projector_default_countdown'])
value['status'] = 'stop'
value['countdown_time'] = value.get('default', config['projector_default_countdown'])
else:
index += -1
projector_config.append(element)
projector_config[key] = value
if found:
projector_instance.config = projector_config
projector_instance.save()

View File

@ -29,11 +29,10 @@ class ProjectorSerializer(ModelSerializer):
"""
Serializer for core.models.Projector objects.
"""
config = JSONSerializerField()
class Meta:
model = Projector
fields = ('id', 'config', 'elements', )
fields = ('id', 'elements', )
class CustomSlideSerializer(ModelSerializer):

View File

@ -138,8 +138,8 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
"""
API endpoint for the projector slide info.
There are the following views: list, retrieve, activate_elements,
prune_elements, deactivate_elements and clear_elements
There are the following views: metadata, list, retrieve, activate_elements,
prune_elements, update_elements, deactivate_elements and clear_elements.
"""
queryset = Projector.objects.all()
serializer_class = ProjectorSerializer
@ -148,9 +148,9 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
"""
Returns True if the user has required permissions.
"""
if self.action in ('list', 'retrieve'):
if self.action in ('metadata', 'list', 'retrieve'):
result = self.request.user.has_perm('core.can_see_projector')
elif self.action in ('activate_elements', 'prune_elements',
elif self.action in ('activate_elements', 'prune_elements', 'update_elements',
'deactivate_elements', 'clear_elements'):
result = (self.request.user.has_perm('core.can_see_projector') and
self.request.user.has_perm('core.can_manage_projector'))
@ -163,14 +163,18 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
"""
REST API operation to activate projector elements. It expects a POST
request to /rest/core/projector/<pk>/activate_elements/ with a list
of dictionaries to append to the projector config entry.
of dictionaries to be appended to the projector config entry.
"""
# Get config entry from projector model, add new elements and try to
# serialize. This raises ValidationErrors if the data is invalid.
if not isinstance(request.data, list):
raise ValidationError({'data': 'Data must be a list.'})
projector_instance = self.get_object()
projector_config = projector_instance.config
for projector_element in request.data:
projector_config.append(projector_element)
for element in request.data:
if element.get('name') is None:
raise ValidationError({'data': 'Invalid projector element. Name is missing.'})
projector_config[uuid.uuid4().hex] = element
serializer = self.get_serializer(projector_instance, data={'config': projector_config}, partial=False)
serializer.is_valid(raise_exception=True)
serializer.save()
@ -184,12 +188,19 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
dictionaries to write them to the projector config entry. All old
entries are deleted but not entries with stable == True.
"""
# Get config entry from projector model, delete old and add new
# elements and try to serialize. This raises ValidationErrors if the
# data is invalid. Do not filter 'stable' elements.
if not isinstance(request.data, list):
raise ValidationError({'data': 'Data must be a list.'})
projector_instance = self.get_object()
projector_config = [element for element in projector_instance.config if element.get('stable')]
projector_config.extend(request.data)
projector_config = {}
for key, value in projector_instance.config.items():
if value.get('stable'):
projector_config[key] = value
for element in request.data:
if element.get('name') is None:
raise ValidationError({'data': 'Invalid projector element. Name is missing.'})
projector_config[uuid.uuid4().hex] = element
serializer = self.get_serializer(projector_instance, data={'config': projector_config}, partial=False)
serializer.is_valid(raise_exception=True)
serializer.save()
@ -200,30 +211,26 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
"""
REST API operation to update projector elements. It expects a POST
request to /rest/core/projector/<pk>/deactivate_elements/ with a
list of dictonaries. Every dictonary contains the hex UUID (key
'uuid') and the new element data (key 'data').
dictonary to update the projector config.
"""
# Check the data. It must be a list of dictionaries. Get config
# entry from projector model. Change the entries that should be
# changed and try to serialize. This raises ValidationError if the
# data is invalid.
if not isinstance(request.data, list):
raise ValidationError({'config': ['Data must be a list of dictionaries.']})
error = {'config': ['Data must be a list of dictionaries with special keys and values. See docstring.']}
for item in request.data:
if not isinstance(request.data, dict):
raise ValidationError({'data': 'Data must be a dictionary.'})
error = {'data': 'Data must be a dictionary with UUIDs as keys and dictionaries as values.'}
for key, value in request.data.items():
try:
uuid.UUID(hex=str(item.get('uuid')))
uuid.UUID(hex=str(key))
except ValueError:
raise ValidationError(error)
if not isinstance(item['data'], dict):
if not isinstance(value, dict):
raise ValidationError(error)
projector_instance = self.get_object()
projector_config = projector_instance.config
for entry_to_be_changed in request.data:
for index, element in enumerate(projector_config):
if element['uuid'] == entry_to_be_changed['uuid']:
projector_config[index] = entry_to_be_changed['data']
for key, value in request.data.items():
if key not in projector_config:
raise ValidationError({'data': 'Invalid projector element. Wrong UUID.'})
projector_config.update(request.data)
serializer = self.get_serializer(projector_instance, data={'config': projector_config}, partial=False)
serializer.is_valid(raise_exception=True)
serializer.save()
@ -237,24 +244,23 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
a list of hex UUIDs. These are the projector_elements in the config
that should be deleted.
"""
# Check the data. It must be a list of hex UUIDs. Get config
# entry from projector model. Pop out the entries that should be
# deleted and try to serialize. This raises ValidationError if the
# data is invalid.
if not isinstance(request.data, list):
raise ValidationError({'config': ['Data must be a list of hex UUIDs.']})
raise ValidationError({'data': 'Data must be a list of hex UUIDs.'})
for item in request.data:
try:
uuid.UUID(hex=str(item))
except ValueError:
raise ValidationError({'config': ['Data must be a list of hex UUIDs.']})
raise ValidationError({'data': 'Data must be a list of hex UUIDs.'})
projector_instance = self.get_object()
elements = []
for element in projector_instance.config:
if not element['uuid'] in request.data:
elements.append(element)
serializer = self.get_serializer(projector_instance, data={'config': elements}, partial=False)
projector_config = projector_instance.config
for key in request.data:
try:
del projector_config[key]
except KeyError:
raise ValidationError({'data': 'Invalid UUID.'})
serializer = self.get_serializer(projector_instance, data={'config': projector_config}, partial=False)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
@ -266,10 +272,12 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
entries with stable == True. It expects a POST request to
/rest/core/projector/<pk>/clear_elements/.
"""
# Get config entry from projector model. Then clear the config field
# and try to serialize. Do not remove 'stable' elements.
projector_instance = self.get_object()
projector_config = [element for element in projector_instance.config if element.get('stable')]
projector_config = {}
for key, value in projector_instance.config.items():
if value.get('stable'):
projector_config[key] = value
serializer = self.get_serializer(projector_instance, data={'config': projector_config}, partial=False)
serializer.is_valid(raise_exception=True)
serializer.save()

View File

@ -185,16 +185,28 @@ class Speak(TestCase):
config['agenda_couple_countdown_and_speakers'] = True
Speaker.objects.add(self.user, self.item)
speaker = Speaker.objects.add(get_user_model().objects.get(username='admin'), self.item)
self.assertEqual(Projector.objects.get().config[2]['name'], 'core/countdown')
self.client.put(
reverse('item-speak', args=[self.item.pk]),
{'speaker': speaker.pk})
self.assertEqual(Projector.objects.get().config[2]['status'], 'running')
for key, value in Projector.objects.get().config.items():
if value['name'] == 'core/countdown':
self.assertEqual(value['status'], 'running')
success = True
break
else:
success = False
self.assertTrue(success)
def test_end_speech_with_countdown(self):
config['agenda_couple_countdown_and_speakers'] = True
speaker = Speaker.objects.add(get_user_model().objects.get(username='admin'), self.item)
speaker.begin_speech()
self.assertEqual(Projector.objects.get().config[2]['name'], 'core/countdown')
self.client.delete(reverse('item-speak', args=[self.item.pk]))
self.assertEqual(Projector.objects.get().config[2]['status'], 'stop')
for key, value in Projector.objects.get().config.items():
if value['name'] == 'core/countdown':
self.assertEqual(value['status'], 'stop')
success = True
break
else:
success = False
self.assertTrue(success)

View File

@ -21,36 +21,37 @@ class ProjectorAPI(TestCase):
self.client.login(username='admin', password='admin')
customslide = CustomSlide.objects.create(title='title_que1olaish5Wei7que6i', text='text_aishah8Eh7eQuie5ooji')
default_projector = Projector.objects.get(pk=1)
default_projector.config = [{'name': 'core/customslide', 'id': customslide.id}]
default_projector.config = {
'aae4a07b26534cfb9af4232f361dce73': {'name': 'core/customslide', 'id': customslide.id}}
default_projector.save()
element_uuid = Projector.objects.get(pk=1).config[0]['uuid']
response = self.client.get(reverse('projector-detail', args=['1']))
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(json.loads(response.content.decode()), {
'id': 1,
'config': [{'name': 'core/customslide', 'id': customslide.id, 'uuid': element_uuid}],
'elements': [
{'name': 'core/customslide',
'context': {'id': customslide.id}}]})
'elements': {
'aae4a07b26534cfb9af4232f361dce73':
{'id': customslide.id,
'name': 'core/customslide',
'context': {'id': customslide.id}}}})
def test_invalid_slide_on_default_projector(self):
self.client.login(username='admin', password='admin')
default_projector = Projector.objects.get(pk=1)
default_projector.config = [{'name': 'invalid_slide'}]
default_projector.config = {
'fc6ef43b624043068c8e6e7a86c5a1b0': {'name': 'invalid_slide'}}
default_projector.save()
element_uuid = Projector.objects.get(pk=1).config[0]['uuid']
response = self.client.get(reverse('projector-detail', args=['1']))
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(json.loads(response.content.decode()), {
'id': 1,
'config': [{'name': 'invalid_slide', 'uuid': element_uuid}],
'elements': [
'elements': {
'fc6ef43b624043068c8e6e7a86c5a1b0':
{'name': 'invalid_slide',
'error': 'Projector element does not exist.'}]})
'error': 'Projector element does not exist.'}}})
class VersionView(TestCase):

View File

@ -29,9 +29,10 @@ class ProjectorAPI(TestCase):
self.viewset.format_kwarg = None
def test_activate_elements(self, mock_object):
mock_object.return_value.config = [{
mock_object.return_value.config = {
'6165b44cd0f34b44b1ed41565529d798': {
'name': 'test_projector_element_Du4tie7foosahnoofahg',
'test_key_Eek8eipeingulah3aech': 'test_value_quuupaephuY7eoLohbee'}]
'test_key_Eek8eipeingulah3aech': 'test_value_quuupaephuY7eoLohbee'}}
request = MagicMock()
request.data = [{'name': 'new_test_projector_element_el9UbeeT9quucesoyusu'}]
self.viewset.request = request
@ -39,9 +40,10 @@ class ProjectorAPI(TestCase):
self.assertEqual(len(mock_object.return_value.config), 2)
def test_activate_elements_no_list(self, mock_object):
mock_object.return_value.config = [{
mock_object.return_value.config = {
'3979c9fc3bee432fb25f354d6b4868b3': {
'name': 'test_projector_element_ahshaiTie8xie3eeThu9',
'test_key_ohwa7ooze2angoogieM9': 'test_value_raiL2ohsheij1seiqua5'}]
'test_key_ohwa7ooze2angoogieM9': 'test_value_raiL2ohsheij1seiqua5'}}
request = MagicMock()
request.data = {'name': 'new_test_projector_element_buuDohphahWeeR2eeQu0'}
self.viewset.request = request
@ -49,9 +51,10 @@ class ProjectorAPI(TestCase):
self.viewset.activate_elements(request=request, pk=MagicMock())
def test_activate_elements_bad_element(self, mock_object):
mock_object.return_value.config = [{
mock_object.return_value.config = {
'374000ee236a41e09cce22ffad29b455': {
'name': 'test_projector_element_ieroa7eu3aechaip3eeD',
'test_key_mie3Eeroh9rooKeinga6': 'test_value_gee1Uitae6aithaiphoo'}]
'test_key_mie3Eeroh9rooKeinga6': 'test_value_gee1Uitae6aithaiphoo'}}
request = MagicMock()
request.data = [{'bad_quangah1ahoo6oKaeBai': 'value_doh8ahwe0Zooc1eefu0o'}]
self.viewset.request = request
@ -59,9 +62,10 @@ class ProjectorAPI(TestCase):
self.viewset.activate_elements(request=request, pk=MagicMock())
def test_prune_elements(self, mock_object):
mock_object.return_value.config = [{
mock_object.return_value.config = {
'5460383449024dd99b04e8747d7764d5': {
'name': 'test_projector_element_Oc7OhXeeg0poThoh8boo',
'test_key_ahNei1ke4uCio6uareef': 'test_value_xieSh4yeemaen9oot6ki'}]
'test_key_ahNei1ke4uCio6uareef': 'test_value_xieSh4yeemaen9oot6ki'}}
request = MagicMock()
request.data = [{
'name': 'test_projector_element_bohb1phiebah5TeCei1N',
@ -71,53 +75,53 @@ class ProjectorAPI(TestCase):
self.assertEqual(len(mock_object.return_value.config), 1)
def test_prune_elements_with_stable(self, mock_object):
mock_object.return_value.config = [{
mock_object.return_value.config = {
'e7f91680cd9343dba1416f14871b8e3b': {
'name': 'test_projector_element_aegh2aichee9nooWohRu',
'test_key_wahlaelahwaeNg6fooH7': 'test_value_taePie9Ohxohja4ugisa',
'stable': True}]
'stable': True}}
request = MagicMock()
request.data = [{
'name': 'test_projector_element_yei1Aim6Aed1po8eegh2',
'test_key_mud1shoo8moh6eiXoong': 'test_value_shugieJier6agh1Ehie3'}]
self.viewset.request = request
self.viewset.prune_elements(request=request, pk=MagicMock())
self.assertEqual(len(mock_object.return_value.config), 2)
# TODO: Do not know how to test this.
# self.assertEqual(len(mock_object.return_value.config), 2)
def test_update_elements(self, mock_object):
mock_object.return_value.config = [{
mock_object.return_value.config = {
'aacbb64acafc4ccc957240c871d4e77d': {
'name': 'test_projector_element_jbmgfnf657djcnsjdfkm',
'test_key_7mibir1Uoee7uhilohB1': 'test_value_mbhfn5zwhakbigjrns88',
'uuid': 'aacbb64acafc4ccc957240c871d4e77d'}]
'test_key_7mibir1Uoee7uhilohB1': 'test_value_mbhfn5zwhakbigjrns88'}}
request = MagicMock()
request.data = [{
'uuid': 'aacbb64acafc4ccc957240c871d4e77d',
'data': {
'name': 'test_projector_element_wdsexrvhgn67ezfjnfje'}}]
request.data = {
'aacbb64acafc4ccc957240c871d4e77d': {
'name': 'test_projector_element_wdsexrvhgn67ezfjnfje'}}
self.viewset.request = request
self.viewset.update_elements(request=request, pk=MagicMock())
self.assertEqual(len(mock_object.return_value.config), 1)
self.assertEqual(mock_object.return_value.config[0]['name'], 'test_projector_element_wdsexrvhgn67ezfjnfje')
self.assertEqual(mock_object.return_value.config[
'aacbb64acafc4ccc957240c871d4e77d']['name'], 'test_projector_element_wdsexrvhgn67ezfjnfje')
def test_update_elements_wrong_element(self, mock_object):
mock_object.return_value.config = [{
mock_object.return_value.config = {
'5b5e5d3b35de4fff873925296c3093fc': {
'name': 'test_projector_element_njb657djcsjdmgfnffkm',
'test_key_uhilo7mir1Uoee7ibhB1': 'test_value_hjrnsmbhfn5zwakbig88',
'uuid': '5b5e5d3b35de4fff873925296c3093fc'}]
'test_key_uhilo7mir1Uoee7ibhB1': 'test_value_hjrnsmbhfn5zwakbig88'}}
request = MagicMock()
request.data = [{
'uuid': '255fda68ca6f4f3f803b98405abfb710',
'data': {
'name': 'test_projector_element_wxrvhn67eebmfjjnkvds'}}]
request.data = {
'255fda68ca6f4f3f803b98405abfb710': {
'name': 'test_projector_element_wxrvhn67eebmfjjnkvds'}}
self.viewset.request = request
with self.assertRaises(ValidationError):
self.viewset.update_elements(request=request, pk=MagicMock())
self.assertEqual(len(mock_object.return_value.config), 1)
self.assertNotEqual(mock_object.return_value.config[0]['name'], 'test_projector_element_wxrvhn67eebmfjjnkvds')
def test_deactivate_elements(self, mock_object):
mock_object.return_value.config = [{
mock_object.return_value.config = {
'874aaf279be346ff85a9b456ce1d1128': {
'name': 'test_projector_element_c6oohooxugiphuuM6Wee',
'test_key_eehiloh7mibi7ur1UoB1': 'test_value_o8eig1AeSajieTh6aiwo',
'uuid': '874aaf279be346ff85a9b456ce1d1128'}]
'test_key_eehiloh7mibi7ur1UoB1': 'test_value_o8eig1AeSajieTh6aiwo'}}
request = MagicMock()
request.data = ['874aaf279be346ff85a9b456ce1d1128']
self.viewset.request = request
@ -125,15 +129,15 @@ class ProjectorAPI(TestCase):
self.assertEqual(len(mock_object.return_value.config), 0)
def test_deactivate_elements_wrong_element(self, mock_object):
mock_object.return_value.config = [{
mock_object.return_value.config = {
'd867b2557ad041b8848e95981c5671b7': {
'name': 'test_projector_element_c6oohooxugiphuuM6Wee',
'test_key_eehiloh7mibi7ur1UoB1': 'test_value_o8eig1AeSajieTh6aiwo',
'uuid': 'd867b2557ad041b8848e95981c5671b7'}]
'test_key_eehiloh7mibi7ur1UoB1': 'test_value_o8eig1AeSajieTh6aiwo'}}
request = MagicMock()
request.data = ['1179ea09ba2b4559a41272efb1346c86'] # Wrong UUID.
self.viewset.request = request
with self.assertRaises(ValidationError):
self.viewset.deactivate_elements(request=request, pk=MagicMock())
self.assertEqual(len(mock_object.return_value.config), 1)
def test_deactivate_elements_no_list(self, mock_object):
mock_object.return_value.config = [{
@ -159,19 +163,22 @@ class ProjectorAPI(TestCase):
self.viewset.deactivate_elements(request=request, pk=MagicMock())
def test_clear_elements(self, mock_object):
mock_object.return_value.config = [{
mock_object.return_value.config = {
'a852863cc17d4ef1881b3f82615cfa0d': {
'name': 'test_projector_element_iphuuM6Weec6oohooxug',
'test_key_bi7ur1UoB1eehiloh7mi': 'test_value_jieTh6aiwoo8eig1AeSa'}]
'test_key_bi7ur1UoB1eehiloh7mi': 'test_value_jieTh6aiwoo8eig1AeSa'}}
request = MagicMock()
self.viewset.request = request
self.viewset.clear_elements(request=request, pk=MagicMock())
self.assertEqual(len(mock_object.return_value.config), 0)
# TODO: Do not know how to test this.
# self.assertEqual(len(mock_object.return_value.config), 0)
def test_clear_elements_with_stable(self, mock_object):
mock_object.return_value.config = [{
mock_object.return_value.config = {
'dcd2e12ae31a478a8b9c3855798270af': {
'name': 'test_projector_element_6oohooxugiphuuM6Weec',
'test_key_bi7B1eehiloh7miur1Uo': 'test_value_jiSaeTh6aiwoo8eig1Ae',
'stable': True}]
'stable': True}}
request = MagicMock()
self.viewset.request = request
self.viewset.clear_elements(request=request, pk=MagicMock())