Example #1
0
    def test_list_shelves_with_offset(self):
        previouse_shelf_locations = []
        request = shelf_messages.Shelf(enabled=True,
                                       page_size=1,
                                       page_number=1)
        response = self.service.list_shelves(request)
        self.assertEqual(len(response.shelves), 1)
        previouse_shelf_locations.append(response.shelves[0].location)

        # Get next page results and make sure it's not the same as last.
        request = shelf_messages.Shelf(enabled=True,
                                       page_size=1,
                                       page_number=2)
        response = self.service.list_shelves(request)
        self.assertEqual(len(response.shelves), 1)
        self.assertNotIn(response.shelves[0], previouse_shelf_locations)
        previouse_shelf_locations.append(response.shelves[0].location)

        # Get next page results and make sure it's not the same as last 2.
        request = shelf_messages.Shelf(enabled=True,
                                       page_size=1,
                                       page_number=3)
        response = self.service.list_shelves(request)
        self.assertEqual(len(response.shelves), 1)
        self.assertNotIn(response.shelves[0], previouse_shelf_locations)
        previouse_shelf_locations.append(response.shelves[0].location)
Example #2
0
 def test_list_shelves_with_page_token(self):
   request = shelf_messages.Shelf(enabled=True, page_size=1)
   response_shelves = []
   while True:
     response = self.service.list_shelves(request)
     for shelf in response.shelves:
       self.assertIn(shelf.location, self.shelf_locations)
       response_shelves.append(shelf)
     request = shelf_messages.Shelf(
         enabled=True, page_size=1, page_token=response.page_token)
     if not response.has_additional_results:
       break
   self.assertLen(response_shelves, 3)
