def test_list_devices_with_offset(self): request = device_messages.Device(page_size=1, page_number=1) response = self.service.list_devices(request) self.assertEqual(1, len(response.devices)) previouse_response = response # Get next page results and make sure it's not the same as last. request = device_messages.Device(page_size=1, page_number=2) response = self.service.list_devices(request) self.assertEqual(1, len(response.devices)) self.assertNotEqual(response, previouse_response)
def testListUserDeviceResponse(self): device1 = device_messages.Device(serial_number='FAKE-DEVICE-SERIAL-1') device2 = device_messages.Device(serial_number='FAKE-DEVICE-SERIAL-2') list_device_resp = device_messages.ListUserDeviceResponse( devices=[device1, device2]) self.assertEqual(list_device_resp.devices[0].serial_number, 'FAKE-DEVICE-SERIAL-1') self.assertEqual(list_device_resp.devices[1].serial_number, 'FAKE-DEVICE-SERIAL-2')
def test_list_devices_with_page_token(self): request = device_messages.Device(enrolled=True, page_size=1) response_devices = [] while True: response = self.service.list_devices(request) for device in response.devices: response_devices.append(device) request = device_messages.Device(enrolled=True, page_size=1, page_token=response.page_token) if not response.has_additional_results: break self.assertLen(response_devices, 2)
def testListDevicesResponse(self): device1 = device_messages.Device(serial_number='FAKE-DEVICE-SERIAL-1') device2 = device_messages.Device(serial_number='FAKE-DEVICE-SERIAL-2') list_device_resp = device_messages.ListDevicesResponse( devices=[device1, device2], has_additional_results=True, page_token='FAKE-PAGE-TOKEN') self.assertTrue(list_device_resp.has_additional_results) self.assertEqual(list_device_resp.devices[0].serial_number, 'FAKE-DEVICE-SERIAL-1') self.assertEqual(list_device_resp.devices[1].serial_number, 'FAKE-DEVICE-SERIAL-2') self.assertEqual(list_device_resp.page_token, 'FAKE-PAGE-TOKEN')
def test_list_devices_with_search_constraints(self): expressions = shared_messages.SearchExpression( expression='serial_number') expected_response = device_messages.ListDevicesResponse( devices=[device_messages.Device(serial_number='6789')], has_additional_results=False) request = device_messages.Device(query=shared_messages.SearchRequest( query_string='sn:6789', expressions=[expressions], returned_fields=['serial_number'])) response = self.service.list_devices(request) self.assertEqual(response.devices[0].serial_number, expected_response.devices[0].serial_number) self.assertFalse(response.has_additional_results)
def test_list_devices_with_search_constraints(self): expressions = shared_messages.SearchExpression( expression='serial_number') expected_response = device_messages.ListDevicesResponse( devices=[ device_messages.Device(serial_number='6789', guest_permitted=True) ], total_results=1, total_pages=1) request = device_messages.Device(query=shared_messages.SearchRequest( query_string='sn:6789', expressions=[expressions], returned_fields=['serial_number'])) response = self.service.list_devices(request) self.assertEqual(response, expected_response)
def test_build_device_message_from_model(self): """Test the construction of a device message from a device entity.""" test_device = device_model.Device( serial_number='test_serial_value', asset_tag='test_asset_tag_value', enrolled=True, device_model='test model value', due_date=datetime.datetime(year=2018, month=1, day=1), last_known_healthy=datetime.datetime(year=2018, month=1, day=2), shelf=self.test_shelf_model.key, assigned_user='******', assignment_date=datetime.datetime(year=2018, month=1, day=3), current_ou=constants.ORG_UNIT_DICT['GUEST'], ou_changed_date=datetime.datetime(year=2018, month=1, day=4), locked=True, lost=False, mark_pending_return_date=datetime.datetime(year=2018, month=1, day=5), chrome_device_id='device id value', last_heartbeat=datetime.datetime(year=2018, month=1, day=6), damaged=None, damaged_reason='Not damaged', last_reminder=device_model.Reminder(level=1), next_reminder=device_model.Reminder(level=2), ).put().get() expected_message = device_messages.Device( serial_number='test_serial_value', asset_tag='test_asset_tag_value', identifier='test_asset_tag_value', enrolled=True, device_model='test model value', due_date=datetime.datetime(year=2018, month=1, day=1), last_known_healthy=datetime.datetime(year=2018, month=1, day=2), shelf=self.expected_shelf_message, assigned_user='******', assignment_date=datetime.datetime(year=2018, month=1, day=3), current_ou=constants.ORG_UNIT_DICT['GUEST'], ou_changed_date=datetime.datetime(year=2018, month=1, day=4), locked=True, lost=False, mark_pending_return_date=datetime.datetime(year=2018, month=1, day=5), chrome_device_id='device id value', last_heartbeat=datetime.datetime(year=2018, month=1, day=6), damaged=None, damaged_reason='Not damaged', last_reminder=device_messages.Reminder(level=1), next_reminder=device_messages.Reminder(level=2), guest_permitted=True, guest_enabled=True, max_extend_date=device_model.calculate_return_dates( test_device.assignment_date).max, overdue=True, ) actual_message = api_utils.build_device_message_from_model( test_device, True) self.assertEqual(actual_message, expected_message)
def testHistoryResponse(self): now = datetime.datetime.now() device1 = device_messages.Device(serial_number='FAKE-DEVICE-SERIAL-1') device2 = device_messages.Device(serial_number='FAKE-DEVICE-SERIAL-2') hist_resp = device_messages.HistoryResponse( devices=[device1, device2], timestamp=[now], actor=['FAKE-ACTOR-1'], summary=['FAKE-SUMMARY-1', 'FAKE-SUMMARY-2']) self.assertListEqual(hist_resp.timestamp, [now]) self.assertListEqual(hist_resp.actor, ['FAKE-ACTOR-1']) self.assertListEqual(hist_resp.summary, ['FAKE-SUMMARY-1', 'FAKE-SUMMARY-2']) self.assertEqual(hist_resp.devices[0].serial_number, 'FAKE-DEVICE-SERIAL-1') self.assertEqual(hist_resp.devices[1].serial_number, 'FAKE-DEVICE-SERIAL-2')
def build_device_message_from_model(device, guest_permitted): """Builds a device_messages.Device ProtoRPC message. Args: device: device_model.Device, a device entity to convert into a message. guest_permitted: bool, whether or not guest is permitted for this organization. Returns: A populated device_messages.Device ProtoRPC message. """ message = device_messages.Device( serial_number=device.serial_number, asset_tag=device.asset_tag, identifier=device.identifier, enrolled=device.enrolled, device_model=device.device_model, due_date=device.due_date, last_known_healthy=device.last_known_healthy, assigned_user=device.assigned_user, assignment_date=device.assignment_date, current_ou=device.current_ou, ou_changed_date=device.ou_changed_date, locked=device.locked, lost=device.lost, mark_pending_return_date=device.mark_pending_return_date, chrome_device_id=device.chrome_device_id, last_heartbeat=device.last_heartbeat, damaged=device.damaged, damaged_reason=device.damaged_reason, guest_enabled=device.guest_enabled, guest_permitted=guest_permitted, overdue=device.overdue, ) if device.last_reminder: message.last_reminder = build_reminder_message_from_model( device.last_reminder) if device.next_reminder: message.next_reminder = build_reminder_message_from_model( device.next_reminder) if device.is_assigned: message.max_extend_date = device.return_dates.max if device.shelf: message.shelf = build_shelf_message_from_model(device.shelf.get()) for tag_data in device.tags: tag_data_message = tag_messages.TagData() urlsafe_key = tag_model.Tag.get(tag_data.tag.name).key.urlsafe() tag_data_message.tag = tag_messages.Tag( name=tag_data.tag.name, hidden=tag_data.tag.hidden, color=tag_data.tag.color, protect=tag_data.tag.protect, description=tag_data.tag.description, urlsafe_key=urlsafe_key) tag_data_message.more_info = tag_data.more_info message.tags.append(tag_data_message) return message
def test_list_devices_with_shelf_filter(self, mock_get_shelf): # Test for shelf location as filter. mock_get_shelf.return_value = self.shelf shelf_request_message = shelf_messages.ShelfRequest( location=self.shelf.location) message = shelf_messages.Shelf(shelf_request=shelf_request_message) request = device_messages.Device(shelf=message) response = self.service.list_devices(request) mock_get_shelf.assert_called_once_with(shelf_request_message) self.assertEqual(len(response.devices), 2)
def test_list_devices_inactive_no_shelf(self): request = device_messages.Device(enrolled=False, page_size=1) response = self.service.list_devices(request) expected_response = device_messages.ListDevicesResponse( devices=[ device_messages.Device( serial_number=self.unenrolled_device.serial_number, identifier=self.unenrolled_device.serial_number, enrolled=self.unenrolled_device.enrolled, device_model=self.unenrolled_device.device_model, current_ou=self.unenrolled_device.current_ou, locked=self.unenrolled_device.locked, lost=self.unenrolled_device.lost, chrome_device_id=self.unenrolled_device.chrome_device_id, damaged=self.unenrolled_device.damaged, guest_permitted=True) ], has_additional_results=False) self.assertEqual(expected_response, response)
def test_list_devices_with_filter_message(self): message = device_messages.Device(enrolled=True, device_model='HP Chromebook 13 G1', current_ou='/') filters = api_utils.to_dict(message, device_model.Device) request = device_messages.Device(**filters) response = self.service.list_devices(request) expected_response = device_messages.ListDevicesResponse( devices=[ device_messages.Device(serial_number='6789', identifier='6789', enrolled=True, device_model='HP Chromebook 13 G1', current_ou='/', locked=False, lost=False, chrome_device_id='unique_id_2', damaged=False, guest_permitted=True) ], has_additional_results=False) self.assertEqual(response, expected_response)
def build_device_message_from_model(device, guest_permitted): """Builds a device_messages.Device ProtoRPC message. Args: device: device_model.Device, a device entity to convert into a message. guest_permitted: bool, whether or not guest is permitted for this organization. Returns: A populated device_messages.Device ProtoRPC message. """ message = device_messages.Device( serial_number=device.serial_number, asset_tag=device.asset_tag, identifier=device.identifier, enrolled=device.enrolled, device_model=device.device_model, due_date=device.due_date, last_known_healthy=device.last_known_healthy, assigned_user=device.assigned_user, assignment_date=device.assignment_date, current_ou=device.current_ou, ou_changed_date=device.ou_changed_date, locked=device.locked, lost=device.lost, mark_pending_return_date=device.mark_pending_return_date, chrome_device_id=device.chrome_device_id, last_heartbeat=device.last_heartbeat, damaged=device.damaged, damaged_reason=device.damaged_reason, guest_enabled=device.guest_enabled, guest_permitted=guest_permitted, overdue=device.overdue, ) if device.last_reminder: message.last_reminder = build_reminder_message_from_model( device.last_reminder) if device.next_reminder: message.next_reminder = build_reminder_message_from_model( device.next_reminder) if device.is_assigned: message.max_extend_date = device_model.calculate_return_dates( device.assignment_date).max if device.shelf: message.shelf = build_shelf_message_from_model(device.shelf.get()) return message
def list_devices(self, request): """Lists all devices based on any device attribute.""" self.check_xsrf_token(self.request_state) if request.page_size <= 0: raise endpoints.BadRequestException( 'The value for page_size must be greater than 0.') query, sort_options, returned_fields = ( search_utils.set_search_query_options(request.query)) if not query: shelf_query = '' if request.shelf: shelf_urlsafe_key = request.shelf.shelf_request.urlsafe_key if not shelf_urlsafe_key: shelf_urlsafe_key = shelf_api.get_shelf( request.shelf.shelf_request).key.urlsafe() request.shelf = None shelf_query = ':'.join(('shelf', shelf_urlsafe_key)) query = search_utils.to_query(request, device_model.Device) query = ' '.join((query, shelf_query)) offset = search_utils.calculate_page_offset( page_size=request.page_size, page_number=request.page_number) search_results = device_model.Device.search( query_string=query, query_limit=request.page_size, offset=offset, sort_options=sort_options, returned_fields=returned_fields) total_pages = search_utils.calculate_total_pages( page_size=request.page_size, total_results=search_results.number_found) guest_permitted = config_model.Config.get('allow_guest_mode') messages = [] for document in search_results.results: message = search_utils.document_to_message( document, device_messages.Device()) message.guest_permitted = guest_permitted messages.append(message) return device_messages.ListDevicesResponse( devices=messages, total_results=search_results.number_found, total_pages=total_pages)
def get_history(self, request): """Gets historical data for a given device.""" self.check_xsrf_token(self.request_state) client = bigquery.BigQueryClient() device = _get_device(request.device) serial = device.serial_number info = client.get_device_info(serial) if not info: raise endpoints.NotFoundException( 'No history for the requested serial number.') historical_device = device_messages.Device() response = device_messages.HistoryResponse() historical_device.asset_tag = info[0][5]['asset_tag'] for row in info: response.devices.append(historical_device) response.timestamp.append(row[1]) response.actor.append(row[2]) response.summary.append(row[4]) return response
def list_devices(self, request): """Lists all devices based on any device attribute.""" self.check_xsrf_token(self.request_state) query, sort_options, returned_fields = ( search_utils.set_search_query_options(request.query)) if not query: shelf_query = '' if request.shelf: shelf_urlsafe_key = request.shelf.shelf_request.urlsafe_key if not shelf_urlsafe_key: shelf_urlsafe_key = shelf_api.get_shelf( request.shelf.shelf_request).key.urlsafe() request.shelf = None shelf_query = ':'.join(('shelf', shelf_urlsafe_key)) query = search_utils.to_query(request, device_model.Device) query = ' '.join((query, shelf_query)) cursor = search_utils.get_search_cursor(request.page_token) search_results = device_model.Device.search( query_string=query, query_limit=request.page_size, cursor=cursor, sort_options=sort_options, returned_fields=returned_fields) new_search_cursor = None if search_results.cursor: new_search_cursor = search_results.cursor.web_safe_string guest_permitted = config_model.Config.get('allow_guest_mode') messages = [] for document in search_results.results: message = search_utils.document_to_message( document, device_messages.Device()) message.guest_permitted = guest_permitted if message.current_ou == constants.ORG_UNIT_DICT['GUEST']: message.guest_enabled = True messages.append(message) return device_messages.ListDevicesResponse( devices=messages, has_additional_results=bool(new_search_cursor), page_token=new_search_cursor)
def test_list_devices_invalid_page_size(self): with self.assertRaises(endpoints.BadRequestException): request = device_messages.Device(page_size=0) self.service.list_devices(request)
class SearchTest(loanertest.EndpointsTestCase, parameterized.TestCase): _ASSIGNED_DATE = datetime.datetime(year=2017, month=1, day=1) @parameterized.parameters(( shelf_messages.Shelf(location='NY', capacity=50), 'location:NY capacity:50 enabled:True', ), ( shelf_messages.Shelf(location='NY', capacity=50, enabled=False), 'location:NY capacity:50 enabled:False', )) def test_to_query(self, message, expected_query): """Tests the creation of a valid search query from ndb properties.""" query = search_utils.to_query(message, shelf_model.Shelf) # The query is split because ndb properties are unordered when called by # model_class._properties. This test would be flaky otherwise. self.assertCountEqual(query.split(' '), expected_query.split(' ')) @parameterized.named_parameters( ('Shelf Message', shelf_messages.Shelf(), search.ScoredDocument( doc_id='test_doc_id', fields=[ search.NumberField(name='capacity', value=20.0), search.TextField(name='location', value='US MTV'), search.AtomField(name='location', value='US-MTV'), search.AtomField(name='enabled', value='True'), search.GeoField(name='lat_long', value=search.GeoPoint(52.37, 4.88)), search.TextField(name='not_present', value='MTV') ]), shelf_messages.Shelf(enabled=True, location='US-MTV', capacity=20, latitude=52.37, longitude=4.88), 1), ('Device Message', device_messages.Device(), search.ScoredDocument( doc_id='test_doc_id', fields=[ search.DateField(name='assignment_date', value=_ASSIGNED_DATE), search.TextField(name='serial_number', value='1234'), search.AtomField(name='enrolled', value='True'), search.TextField(name='assigned_user', value='user') ]), device_messages.Device( enrolled=True, serial_number='1234', assigned_user='******', max_extend_date=_ASSIGNED_DATE + datetime.timedelta(days=14), assignment_date=_ASSIGNED_DATE), 0)) def test_document_to_message(self, message, test_search_document, expected_message, log_call_count): """Tests the creation of a protorpc message from a search document.""" with mock.patch.object(search_utils, 'logging', autospec=True) as mock_logging: response_message = search_utils.document_to_message( test_search_document, message) self.assertEqual(response_message, expected_message) self.assertEqual(mock_logging.error.call_count, log_call_count) def test_calculate_page_offset(self): """Tests the calculation of page offset.""" page_size = 10 page_number = 5 offset = search_utils.calculate_page_offset(page_size, page_number) self.assertEqual(40, offset) def test_calculate_total_pages(self): """Tests the calculation of total pages.""" page_size = 6 total_results = 11 total_pages = search_utils.calculate_total_pages( page_size, total_results) self.assertEqual(2, total_pages) @parameterized.named_parameters( { 'testcase_name': 'QueryStringOnly', 'request': shared_messages.SearchRequest(query_string='enrolled:True'), 'expected_values': ('enrolled:True', None, []) }, { 'testcase_name': 'QueryStringWithReturnedFields', 'request': shared_messages.SearchRequest(query_string='location:US-NYC', returned_fields=['location']), 'expected_values': ('location:US-NYC', None, ['location']) }, ) def test_set_search_query_options(self, request, expected_values): """Tests setting the query options without sort options from message.""" returned_query, returned_sort_options, returned_returned_fields = ( search_utils.set_search_query_options(request)) expected_query, expected_sort_options, expcted_returned_fields = ( expected_values) self.assertEqual(expected_sort_options, returned_sort_options) self.assertEqual(expected_query, returned_query) self.assertEqual(expcted_returned_fields, returned_returned_fields) @parameterized.named_parameters( { 'testcase_name': 'ExpressionWithDirection', 'request': shared_messages.SearchRequest( query_string='enrolled:True', expressions=[ shared_messages.SearchExpression( expression='enrolled', direction=shared_messages.SortDirection.ASCENDING) ]), 'expected_sort_options_expressions': [ search.SortExpression( expression='enrolled', direction=search.SortExpression.ASCENDING) ] }, { 'testcase_name': 'MultipleExpressionsWithDirection', 'request': shared_messages.SearchRequest( query_string='enrolled:True', expressions=[ shared_messages.SearchExpression( expression='enrolled', direction=shared_messages.SortDirection.ASCENDING), shared_messages.SearchExpression( expression='serial_number', direction=shared_messages.SortDirection.DESCENDING) ]), 'expected_sort_options_expressions': [ search.SortExpression( expression='enrolled', direction=search.SortExpression.ASCENDING), search.SortExpression( expression='serial_number', direction=search.SortExpression.DESCENDING) ] }, { 'testcase_name': 'ExpressionWithoutDirection', 'request': shared_messages.SearchRequest( query_string='enrolled:True', expressions=[ shared_messages.SearchExpression(expression='enrolled') ]), 'expected_sort_options_expressions': [search.SortExpression(expression='enrolled')] }, { 'testcase_name': 'MultipleExpressionsWithoutDirection', 'request': shared_messages.SearchRequest( query_string='enrolled:True', expressions=[ shared_messages.SearchExpression(expression='enrolled'), shared_messages.SearchExpression( expression='serial_number') ]), 'expected_sort_options_expressions': [ search.SortExpression( expression='enrolled', direction=search.SortExpression.DESCENDING), search.SortExpression( expression='serial_number', direction=search.SortExpression.DESCENDING) ] }, ) def test_set_search_query_options_with_sort_options( self, request, expected_sort_options_expressions): """Tests setting query options with sort options from message.""" returned_query, returned_sort_options, returned_returned_fields = ( search_utils.set_search_query_options(request)) del returned_query # Unused. del returned_returned_fields # Unused. for i in range(len(returned_sort_options.expressions)): self.assertEqual(returned_sort_options.expressions[i].expression, expected_sort_options_expressions[i].expression) self.assertEqual(returned_sort_options.expressions[i].direction, expected_sort_options_expressions[i].direction)
def test_list_devices_with_malformed_page_token(self, mock_to_query): """Test list devices with a fake token, raises BadRequestException.""" request = device_messages.Device(page_token='malformedtoken') with self.assertRaises(endpoints.BadRequestException): self.service.list_devices(request)
def test_get_history(self, mock_xsrf_token, mock_bigquery): device_request = device_messages.DeviceRequest() device_request.asset_tag = '12345' request = device_messages.HistoryRequest(device=device_request) device_response = device_messages.Device() device_response.asset_tag = '12345' expected_response = device_messages.HistoryResponse() for _ in range(2): expected_response.devices.append(device_response) expected_response.timestamp.append( datetime.datetime(2019, 10, 22, 20, 43, 37)) expected_response.actor.append('*****@*****.**') expected_response.summary.append( 'Beginning new loan for user [email protected] with device 12345.' ) bigquery_response = [ (u"Key('Device', 5158133238333440)", datetime.datetime(2019, 10, 22, 20, 43, 37), u'*****@*****.**', u'enable_guest_mode', u'Beginning new loan for user [email protected] with device 12345.', { u'ou_changed_date': datetime.datetime(2019, 10, 22, 20, 43, 37), u'current_ou': u'/', u'shelf': None, u'due_date': datetime.datetime(2019, 10, 22, 20, 43, 37), u'chrome_device_id': u'unique_id_1', u'mark_pending_return_date': None, u'asset_tag': u'12345', u'last_known_healthy': datetime.datetime(2019, 10, 22, 20, 43, 37), u'locked': False, u'last_reminder': { u'count': 1, u'time': datetime.datetime(2019, 10, 22, 20, 43, 37), u'level': 1 }, u'next_reminder': None, u'device_model': u'Chromebook', u'enrolled': True, u'serial_number': u'123ABC', u'damaged': False, u'onboarded': True, u'assignment_date': datetime.datetime(2019, 10, 22, 20, 43, 37), u'damaged_reason': None, u'assigned_user': u'*****@*****.**', u'lost': False, u'last_heartbeat': datetime.datetime(2019, 10, 22, 20, 43, 37) }), (u"Key('Device', 5158133238333440)", datetime.datetime(2019, 10, 22, 20, 43, 37), u'*****@*****.**', u'enable_guest_mode', u'Beginning new loan for user [email protected] with device 12345.', { u'ou_changed_date': datetime.datetime(2019, 10, 22, 20, 43, 37), u'current_ou': u'/', u'shelf': None, u'due_date': datetime.datetime(2019, 10, 22, 20, 43, 37), u'chrome_device_id': u'unique_id_1', u'mark_pending_return_date': None, u'asset_tag': u'12345', u'last_known_healthy': datetime.datetime(2019, 10, 22, 20, 43, 37), u'locked': False, u'last_reminder': { u'count': 1, u'time': datetime.datetime(2019, 10, 22, 20, 43, 37), u'level': 1 }, u'next_reminder': None, u'device_model': u'Chromebook', u'enrolled': True, u'serial_number': u'123ABC', u'damaged': False, u'onboarded': True, u'assignment_date': datetime.datetime(2019, 10, 22, 20, 43, 37), u'damaged_reason': None, u'assigned_user': u'*****@*****.**', u'lost': False, u'last_heartbeat': datetime.datetime(2019, 10, 22, 20, 43, 37) }), ] mock_bigquery_client = mock.Mock() mock_bigquery_client.get_device_info.return_value = bigquery_response mock_bigquery.return_value = mock_bigquery_client actual_response = self.service.get_history(request) self.assertEqual(actual_response, expected_response)
def testDevice(self): due_date = datetime.datetime.now() last_heartbeat = datetime.datetime.now() assignment_date = datetime.datetime.now() ou_changed_date = datetime.datetime.now() last_known_healthy = datetime.datetime.now() mark_pending_return_date = datetime.datetime.now() max_extend_date = datetime.datetime.now() device = device_messages.Device( serial_number='FAKE-SERIAL-NUMBER', asset_tag='FAKE-TAG', identifier='FAKE-IDENTIFIER', urlkey='FAKE-URL-KEY', enrolled=False, device_model='FAKE-DEVICE-MODEL', due_date=due_date, last_known_healthy=last_known_healthy, assigned_user='******', assignment_date=assignment_date, current_ou='FAKE-CURRENT-OU', ou_changed_date=ou_changed_date, locked=True, lost=True, mark_pending_return_date=mark_pending_return_date, chrome_device_id='FAKE-CHROME-DEVICE-ID', last_heartbeat=last_heartbeat, damaged=True, damaged_reason='FAKE-DAMAGED-REASON', page_token='FAKE-PAGE-TOKEN', page_size=50, max_extend_date=max_extend_date, guest_enabled=False, guest_permitted=True, given_name='FAKE-GIVEN-NAME', overdue=True, onboarded=True) self.assertTrue(device.lost) self.assertTrue(device.locked) self.assertTrue(device.overdue) self.assertTrue(device.damaged) self.assertFalse(device.enrolled) self.assertTrue(device.onboarded) self.assertEqual(device.page_size, 50) self.assertFalse(device.guest_enabled) self.assertTrue(device.guest_permitted) self.assertEqual(device.due_date, due_date) self.assertEqual(device.asset_tag, 'FAKE-TAG') self.assertEqual(device.urlkey, 'FAKE-URL-KEY') self.assertEqual(device.identifier, 'FAKE-IDENTIFIER') self.assertEqual(device.current_ou, 'FAKE-CURRENT-OU') self.assertEqual(device.page_token, 'FAKE-PAGE-TOKEN') self.assertEqual(device.given_name, 'FAKE-GIVEN-NAME') self.assertEqual(device.last_heartbeat, last_heartbeat) self.assertEqual(device.assignment_date, assignment_date) self.assertEqual(device.ou_changed_date, ou_changed_date) self.assertEqual(device.max_extend_date, max_extend_date) self.assertEqual(device.device_model, 'FAKE-DEVICE-MODEL') self.assertEqual(device.serial_number, 'FAKE-SERIAL-NUMBER') self.assertEqual(device.assigned_user, 'FAKE-ASSIGNED-USER') self.assertEqual(device.damaged_reason, 'FAKE-DAMAGED-REASON') self.assertEqual(device.last_known_healthy, last_known_healthy) self.assertEqual(device.chrome_device_id, 'FAKE-CHROME-DEVICE-ID') self.assertEqual(device.mark_pending_return_date, mark_pending_return_date)
class DeviceApiTest(parameterized.TestCase, loanertest.EndpointsTestCase): """Tests for the Device API.""" def setUp(self): super(DeviceApiTest, self).setUp() self.service = device_api.DeviceApi() self.login_admin_endpoints_user() self.shelf = shelf_model.Shelf.enroll(user_email=loanertest.USER_EMAIL, location='NYC', capacity=10, friendly_name='GnG', latitude=40.6892534, longitude=-74.0466891, altitude=1.0) self.device = device_model.Device() self.device.serial_number = '123ABC' self.device.asset_tag = '12345' self.device.enrolled = True self.device.device_model = 'Google Pixelbook' self.device.due_date = datetime.datetime(2017, 11, 15) self.device.last_known_healthy = datetime.datetime(2017, 11, 1) self.device.shelf = self.shelf.key self.device.assigned_user = loanertest.USER_EMAIL self.device.assignment_date = datetime.datetime(2017, 11, 1) self.device.current_ou = '/' self.device.ou_changed_date = datetime.datetime(2017, 11, 1) self.device.locked = False self.device.lost = False self.device.chrome_device_id = 'unique_id_1' self.device.last_heartbeat = datetime.datetime(2017, 11, 1) self.device.damaged = False self.device.damaged_reason = None self.device.put() self.device.set_last_reminder(0) self.device.set_next_reminder(1, datetime.timedelta(hours=2)) device_model.Device( serial_number='6789', enrolled=True, device_model='HP Chromebook 13 G1', current_ou='/', chrome_device_id='unique_id_2', shelf=self.shelf.key, damaged=False, ).put() self.unenrolled_device = device_model.Device( serial_number='4567', enrolled=False, device_model='HP Chromebook 13 G1', current_ou='/', chrome_device_id='unique_id_3', damaged=False, ) self.unenrolled_device.put() self.unenrolled_device_directory = { 'deviceId': 'unique_id', 'serialNumber': '4567', 'status': 'ACTIVE', 'lastSync': datetime.datetime.utcnow(), 'model': 'HP Chromebook 13 G1', 'orgUnitPath': constants.ORG_UNIT_DICT['DEFAULT'], } def tearDown(self): super(DeviceApiTest, self).tearDown() self.service = None @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_enroll(self, mock_directoryclass): """Tests Enroll with mock methods.""" mock_directoryclient = mock_directoryclass.return_value mock_directoryclient.get_chrome_device.return_value = ( self.unenrolled_device) mock_directoryclient.get_chrome_device_by_serial.return_value = ( self.unenrolled_device_directory) retrieved_device = device_model.Device.get( serial_number=self.unenrolled_device.serial_number) self.assertFalse(retrieved_device.enrolled) request = device_messages.DeviceRequest( serial_number=self.unenrolled_device.serial_number) with mock.patch.object(self.service, 'check_xsrf_token', autospec=True) as mock_xsrf_token: response = self.service.enroll(request) self.assertIsInstance(response, message_types.VoidMessage) retrieved_device = device_model.Device.get( serial_number=self.unenrolled_device.serial_number) self.assertTrue(retrieved_device.enrolled) self.assertEqual(mock_xsrf_token.call_count, 1) @parameterized.parameters((datastore_errors.BadValueError, ), (device_model.DeviceCreationError, )) @mock.patch.object(device_model, 'Device', autospec=True) def test_enroll_error(self, test_error, mock_device_cls): mock_device_cls.enroll.side_effect = test_error request = device_messages.DeviceRequest( serial_number=self.unenrolled_device.serial_number) with self.assertRaises(endpoints.BadRequestException): self.service.enroll(request) @mock.patch.object(device_model, 'Device', autospec=True) def test_unenroll_error(self, mock_device_cls): mock_device_cls.get.return_value.unenroll.side_effect = ( device_model.FailedToUnenrollError()) request = device_messages.DeviceRequest( serial_number=self.unenrolled_device.serial_number) with self.assertRaises(endpoints.BadRequestException): self.service.unenroll(request) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_unenroll(self, mock_xsrf_token, mock_directoryclass): mock_directoryclient = mock_directoryclass.return_value mock_directoryclient.move_chrome_device_org_unit.return_value = ( loanertest.TEST_DIR_DEVICE_DEFAULT) request = device_messages.DeviceRequest( serial_number=self.device.serial_number) self.assertTrue(self.device.enrolled) response = self.service.unenroll(request) self.assertFalse(self.device.enrolled) self.assertIsNone(self.device.assigned_user) self.assertIsNone(self.device.due_date) self.assertIsInstance(response, message_types.VoidMessage) assert mock_xsrf_token.call_count == 1 @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_unlock(self, mock_xsrf_token, mock_directoryclass): self.device.lost = True self.device.locked = True self.device.put() mock_directoryclient = mock_directoryclass.return_value mock_directoryclient.move_chrome_device_org_unit.return_value = ( loanertest.TEST_DIR_DEVICE_DEFAULT) request = device_messages.DeviceRequest( serial_number=self.device.serial_number) response = self.service.unlock(request) self.assertFalse(self.device.locked) self.assertFalse(self.device.lost) self.assertIsInstance(response, message_types.VoidMessage) assert mock_xsrf_token.call_count == 1 @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_unlock_directory_error(self, mock_directory_class): mock_directory_client = mock_directory_class.return_value mock_directory_client.reenable_chrome_device.side_effect = ( directory.DirectoryRPCError) with self.assertRaises(endpoints.BadRequestException): self.service.unlock( device_messages.DeviceRequest(asset_tag='12345')) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_unlock_move_ou_error(self, mock_directory_class): del mock_directory_class # Unused. with mock.patch.object( self.device, 'move_to_default_ou', side_effect=device_model.UnableToMoveToDefaultOUError): with self.assertRaises(endpoints.BadRequestException): self.service.unlock( device_messages.DeviceRequest(asset_tag='12345')) @mock.patch('__main__.device_model.Device.device_audit_check') def test_device_audit_check(self, mock_device_audit_check): request = device_messages.DeviceRequest(unknown_identifier='6765') self.assertRaisesRegexp(device_api.endpoints.NotFoundException, device_api._NO_DEVICE_MSG % '6765', self.service.device_audit_check, request) device_model.Device(serial_number='12345', enrolled=True, device_model='HP Chromebook 13 G1', current_ou='/', chrome_device_id='unique_id_1', damaged=False).put() request = device_messages.DeviceRequest(unknown_identifier='12345') response = self.service.device_audit_check(request) assert mock_device_audit_check.call_count == 1 self.assertIsInstance(response, message_types.VoidMessage) def test_device_audit_check_device_not_enrolled(self): request = device_messages.DeviceRequest( unknown_identifier=self.device.serial_number) self.device.enrolled = False with self.assertRaises(device_api.endpoints.BadRequestException): self.service.device_audit_check(request) def test_device_audit_check_device_damaged(self): request = device_messages.DeviceRequest( unknown_identifier=self.device.serial_number) self.device.damaged = True with self.assertRaises(device_api.endpoints.BadRequestException): self.service.device_audit_check(request) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_get_device_not_found(self, mock_directory_class): mock_directory_client = mock_directory_class.return_value mock_directory_client.given_name.return_value = 'given name value' request = device_messages.DeviceRequest(unknown_identifier='not-found') with self.assertRaises(device_api.endpoints.NotFoundException): self.service.get_device(request) def test_get_device_unenrolled(self): request = device_messages.DeviceRequest( unknown_identifier=self.device.serial_number) self.device.enrolled = False with self.assertRaises(device_api.endpoints.BadRequestException): self.service.get_device(request) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_get_device(self, mock_directory_class): mock_directory_client = mock_directory_class.return_value mock_directory_client.given_name.return_value = 'given name value' asset_tag_response = self.service.get_device( device_messages.DeviceRequest(asset_tag='12345')) chrome_device_id_response = self.service.get_device( device_messages.DeviceRequest(chrome_device_id='unique_id_1')) serial_number_response = self.service.get_device( device_messages.DeviceRequest(serial_number='123ABC')) urlkey_response = self.service.get_device( device_messages.DeviceRequest(urlkey=self.device.key.urlsafe())) unknown_identifier_response = self.service.get_device( device_messages.DeviceRequest(unknown_identifier='123ABC')) self.assertIsInstance(asset_tag_response, device_messages.Device) self.assertIsInstance(chrome_device_id_response, device_messages.Device) self.assertIsInstance(serial_number_response, device_messages.Device) self.assertIsInstance(urlkey_response, device_messages.Device) self.assertIsInstance(unknown_identifier_response, device_messages.Device) self.assertEqual(self.device.serial_number, asset_tag_response.serial_number) self.assertEqual(self.device.device_model, urlkey_response.device_model) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_get_device_no_permission(self, mock_directory_class): mock_directory_client = mock_directory_class.return_value mock_directory_client.given_name.return_value = 'given name value' email = 'random@{}'.format(loanertest.USER_DOMAIN) self.login_endpoints_user(email=email) with self.assertRaises(endpoints.UnauthorizedException): self.service.get_device( device_messages.DeviceRequest( serial_number=self.device.serial_number)) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_get_device_has_permission(self, mock_directory_class): mock_directory_client = mock_directory_class.return_value mock_directory_client.given_name.return_value = 'given name value' device = self.service.get_device( device_messages.DeviceRequest( serial_number=self.device.serial_number)) self.assertIsInstance(device, device_messages.Device) self.assertEqual(device.serial_number, self.device.serial_number) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_get_device_assigned_user(self, mock_directory_class): mock_directory_client = mock_directory_class.return_value mock_directory_client.given_name.return_value = 'given name value' email = 'random@{}'.format(loanertest.USER_DOMAIN) self.login_endpoints_user(email=email) self.device.assigned_user = email self.device.put() device = self.service.get_device( device_messages.DeviceRequest( serial_number=self.device.serial_number)) self.assertIsInstance(device, device_messages.Device) self.assertEqual(device.serial_number, self.device.serial_number) @parameterized.parameters(directory.DirectoryRPCError, directory.GivenNameDoesNotExistError) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_get_device_directory_errors(self, test_error, mock_directory_class): request = device_messages.DeviceRequest(asset_tag='12345') mock_directory_client = mock_directory_class.return_value mock_directory_client.given_name.side_effect = test_error self.assertIsNone(self.service.get_device(request).given_name) @parameterized.parameters(( device_messages.Device(enrolled=True), 2, ), ( device_messages.Device(current_ou='/'), 2, ), ( device_messages.Device(enrolled=False), 1, ), ( device_messages.Device(query=shared_messages.SearchRequest( query_string='sn:6789')), 1, ), ( device_messages.Device(query=shared_messages.SearchRequest( query_string='at:12345')), 1, )) def test_list_devices(self, request, response_length): response = self.service.list_devices(request) self.assertEqual(response_length, len(response.devices)) def test_list_devices_invalid_page_size(self): with self.assertRaises(endpoints.BadRequestException): request = device_messages.Device(page_size=0) self.service.list_devices(request) def test_list_devices_with_search_constraints(self): expressions = shared_messages.SearchExpression( expression='serial_number') expected_response = device_messages.ListDevicesResponse( devices=[ device_messages.Device(serial_number='6789', guest_permitted=True) ], total_results=1, total_pages=1) request = device_messages.Device(query=shared_messages.SearchRequest( query_string='sn:6789', expressions=[expressions], returned_fields=['serial_number'])) response = self.service.list_devices(request) self.assertEqual(response, expected_response) def test_list_devices_with_filter_message(self): message = device_messages.Device(enrolled=True, device_model='HP Chromebook 13 G1', current_ou='/') filters = api_utils.to_dict(message, device_model.Device) request = device_messages.Device(**filters) response = self.service.list_devices(request) expected_response = device_messages.ListDevicesResponse( devices=[ device_messages.Device(serial_number='6789', identifier='6789', enrolled=True, device_model='HP Chromebook 13 G1', current_ou='/', locked=False, lost=False, chrome_device_id='unique_id_2', damaged=False, guest_permitted=True) ], total_results=1, total_pages=1) self.assertEqual(response, expected_response) @mock.patch('__main__.device_api.shelf_api.get_shelf') def test_list_devices_with_shelf_filter(self, mock_get_shelf): # Test for shelf location as filter. mock_get_shelf.return_value = self.shelf shelf_request_message = shelf_messages.ShelfRequest( location=self.shelf.location) message = shelf_messages.Shelf(shelf_request=shelf_request_message) request = device_messages.Device(shelf=message) response = self.service.list_devices(request) mock_get_shelf.assert_called_once_with(shelf_request_message) self.assertEqual(len(response.devices), 2) def test_list_devices_with_offset(self): request = device_messages.Device(page_size=1, page_number=1) response = self.service.list_devices(request) self.assertEqual(1, len(response.devices)) previouse_response = response # Get next page results and make sure it's not the same as last. request = device_messages.Device(page_size=1, page_number=2) response = self.service.list_devices(request) self.assertEqual(1, len(response.devices)) self.assertNotEqual(response, previouse_response) def test_list_devices_inactive_no_shelf(self): request = device_messages.Device(enrolled=False, page_size=1) response = self.service.list_devices(request) expected_response = device_messages.ListDevicesResponse( devices=[ device_messages.Device( serial_number=self.unenrolled_device.serial_number, identifier=self.unenrolled_device.serial_number, enrolled=self.unenrolled_device.enrolled, device_model=self.unenrolled_device.device_model, current_ou=self.unenrolled_device.current_ou, locked=self.unenrolled_device.locked, lost=self.unenrolled_device.lost, chrome_device_id=self.unenrolled_device.chrome_device_id, damaged=self.unenrolled_device.damaged, guest_permitted=True) ], total_results=1, total_pages=1) self.assertEqual(expected_response, response) @mock.patch('__main__.device_model.Device.list_by_user') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_list_user_devices(self, mock_xsrf_token, mock_list_by_user): self.login_endpoints_user() device2 = device_model.Device() device2.serial_number = '123ABC' device2.assigned_user = loanertest.USER_EMAIL device2.assignment_date = datetime.datetime(2017, 11, 1) device2.due_date = datetime.datetime(2017, 11, 4) device2.put() request = message_types.VoidMessage() mock_list_by_user.return_value = [self.device, device2] response = self.service.list_user_devices(request) self.assertEqual(response.devices[0].serial_number, self.device.serial_number) self.assertEqual(len(response.devices), 2) assert mock_xsrf_token.call_count == 1 mock_list_by_user.assert_called_once_with(loanertest.USER_EMAIL) @mock.patch('__main__.device_model.Device.enable_guest_mode') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_enable_guest_mode(self, mock_xsrf_token, mock_enableguest): config_model.Config.set('allow_guest_mode', True) self.login_endpoints_user() self.service.enable_guest_mode( device_messages.DeviceRequest(urlkey=self.device.key.urlsafe())) assert mock_enableguest.called assert mock_xsrf_token.call_count == 1 mock_xsrf_token.reset_mock() mock_enableguest.reset_mock() self.service.enable_guest_mode( device_messages.DeviceRequest( chrome_device_id=self.device.chrome_device_id)) assert mock_enableguest.called assert mock_xsrf_token.call_count == 1 def guest_disabled_error(*args, **kwargs): del args, kwargs # Unused. raise device_model.GuestNotAllowedError( device_model._GUEST_MODE_DISABLED_MSG) def directory_error(*args, **kwargs): del args, kwargs # Unused. raise device_model.EnableGuestError( 'Directory broke, all your fault.') mock_enableguest.side_effect = guest_disabled_error with self.assertRaises(endpoints.UnauthorizedException): self.service.enable_guest_mode( device_messages.DeviceRequest( chrome_device_id=self.device.chrome_device_id)) mock_enableguest.side_effect = directory_error with self.assertRaises(endpoints.InternalServerErrorException): self.service.enable_guest_mode( device_messages.DeviceRequest( chrome_device_id=self.device.chrome_device_id)) def test_enable_guest_unassigned(self): config_model.Config.set('allow_guest_mode', True) self.device.assigned_user = None self.device.put() with self.assertRaisesRegexp(endpoints.UnauthorizedException, device_model._UNASSIGNED_DEVICE): self.service.enable_guest_mode( device_messages.DeviceRequest( urlkey=self.device.key.urlsafe())) @mock.patch('__main__.device_model.Device.loan_extend') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_extend_loan(self, mock_xsrf_token, mock_loanextend): tomorrow = datetime.datetime.utcnow() + datetime.timedelta(days=1) self.login_endpoints_user() self.service.extend_loan( device_messages.ExtendLoanRequest( device=device_messages.DeviceRequest( urlkey=self.device.key.urlsafe()), extend_date=tomorrow)) mock_loanextend.assert_called_once_with( user_email=loanertest.USER_EMAIL, extend_date_time=tomorrow) assert mock_xsrf_token.call_count == 1 mock_xsrf_token.reset_mock() mock_loanextend.reset_mock() self.service.extend_loan( device_messages.ExtendLoanRequest( device=device_messages.DeviceRequest( chrome_device_id=self.device.chrome_device_id), extend_date=tomorrow)) mock_loanextend.assert_called_once_with( user_email=loanertest.USER_EMAIL, extend_date_time=tomorrow) assert mock_xsrf_token.call_count == 1 mock_loanextend.side_effect = device_model.ExtendError self.assertRaises( device_api.endpoints.BadRequestException, self.service.extend_loan, device_messages.ExtendLoanRequest( device=device_messages.DeviceRequest( chrome_device_id=self.device.chrome_device_id), extend_date=tomorrow)) def test_extend_loan_unassigned(self): self.device.assigned_user = None self.device.put() with self.assertRaisesRegexp(endpoints.UnauthorizedException, device_model._UNASSIGNED_DEVICE): self.service.extend_loan( device_messages.ExtendLoanRequest( device=device_messages.DeviceRequest( chrome_device_id=self.device.chrome_device_id))) @mock.patch('__main__.device_model.Device.mark_damaged') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_mark_damaged(self, mock_xsrf_token, mock_markdamaged): self.login_endpoints_user() self.service.mark_damaged( device_messages.DamagedRequest( device=device_messages.DeviceRequest( urlkey=self.device.key.urlsafe()), damaged_reason='Foo')) mock_markdamaged.assert_called_once_with( user_email=loanertest.USER_EMAIL, damaged_reason='Foo') assert mock_xsrf_token.call_count == 1 mock_xsrf_token.reset_mock() mock_markdamaged.reset_mock() self.service.mark_damaged( device_messages.DamagedRequest( # No reason given. device=device_messages.DeviceRequest( urlkey=self.device.key.urlsafe()))) mock_markdamaged.assert_called_once_with( user_email=loanertest.USER_EMAIL, damaged_reason=None) assert mock_xsrf_token.call_count == 1 @mock.patch.object(device_model.Device, 'mark_damaged') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_mark_damaged__unauthorized(self, mock_xsrf, mock_markdamaged): del mock_xsrf # unusued. self.login_endpoints_user() mock_markdamaged.side_effect = device_model.UnauthorizedError() with self.assertRaises(endpoints.UnauthorizedException): self.service.mark_damaged( device_messages.DamagedRequest( device=device_messages.DeviceRequest( urlkey=self.device.key.urlsafe()), damaged_reason='Foo')) def test_mark_undamaged(self): with mock.patch.object(self.device, 'mark_undamaged') as mock_markundamaged: self.service.mark_undamaged( device_messages.DeviceRequest( urlkey=self.device.key.urlsafe())) mock_markundamaged.assert_called_once_with( user_email=loanertest.SUPER_ADMIN_EMAIL) @mock.patch.object(device_model.Device, 'mark_undamaged') def test_mark_undamaged__unauthorized(self, mock_markundamaged): self.login_endpoints_user() with mock.patch.object(self.service, 'check_xsrf_token') as mock_xsrf: mock_markundamaged.side_effect = device_model.UnauthorizedError() with self.assertRaises(endpoints.UnauthorizedException): self.service.mark_undamaged( device_messages.DeviceRequest( urlkey=self.device.key.urlsafe())) assert mock_xsrf.call_count == 1 @mock.patch('__main__.device_model.Device.mark_lost') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_mark_lost(self, mock_xsrf_token, mock_marklost): self.service.mark_lost( device_messages.DeviceRequest(urlkey=self.device.key.urlsafe())) mock_marklost.assert_called_once_with( user_email=loanertest.SUPER_ADMIN_EMAIL) assert mock_xsrf_token.call_count == 1 @mock.patch.object(device_model.Device, 'mark_lost') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_mark_lost__unauthorized(self, mock_xsrf_token, mock_marklost): del mock_xsrf_token # unused. mock_marklost.side_effect = device_model.UnauthorizedError() with self.assertRaises(endpoints.UnauthorizedException): self.service.mark_lost( device_messages.DeviceRequest( urlkey=self.device.key.urlsafe())) @mock.patch('__main__.device_model.Device.mark_pending_return') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_mark_pending_return(self, mock_xsrf_token, mock_markreturned): self.login_endpoints_user() self.service.mark_pending_return( device_messages.DeviceRequest(urlkey=self.device.key.urlsafe())) mock_markreturned.assert_called_once_with( user_email=loanertest.USER_EMAIL) assert mock_xsrf_token.call_count == 1 def test_mark_pending_return_unassigned(self): self.device.assigned_user = None self.device.put() with self.assertRaisesRegexp(endpoints.UnauthorizedException, device_model._UNASSIGNED_DEVICE): self.service.mark_pending_return( device_messages.DeviceRequest( urlkey=self.device.key.urlsafe())) @mock.patch('__main__.device_model.Device.resume_loan') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_resume_loan(self, mock_xsrf_token, mock_resume_loan): self.login_endpoints_user() self.service.resume_loan( device_messages.DeviceRequest(urlkey=self.device.key.urlsafe())) assert mock_resume_loan.call_count == 1 assert mock_xsrf_token.call_count == 1 @mock.patch.object(device_model.Device, 'resume_loan') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_resume_loan__unauthorized(self, mock_xsrf_token, mock_resume_loan): del mock_xsrf_token # unused. self.login_endpoints_user() mock_resume_loan.side_effect = device_model.UnauthorizedError() with self.assertRaises(endpoints.UnauthorizedException): self.service.resume_loan( device_messages.DeviceRequest( urlkey=self.device.key.urlsafe())) def test_get_device_errors(self): # No identifiers. with self.assertRaises(endpoints.BadRequestException): device_api._get_device(device_messages.DeviceRequest()) # URL-safe key that is still URL-safe, but technically not a key. with self.assertRaises(device_api.endpoints.BadRequestException): device_api._get_device( device_messages.DeviceRequest(urlkey='bad-key'))
class DeviceApiTest(parameterized.TestCase, loanertest.EndpointsTestCase): """Tests for the Device API.""" def setUp(self): super(DeviceApiTest, self).setUp() self.service = device_api.DeviceApi() self.login_admin_endpoints_user() # Set bootstrap to completed so that maintenance mode will not be invoked. config_model.Config.set('bootstrap_completed', True) self.shelf = shelf_model.Shelf.enroll(user_email=loanertest.USER_EMAIL, location='NYC', capacity=10, friendly_name='GnG', latitude=40.6892534, longitude=-74.0466891, altitude=1.0) self.device = device_model.Device() self.device.serial_number = '123ABC' self.device.asset_tag = '12345' self.device.enrolled = True self.device.device_model = 'Google Pixelbook' self.device.due_date = datetime.datetime(2017, 11, 15) self.device.last_known_healthy = datetime.datetime(2017, 11, 1) self.device.shelf = self.shelf.key self.device.assigned_user = loanertest.USER_EMAIL self.device.assignment_date = datetime.datetime(2017, 11, 1) self.device.current_ou = '/' self.device.ou_changed_date = datetime.datetime(2017, 11, 1) self.device.locked = False self.device.lost = False self.device.chrome_device_id = 'unique_id_1' self.device.last_heartbeat = datetime.datetime(2017, 11, 1) self.device.damaged = False self.device.damaged_reason = None self.device.put() self.device.set_last_reminder(0) self.device.set_next_reminder(1, datetime.timedelta(hours=2)) device_model.Device( serial_number='6789', enrolled=True, device_model='HP Chromebook 13 G1', current_ou='/', chrome_device_id='unique_id_2', shelf=self.shelf.key, damaged=False, ).put() self.unenrolled_device = device_model.Device( serial_number='4567', enrolled=False, device_model='HP Chromebook 13 G1', current_ou='/', chrome_device_id='unique_id_3', damaged=False, ) self.unenrolled_device.put() self.unenrolled_device_directory = { 'deviceId': 'unique_id', 'serialNumber': '4567', 'status': 'ACTIVE', 'lastSync': datetime.datetime.utcnow(), 'model': 'HP Chromebook 13 G1', 'orgUnitPath': constants.ORG_UNIT_DICT['DEFAULT'], } def tearDown(self): super(DeviceApiTest, self).tearDown() self.service = None @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_enroll(self, mock_directoryclass): """Tests Enroll with mock methods.""" mock_directoryclient = mock_directoryclass.return_value mock_directoryclient.get_chrome_device.return_value = ( self.unenrolled_device) mock_directoryclient.get_chrome_device_by_serial.return_value = ( self.unenrolled_device_directory) retrieved_device = device_model.Device.get( serial_number=self.unenrolled_device.serial_number) self.assertFalse(retrieved_device.enrolled) request = device_messages.DeviceRequest( serial_number=self.unenrolled_device.serial_number) with mock.patch.object(self.service, 'check_xsrf_token', autospec=True) as mock_xsrf_token: response = self.service.enroll(request) self.assertIsInstance(response, message_types.VoidMessage) retrieved_device = device_model.Device.get( serial_number=self.unenrolled_device.serial_number) self.assertTrue(retrieved_device.enrolled) self.assertEqual(mock_xsrf_token.call_count, 1) @parameterized.parameters((datastore_errors.BadValueError, ), (device_model.DeviceCreationError, )) @mock.patch.object(device_model, 'Device', autospec=True) def test_enroll_error(self, test_error, mock_device_cls): mock_device_cls.enroll.side_effect = test_error request = device_messages.DeviceRequest( serial_number=self.unenrolled_device.serial_number) with self.assertRaises(endpoints.BadRequestException): self.service.enroll(request) @mock.patch.object(device_model, 'Device', autospec=True) def test_unenroll_error(self, mock_device_cls): mock_device_cls.get.return_value.unenroll.side_effect = ( device_model.FailedToUnenrollError()) request = device_messages.DeviceRequest( serial_number=self.unenrolled_device.serial_number) with self.assertRaises(endpoints.BadRequestException): self.service.unenroll(request) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_unenroll(self, mock_xsrf_token, mock_directoryclass): mock_directoryclient = mock_directoryclass.return_value mock_directoryclient.move_chrome_device_org_unit.return_value = ( loanertest.TEST_DIR_DEVICE_DEFAULT) request = device_messages.DeviceRequest( serial_number=self.device.serial_number) self.assertTrue(self.device.enrolled) response = self.service.unenroll(request) self.assertFalse(self.device.enrolled) self.assertIsNone(self.device.assigned_user) self.assertIsNone(self.device.due_date) self.assertIsInstance(response, message_types.VoidMessage) self.assertEqual(mock_xsrf_token.call_count, 1) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_unlock(self, mock_xsrf_token, mock_directoryclass): self.device.lost = True self.device.locked = True self.device.put() mock_directoryclient = mock_directoryclass.return_value mock_directoryclient.move_chrome_device_org_unit.return_value = ( loanertest.TEST_DIR_DEVICE_DEFAULT) request = device_messages.DeviceRequest( serial_number=self.device.serial_number) response = self.service.unlock(request) self.assertFalse(self.device.locked) self.assertFalse(self.device.lost) self.assertIsInstance(response, message_types.VoidMessage) self.assertEqual(mock_xsrf_token.call_count, 1) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_unlock_directory_error(self, mock_directory_class): mock_directory_client = mock_directory_class.return_value mock_directory_client.reenable_chrome_device.side_effect = ( directory.DirectoryRPCError) with self.assertRaises(endpoints.BadRequestException): self.service.unlock( device_messages.DeviceRequest(asset_tag='12345')) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_unlock_move_ou_error(self, mock_directory_class): del mock_directory_class # Unused. with mock.patch.object( self.device, 'move_to_default_ou', side_effect=device_model.UnableToMoveToDefaultOUError): with self.assertRaises(endpoints.BadRequestException): self.service.unlock( device_messages.DeviceRequest(asset_tag='12345')) @mock.patch('__main__.device_model.Device.device_audit_check') def test_device_audit_check(self, mock_device_audit_check): request = device_messages.DeviceRequest(identifier='6765') self.assertRaisesRegexp(device_api.endpoints.NotFoundException, device_api._NO_DEVICE_MSG % '6765', self.service.device_audit_check, request) device_model.Device(serial_number='12345', enrolled=True, device_model='HP Chromebook 13 G1', current_ou='/', chrome_device_id='unique_id_1', damaged=False).put() request = device_messages.DeviceRequest(identifier='12345') response = self.service.device_audit_check(request) self.assertEqual(mock_device_audit_check.call_count, 1) self.assertIsInstance(response, message_types.VoidMessage) def test_device_audit_check_device_not_enrolled(self): request = device_messages.DeviceRequest( identifier=self.device.serial_number) self.device.enrolled = False with self.assertRaises(device_api.endpoints.BadRequestException): self.service.device_audit_check(request) def test_device_audit_check_device_damaged(self): request = device_messages.DeviceRequest( identifier=self.device.serial_number) self.device.damaged = True with self.assertRaises(device_api.endpoints.BadRequestException): self.service.device_audit_check(request) def test_device_audit_check_audit_error(self): request = device_messages.DeviceRequest( identifier=self.device.serial_number) self.testbed.mock_raiseevent.side_effect = device_model.DeviceAuditEventError with self.assertRaises(device_api.endpoints.BadRequestException): self.service.device_audit_check(request) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_get_device_not_found(self, mock_directory_class): mock_directory_client = mock_directory_class.return_value mock_directory_client.given_name.return_value = 'given name value' request = device_messages.DeviceRequest(identifier='not-found') with self.assertRaises(device_api.endpoints.NotFoundException): self.service.get_device(request) def test_get_device_unenrolled(self): request = device_messages.DeviceRequest( identifier=self.device.serial_number) self.device.enrolled = False with self.assertRaises(device_api.endpoints.BadRequestException): self.service.get_device(request) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_get_device(self, mock_directory_class): mock_directory_client = mock_directory_class.return_value mock_directory_client.given_name.return_value = 'given name value' asset_tag_response = self.service.get_device( device_messages.DeviceRequest(asset_tag='12345')) chrome_device_id_response = self.service.get_device( device_messages.DeviceRequest(chrome_device_id='unique_id_1')) serial_number_response = self.service.get_device( device_messages.DeviceRequest(serial_number='123ABC')) urlkey_response = self.service.get_device( device_messages.DeviceRequest(urlkey=self.device.key.urlsafe())) identifier_response = self.service.get_device( device_messages.DeviceRequest(identifier='123ABC')) self.assertIsInstance(asset_tag_response, device_messages.Device) self.assertIsInstance(chrome_device_id_response, device_messages.Device) self.assertIsInstance(serial_number_response, device_messages.Device) self.assertIsInstance(urlkey_response, device_messages.Device) self.assertIsInstance(identifier_response, device_messages.Device) self.assertEqual(self.device.serial_number, asset_tag_response.serial_number) self.assertEqual(self.device.device_model, urlkey_response.device_model) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_get_device_no_permission(self, mock_directory_class): mock_directory_client = mock_directory_class.return_value mock_directory_client.given_name.return_value = 'given name value' email = 'random@{}'.format(loanertest.USER_DOMAIN) self.login_endpoints_user(email=email) with self.assertRaises(endpoints.UnauthorizedException): self.service.get_device( device_messages.DeviceRequest( serial_number=self.device.serial_number)) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_get_device_has_permission(self, mock_directory_class): mock_directory_client = mock_directory_class.return_value mock_directory_client.given_name.return_value = 'given name value' device = self.service.get_device( device_messages.DeviceRequest( serial_number=self.device.serial_number)) self.assertIsInstance(device, device_messages.Device) self.assertEqual(device.serial_number, self.device.serial_number) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_get_device_assigned_user(self, mock_directory_class): mock_directory_client = mock_directory_class.return_value mock_directory_client.given_name.return_value = 'given name value' email = 'random@{}'.format(loanertest.USER_DOMAIN) self.login_endpoints_user(email=email) self.device.assigned_user = email self.device.put() device = self.service.get_device( device_messages.DeviceRequest( serial_number=self.device.serial_number)) self.assertIsInstance(device, device_messages.Device) self.assertEqual(device.serial_number, self.device.serial_number) @parameterized.parameters(directory.DirectoryRPCError, directory.GivenNameDoesNotExistError) @mock.patch.object(directory, 'DirectoryApiClient', autospec=True) def test_get_device_directory_errors(self, test_error, mock_directory_class): request = device_messages.DeviceRequest(asset_tag='12345') mock_directory_client = mock_directory_class.return_value mock_directory_client.given_name.side_effect = test_error self.assertIsNone(self.service.get_device(request).given_name) @parameterized.parameters(( device_messages.Device(enrolled=True), 2, ), ( device_messages.Device(current_ou='/'), 2, ), ( device_messages.Device(enrolled=False), 1, ), ( device_messages.Device(query=shared_messages.SearchRequest( query_string='sn:6789')), 1, ), ( device_messages.Device(query=shared_messages.SearchRequest( query_string='at:12345')), 1, )) def test_list_devices(self, request, response_length): response = self.service.list_devices(request) self.assertLen(response.devices, response_length) def test_list_devices_with_search_constraints(self): expressions = shared_messages.SearchExpression( expression='serial_number') expected_response = device_messages.ListDevicesResponse( devices=[device_messages.Device(serial_number='6789')], has_additional_results=False) request = device_messages.Device(query=shared_messages.SearchRequest( query_string='sn:6789', expressions=[expressions], returned_fields=['serial_number'])) response = self.service.list_devices(request) self.assertEqual(response.devices[0].serial_number, expected_response.devices[0].serial_number) self.assertFalse(response.has_additional_results) def test_list_devices_with_filter_message(self): message = device_messages.Device(enrolled=True, device_model='HP Chromebook 13 G1', current_ou='/') filters = api_utils.to_dict(message, device_model.Device) request = device_messages.Device(**filters) response = self.service.list_devices(request) expected_response = device_messages.ListDevicesResponse( devices=[ device_messages.Device(serial_number='6789', identifier='6789', enrolled=True, device_model='HP Chromebook 13 G1', current_ou='/', locked=False, lost=False, chrome_device_id='unique_id_2', damaged=False, guest_permitted=True, onboarded=False) ], has_additional_results=False) self.assertEqual(response, expected_response) @mock.patch('__main__.device_api.shelf_api.get_shelf') def test_list_devices_with_shelf_filter(self, mock_get_shelf): # Test for shelf location as filter. mock_get_shelf.return_value = self.shelf shelf_request_message = shelf_messages.ShelfRequest( location=self.shelf.location) message = shelf_messages.Shelf(shelf_request=shelf_request_message) request = device_messages.Device(shelf=message) response = self.service.list_devices(request) mock_get_shelf.assert_called_once_with(shelf_request_message) self.assertLen(response.devices, 2) def test_list_devices_with_page_token(self): request = device_messages.Device(enrolled=True, page_size=1) response_devices = [] while True: response = self.service.list_devices(request) for device in response.devices: response_devices.append(device) request = device_messages.Device(enrolled=True, page_size=1, page_token=response.page_token) if not response.has_additional_results: break self.assertLen(response_devices, 2) @mock.patch.object(search_utils, 'to_query', return_value='enrolled:enrolled', autospec=True) def test_list_devices_with_malformed_page_token(self, mock_to_query): """Test list devices with a fake token, raises BadRequestException.""" request = device_messages.Device(page_token='malformedtoken') with self.assertRaises(endpoints.BadRequestException): self.service.list_devices(request) def test_list_devices_inactive_no_shelf(self): request = device_messages.Device(enrolled=False, page_size=1) response = self.service.list_devices(request) expected_response = device_messages.ListDevicesResponse( devices=[ device_messages.Device( serial_number=self.unenrolled_device.serial_number, identifier=self.unenrolled_device.serial_number, enrolled=self.unenrolled_device.enrolled, device_model=self.unenrolled_device.device_model, current_ou=self.unenrolled_device.current_ou, locked=self.unenrolled_device.locked, lost=self.unenrolled_device.lost, chrome_device_id=self.unenrolled_device.chrome_device_id, damaged=self.unenrolled_device.damaged, guest_permitted=True, onboarded=False) ], has_additional_results=False) self.assertEqual(expected_response, response) @mock.patch('__main__.device_model.Device.list_by_user') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_list_user_devices(self, mock_xsrf_token, mock_list_by_user): self.login_endpoints_user() device2 = device_model.Device() device2.serial_number = '123ABC' device2.assigned_user = loanertest.USER_EMAIL device2.assignment_date = datetime.datetime(2017, 11, 1) device2.due_date = datetime.datetime(2017, 11, 4) device2.put() request = message_types.VoidMessage() mock_list_by_user.return_value = [self.device, device2] response = self.service.list_user_devices(request) self.assertEqual(response.devices[0].serial_number, self.device.serial_number) self.assertLen(response.devices, 2) self.assertEqual(mock_xsrf_token.call_count, 1) mock_list_by_user.assert_called_once_with(loanertest.USER_EMAIL) @mock.patch('__main__.device_model.Device.enable_guest_mode') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_enable_guest_mode(self, mock_xsrf_token, mock_enableguest): config_model.Config.set('allow_guest_mode', True) self.login_endpoints_user() self.service.enable_guest_mode( device_messages.DeviceRequest(urlkey=self.device.key.urlsafe())) self.assertTrue(mock_enableguest.called) self.assertEqual(mock_xsrf_token.call_count, 1) mock_xsrf_token.reset_mock() mock_enableguest.reset_mock() self.service.enable_guest_mode( device_messages.DeviceRequest( chrome_device_id=self.device.chrome_device_id)) self.assertTrue(mock_enableguest.called) self.assertEqual(mock_xsrf_token.call_count, 1) def guest_disabled_error(*args, **kwargs): del args, kwargs # Unused. raise device_model.GuestNotAllowedError( device_model._GUEST_MODE_DISABLED_MSG) def directory_error(*args, **kwargs): del args, kwargs # Unused. raise device_model.EnableGuestError( 'Directory broke, all your fault.') mock_enableguest.side_effect = guest_disabled_error with self.assertRaises(endpoints.UnauthorizedException): self.service.enable_guest_mode( device_messages.DeviceRequest( chrome_device_id=self.device.chrome_device_id)) mock_enableguest.side_effect = directory_error with self.assertRaises(endpoints.InternalServerErrorException): self.service.enable_guest_mode( device_messages.DeviceRequest( chrome_device_id=self.device.chrome_device_id)) def test_enable_guest_unassigned(self): config_model.Config.set('allow_guest_mode', True) self.device.assigned_user = None self.device.put() with self.assertRaisesRegexp( endpoints.UnauthorizedException, device_model._UNASSIGNED_DEVICE % self.device.identifier): self.service.enable_guest_mode( device_messages.DeviceRequest( urlkey=self.device.key.urlsafe())) @mock.patch('__main__.device_model.Device.loan_extend') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_extend_loan(self, mock_xsrf_token, mock_loanextend): tomorrow = datetime.datetime.utcnow() + datetime.timedelta(days=1) self.login_endpoints_user() self.service.extend_loan( device_messages.ExtendLoanRequest( device=device_messages.DeviceRequest( urlkey=self.device.key.urlsafe()), extend_date=tomorrow)) mock_loanextend.assert_called_once_with( user_email=loanertest.USER_EMAIL, extend_date_time=tomorrow) self.assertEqual(mock_xsrf_token.call_count, 1) mock_xsrf_token.reset_mock() mock_loanextend.reset_mock() self.service.extend_loan( device_messages.ExtendLoanRequest( device=device_messages.DeviceRequest( chrome_device_id=self.device.chrome_device_id), extend_date=tomorrow)) mock_loanextend.assert_called_once_with( user_email=loanertest.USER_EMAIL, extend_date_time=tomorrow) self.assertEqual(mock_xsrf_token.call_count, 1) mock_loanextend.side_effect = device_model.ExtendError self.assertRaises( device_api.endpoints.BadRequestException, self.service.extend_loan, device_messages.ExtendLoanRequest( device=device_messages.DeviceRequest( chrome_device_id=self.device.chrome_device_id), extend_date=tomorrow)) def test_extend_loan_unassigned(self): self.device.assigned_user = None self.device.put() with self.assertRaisesRegexp( endpoints.UnauthorizedException, device_model._UNASSIGNED_DEVICE % self.device.identifier): self.service.extend_loan( device_messages.ExtendLoanRequest( device=device_messages.DeviceRequest( chrome_device_id=self.device.chrome_device_id))) @mock.patch('__main__.device_model.Device.mark_damaged') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_mark_damaged(self, mock_xsrf_token, mock_markdamaged): self.login_endpoints_user() self.service.mark_damaged( device_messages.DamagedRequest( device=device_messages.DeviceRequest( urlkey=self.device.key.urlsafe()), damaged_reason='Foo')) mock_markdamaged.assert_called_once_with( user_email=loanertest.USER_EMAIL, damaged_reason='Foo') self.assertEqual(mock_xsrf_token.call_count, 1) mock_xsrf_token.reset_mock() mock_markdamaged.reset_mock() self.service.mark_damaged( device_messages.DamagedRequest( # No reason given. device=device_messages.DeviceRequest( urlkey=self.device.key.urlsafe()))) mock_markdamaged.assert_called_once_with( user_email=loanertest.USER_EMAIL, damaged_reason=None) self.assertEqual(mock_xsrf_token.call_count, 1) @mock.patch.object(device_model.Device, 'mark_damaged') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_mark_damaged__unauthorized(self, mock_xsrf, mock_markdamaged): del mock_xsrf # Unused. self.login_endpoints_user() mock_markdamaged.side_effect = device_model.UnauthorizedError() with self.assertRaises(endpoints.UnauthorizedException): self.service.mark_damaged( device_messages.DamagedRequest( device=device_messages.DeviceRequest( urlkey=self.device.key.urlsafe()), damaged_reason='Foo')) def test_mark_undamaged(self): with mock.patch.object(self.device, 'mark_undamaged') as mock_markundamaged: self.service.mark_undamaged( device_messages.DeviceRequest( urlkey=self.device.key.urlsafe())) mock_markundamaged.assert_called_once_with( user_email=loanertest.SUPER_ADMIN_EMAIL) @mock.patch.object(device_model.Device, 'mark_undamaged') def test_mark_undamaged__unauthorized(self, mock_markundamaged): self.login_endpoints_user() with mock.patch.object(self.service, 'check_xsrf_token') as mock_xsrf_token: mock_markundamaged.side_effect = device_model.UnauthorizedError() with self.assertRaises(endpoints.UnauthorizedException): self.service.mark_undamaged( device_messages.DeviceRequest( urlkey=self.device.key.urlsafe())) self.assertEqual(mock_xsrf_token.call_count, 1) @mock.patch('__main__.device_model.Device.mark_lost') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_mark_lost(self, mock_xsrf_token, mock_marklost): self.service.mark_lost( device_messages.DeviceRequest(urlkey=self.device.key.urlsafe())) mock_marklost.assert_called_once_with( user_email=loanertest.SUPER_ADMIN_EMAIL) self.assertEqual(mock_xsrf_token.call_count, 1) @mock.patch.object(device_model.Device, 'mark_lost') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_mark_lost__unauthorized(self, mock_xsrf_token, mock_marklost): del mock_xsrf_token # Unused. mock_marklost.side_effect = device_model.UnauthorizedError() with self.assertRaises(endpoints.UnauthorizedException): self.service.mark_lost( device_messages.DeviceRequest( urlkey=self.device.key.urlsafe())) @mock.patch('__main__.device_model.Device.mark_pending_return') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_mark_pending_return(self, mock_xsrf_token, mock_markreturned): self.login_endpoints_user() self.service.mark_pending_return( device_messages.DeviceRequest(urlkey=self.device.key.urlsafe())) mock_markreturned.assert_called_once_with( user_email=loanertest.USER_EMAIL) self.assertEqual(mock_xsrf_token.call_count, 1) def test_mark_pending_return_unassigned(self): self.device.assigned_user = None self.device.put() with self.assertRaisesRegexp( endpoints.UnauthorizedException, device_model._UNASSIGNED_DEVICE % self.device.identifier): self.service.mark_pending_return( device_messages.DeviceRequest( urlkey=self.device.key.urlsafe())) @mock.patch.object(device_model.Device, 'complete_onboard') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_complete_onboard(self, mock_xsrf_token, mock_completeonboard): self.login_endpoints_user() self.service.complete_onboard( device_messages.DeviceRequest(urlkey=self.device.key.urlsafe())) mock_completeonboard.assert_called_once_with( user_email=loanertest.USER_EMAIL) self.assertEqual(mock_xsrf_token.call_count, 1) @mock.patch('__main__.device_model.Device.resume_loan') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_resume_loan(self, mock_xsrf_token, mock_resume_loan): self.login_endpoints_user() self.service.resume_loan( device_messages.DeviceRequest(urlkey=self.device.key.urlsafe())) self.assertEqual(mock_resume_loan.call_count, 1) self.assertEqual(mock_xsrf_token.call_count, 1) @mock.patch.object(device_model.Device, 'resume_loan') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_resume_loan__unauthorized(self, mock_xsrf_token, mock_resume_loan): del mock_xsrf_token # Unused. self.login_endpoints_user() mock_resume_loan.side_effect = device_model.UnauthorizedError() with self.assertRaises(endpoints.UnauthorizedException): self.service.resume_loan( device_messages.DeviceRequest( urlkey=self.device.key.urlsafe())) @mock.patch.object(bigquery, 'BigQueryClient') @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True) def test_get_history(self, mock_xsrf_token, mock_bigquery): device_request = device_messages.DeviceRequest() device_request.asset_tag = '12345' request = device_messages.HistoryRequest(device=device_request) device_response = device_messages.Device() device_response.asset_tag = '12345' expected_response = device_messages.HistoryResponse() for _ in range(2): expected_response.devices.append(device_response) expected_response.timestamp.append( datetime.datetime(2019, 10, 22, 20, 43, 37)) expected_response.actor.append('*****@*****.**') expected_response.summary.append( 'Beginning new loan for user [email protected] with device 12345.' ) bigquery_response = [ (u"Key('Device', 5158133238333440)", datetime.datetime(2019, 10, 22, 20, 43, 37), u'*****@*****.**', u'enable_guest_mode', u'Beginning new loan for user [email protected] with device 12345.', { u'ou_changed_date': datetime.datetime(2019, 10, 22, 20, 43, 37), u'current_ou': u'/', u'shelf': None, u'due_date': datetime.datetime(2019, 10, 22, 20, 43, 37), u'chrome_device_id': u'unique_id_1', u'mark_pending_return_date': None, u'asset_tag': u'12345', u'last_known_healthy': datetime.datetime(2019, 10, 22, 20, 43, 37), u'locked': False, u'last_reminder': { u'count': 1, u'time': datetime.datetime(2019, 10, 22, 20, 43, 37), u'level': 1 }, u'next_reminder': None, u'device_model': u'Chromebook', u'enrolled': True, u'serial_number': u'123ABC', u'damaged': False, u'onboarded': True, u'assignment_date': datetime.datetime(2019, 10, 22, 20, 43, 37), u'damaged_reason': None, u'assigned_user': u'*****@*****.**', u'lost': False, u'last_heartbeat': datetime.datetime(2019, 10, 22, 20, 43, 37) }), (u"Key('Device', 5158133238333440)", datetime.datetime(2019, 10, 22, 20, 43, 37), u'*****@*****.**', u'enable_guest_mode', u'Beginning new loan for user [email protected] with device 12345.', { u'ou_changed_date': datetime.datetime(2019, 10, 22, 20, 43, 37), u'current_ou': u'/', u'shelf': None, u'due_date': datetime.datetime(2019, 10, 22, 20, 43, 37), u'chrome_device_id': u'unique_id_1', u'mark_pending_return_date': None, u'asset_tag': u'12345', u'last_known_healthy': datetime.datetime(2019, 10, 22, 20, 43, 37), u'locked': False, u'last_reminder': { u'count': 1, u'time': datetime.datetime(2019, 10, 22, 20, 43, 37), u'level': 1 }, u'next_reminder': None, u'device_model': u'Chromebook', u'enrolled': True, u'serial_number': u'123ABC', u'damaged': False, u'onboarded': True, u'assignment_date': datetime.datetime(2019, 10, 22, 20, 43, 37), u'damaged_reason': None, u'assigned_user': u'*****@*****.**', u'lost': False, u'last_heartbeat': datetime.datetime(2019, 10, 22, 20, 43, 37) }), ] mock_bigquery_client = mock.Mock() mock_bigquery_client.get_device_info.return_value = bigquery_response mock_bigquery.return_value = mock_bigquery_client actual_response = self.service.get_history(request) self.assertEqual(actual_response, expected_response) def test_get_device_errors(self): # No identifiers. with self.assertRaises(endpoints.BadRequestException): device_api._get_device(device_messages.DeviceRequest()) # URL-safe key that is still URL-safe, but technically not a key. with self.assertRaises(device_api.endpoints.BadRequestException): device_api._get_device( device_messages.DeviceRequest(urlkey='bad-key'))