def handle_noargs(self, **options):
     client = ProximityClient()
     
     try:
         client.flush()
     except ProximityClientConnectionError, e:
         raise CommandError(e)
class ProximityClientTestCase(TestCase):

    def setUp(self):
        self.old_setting = settings.PROXIMITY_SERVER['default']
        settings.PROXIMITY_SERVER['default'] = settings.PROXIMITY_SERVER['test']
        self.proximity_client = ProximityClient()
        self.proximity_client.flush()

    def tearDown(self):
        settings.PROXIMITY_SERVER['default'] = self.old_setting
    
    def test_good_add_set_get_flush(self):
        self.proximity_client.add_device('aa:aa:aa:aa:aa:aa')
        group = self.proximity_client.get_group('aa:aa:aa:aa:aa:aa')
        self.assertEqual(group, [])
        
        self.proximity_client.add_device('bb:bb:bb:bb:bb:bb')
        group = self.proximity_client.get_group('aa:aa:aa:aa:aa:aa')
        self.assertEqual(group, [])
        
        self.proximity_client.add_device('cc:cc:cc:cc:cc:cc')
        group = self.proximity_client.get_group('cc:cc:cc:cc:cc:cc')
        self.assertEqual(group, [])
        
        
        self.proximity_client.set_group('aa:aa:aa:aa:aa:aa', ['bb:bb:bb:bb:bb:bb'])
        group = self.proximity_client.get_group('aa:aa:aa:aa:aa:aa')
        self.assertEqual(group, ['bb:bb:bb:bb:bb:bb'])
        group = self.proximity_client.get_group('bb:bb:bb:bb:bb:bb')
        self.assertEqual(group, ['aa:aa:aa:aa:aa:aa'])
        group = self.proximity_client.get_group('cc:cc:cc:cc:cc:cc')
        self.assertEqual(group, [])
        
        self.proximity_client.set_group('cc:cc:cc:cc:cc:cc', ['bb:bb:bb:bb:bb:bb'])
        group = self.proximity_client.get_group('aa:aa:aa:aa:aa:aa')
        self.assertEqual(group, ['bb:bb:bb:bb:bb:bb', 'cc:cc:cc:cc:cc:cc'])
        group = self.proximity_client.get_group('bb:bb:bb:bb:bb:bb')
        self.assertEqual(group, ['aa:aa:aa:aa:aa:aa', 'cc:cc:cc:cc:cc:cc'])
        group = self.proximity_client.get_group('cc:cc:cc:cc:cc:cc')
        self.assertEqual(group, ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb'])
        
        self.proximity_client.flush()
        group = self.proximity_client.get_group('aa:aa:aa:aa:aa:aa')
        self.assertEqual(group, [])
        group = self.proximity_client.get_group('bb:bb:bb:bb:bb:bb')
        self.assertEqual(group, [])
        group = self.proximity_client.get_group('cc:cc:cc:cc:cc:cc')
        self.assertEqual(group, [])
        
class InterfaceFileAPITestCase(TestCase):
    fixtures = ['interface_file_api_testdata']
    
    def setUp(self):
        self.old_setting = settings.PROXIMITY_SERVER['default']
        settings.PROXIMITY_SERVER['default'] = settings.PROXIMITY_SERVER['test']
        self.proximity_client = ProximityClient()
        self.proximity_client.flush()
        
    def tearDown(self):
        settings.PROXIMITY_SERVER['default'] = self.old_setting
    
    def test_good_upload(self, MirriMockClass):
        # Check the initial amount of interfaces in the database
        self.assertEqual(Interface.objects.count(), 1)
        
        # Check the initial amount of methods in the database
        self.assertEqual(Method.objects.count(), 2)
        
        # Check the initial amount of method parameters in the database
        self.assertEqual(MethodParameter.objects.count(), 0)
        
        # Check the initial amount of triggers in the database
        self.assertEqual(Trigger.objects.count(), 0)
        
        # TalkingDevice
        f = open('core/fixtures/talkingDevices/talkingDevice.py')
        response = self.client.post('/api/interface_file/', {'file': f})
        f.seek(0)
        interface_code = f.read()
        f.close()
        
        self.assertEqual(response.status_code, 201)
        
        self.assertTrue(Interface.objects.filter(name='TalkingDevice').exists())
        self.assertTrue(Method.objects.filter(interface__name='TalkingDevice', name='isWilling').exists())
        self.assertTrue(Method.objects.filter(interface__name='TalkingDevice', name='isSilent').exists())
        self.assertTrue(Trigger.objects.filter(method__interface__name='TalkingDevice', method__name='isSilent').exists())
        
        # Check that the file was uploaded to Mirri
        mirri_mock = MirriMockClass.return_value
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 1)
        self.assertEqual(len(mirri_mock.upload_interface_file.call_args[0]), 2)
        self.assertEqual(mirri_mock.upload_interface_file.call_args[0][0], 'TalkingDevice')
        mirri_mock.upload_interface_file.call_args[0][1].seek(0)
        self.assertEqual(mirri_mock.upload_interface_file.call_args[0][1].read(), interface_code)
        
        
        # CalendarSource
        mirri_mock.reset_mock()
        f = open('core/fixtures/calendarReminders/calendarSource.py')
        response = self.client.post('/api/interface_file/', {'file': f})
        f.seek(0)
        interface_code = f.read()
        f.close()
        
        self.assertEqual(response.status_code, 201)
        
        self.assertTrue(Interface.objects.filter(name='CalendarSource').exists())
        self.assertTrue(Method.objects.filter(interface__name='CalendarSource', name='eventApproaching').exists())
        self.assertTrue(MethodParameter.objects.filter(method__interface__name='CalendarSource', method__name='eventApproaching', name='eid').exists())
        self.assertTrue(Trigger.objects.filter(method__interface__name='CalendarSource', method__name='eventApproaching').exists())
        
        # Check that the file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 1)
        self.assertEqual(len(mirri_mock.upload_interface_file.call_args[0]), 2)
        self.assertEqual(mirri_mock.upload_interface_file.call_args[0][0], 'CalendarSource')
        mirri_mock.upload_interface_file.call_args[0][1].seek(0)
        self.assertEqual(mirri_mock.upload_interface_file.call_args[0][1].read(), interface_code)
        
        
        # Check the final amount of interfaces in the database
        self.assertEqual(Interface.objects.count(), 3)
        
        # Check the final amount of methods in the database
        self.assertEqual(Method.objects.count(), 5)
        
        # Check the final amount of method parameters in the database
        self.assertEqual(MethodParameter.objects.count(), 1)
        
        # Check the final amount of triggers in the database
        self.assertEqual(Trigger.objects.count(), 2)
    
    
    def test_bad_upload(self, MirriMockClass):
        # Check the initial amount of interfaces in the database
        self.assertEqual(Interface.objects.count(), 1)
        
        # Check the initial amount of methods in the database
        self.assertEqual(Method.objects.count(), 2)
        
        # Check the initial amount of method parameters in the database
        self.assertEqual(MethodParameter.objects.count(), 0)
        
        # Check the initial amount of triggers in the database
        self.assertEqual(Trigger.objects.count(), 0)
        
        
        # A syntax error in the interface file
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevice_syntax_error.py')
        response = self.client.post('/api/interface_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['File talkingDevice_syntax_error.py contains syntax errors (line 15, col 22): class TalkingDevice()\n'])
        
        # Check that no file was uploaded to Mirri
        mirri_mock = MirriMockClass.return_value
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The interface file does not contain any interfaces
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevice_no_interface.py')
        response = self.client.post('/api/interface_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Interface parse error in file talkingDevice_no_interface.py: Interface decorator @deviceInterface is missing.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The interface file does not contain any precondition methods
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevice_no_precondition_methods.py')
        response = self.client.post('/api/interface_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Interface parse error in file talkingDevice_no_precondition_methods.py: Interface TalkingDevice does not have any precondition methods defined with decorator @precondition.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The interface file does not contain any triggers
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevice_no_triggers.py')
        response = self.client.post('/api/interface_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Interface parse error in file talkingDevice_no_triggers.py: No trigger method class with base class TriggeringEvent has been defined.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # A trigger in the interface file does not match any of the interface precondition methods
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevice_no_trigger_match.py')
        response = self.client.post('/api/interface_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Interface parse error in file talkingDevice_no_trigger_match.py: The name of the trigger method class IsFree does not match any of the precondition methods defined in interface TalkingDevice.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The interface file contains multiple interfaces
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevice_multiple_interfaces.py')
        response = self.client.post('/api/interface_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Interface parse error in file talkingDevice_multiple_interfaces.py: Multiple interface classes with decorator @deviceInterface have been defined.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The interface file contains a duplicate precondition method
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevice_duplicate_precondition_method.py')
        response = self.client.post('/api/interface_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Interface parse error in file talkingDevice_duplicate_precondition_method.py: Duplicate precondition method isWilling.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The interface file contains a duplicate trigger
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevice_duplicate_trigger.py')
        response = self.client.post('/api/interface_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Interface parse error in file talkingDevice_duplicate_trigger.py: Duplicate trigger method class IsSilent.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The interface file contains a duplicate method parameter
        mirri_mock.reset_mock()
        f = open('core/fixtures/calendarReminders/invalid_files/calendarSource_duplicate_method_parameter.py')
        response = self.client.post('/api/interface_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Interface parse error in file calendarSource_duplicate_method_parameter.py: Duplicate parameter eid for precondition method eventApproaching in interface CalendarSource.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The interface in the interface file already exists
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevice_interface_exists.py')
        response = self.client.post('/api/interface_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Interface TalkingDeviceTest already exists.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # Check the final amount of interfaces in the database
        self.assertEqual(Interface.objects.count(), 1)
        
        # Check the final amount of methods in the database
        self.assertEqual(Method.objects.count(), 2)
        
        # Check the final amount of method parameters in the database
        self.assertEqual(MethodParameter.objects.count(), 0)
        
        # Check the final amount of triggers in the database
        self.assertEqual(Trigger.objects.count(), 0)
class DeviceInterfaceAPITestCase(TestCase):
    fixtures = ['devices_testdata']
    
    def setUp(self):
        self.old_setting = settings.PROXIMITY_SERVER['default']
        settings.PROXIMITY_SERVER['default'] = settings.PROXIMITY_SERVER['test']
        self.proximity_client = ProximityClient()
        self.proximity_client.flush()
        
    def tearDown(self):
        settings.PROXIMITY_SERVER['default'] = self.old_setting
    
    def test_good_device_interface_post(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check the initial amount of interfaces that the device has in the database
        self.assertEqual(DeviceInterface.objects.filter(device__mac_address=mac_address).count(), 4)
        
        # The interface data
        payload = json.dumps({'interface_name': 'CalendarDevice'})
        
        # Issue a POST request
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/', payload, 'application/json')
        
        # Check that the response is 201 Created
        self.assertEqual(response.status_code, 201)
        self.assertEqual(response['Location'], 'http://testserver/api/v2/device/' + mac_address + '/interface/CalendarDevice/')
        
        # Check the final amount of devices in the database
        self.assertEqual(DeviceInterface.objects.filter(device__mac_address=mac_address).count(), 5)
    
    def test_bad_device_interface_posts(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check the initial amount of interfaces that the device has in the database
        self.assertEqual(DeviceInterface.objects.filter(device__mac_address=mac_address).count(), 4)
        
        # Send post without data and check that the response is 400 Bad Request
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/', content_type='application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['interface_name'], 'Interface name is a required field')
        
        
        # Send post without interface name and check that the response is 400 Bad Request
        payload = json.dumps({})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['interface_name'], 'Interface name is a required field')
        
        
        # Send junk data and check that the response is 400 Bad Request
        payload = json.dumps({'foo': 'bar'})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['interface_name'], 'Interface name is a required field')
        
        
        # Send post with non-existent interface name and check that the response is 400 Bad Request
        payload = json.dumps({'interface_name': 'FooBarInterface'})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['interface_name'], 'Interface FooBarInterface does not exist.')
    
        
        # Send post with empty interface name
        payload = json.dumps({'interface_name': ''})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['interface_name'], 'Interface name cannot be an empty string')
        
        
        # Send post for non-existent device
        payload = json.dumps({'interface_name': 'TalkingDevice'})
        response = self.client.post('/api/v2/device/aa:bb:cc:dd:ee:ff/interface/', payload, 'application/json')
        self.assertEqual(response.status_code, 404)
        content = json.loads(response.content)
        self.assertEqual(content['error_message'], 'Sorry, this request could not be processed. Please try again later.')
    
        
        # Send post with an interface name that already exists for the specific device in the database
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name='TalkingDevice').exists())
        payload = json.dumps({'interface_name': 'TalkingDevice'})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['interface_name'], 'Duplicate interface. Device aa:aa:aa:aa:aa:aa already has interface TalkingDevice.')
        
        
        # Check the final amount of interfaces for the device in the database is the same as in the beginning
        self.assertEqual(DeviceInterface.objects.filter(device__mac_address=mac_address).count(), 4)
    
    
    def test_good_device_interface_delete(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TalkingDevice'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check the initial amount of interfaces that the device has in the database
        self.assertEqual(DeviceInterface.objects.filter(device__mac_address=mac_address).count(), 4)
        
        # Check that the device interface actually exists
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        
        # Issue a DELETE request
        response = self.client.delete('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/')
        
        # Check that the response is 204 No Content
        self.assertEqual(response.status_code, 204)
        
        # Check that the device interface does not exist in the database anymore
        self.assertFalse(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        
        # Check the final amount of device interfaces in the database
        self.assertEqual(DeviceInterface.objects.filter(device__mac_address=mac_address).count(), 3)
        
        # TODO: cascade check
    
    
    def test_bad_device_interface_deletes(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TalkingDevice'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check the initial amount of interfaces that the device has in the database
        self.assertEqual(DeviceInterface.objects.filter(device__mac_address=mac_address).count(), 4)
        
        
        # Ensure that the deletion of a non-existent device interface throws 404 Not Found
        self.assertFalse(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name='FooBarInterface').exists())
        response = self.client.delete('/api/v2/device/' + mac_address + '/interface/FooBarInterface/')
        self.assertEqual(response.status_code, 404)
        
        
        # Ensure that the deletion of an interface of a non-existent device throws 404 Not Found
        self.assertFalse(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name='FooBarInterface').exists())
        response = self.client.delete('/api/v2/device/aa:bb:cc:dd:ee:ff/interface/' + interface_name + '/')
        self.assertEqual(response.status_code, 404)
        
        
        # The deletion of all device interfaces should throw 405 Method Not Allowed
        response = self.client.delete('/api/v2/device/' + mac_address + '/interface/')
        self.assertEqual(response.status_code, 405)
        
        
        # Check the final amount of interfaces that the device has in the database is the same as in the beginning
        self.assertEqual(DeviceInterface.objects.filter(device__mac_address=mac_address).count(), 4)
    
    
    def test_good_device_interface_get_list(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check the initial amount of interfaces that the device has in the database
        self.assertEqual(DeviceInterface.objects.filter(device__mac_address=mac_address).count(), 4)
        
        # Get a list of devices including their information
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/')
        
        # Check that the response code is 200 OK
        self.assertEqual(response.status_code, 200)
        
        # Convert the json to python
        content = json.loads(response.content)
        
        # Check that all the interfaces of the device are in the list
        self.assertEqual([deviceinterface['interface_name'] for deviceinterface in content['objects']], ['TalkingDevice', 'SingingDevice', 'CalendarSource', 'ScreenDevice'])
        
        # Check that the number of device interfaces in the list is 4
        self.assertEqual(len(content['objects']), 4)
    
    
    def test_good_device_interface_get_detail(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TalkingDevice'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check that the device interface actually exists
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        
        # Get the information related to one device interface
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/')
        
        # Check that the response code is 200 OK
        self.assertEqual(response.status_code, 200)
        
        # Check that the values are correct
        content = json.loads(response.content)
        self.assertEqual(content['created_at'], '2011-12-19T16:21:43.912345')
        self.assertEqual(content['interface_name'], 'TalkingDevice')
        self.assertEqual(content['resource_uri'], '/api/v2/device/aa:aa:aa:aa:aa:aa/interface/TalkingDevice/')
    
    
    def test_bad_device_interface_get_details(self):
        
        # Get a device interface for a non-existent interface
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TestInterface'
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        self.assertFalse(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/')
        self.assertEqual(response.status_code, 404)
        
        # Get a device interface for a non-existent device
        mac_address = 'aa:bb:cc:dd:ee:ff'
        interface_name = 'TalkingDevice'
        self.assertFalse(Device.objects.filter(mac_address=mac_address).exists())
        self.assertFalse(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/')
        self.assertEqual(response.status_code, 404)
        
    def test_bad_device_interface_update(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TalkingDevice'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check that the device interface actually exists
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        
        # The device data to be updated
        payload = json.dumps({'interface_name': 'TestInterface'})
        
        # Issue a PUT request
        response = self.client.put('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/', payload, 'application/json')
        
        # Check that the response is 405 Method Not Allowed
        self.assertEqual(response.status_code, 405)
class InterfaceAPITestCase(TestCase):
    fixtures = ['interfaces_testdata']
    
    def setUp(self):
        self.old_setting = settings.PROXIMITY_SERVER['default']
        settings.PROXIMITY_SERVER['default'] = settings.PROXIMITY_SERVER['test']
        self.proximity_client = ProximityClient()
        self.proximity_client.flush()
        
    def tearDown(self):
        settings.PROXIMITY_SERVER['default'] = self.old_setting
    
    def test_bad_interface_post(self):
        # Check the initial amount of interfaces in the database
        self.assertEqual(Interface.objects.count(), 2)
        
        # The interface data
        payload = json.dumps({'name': 'SingingDevice'})
        
        # Issue a POST request
        response = self.client.post('/api/v2/interface/', payload, 'application/json')
        
        # Check that the response is 405 Method Not Allowed
        self.assertEqual(response.status_code, 405)
        
        # Check the amount of interfaces in the database is the same as in the beginning
        self.assertEqual(Interface.objects.count(), 2)
        
    def test_bad_interface_delete(self):
        # Check the initial amount of interfaces in the database
        self.assertEqual(Interface.objects.count(), 2)
        
        # The deletion of all devices should throw 405 Method Not Allowed
        response = self.client.delete('/api/v2/interface/')
        self.assertEqual(response.status_code, 405)
        
        # The deletion of an interface should throw 405 Method Not Allowed
        name = 'TalkingDevice'
        response = self.client.delete('/api/v2/interface/' + name + '/')
        self.assertEqual(response.status_code, 405)
        
        # Check the amount of interfaces in the database is the same as in the beginning
        self.assertEqual(Interface.objects.count(), 2)
    
    def test_good_interface_get_list(self):
        # Check the initial amount of interfaces in the database
        self.assertEqual(Interface.objects.count(), 2)
        
        # Get a list of interfaces including their information
        response = self.client.get('/api/v2/interface/')
        
        # Check that the response code is 200 OK
        self.assertEqual(response.status_code, 200)
        
        # Convert the json to python
        content = json.loads(response.content)
        
        # Check that all the interfaces are in the list
        self.assertEqual([interface['name'] for interface in content['objects']], ['TalkingDevice', 'CalendarSource'])
        
        # Check that the number of interfaces in the list is 2
        self.assertEqual(len(content['objects']), 2)
    
    def test_good_interface_get_detail(self):
        name = 'TalkingDevice'
        
        # Check that the interface actually exists in the database
        self.assertTrue(Interface.objects.filter(name=name).exists())
        
        # Get the information related to one interface
        response = self.client.get('/api/v2/interface/' + name + '/')
        
        # Check that the response code is 200 OK
        self.assertEqual(response.status_code, 200)
        
        # Check that the values are correct
        content = json.loads(response.content)
        self.assertEqual(content['created_at'], '2011-12-22T16:21:43.834112')
        self.assertEqual(content['name'], 'TalkingDevice')
        self.assertEqual(content['resource_uri'], '/api/v2/interface/TalkingDevice/')
        self.assertEqual(content['updated_at'], '2011-12-22T23:49:03.998318')
    
    def test_bad_interface_get_details(self):
        name = 'SingingDevice'
        
        # Check that the device does not exist in the database
        self.assertFalse(Interface.objects.filter(name=name).exists())
        
        # Issue a get request on a non-existent interface
        response = self.client.get('/api/v2/interface/' + name + '/')
        
        # Check that the response code is 404 Not Found
        self.assertEqual(response.status_code, 404)
    
    def test_bad_interface_update(self):
        name = 'TalkingDevice'
        
        # Check that the device actually exists in the database
        self.assertTrue(Interface.objects.filter(name=name).exists())
        
        # The interface data to be updated
        payload = json.dumps({'name': 'SingingDevice'})
        
        # Issue a PUT request in order to update the interface
        response = self.client.put('/api/v2/interface/' + name + '/', payload, 'application/json')
        
        # Check that the response is 405 Method Not Allowed
        self.assertEqual(response.status_code, 405)
class ActionFileAPITestCase(TestCase):
    fixtures = ['action_file_api_testdata']
    
    def setUp(self):
        self.old_setting = settings.PROXIMITY_SERVER['default']
        settings.PROXIMITY_SERVER['default'] = settings.PROXIMITY_SERVER['test']
        self.proximity_client = ProximityClient()
        self.proximity_client.flush()
        
    def tearDown(self):
        settings.PROXIMITY_SERVER['default'] = self.old_setting
    
    def test_good_upload(self, MirriMockClass):
        # Check the initial amount of actions in the database
        self.assertEqual(Action.objects.count(), 1)
        
        # Check the initial amount of action devices in the database
        self.assertEqual(ActionDevice.objects.count(), 2)
        
        # Check the initial amount of action device interfaces in the database
        self.assertEqual(ActionDeviceInterface.objects.count(), 2)
        
        # Check the initial amount of action precondition methods in the database
        self.assertEqual(ActionPreconditionMethod.objects.count(), 3)
        
        
        # TalkingDevice - Dialog
        f = open('core/fixtures/talkingDevices/dialog.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.seek(0)
        action_code = f.read()
        f.close()
        
        self.assertEqual(response.status_code, 201)
        
        self.assertTrue(Action.objects.filter(name='Dialog', precondition_expression='(? and ? and ?)').exists())
        self.assertTrue(ActionDevice.objects.filter(action__name='Dialog', name='d1', parameter_position=0).exists())
        self.assertTrue(ActionDevice.objects.filter(action__name='Dialog', name='d2', parameter_position=1).exists())
        self.assertTrue(ActionDeviceInterface.objects.filter(action_device__action__name='Dialog', action_device__name='d1', interface__name='TalkingDevice').exists())
        self.assertTrue(ActionDeviceInterface.objects.filter(action_device__action__name='Dialog', action_device__name='d2', interface__name='TalkingDevice').exists())
        self.assertTrue(ActionPreconditionMethod.objects.filter(expression_position=0, action__name='Dialog', action_device__name='d1', method__name='isWilling').exists())
        self.assertTrue(ActionPreconditionMethod.objects.filter(expression_position=1, action__name='Dialog', action_device__name='d2', method__name='isWilling').exists())
        self.assertTrue(ActionPreconditionMethod.objects.filter(expression_position=2, action__name='Dialog', action_device__name='d1', method__name='isSilent').exists())
        
        # Check that the file was uploaded to Mirri
        mirri_mock = MirriMockClass.return_value
        self.assertEqual(mirri_mock.upload_action_file.call_count, 1)
        self.assertEqual(len(mirri_mock.upload_action_file.call_args[0]), 1)
        mirri_mock.upload_action_file.call_args[0][0].seek(0)
        self.assertEqual(mirri_mock.upload_action_file.call_args[0][0].read(), action_code)
        
        
        # TalkingDevice - ConversationOfThree
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/conversationOfThree.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.seek(0)
        action_code = f.read()
        f.close()
        
        self.assertEqual(response.status_code, 201)
        
        self.assertTrue(Action.objects.filter(name='ConversationOfThree', precondition_expression='(? and ? and ? and ?)').exists())
        self.assertTrue(ActionDevice.objects.filter(action__name='ConversationOfThree', name='d1', parameter_position=0).exists())
        self.assertTrue(ActionDevice.objects.filter(action__name='ConversationOfThree', name='d2', parameter_position=1).exists())
        self.assertTrue(ActionDevice.objects.filter(action__name='ConversationOfThree', name='d3', parameter_position=2).exists())
        self.assertTrue(ActionDeviceInterface.objects.filter(action_device__action__name='ConversationOfThree', action_device__name='d1', interface__name='TalkingDevice').exists())
        self.assertTrue(ActionDeviceInterface.objects.filter(action_device__action__name='ConversationOfThree', action_device__name='d2', interface__name='TalkingDevice').exists())
        self.assertTrue(ActionDeviceInterface.objects.filter(action_device__action__name='ConversationOfThree', action_device__name='d3', interface__name='TalkingDevice').exists())
        self.assertTrue(ActionPreconditionMethod.objects.filter(expression_position=0, action__name='ConversationOfThree', action_device__name='d1', method__name='isWilling').exists())
        self.assertTrue(ActionPreconditionMethod.objects.filter(expression_position=1, action__name='ConversationOfThree', action_device__name='d2', method__name='isWilling').exists())
        self.assertTrue(ActionPreconditionMethod.objects.filter(expression_position=2, action__name='ConversationOfThree', action_device__name='d3', method__name='isWilling').exists())
        self.assertTrue(ActionPreconditionMethod.objects.filter(expression_position=3, action__name='ConversationOfThree', action_device__name='d1', method__name='isSilent').exists())
        
        # Check that the file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_action_file.call_count, 1)
        self.assertEqual(len(mirri_mock.upload_action_file.call_args[0]), 1)
        mirri_mock.upload_action_file.call_args[0][0].seek(0)
        self.assertEqual(mirri_mock.upload_action_file.call_args[0][0].read(), action_code)
        
        
        # CalendarSource - Conversation
        mirri_mock.reset_mock()
        f = open('core/fixtures/calendarReminders/conversation.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.seek(0)
        action_code = f.read()
        f.close()
        
        self.assertEqual(response.status_code, 201)
        
        self.assertTrue(Action.objects.filter(name='Conversation', precondition_expression='(?)').exists())
        self.assertTrue(ActionDevice.objects.filter(action__name='Conversation', name='source', parameter_position=0).exists())
        self.assertTrue(ActionDevice.objects.filter(action__name='Conversation', name='d2', parameter_position=1).exists())
        self.assertTrue(ActionDevice.objects.filter(action__name='Conversation', name='d3', parameter_position=2).exists())
        self.assertTrue(ActionDeviceInterface.objects.filter(action_device__action__name='Conversation', action_device__name='source', interface__name='TalkingDevice').exists())
        self.assertTrue(ActionDeviceInterface.objects.filter(action_device__action__name='Conversation', action_device__name='source', interface__name='CalendarSource').exists())
        self.assertTrue(ActionDeviceInterface.objects.filter(action_device__action__name='Conversation', action_device__name='d2', interface__name='TalkingDevice').exists())
        self.assertTrue(ActionDeviceInterface.objects.filter(action_device__action__name='Conversation', action_device__name='d3', interface__name='TalkingDevice').exists())
        self.assertTrue(ActionPreconditionMethod.objects.filter(expression_position=0, action__name='Conversation', action_device__name='source', method__name='eventApproaching').exists())
        
        # Check that the file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_action_file.call_count, 1)
        self.assertEqual(len(mirri_mock.upload_action_file.call_args[0]), 1)
        mirri_mock.upload_action_file.call_args[0][0].seek(0)
        self.assertEqual(mirri_mock.upload_action_file.call_args[0][0].read(), action_code)
        
        
        # CalendarSource - FakeCall
        mirri_mock.reset_mock()
        f = open('core/fixtures/calendarReminders/fakeCall.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.seek(0)
        action_code = f.read()
        f.close()
        
        self.assertEqual(response.status_code, 201)
        
        self.assertTrue(Action.objects.filter(name='FakeCall', precondition_expression='(?)').exists())
        self.assertTrue(ActionDevice.objects.filter(action__name='FakeCall', name='d1', parameter_position=0).exists())
        self.assertTrue(ActionDevice.objects.filter(action__name='FakeCall', name='d2', parameter_position=1).exists())
        self.assertTrue(ActionDeviceInterface.objects.filter(action_device__action__name='FakeCall', action_device__name='d1', interface__name='TalkingDevice').exists())
        self.assertTrue(ActionDeviceInterface.objects.filter(action_device__action__name='FakeCall', action_device__name='d1', interface__name='CalendarSource').exists())
        self.assertTrue(ActionDeviceInterface.objects.filter(action_device__action__name='FakeCall', action_device__name='d2', interface__name='TalkingDevice').exists())
        self.assertTrue(ActionPreconditionMethod.objects.filter(expression_position=0, action__name='FakeCall', action_device__name='d1', method__name='eventApproaching').exists())
        
        # Check that the file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_action_file.call_count, 1)
        self.assertEqual(len(mirri_mock.upload_action_file.call_args[0]), 1)
        mirri_mock.upload_action_file.call_args[0][0].seek(0)
        self.assertEqual(mirri_mock.upload_action_file.call_args[0][0].read(), action_code)
        
        
        # Check the final amount of actions in the database
        self.assertEqual(Action.objects.count(), 5)
        
        # Check the final amount of action devices in the database
        self.assertEqual(ActionDevice.objects.count(), 12)
        
        # Check the final amount of action device interfaces in the database
        self.assertEqual(ActionDeviceInterface.objects.count(), 14)
        
        # Check the final amount of action precondition methods in the database
        self.assertEqual(ActionPreconditionMethod.objects.count(), 12)
        
        
    def test_bad_upload(self, MirriMockClass):
        # Check the initial amount of actions in the database
        self.assertEqual(Action.objects.count(), 1)
        
        # Check the initial amount of action devices in the database
        self.assertEqual(ActionDevice.objects.count(), 2)
        
        # Check the initial amount of action device interfaces in the database
        self.assertEqual(ActionDeviceInterface.objects.count(), 2)
        
        # Check the initial amount of action precondition methods in the database
        self.assertEqual(ActionPreconditionMethod.objects.count(), 3)
        
        
        # A syntax error in the action file
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_syntax_error.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['File dialog_syntax_error.py contains syntax errors (line 13, col 21): class Dialog(Action)\n'])
        
        # Check that no file was uploaded to Mirri
        mirri_mock = MirriMockClass.return_value
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The action file does not contain any actions
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_no_action.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_no_action.py: No action class with base class Action has been defined.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The action file does not contain an action precondition
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_no_action_precondition.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_no_action_precondition.py: No method with decorator @actionprecondition has been defined for action class Dialog.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The action precondition does not have any parameters
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_no_action_precondition_parameters.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_no_action_precondition_parameters.py: Precondition method precondition does not have any parameters.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The action precondition does not have a return statement
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_no_action_precondition_return.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_no_action_precondition_return.py: The precondition method precondition does not have a return statement.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The return statement in the action precondition does not contain a boolean expression
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_no_boolean_in_return.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_no_boolean_in_return.py: The return statement in the precondition method does not contain a boolean expression.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # No interfaces have been declared for the devices in the action precondition
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_no_action_device_interfaces.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_no_action_device_interfaces.py: Method hasInterface() has not been called in the return statement of the precondition method.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The return statement does not contain a valid boolean precondition expression
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_no_precondition_expression.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_no_precondition_expression.py: The return statement of the precondition method in class Dialog does not contain a valid boolean precondition expression consisting of precondition methods.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # An action device is not declared in the precondition parameters
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_no_device_parameter.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_no_device_parameter.py: Device d1 is not declared in the precondition parameters.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # A precondition method call is incorrect in the action precondition
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_precondition_method_call_error.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_precondition_method_call_error.py: The format of the precondition method call is incorrect (line 21, col 44): isWilling. The format should be <device>.<interface>.<precondition_method>.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # A device has not been declared any interfaces
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_device_without_interfaces.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_device_without_interfaces.py: No interfaces have been declared for device d1 with method hasInterface().'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # A device has not been declared any interfaces
        mirri_mock.reset_mock()
        f = open('core/fixtures/calendarReminders/invalid_files/conversation_device_interface_missing.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file conversation_device_interface_missing.py: Interface TalkingDevice has not been declared for device source with method hasInterface().'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The return statement in the action precondition contains a value other than 
        # a function call or a boolean expression
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_invalid_return.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_invalid_return.py: The boolean expression in the return statement of the action precondition method can only consist of function calls or nested boolean expressions.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The action file contains multiple actions
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_multiple_actions.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_multiple_actions.py: Multiple action classes with base class Action have been defined.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # The action precondition contains a duplicate parameter
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_duplicate_precondition_parameter.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_duplicate_precondition_parameter.py: Duplicate parameter d1 for precondition method precondition.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # A device has a duplicate interface
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_duplicate_device_interface.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action parse error in file dialog_duplicate_device_interface.py: Method hasInterface(\'TalkingDevice\') called multiple times for action device d1.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # An action already exists
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_action_exists.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action DialogTest already exists.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # A non-existent interface
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_non_existent_interface.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Interface TalkingDeviceTest does not exist.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        # A non-existent method
        mirri_mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/dialog_non_existent_method.py')
        response = self.client.post('/api/action_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Method isWillingTest does not exist for interface TalkingDevice.'])
        
        # Check that no file was uploaded to Mirri
        self.assertEqual(mirri_mock.upload_interface_file.call_count, 0)
        
        
        
        # Check the final amount of actions in the database
        self.assertEqual(Action.objects.count(), 1)
        
        # Check the final amount of action devices in the database
        self.assertEqual(ActionDevice.objects.count(), 2)
        
        # Check the final amount of action device interfaces in the database
        self.assertEqual(ActionDeviceInterface.objects.count(), 2)
        
        # Check the final amount of action precondition methods in the database
        self.assertEqual(ActionPreconditionMethod.objects.count(), 3)
Exemple #7
0
class DeviceAPITestCase(TestCase):
    fixtures = ['devices_testdata']

    def setUp(self):
        self.old_setting = settings.PROXIMITY_SERVER['default']
        settings.PROXIMITY_SERVER['default'] = settings.PROXIMITY_SERVER['test']
        self.proximity_client = ProximityClient()
        self.proximity_client.flush()
        
    def tearDown(self):
        settings.PROXIMITY_SERVER['default'] = self.old_setting
    
    def test_good_device_post(self):
        # Check the initial amount of devices in the database
        self.assertEqual(Device.objects.count(), 4)
        
        # The device data (mac_address, name)
        payload = json.dumps({'mac_address': 'aa:bb:cc:dd:ee:ff', 'name': 'Device one'})
        
        # Issue a POST request
        response = self.client.post('/api/v2/device/', payload, 'application/json')
        
        # Check that the response is 201 Created and that the location is correct
        self.assertEqual(response.status_code, 201)
        self.assertEqual(response['Location'], 'http://testserver/api/v2/device/aa:bb:cc:dd:ee:ff/')
        
        # Check the final amount of devices in the database
        self.assertEqual(Device.objects.count(), 5)
    
    def test_bad_device_posts(self):
        # Check the initial amount of devices in the database
        self.assertEqual(Device.objects.count(), 4)
        
        
        # Send post without data and check that the response is 400 Bad Request
        response = self.client.post('/api/v2/device/', content_type='application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['__all__'], 'Missing data')
        
        
        # Send post without mac address and check that the response is 400 Bad Request
        payload = json.dumps({'name': 'Device one'})
        response = self.client.post('/api/v2/device/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        
        
        # Send post without name and check that the response is 400 Bad Request
        payload = json.dumps({'mac_address': 'aa:bb:cc:dd:ee:ff'})
        response = self.client.post('/api/v2/device/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['name'], 'Device name is a required field')
        
        
        # Send junk data and check that the response is 400 Bad Request
        payload = json.dumps({'foo': 'bar'})
        response = self.client.post('/api/v2/device/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['mac_address'], 'Mac address is a required field')
        self.assertEqual(content['name'], 'Device name is a required field')
        
        
        # Send post with invalid mac address and check that the response is 400 Bad Request
        payload = json.dumps({'mac_address': 'aa:bb:cc:aa:ee:ff:tt', 'name': 'Device one'})
        response = self.client.post('/api/v2/device/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['mac_address'], 'Mac address format is incorrect')
        
        
        # Send post with a mac address that already exists in the database
        self.assertTrue(Device.objects.filter(mac_address='aa:aa:aa:aa:aa:aa').exists())
        payload = json.dumps({'mac_address': 'aa:aa:aa:aa:aa:aa', 'name': 'Device one'})
        response = self.client.post('/api/v2/device/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['mac_address'], 'Duplicate mac address. Mac address aa:aa:aa:aa:aa:aa already exists.')
        
        
        # Send post with empty name
        payload = json.dumps({'mac_address': 'aa:bb:cc:dd:ee:ff', 'name': ''})
        response = self.client.post('/api/v2/device/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['name'], 'Device name cannot be an empty string')
        
        # Check the amount of devices in the database is the same as in the beginning
        self.assertEqual(Device.objects.count(), 4)
        
    
    def test_good_device_delete(self):
        # Check the initial amount of devices in the database
        self.assertEqual(Device.objects.count(), 4)
        
        mac_address = 'aa:aa:aa:aa:aa:aa'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Issue a DELETE request
        response = self.client.delete('/api/v2/device/' + mac_address + '/')
        
        # Check that the response is 204 No Content
        self.assertEqual(response.status_code, 204)
        
        # Check that the device does not exist in the database anymore
        self.assertFalse(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check the final amount of devices in the database
        self.assertEqual(Device.objects.count(), 3)
    
    
    def test_bad_device_deletes(self):
        # Check the initial amount of devices in the database
        self.assertEqual(Device.objects.count(), 4)
        
        # Ensure that the deletion of a non-existent device throws 404 Not Found
        mac_address = 'ff:ff:ff:ff:ff:ff'
        self.assertFalse(Device.objects.filter(mac_address=mac_address).exists())
        response = self.client.delete('/api/v2/device/' + mac_address + '/')
        self.assertEqual(response.status_code, 404)
        
        
        # The deletion of all devices should throw 405 Method Not Allowed
        response = self.client.delete('/api/v2/device/')
        self.assertEqual(response.status_code, 405)
        
        
        # Check the amount of devices in the database is the same as in the beginning
        self.assertEqual(Device.objects.count(), 4)
    
    def test_good_device_get_list(self):
        # Check the initial amount of devices in the database
        self.assertEqual(Device.objects.count(), 4)
        
        # Get a list of devices including their information
        response = self.client.get('/api/v2/device/')
        
        # Check that the response code is 200 OK
        self.assertEqual(response.status_code, 200)
        
        # Convert the json to python
        content = json.loads(response.content)
        
        # Check that all the devices are in the list
        self.assertEqual([device['mac_address'] for device in content['objects']], ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb', 'cc:cc:cc:cc:cc:cc', 'dd:dd:dd:dd:dd:dd'])
        
        # Check that the number of devices in the list is 4
        # (the amount of devices in the fixture)
        self.assertEqual(len(content['objects']), 4)
        
    def test_good_device_get_detail(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Get the information related to one device
        response = self.client.get('/api/v2/device/' + mac_address + '/')
        
        # Check that the response code is 200 OK
        self.assertEqual(response.status_code, 200)
        
        # Check that the values are correct
        content = json.loads(response.content)
        self.assertEqual(content['created_at'], '2011-12-19T16:21:43.834112')
        self.assertFalse(content['is_reserved'])
        self.assertEqual(content['mac_address'], 'aa:aa:aa:aa:aa:aa')
        self.assertEqual(content['name'], 'Device one')
        self.assertEqual(content['proximity_devices'], [])
        self.assertEqual(content['resource_uri'], '/api/v2/device/aa:aa:aa:aa:aa:aa/')
        self.assertEqual(content['updated_at'], '2011-12-20T12:49:03.998318')
        
    
    def test_bad_device_get_details(self):
        mac_address = 'ff:ff:ff:ff:ff:ff'
        
        # Check that the device does not exist in the database
        self.assertFalse(Device.objects.filter(mac_address=mac_address).exists())
        
        # Issue a get request on a non-existent device
        response = self.client.get('/api/v2/device/' + mac_address + '/')
        
        # Check that the response code is 404 Not Found
        self.assertEqual(response.status_code, 404)
    
    def test_good_device_updates(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Send a put request to update is_reserved to True
        response = self.client.get('/api/v2/device/' + mac_address + '/')
        self.assertEqual(response.status_code, 200)
        content = json.loads(response.content)
        self.assertFalse(content['is_reserved'])
        payload = json.dumps({'is_reserved': True})
        response = self.client.put('/api/v2/device/' + mac_address + '/', payload, 'application/json')
        self.assertEqual(response.status_code, 204)
        response = self.client.get('/api/v2/device/' + mac_address + '/')
        self.assertEqual(response.status_code, 200)
        content = json.loads(response.content)
        self.assertTrue(content['is_reserved'])
        
        
        # Send a put request to update the device name
        response = self.client.get('/api/v2/device/' + mac_address + '/')
        self.assertEqual(response.status_code, 200)
        content = json.loads(response.content)
        self.assertEqual(content['name'], 'Device one')
        payload = json.dumps({'name': 'Test device'})
        response = self.client.put('/api/v2/device/' + mac_address + '/', payload, 'application/json')
        self.assertEqual(response.status_code, 204)
        response = self.client.get('/api/v2/device/' + mac_address + '/')
        self.assertEqual(response.status_code, 200)
        content = json.loads(response.content)
        self.assertEqual(content['name'], 'Test device')
        
        
        # TODO: update proximity devices
    
    def test_bad_device_updates(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Send a put request to update the device mac address
        payload = json.dumps({'mac_address': 'aa:bb:cc:dd:ee:ff'})
        response = self.client.put('/api/v2/device/' + mac_address + '/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['mac_address'], 'Mac address cannot be updated')
        
        
        # Send a put request to update the created_at field
        payload = json.dumps({'created_at': '2011-12-22T16:21:43.834112'})
        response = self.client.put('/api/v2/device/' + mac_address + '/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['created_at'], 'Created at cannot be updated')
        
        
        # Send a put request to update the updated_at field
        payload = json.dumps({'updated_at': '2011-12-22T16:21:43.834112'})
        response = self.client.put('/api/v2/device/' + mac_address + '/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['updated_at'], 'Updated at cannot be updated')
        
        
        # Send a put request to update a non-existent device
        payload = json.dumps({'is_reserved': True})
        response = self.client.put('/api/v2/device/aa:bb:cc:dd:ee:ff/', payload, 'application/json')
        self.assertEqual(response.status_code, 404)
class ScheduleFileAPITestCase(TestCase):
    fixtures = ['schedule_file_api_testdata']
    
    def setUp(self):
        self.old_setting = settings.PROXIMITY_SERVER['default']
        settings.PROXIMITY_SERVER['default'] = settings.PROXIMITY_SERVER['test']
        self.proximity_client = ProximityClient()
        self.proximity_client.flush()
        
    def tearDown(self):
        settings.PROXIMITY_SERVER['default'] = self.old_setting
    
    def test_good_upload(self, MockClass):
        # Check the initial amount of schedules in the database
        self.assertEqual(Schedule.objects.count(), 1)
        
        # Check the initial amount of schedule actions in the database
        self.assertEqual(ScheduleAction.objects.count(), 2)
        
        
        # talkingDevicesSCH
        f = open('core/fixtures/talkingDevices/talkingDevicesSCH.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 201)
        
        self.assertTrue(Schedule.objects.filter(name='talkingDevicesSCH', trigger__method__interface__name='TalkingDevice', trigger__method__name='isSilent').exists())
        self.assertTrue(ScheduleAction.objects.filter(schedule__name='talkingDevicesSCH', action__name='Dialog', trigger_device__action__name='Dialog', trigger_device__parameter_position=0).exists())
        self.assertTrue(ScheduleAction.objects.filter(schedule__name='talkingDevicesSCH', action__name='ConversationOfThree', trigger_device__action__name='ConversationOfThree', trigger_device__parameter_position=0).exists())
        
        # Check that the upload of the schedule file triggered a signal
        # to generate the configuration model in a thread
        self.assertEqual(MockClass.call_count, 1)
        self.assertEqual(MockClass.call_args[0][0].name, 'talkingDevicesSCH')
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 1)
        
        
        # calendarReminderSCH
        MockClass.reset_mock()
        mock.reset_mock()
        f = open('core/fixtures/calendarReminders/calendarReminderSCH.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 201)
        
        self.assertTrue(Schedule.objects.filter(name='calendarReminder', trigger__method__interface__name='CalendarSource', trigger__method__name='eventApproaching').exists())
        self.assertTrue(ScheduleAction.objects.filter(schedule__name='calendarReminder', action__name='Conversation', trigger_device__action__name='Conversation', trigger_device__parameter_position=0).exists())
        self.assertTrue(ScheduleAction.objects.filter(schedule__name='calendarReminder', action__name='FakeCall', trigger_device__action__name='FakeCall', trigger_device__parameter_position=0).exists())
        
        # Check that the upload of the schedule file triggered a signal
        # to generate the configuration model in a thread
        self.assertEqual(MockClass.call_count, 1)
        self.assertEqual(MockClass.call_args[0][0].name, 'calendarReminder')
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 1)
        
        
        # Check the final amount of schedules in the database
        self.assertEqual(Schedule.objects.count(), 3)
        
        # Check the final amount of schedule actions in the database
        self.assertEqual(ScheduleAction.objects.count(), 6)
    
    def test_bad_upload(self, MockClass):
        # Check the initial amount of schedules in the database
        self.assertEqual(Schedule.objects.count(), 1)
        
        # Check the initial amount of schedule actions in the database
        self.assertEqual(ScheduleAction.objects.count(), 2)
        
        
        # A syntax error in the schedule file
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevicesSCH_syntax_error.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['File talkingDevicesSCH_syntax_error.py contains syntax errors (line 16, col 39): def talkingDevicesSCH(triggeringEvent)\n'])
        
        # Check that the configuration model generator thread is not started
        self.assertEqual(MockClass.call_count, 0)
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 0)
        
        
        # The schedule file does not contain any schedules
        MockClass.reset_mock()
        mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevicesSCH_no_schedule.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Schedule parse error in file talkingDevicesSCH_no_schedule.py: No schedule function with decorator @schedulingFunction has been defined.'])
        
        # Check that the configuration model generator thread is not started
        self.assertEqual(MockClass.call_count, 0)
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 0)
        
        
        # The schedule file does not contain any schedule actions
        MockClass.reset_mock()
        mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevicesSCH_no_schedule_actions.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Schedule parse error in file talkingDevicesSCH_no_schedule_actions.py: The schedule function does not contain any actions.'])
        
        # Check that the configuration model generator thread is not started
        self.assertEqual(MockClass.call_count, 0)
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 0)
        
        
        # The schedule file does not contain a trigger method for the schedule
        MockClass.reset_mock()
        mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevicesSCH_no_trigger.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Schedule parse error in file talkingDevicesSCH_no_trigger.py: No trigger method defined for the schedule with scheduling.addSchedule() in __main__.'])
        
        # Check that the configuration model generator thread is not started
        self.assertEqual(MockClass.call_count, 0)
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 0)
        
        
        # The schedule file does not contain an interface for the trigger method of the schedule
        MockClass.reset_mock()
        mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevicesSCH_no_trigger_interface.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Schedule parse error in file talkingDevicesSCH_no_trigger_interface.py: The trigger method has not been imported from an interface module.'])
        
        # Check that the configuration model generator thread is not started
        self.assertEqual(MockClass.call_count, 0)
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 0)
        
        
        # The schedule function does not have a return statement
        MockClass.reset_mock()
        mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevicesSCH_no_return.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Schedule parse error in file talkingDevicesSCH_no_return.py: The schedule function talkingDevicesSCH does not have a return statement.'])
        
        # Check that the configuration model generator thread is not started
        self.assertEqual(MockClass.call_count, 0)
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 0)
        
        
        # The return statement of the schedule function does not contain a list
        MockClass.reset_mock()
        mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevicesSCH_no_return_list.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Schedule parse error in file talkingDevicesSCH_no_return_list.py: The return statement of the schedule function does not contain a list.'])
        
        # Check that the configuration model generator thread is not started
        self.assertEqual(MockClass.call_count, 0)
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 0)
        
        
        # The return statement of the schedule function does not contain a list of variables
        MockClass.reset_mock()
        mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevicesSCH_no_return_list_variables.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Schedule parse error in file talkingDevicesSCH_no_return_list_variables.py: The list in the return statement of the schedule function does not have variable names as list members.'])
        
        # Check that the configuration model generator thread is not started
        self.assertEqual(MockClass.call_count, 0)
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 0)
        
        
        # The schedule contains a duplicate action
        MockClass.reset_mock()
        mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevicesSCH_duplicate_action.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Schedule parse error in file talkingDevicesSCH_duplicate_action.py: Duplicate schedule action Dialog.'])
        
        # Check that the configuration model generator thread is not started
        self.assertEqual(MockClass.call_count, 0)
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 0)
        
        
        # A schedule already exists
        MockClass.reset_mock()
        mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevicesSCH_schedule_exists.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Schedule talkingDevicesSCHTest already exists.'])
        
        # Check that the configuration model generator thread is not started
        self.assertEqual(MockClass.call_count, 0)
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 0)
        
        
        # Trigger method does not exist
        MockClass.reset_mock()
        mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevicesSCH_non_existent_trigger.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Trigger method isSilentTest does not exist for interface TalkingDevice.'])
        
        # Check that the configuration model generator thread is not started
        self.assertEqual(MockClass.call_count, 0)
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 0)
        
        
        # Action does not exist
        MockClass.reset_mock()
        mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevicesSCH_non_existent_action.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Action DialogTest does not exist.'])
        
        # Check that the configuration model generator thread is not started
        self.assertEqual(MockClass.call_count, 0)
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 0)
        
        
        # Action device does not exist for a specific trigger from position
        MockClass.reset_mock()
        mock.reset_mock()
        f = open('core/fixtures/talkingDevices/invalid_files/talkingDevicesSCH_non_existent_action_device.py')
        response = self.client.post('/api/schedule_file/', {'file': f})
        f.close()
        
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['file'], ['Trigger from position 2 does not correspond to any valid action device position in action Dialog.'])
        
        # Check that the configuration model generator thread is not started
        self.assertEqual(MockClass.call_count, 0)
        mock = MockClass.return_value
        self.assertEqual(mock.start.call_count, 0)
        
        
        
        # Check the final amount of schedules in the database
        self.assertEqual(Schedule.objects.count(), 1)
        
        # Check the final amount of schedule actions in the database
        self.assertEqual(ScheduleAction.objects.count(), 2)
class DeviceStateValueAPITestCase(TestCase):
    fixtures = ['devices_testdata']
    
    def setUp(self):
        self.old_setting = settings.PROXIMITY_SERVER['default']
        settings.PROXIMITY_SERVER['default'] = settings.PROXIMITY_SERVER['test']
        self.proximity_client = ProximityClient()
        self.proximity_client.flush()
        
    def tearDown(self):
        settings.PROXIMITY_SERVER['default'] = self.old_setting
    
    def test_good_device_statevalue_post(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TalkingDevice'
        method_name = 'isSilent'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check that the device interface actually exists
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        
        # Check that the method exists for the interface
        self.assertTrue(Method.objects.filter(interface__name=interface_name, name='isSilent').exists())
        
        # Check the initial amount of state values for the device in the database
        self.assertEqual(StateValue.objects.filter(device__mac_address=mac_address).count(), 2)
        
        # The state value data without arguments
        payload = json.dumps({'method_name': method_name, 'value': False})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 201)
        self.assertEqual(response['Location'], 'http://testserver/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        
        
        interface_name = 'CalendarSource'
        method_name = 'eventApproaching'
        
        # The state value data with arguments
        payload = json.dumps({'method_name': method_name, 'arguments': {'eid': '1234'}, 'value': False})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 201)
        self.assertEqual(response['Location'], 'http://testserver/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        
        
        interface_name = 'ScreenDevice'
        method_name = 'screenAvailable'
        
        # The state value data with an empty argument dictionary
        payload = json.dumps({'method_name': method_name, 'arguments': {}, 'value': False})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 201)
        self.assertEqual(response['Location'], 'http://testserver/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        
        
        # Check the final amount of state values for the device in the database
        self.assertEqual(StateValue.objects.filter(device__mac_address=mac_address).count(), 5)
        
    def test_bad_device_statevalue_posts(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TalkingDevice'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check that the device interface actually exists
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        
        # Check that the method exists for the interface
        self.assertTrue(Method.objects.filter(interface__name=interface_name, name='isSilent').exists())
        
        # Check the initial amount of state values for the device in the database
        self.assertEqual(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name).count(), 1)
        
        
        # Send post without data and check that the response is 400 Bad Request
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/', content_type='application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['method_name'], 'Method name is a required field')
        self.assertEqual(content['value'], 'Value is a required field')
        
        
        # Send post without method name and check that the response is 400 Bad Request
        payload = json.dumps({'value': False})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['method_name'], 'Method name is a required field')
        
        
        # Send post without value and check that the response is 400 Bad Request
        payload = json.dumps({'method_name': 'isSilent'})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['value'], 'Value is a required field')
        
        
        # Send junk data and check that the response is 400 Bad Request
        payload = json.dumps({'foo': 'bar'})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['method_name'], 'Method name is a required field')
        self.assertEqual(content['value'], 'Value is a required field')
        
        
        # Send post with non-existent method name and check that the response is 400 Bad Request
        payload = json.dumps({'method_name': 'fooBarMethod', 'value': False})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['method_name'], 'Method fooBarMethod does not exist.')
        
        
        # Send post with empty method name
        payload = json.dumps({'method_name': '', 'value': False})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['method_name'], 'Method name cannot be an empty string')
        
        
        # Send post without arguments for a state value that requires arguments
        payload = json.dumps({'method_name': 'eventApproaching', 'value': False})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/CalendarSource/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['arguments'], 'eid is missing from arguments.')
        
        
        # Send post with arguments for a state value that does not require any arguments
        payload = json.dumps({'method_name': 'isWilling', 'arguments': {'eid': '1234'}, 'value': False})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['arguments'], 'Method isWilling does not accept eid as an argument.')
        
        
        # Send post with extra arguments (same as the above)
        payload = json.dumps({'method_name': 'eventApproaching', 'arguments': {'eid': '1234', 'test': '12345'}, 'value': False})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/CalendarSource/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['arguments'], 'Method eventApproaching does not accept test as an argument.')
        
        
        # Send post for non-existent device
        payload = json.dumps({'method_name': 'isSilent', 'value': False})
        response = self.client.post('/api/v2/device/aa:bb:cc:dd:ee:ff/interface/' + interface_name + '/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 404)
        content = json.loads(response.content)
        self.assertEqual(content['error_message'], 'Sorry, this request could not be processed. Please try again later.')
        
        
        # Send post for non-existent interface
        payload = json.dumps({'method_name': 'isSilent', 'value': False})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/fooBarInterface/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 404)
        content = json.loads(response.content)
        self.assertEqual(content['error_message'], 'Sorry, this request could not be processed. Please try again later.')
        
        
        # Send post with a state value that already exists for the specific device in the database
        self.assertTrue(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name='TalkingDevice', method__name='isWilling').exists())
        payload = json.dumps({'method_name': 'isWilling', 'value': False})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['method_name'], 'Duplicate method. Device aa:aa:aa:aa:aa:aa has already added a value for method isWilling in interface TalkingDevice.')
        
        
        # Send post for interface that exists, but is not bound with the device
        self.assertTrue(Interface.objects.filter(name='CalendarDevice').exists())
        payload = json.dumps({'method_name': 'hasEvents', 'value': False})
        response = self.client.post('/api/v2/device/' + mac_address + '/interface/CalendarDevice/method/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['method_name'], 'Device aa:aa:aa:aa:aa:aa does not have the appropriate interface for being able to store a state value for method hasEvents.')
        
        # Check the final amount of state values for the device in the database
        self.assertEqual(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name).count(), 1)
        
    def test_good_device_statevalue_delete(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TalkingDevice'
        method_name = 'isWilling'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check that the device interface actually exists
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        
        # Check that the method exists for the interface
        self.assertTrue(Method.objects.filter(interface__name=interface_name, name=method_name).exists())
        
        # Check the initial amount of state values for the device in the database
        self.assertEqual(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name).count(), 1)
        
        # Check that the state value actually exists in the database
        self.assertTrue(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name, method__name=method_name).exists())
        
        # Issue a DELETE request
        response = self.client.delete('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        
        # Check that the response is 204 No Content
        self.assertEqual(response.status_code, 204)
        
        # Check that the state value does not exist in the database anymore
        self.assertFalse(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name, method__name=method_name).exists())
        
        # Check the final amount of state values for the device in the database
        self.assertEqual(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name).count(), 0)
        
        # TODO: cascade check
    
    def test_bad_device_statevalue_deletes(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TalkingDevice'
        method_name = 'isWilling'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check that the device interface actually exists
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        
        # Check that the method exists for the interface
        self.assertTrue(Method.objects.filter(interface__name=interface_name, name=method_name).exists())
        
        # Check the initial amount of state values for the device in the database
        self.assertEqual(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name).count(), 1)
        
        
        # Ensure that the deletion of a non-existent state value throws 404 Not Found
        self.assertFalse(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name, method__name='fooBarMethod').exists())
        response = self.client.delete('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/fooBarMethod/')
        self.assertEqual(response.status_code, 404)
        
        
        # Ensure that the deletion of a state value of a non-existent device throws 404 Not Found
        self.assertFalse(Device.objects.filter(mac_address='aa:bb:cc:dd:ee:ff').exists())
        response = self.client.delete('/api/v2/device/aa:bb:cc:dd:ee:ff/interface/' + interface_name + '/method/' + method_name + '/')
        self.assertEqual(response.status_code, 404)
        
        
        # Ensure that the deletion of a state value of a non-existent interface throws 404 Not Found
        self.assertFalse(Interface.objects.filter(name='FooBarInterface').exists())
        response = self.client.delete('/api/v2/device/' + mac_address + '/interface/FooBarInterface/method/' + method_name + '/')
        self.assertEqual(response.status_code, 404)
        
        
        # The deletion of all device state values should throw 405 Method Not Allowed
        response = self.client.delete('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/')
        self.assertEqual(response.status_code, 405)
        
        
        # Check that the final amount of state values that the device has in the database is the same as in the beginning
        self.assertEqual(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name).count(), 1)
    
    
    def test_good_device_statevalue_get_list(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TalkingDevice'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check that the device interface actually exists
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        
        # Check the initial amount of state values for the device in the database
        self.assertEqual(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name).count(), 1)
        
        # Get a list of devices including their information
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/')
        
        # Check that the response code is 200 OK
        self.assertEqual(response.status_code, 200)
        
        # Convert the json to python
        content = json.loads(response.content)
        
        # Check that all the state values of the device are in the list
        self.assertEqual([statevalue['method_name'] for statevalue in content['objects']], ['isWilling'])
        
        # Check that the number of state values in the list is 1
        self.assertEqual(len(content['objects']), 1)
        
    
    def test_good_device_statevalue_get_detail(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TalkingDevice'
        method_name = 'isWilling'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check that the device interface actually exists
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        
        # Check that the method exists for the interface
        self.assertTrue(Method.objects.filter(interface__name=interface_name, name=method_name).exists())
        
        # Check that the state value actually exists in the database
        self.assertTrue(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name, method__name=method_name).exists())
        
        # Get the information related to one state value
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        
        # Check that the response code is 200 OK
        self.assertEqual(response.status_code, 200)
        
        # Check that the values are correct
        content = json.loads(response.content)
        self.assertEqual(content['arguments'], {})
        self.assertEqual(content['created_at'], '2011-12-20T17:10:41.314132')
        self.assertEqual(content['method_name'], 'isWilling')
        self.assertEqual(content['resource_uri'], '/api/v2/device/aa:aa:aa:aa:aa:aa/interface/TalkingDevice/method/isWilling/')
        self.assertEqual(content['updated_at'], '2011-12-20T17:10:41.314132')
        self.assertEqual(content['value'], 'False')
        
        
        
        interface_name = 'ScreenDevice'
        method_name = 'hasNext'
        
        # Check that the device interface actually exists
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        
        # Check that the method exists for the interface
        self.assertTrue(Method.objects.filter(interface__name=interface_name, name=method_name).exists())
        
        # Check that the state value actually exists in the database
        self.assertTrue(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name, method__name=method_name).exists())
        
        # Get the information related to one state value
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        
        # Check that the response code is 200 OK
        self.assertEqual(response.status_code, 200)
        
        # Check that the values are correct
        content = json.loads(response.content)
        self.assertEqual(content['arguments'], {'screenId': '1234'})
        self.assertEqual(content['created_at'], '2011-12-20T17:10:41.314132')
        self.assertEqual(content['method_name'], 'hasNext')
        self.assertEqual(content['resource_uri'], '/api/v2/device/aa:aa:aa:aa:aa:aa/interface/ScreenDevice/method/hasNext/')
        self.assertEqual(content['updated_at'], '2011-12-20T17:10:41.314132')
        self.assertEqual(content['value'], 'False')
    
    def test_bad_device_statevalue_get_details(self):
        
        # Get a state value for a non-existent interface method
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TalkingDevice'
        method_name = 'fooBarMethod'
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        self.assertFalse(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name, method__name=method_name).exists())
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        self.assertEqual(response.status_code, 404)
        
        
        # Get a state value for a non-existent device
        mac_address = 'aa:bb:cc:dd:ee:ff'
        interface_name = 'TalkingDevice'
        method_name = 'isWilling'
        self.assertFalse(Device.objects.filter(mac_address=mac_address).exists())
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        self.assertEqual(response.status_code, 404)
        
        
        # Get a state value for a non-existent interface
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'FooBarInterface'
        method_name = 'isWilling'
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        self.assertFalse(Interface.objects.filter(name=interface_name).exists())
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        self.assertEqual(response.status_code, 404)
    
    
    def test_good_device_statevalue_update(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TalkingDevice'
        method_name = 'isWilling'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check that the device interface actually exists
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        
        # Check that the method exists for the interface
        self.assertTrue(Method.objects.filter(interface__name=interface_name, name=method_name).exists())
        
        # Check that the state value actually exists in the database
        self.assertTrue(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name, method__name=method_name).exists())
        
        
        # Send a put request to update the value of isWilling to True
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        self.assertEqual(response.status_code, 200)
        content = json.loads(response.content)
        self.assertEqual(content['value'], 'False')
        payload = json.dumps({'value': 'True'})
        response = self.client.put('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/', payload, 'application/json')
        self.assertEqual(response.status_code, 204)
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        self.assertEqual(response.status_code, 200)
        content = json.loads(response.content)
        self.assertEqual(content['value'], 'True')
        
        
        # Send a put request to update the value of isWilling to True with an empty argument dictionary
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        self.assertEqual(response.status_code, 200)
        content = json.loads(response.content)
        self.assertEqual(content['value'], 'True')
        payload = json.dumps({'arguments': {}, 'value': 'False'})
        response = self.client.put('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/', payload, 'application/json')
        self.assertEqual(response.status_code, 204)
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        self.assertEqual(response.status_code, 200)
        content = json.loads(response.content)
        self.assertEqual(content['value'], 'False')
        
        
        interface_name = 'ScreenDevice'
        method_name = 'hasNext'
        
        # Send a put request to update the value of eventApproaching to True with arguments
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        self.assertEqual(response.status_code, 200)
        content = json.loads(response.content)
        self.assertEqual(content['value'], 'False')
        self.assertEqual(content['arguments']['screenId'], '1234')
        payload = json.dumps({'arguments': {'screenId': '12345'}, 'value': 'True'})
        response = self.client.put('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/', payload, 'application/json')
        self.assertEqual(response.status_code, 204)
        response = self.client.get('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/')
        self.assertEqual(response.status_code, 200)
        content = json.loads(response.content)
        self.assertEqual(content['value'], 'True')
        self.assertEqual(content['arguments']['screenId'], '12345')
    
    
    def test_bad_device_statevalue_updates(self):
        mac_address = 'aa:aa:aa:aa:aa:aa'
        interface_name = 'TalkingDevice'
        method_name = 'isWilling'
        
        # Check that the device actually exists in the database
        self.assertTrue(Device.objects.filter(mac_address=mac_address).exists())
        
        # Check that the device interface actually exists
        self.assertTrue(DeviceInterface.objects.filter(device__mac_address=mac_address, interface__name=interface_name).exists())
        
        # Check that the method exists for the interface
        self.assertTrue(Method.objects.filter(interface__name=interface_name, name=method_name).exists())
        
        # Check that the state value actually exists in the database
        self.assertTrue(StateValue.objects.filter(device__mac_address=mac_address, method__interface__name=interface_name, method__name=method_name).exists())
        
        
        # Send a put request to update the method name
        payload = json.dumps({'method_name': 'fooBarMethod'})
        response = self.client.put('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['method_name'], 'Method name cannot be updated')
        
        
        # Send a put request to update the created_at field
        payload = json.dumps({'created_at': '2011-12-22T16:21:43.834112'})
        response = self.client.put('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['created_at'], 'Created at cannot be updated')
        
        
        # Send a put request to update the updated_at field
        payload = json.dumps({'updated_at': '2011-12-22T16:21:43.834112'})
        response = self.client.put('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['updated_at'], 'Updated at cannot be updated')
        
        
        # Send a put request without arguments for a state value that requires arguments
        payload = json.dumps({'value': False})
        response = self.client.put('/api/v2/device/' + mac_address + '/interface/ScreenDevice/method/hasNext/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['arguments'], 'screenId is missing from arguments.')
        
        
        # Send a put request with arguments for a state value that does not require any arguments
        payload = json.dumps({'arguments': {'eid': '1234'}, 'value': False})
        response = self.client.put('/api/v2/device/' + mac_address + '/interface/' + interface_name + '/method/' + method_name + '/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['arguments'], 'Method isWilling does not accept eid as an argument.')
        
        
        # Send a put request with extra arguments (same as the above)
        payload = json.dumps({'arguments': {'screenId': '1234', 'test': '12345'}, 'value': False})
        response = self.client.put('/api/v2/device/' + mac_address + '/interface/ScreenDevice/method/hasNext/', payload, 'application/json')
        self.assertEqual(response.status_code, 400)
        content = json.loads(response.content)
        self.assertEqual(content['arguments'], 'Method hasNext does not accept test as an argument.')