Example #3
0
  def list_shelves(self, request):
    """List enabled or all shelves based on any shelf 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:
      query = search_utils.to_query(request, shelf_model.Shelf)

    offset = search_utils.calculate_page_offset(
        page_size=request.page_size, page_number=request.page_number)

    search_results = shelf_model.Shelf.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)

    shelves_messages = []
    for document in search_results.results:
      message = search_utils.document_to_message(
          document, shelf_messages.Shelf())
      message.shelf_request = shelf_messages.ShelfRequest()
      message.shelf_request.urlsafe_key = document.doc_id
      message.shelf_request.location = message.location
      shelves_messages.append(message)

    return shelf_messages.ListShelfResponse(
        shelves=shelves_messages,
        total_results=search_results.number_found,
        total_pages=total_pages)
Example #4
0
 def setUp(self):
     super(ApiUtilsTest, self).setUp()
     self.test_shelf_model = shelf_model.Shelf(
         enabled=True,
         friendly_name='test_friendly_name',
         location='test_location',
         lat_long=ndb.GeoPt(10.10, 20.20),
         altitude=1.1,
         capacity=10,
         audit_interval_override=12,
         audit_notification_enabled=False,
         audit_requested=True,
         responsible_for_audit='test_group',
         last_audit_time=datetime.datetime(year=2018, month=1, day=1),
         last_audit_by='test_auditer').put().get()
     self.expected_shelf_message = shelf_messages.Shelf(
         shelf_request=shelf_messages.ShelfRequest(
             location='test_location',
             urlsafe_key=self.test_shelf_model.key.urlsafe()),
         enabled=True,
         friendly_name='test_friendly_name',
         location='test_location',
         identifier='test_friendly_name',
         latitude=10.10,
         longitude=20.20,
         altitude=1.1,
         capacity=10,
         audit_notification_enabled=False,
         audit_requested=True,
         responsible_for_audit='test_group',
         last_audit_time=datetime.datetime(year=2018, month=1, day=1),
         last_audit_by='test_auditer')
Example #5
0
 def test_list_shelves_with_search_constraints(self):
     expressions = shared_messages.SearchExpression(expression='location')
     expected_response = shelf_messages.ListShelfResponse(shelves=[
         shelf_messages.Shelf(location=self.shelf.location,
                              shelf_request=shelf_messages.ShelfRequest(
                                  location=self.shelf.location,
                                  urlsafe_key=self.shelf.key.urlsafe()))
     ],
                                                          total_results=1,
                                                          total_pages=1)
     request = shelf_messages.Shelf(
         query=shared_messages.SearchRequest(query_string='location:NYC',
                                             expressions=[expressions],
                                             returned_fields=['location']))
     response = self.service.list_shelves(request)
     self.assertEqual(response, expected_response)
Example #6
0
def build_shelf_message_from_model(shelf):
    """Builds a shelf_messages.Shelf ProtoRPC message.

  Args:
    shelf: shelf_model.Shelf, the shelf to build a message for.

  Returns:
    A shelf_messages.Shelf ProtoRPC message for the given shelf.
  """
    return shelf_messages.Shelf(
        shelf_request=shelf_messages.ShelfRequest(
            location=shelf.location, urlsafe_key=shelf.key.urlsafe()),
        enabled=shelf.enabled,
        friendly_name=shelf.friendly_name,
        location=shelf.location,
        latitude=shelf.latitude,
        longitude=shelf.longitude,
        altitude=shelf.altitude,
        capacity=shelf.capacity,
        audit_notification_enabled=shelf.audit_notification_enabled,
        audit_requested=shelf.audit_requested,
        responsible_for_audit=shelf.responsible_for_audit,
        last_audit_time=shelf.last_audit_time,
        last_audit_by=shelf.last_audit_by,
    )
Example #7
0
    def list_shelves(self, request):
        """List enabled or all shelves based on any shelf attribute."""
        self.check_xsrf_token(self.request_state)
        query, sort_options, returned_fields = (
            search_utils.set_search_query_options(request.query))
        if not query:
            query = search_utils.to_query(request, shelf_model.Shelf)

        cursor = search_utils.get_search_cursor(request.page_token)
        search_results = shelf_model.Shelf.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

        shelves_messages = []
        for document in search_results.results:
            message = search_utils.document_to_message(document,
                                                       shelf_messages.Shelf())
            message.shelf_request = shelf_messages.ShelfRequest()
            message.shelf_request.urlsafe_key = document.doc_id
            message.shelf_request.location = message.location
            shelves_messages.append(message)

        return shelf_messages.ListShelfResponse(
            shelves=shelves_messages,
            additional_results=bool(new_search_cursor),
            page_token=new_search_cursor)
Example #8
0
 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)
Example #9
0
 def test_to_dict(self):
   """Test that a dictionary is build from a ProtoRPC message."""
   message = shelf_messages.Shelf(
       location='NY', capacity=50, friendly_name='The_Big_Apple',
       audit_requested=False, responsible_for_audit='daredevils',
       last_audit_by=loanertest.USER_EMAIL, enabled=True)
   expected_dict = {
       'location': 'NY', 'capacity': 50, 'friendly_name': 'The_Big_Apple',
       'audit_requested': False, 'responsible_for_audit': 'daredevils',
       'last_audit_by': loanertest.USER_EMAIL, 'enabled': True}
   filters = api_utils.to_dict(message, shelf_model.Shelf)
   self.assertEqual(filters, expected_dict)
Example #10
0
    def test_document_to_message(self, mock_logging):
        """Tests the creation of a protorpc message from a search document."""
        test_search_document = 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')
            ])
        expected_message = shelf_messages.Shelf(enabled=True,
                                                location='US-MTV',
                                                capacity=20,
                                                latitude=52.37,
                                                longitude=4.88)

        response_message = search_utils.document_to_message(
            test_search_document, shelf_messages.Shelf())
        self.assertEqual(response_message, expected_message)
        self.assertTrue(response_message.enabled)
        assert mock_logging.error.call_count == 1
Example #11
0
    def testShelf(self):
        last_audit_date = datetime.datetime.now()
        shelf = shelf_messages.Shelf(enabled=True,
                                     friendly_name='FAKE-FRIENDLY-NAME',
                                     location='FAKE-LOCATION',
                                     identifier='FAKE-IDENTIFIER',
                                     latitude=20.45,
                                     longitude=30.85,
                                     altitude=25.3,
                                     capacity=10,
                                     audit_notification_enabled=True,
                                     audit_requested=False,
                                     responsible_for_audit='FAKE-AUDIT-PERSON',
                                     last_audit_time=last_audit_date,
                                     last_audit_by='FAKE-LAST-AUDIT-PERSON',
                                     page_token='FAKE-PAGE-TOKEN',
                                     page_size=50,
                                     audit_interval_override=20,
                                     audit_enabled=True)

        self.assertTrue(shelf.enabled)
        self.assertTrue(shelf.audit_enabled)
        self.assertFalse(shelf.audit_requested)
        self.assertTrue(shelf.audit_notification_enabled)

        self.assertEqual(shelf.capacity, 10)
        self.assertEqual(shelf.page_size, 50)
        self.assertEqual(shelf.altitude, 25.3)
        self.assertEqual(shelf.latitude, 20.45)
        self.assertEqual(shelf.longitude, 30.85)
        self.assertEqual(shelf.audit_interval_override, 20)

        self.assertEqual(shelf.last_audit_time, last_audit_date)

        self.assertEqual(shelf.location, 'FAKE-LOCATION')
        self.assertEqual(shelf.identifier, 'FAKE-IDENTIFIER')
        self.assertEqual(shelf.page_token, 'FAKE-PAGE-TOKEN')
        self.assertEqual(shelf.friendly_name, 'FAKE-FRIENDLY-NAME')
        self.assertEqual(shelf.last_audit_by, 'FAKE-LAST-AUDIT-PERSON')
        self.assertEqual(shelf.responsible_for_audit, 'FAKE-AUDIT-PERSON')
Example #12
0
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)
Example #13
0
class ApiUtilsTest(parameterized.TestCase, loanertest.TestCase):
    def setUp(self):
        super(ApiUtilsTest, self).setUp()
        self.test_shelf_model = shelf_model.Shelf(
            enabled=True,
            friendly_name='test_friendly_name',
            location='test_location',
            lat_long=ndb.GeoPt(10.10, 20.20),
            altitude=1.1,
            capacity=10,
            audit_interval_override=12,
            audit_notification_enabled=False,
            audit_requested=True,
            responsible_for_audit='test_group',
            last_audit_time=datetime.datetime(year=2018, month=1, day=1),
            last_audit_by='test_auditer').put().get()
        self.expected_shelf_message = shelf_messages.Shelf(
            shelf_request=shelf_messages.ShelfRequest(
                location='test_location',
                urlsafe_key=self.test_shelf_model.key.urlsafe()),
            enabled=True,
            friendly_name='test_friendly_name',
            location='test_location',
            identifier='test_friendly_name',
            latitude=10.10,
            longitude=20.20,
            altitude=1.1,
            capacity=10,
            audit_notification_enabled=False,
            audit_requested=True,
            responsible_for_audit='test_group',
            last_audit_time=datetime.datetime(year=2018, month=1, day=1),
            last_audit_by='test_auditer')

    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=test_device.return_dates.max,
            overdue=True,
        )
        actual_message = api_utils.build_device_message_from_model(
            test_device, True)
        self.assertEqual(actual_message, expected_message)

    @parameterized.parameters(
        (1, datetime.datetime(year=2018, month=1, day=1), 2),
        (3, datetime.datetime(year=2017, month=4, day=2), None),
        (5, None, 6),
    )
    def test_build_reminder_message_from_model(self, test_level, test_datetime,
                                               test_count):
        """Test the construction of a reminder message from a reminder entity."""
        test_reminder = device_model.Reminder(level=test_level,
                                              time=test_datetime,
                                              count=test_count).put().get()
        expected_message = device_messages.Reminder(level=test_level,
                                                    time=test_datetime,
                                                    count=test_count)
        returned_message = api_utils.build_reminder_message_from_model(
            test_reminder)
        self.assertEqual(returned_message, expected_message)

    def test_build_shelf_message_from_model(self):
        """Test the construction of a shelf message from a shelf entitiy."""
        actual_message = api_utils.build_shelf_message_from_model(
            self.test_shelf_model)
        self.assertEqual(actual_message, self.expected_shelf_message)

    @parameterized.named_parameters(
        {
            'testcase_name':
            'with_lat_long',
            'message':
            shelf_messages.Shelf(location='NY',
                                 capacity=50,
                                 friendly_name='Big_Apple',
                                 audit_requested=False,
                                 responsible_for_audit='daredevils',
                                 latitude=12.5,
                                 longitude=12.5,
                                 last_audit_by=loanertest.USER_EMAIL,
                                 enabled=True),
            'expected_dict': {
                'location': 'NY',
                'capacity': 50,
                'friendly_name': 'Big_Apple',
                'audit_requested': False,
                'responsible_for_audit': 'daredevils',
                'lat_long': ndb.GeoPt(12.5, 12.5),
                'last_audit_by': loanertest.USER_EMAIL,
                'enabled': True
            },
        }, {
            'testcase_name': 'without_lat_long',
            'message': shelf_messages.Shelf(location='NY'),
            'expected_dict': {
                'location': 'NY',
                'enabled': True
            },
        })
    def test_to_dict(self, message, expected_dict):
        """Test that a dictionary is build from a ProtoRPC message."""
        filters = api_utils.to_dict(message, shelf_model.Shelf)
        self.assertEqual(filters, expected_dict)

    def test_get_ndb_key_not_found(self):
        """Test the get of an ndb.Key, raises endpoints.BadRequestException."""
        with self.assertRaisesRegexp(endpoints.BadRequestException,
                                     api_utils._CORRUPT_KEY_MSG):
            api_utils.get_ndb_key('corruptKey')

    def test_get_datastore_cursor_not_found(self):
        """Test the get of a datastore.Cursor, raises endpoints.BadRequestException.
    """
        with self.assertRaisesRegexp(endpoints.BadRequestException,
                                     api_utils._MALFORMED_PAGE_TOKEN_MSG):
            api_utils.get_datastore_cursor('malformedPageToken')
Example #14
0
class ShelfApiTest(parameterized.TestCase, loanertest.EndpointsTestCase):
    """Test for the Shelf API."""
    def setUp(self):
        super(ShelfApiTest, self).setUp()
        self.patcher_directory = mock.patch(
            '__main__.device_model.directory.DirectoryApiClient')
        self.mock_directoryclass = self.patcher_directory.start()
        self.addCleanup(self.patcher_directory.stop)
        self.service = shelf_api.ShelfApi()
        self.login_admin_endpoints_user()
        self.patcher_xsrf = mock.patch(
            '__main__.shelf_api.root_api.Service.check_xsrf_token')
        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)
        shelf1 = shelf_model.Shelf.enroll(user_email=loanertest.USER_EMAIL,
                                          location='MTV',
                                          capacity=20)
        shelf2 = shelf_model.Shelf.enroll(user_email=loanertest.USER_EMAIL,
                                          location='SAO',
                                          capacity=10)
        self.disabled_shelf = shelf_model.Shelf.enroll(
            user_email=loanertest.USER_EMAIL,
            location='SVL',
            capacity=10,
            friendly_name='Bay')
        self.disabled_shelf.disable(loanertest.USER_EMAIL)
        self.shelf_locations = [
            self.shelf.location, shelf1.location, shelf2.location,
            self.disabled_shelf.location
        ]

        self.device1_key = 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()
        self.device2_key = device_model.Device(
            serial_number='54321',
            enrolled=True,
            device_model='HP Chromebook 13 G1',
            current_ou='/',
            chrome_device_id='unique_id_2',
            damaged=False,
        ).put()
        self.device3_key = device_model.Device(
            serial_number='67890',
            enrolled=True,
            shelf=self.shelf.key,
            device_model='HP Chromebook 13 G1',
            current_ou='/',
            chrome_device_id='unique_id_3',
            damaged=False,
        ).put()
        self.device4_key = device_model.Device(
            serial_number='ABC123',
            enrolled=True,
            shelf=self.shelf.key,
            device_model='HP Chromebook 13 G1',
            current_ou='/',
            chrome_device_id='unique_id_4',
            damaged=False,
        ).put()
        self.device_identifiers = [
            self.device1_key.get().serial_number,
            self.device2_key.get().serial_number,
            self.device3_key.get().serial_number
        ]

    def tearDown(self):
        super(ShelfApiTest, self).tearDown()
        self.service = None

    @mock.patch('__main__.root_api.Service.check_xsrf_token')
    @mock.patch('__main__.shelf_model.Shelf.enroll')
    def test_enroll(self, mock_enroll, mock_xsrf_token):
        """Test Enroll with mock methods."""
        request = shelf_messages.EnrollShelfRequest(
            location='nyc',
            capacity=100,
            friendly_name='test',
            latitude=12.5,
            longitude=12.5,
            altitude=2.0,
            responsible_for_audit='precise',
            audit_interval_override=33,
            audit_notification_enabled=True)
        response = self.service.enroll(request)
        assert mock_xsrf_token.call_count == 1
        self.assertIsInstance(response, message_types.VoidMessage)

    def test_enroll_bad_request(self):
        request = shelf_messages.EnrollShelfRequest(capacity=10)
        with self.assertRaisesRegexp(shelf_api.endpoints.BadRequestException,
                                     'Entity has uninitialized properties'):
            self.service.enroll(request)
        request = shelf_messages.EnrollShelfRequest(location='nyc',
                                                    capacity=10,
                                                    latitude=12.5)
        with self.assertRaisesRegexp(shelf_api.endpoints.BadRequestException,
                                     shelf_model._LAT_LONG_MSG):
            self.service.enroll(request)

    @mock.patch('__main__.root_api.Service.check_xsrf_token')
    def test_get_by_location(self, mock_xsrf_token):
        request = shelf_messages.ShelfRequest(location='NYC')
        response = self.service.get(request)
        assert mock_xsrf_token.call_count == 1
        self.assertEqual(self.shelf.location, response.location)
        self.assertEqual(self.shelf.friendly_name, response.friendly_name)

    def test_disable_by_location(self):
        request = shelf_messages.ShelfRequest(location='NYC')
        self.assertTrue(self.shelf.enabled)
        response = self.service.disable(request)
        self.assertFalse(self.shelf.enabled)
        self.assertIsInstance(response, message_types.VoidMessage)

    @mock.patch('__main__.root_api.Service.check_xsrf_token')
    def test_update_using_location(self, mock_xsrf_token):
        request = shelf_messages.UpdateShelfRequest(
            shelf_request=shelf_messages.ShelfRequest(location='NYC'),
            location='NYC-9th')
        response = self.service.update(request)
        assert mock_xsrf_token.call_count == 1
        self.assertEqual(self.shelf.location, 'NYC-9th')
        shelf = shelf_model.Shelf.get(friendly_name='GnG')
        self.assertEqual(shelf.location, 'NYC-9th')
        self.assertIsInstance(response, message_types.VoidMessage)

    @parameterized.parameters((
        shelf_messages.Shelf(capacity=10),
        2,
    ), (
        shelf_messages.Shelf(enabled=False),
        1,
    ), (
        shelf_messages.Shelf(query=shared_messages.SearchRequest(
            query_string='enabled:True capacity:10')),
        2,
    ), (
        shelf_messages.Shelf(query=shared_messages.SearchRequest(
            query_string='enabled:False')),
        1,
    ))
    @mock.patch('__main__.root_api.Service.check_xsrf_token')
    def test_list_shelves(self, request, response_length, mock_xsrf_token):
        response = self.service.list_shelves(request)
        assert mock_xsrf_token.call_count == 1
        self.assertEqual(response_length, len(response.shelves))

    def test_list_shelves_invalid_page_size(self):
        with self.assertRaises(endpoints.BadRequestException):
            request = shelf_messages.Shelf(page_size=0)
            self.service.list_shelves(request)

    def test_list_shelves_with_search_constraints(self):
        expressions = shared_messages.SearchExpression(expression='location')
        expected_response = shelf_messages.ListShelfResponse(shelves=[
            shelf_messages.Shelf(location=self.shelf.location,
                                 shelf_request=shelf_messages.ShelfRequest(
                                     location=self.shelf.location,
                                     urlsafe_key=self.shelf.key.urlsafe()))
        ],
                                                             total_results=1,
                                                             total_pages=1)
        request = shelf_messages.Shelf(
            query=shared_messages.SearchRequest(query_string='location:NYC',
                                                expressions=[expressions],
                                                returned_fields=['location']))
        response = self.service.list_shelves(request)
        self.assertEqual(response, expected_response)

    def test_list_shelves_with_offset(self):
        previouse_shelf_locations = []
        request = shelf_messages.Shelf(enabled=True,
                                       page_size=1,
                                       page_number=1)
        response = self.service.list_shelves(request)
        self.assertEqual(len(response.shelves), 1)
        previouse_shelf_locations.append(response.shelves[0].location)

        # Get next page results and make sure it's not the same as last.
        request = shelf_messages.Shelf(enabled=True,
                                       page_size=1,
                                       page_number=2)
        response = self.service.list_shelves(request)
        self.assertEqual(len(response.shelves), 1)
        self.assertNotIn(response.shelves[0], previouse_shelf_locations)
        previouse_shelf_locations.append(response.shelves[0].location)

        # Get next page results and make sure it's not the same as last 2.
        request = shelf_messages.Shelf(enabled=True,
                                       page_size=1,
                                       page_number=3)
        response = self.service.list_shelves(request)
        self.assertEqual(len(response.shelves), 1)
        self.assertNotIn(response.shelves[0], previouse_shelf_locations)
        previouse_shelf_locations.append(response.shelves[0].location)

    @mock.patch('__main__.root_api.Service.check_xsrf_token')
    @mock.patch('__main__.shelf_api.logging.info')
    def test_audit_using_shelf_location(self, mock_logging, mock_xsrf_token):
        request = shelf_messages.ShelfAuditRequest(
            shelf_request=shelf_messages.ShelfRequest(location='NYC'),
            device_identifiers=self.device_identifiers)
        response = self.service.audit(request)
        assert mock_xsrf_token.call_count == 1
        mock_logging.assert_called()
        for identifier in self.device_identifiers:
            datastore_device = device_model.Device.get(
                serial_number=identifier)
            self.assertEqual(datastore_device.shelf.get().location, 'NYC')
        self.assertFalse(self.shelf.audit_requested)
        self.assertEqual(self.shelf.last_audit_by,
                         loanertest.SUPER_ADMIN_EMAIL)
        self.assertIsInstance(response, message_types.VoidMessage)

    def test_audit_invalid_device(self):
        request = shelf_messages.ShelfAuditRequest(
            shelf_request=shelf_messages.ShelfRequest(location='NYC'),
            device_identifiers=['Invalid'])
        with self.assertRaisesRegexp(
                endpoints.NotFoundException,
                shelf_api._DEVICE_DOES_NOT_EXIST_MSG % 'Invalid'):
            self.service.audit(request)

    @mock.patch.object(device_model.Device, 'search')
    @mock.patch.object(shelf_api, 'get_shelf', autospec=True)
    def test_audit_remove_devices(self, mock_get_shelf,
                                  mock_model_device_search):
        shelf = self.device2_key.get()
        shelf.shelf = self.shelf.key
        shelf.put()
        mock_model_device_search.return_value = (search.SearchResults(
            results=[
                search.ScoredDocument(doc_id=self.device2_key.urlsafe()),
                search.ScoredDocument(doc_id=self.device3_key.urlsafe()),
                search.ScoredDocument(doc_id=self.device4_key.urlsafe())
            ],
            number_found=3))
        mock_get_shelf.return_value = self.shelf
        request = shelf_messages.ShelfAuditRequest(
            shelf_request=shelf_messages.ShelfRequest(
                location=self.shelf.location),
            device_identifiers=[self.device3_key.get().serial_number])
        self.service.audit(request)
        self.assertEqual(self.device3_key.get().shelf, self.shelf.key)
        self.assertEqual(self.device2_key.get().shelf, None)
        self.assertEqual(self.device4_key.get().shelf, None)

    def test_get_shelf_urlsafe_key(self):
        """Test getting a shelf using the urlsafe key."""
        request = shelf_messages.ShelfRequest(
            urlsafe_key=self.shelf.key.urlsafe())
        shelf = shelf_api.get_shelf(request)
        self.assertEqual(shelf, self.shelf)

    def test_get_shelf_using_location(self):
        """Test getting a shelf using the location."""
        request = shelf_messages.ShelfRequest(location=self.shelf.location)
        shelf = shelf_api.get_shelf(request)
        self.assertEqual(shelf, self.shelf)

    def test_get_shelf_using_location_error(self):
        """Test getting a shelf with an invalid location."""
        request = shelf_messages.ShelfRequest(location='Not_Valid')
        with self.assertRaisesRegexp(
                endpoints.NotFoundException,
                shelf_api._SHELF_DOES_NOT_EXIST_MSG % request.location):
            shelf_api.get_shelf(request)
Example #15
0
 def test_list_shelves_invalid_page_size(self):
     with self.assertRaises(endpoints.BadRequestException):
         request = shelf_messages.Shelf(page_size=0)
         self.service.list_shelves(request)
Example #16
0
class SearchTest(loanertest.EndpointsTestCase, parameterized.TestCase):
    @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(' '))

    @mock.patch.object(search_utils, 'logging', autospec=True)
    def test_document_to_message(self, mock_logging):
        """Tests the creation of a protorpc message from a search document."""
        test_search_document = 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')
            ])
        expected_message = shelf_messages.Shelf(enabled=True,
                                                location='US-MTV',
                                                capacity=20,
                                                latitude=52.37,
                                                longitude=4.88)

        response_message = search_utils.document_to_message(
            test_search_document, shelf_messages.Shelf())
        self.assertEqual(response_message, expected_message)
        self.assertTrue(response_message.enabled)
        assert mock_logging.error.call_count == 1

    def test_get_search_cursor(self):
        """Tests the creation of a search cursor with a web_safe_string."""
        expected_cursor_web_safe_string = 'False:ODUxODBhNTgyYTQ2ZmI0MDU'
        returned_cursor = (
            search_utils.get_search_cursor(expected_cursor_web_safe_string))
        self.assertEqual(expected_cursor_web_safe_string,
                         returned_cursor.web_safe_string)

    @mock.patch.object(search, 'Cursor', autospec=True)
    def test_get_search_cursor_error(self, mock_cursor):
        """Tests the creation of a search cursor when an error occurs."""
        mock_cursor.side_effect = ValueError
        with self.assertRaisesWithLiteralMatch(endpoints.BadRequestException,
                                               search_utils._CORRUPT_KEY_MSG):
            search_utils.get_search_cursor(None)

    @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)