#!/usr/bin/env python # -*- coding: utf-8 -*- # This work was created by participants in the DataONE project, and is # jointly copyrighted by participating institutions in DataONE. For # more information on DataONE, see our web site at http://dataone.org. # # Copyright ${year} # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ''' :mod:`tier_1_mn_read_listobjects` ================================= :Created: 2011-04-22 :Author: DataONE (dahl) :Dependencies: - python 2.6 ''' # Std. import sys import logging import unittest # D1. from d1_common import xmlrunner import d1_common.const import d1_common.types.exceptions import d1_test_case # App. import context import test_client import test_utilities class Test030ListObjects(d1_test_case.D1TestCase): def assert_counts(self, object_list, start, count, total): self.assertEqual(object_list.start, start) self.assertEqual(object_list.count, count) self.assertEqual(object_list.total, total) self.assertEqual(len(object_list.objectInfo), count) def setUp(self): pass def test_010_get_object_count(self): '''Get object count. ''' client = test_client.TestClient(context.node['baseurl']) object_list = client.listObjects(context.TOKEN, start=0, count=0) self.assertEqual(object_list.start, 0) self.assertEqual(object_list.count, 0) # The server is required to have at least 15 objects to pass this test. # Without a few objects to perform tests on, many of the remaining tests in # the suite become meaningless. self.assertTrue(object_list.total >= 15) context.object_total = object_list.total def test_020_validate_object_count_1(self): '''Provided object count is correct (1). ''' # Get a slice that contains the last object. client = test_client.TestClient(context.node['baseurl']) object_list = client.listObjects(context.TOKEN, start=context.object_total - 1, count=d1_common.const.MAX_LISTOBJECTS) self.assert_counts(object_list, context.object_total - 1, 1, object_list.total) def test_020_validate_object_count_2(self): '''Provided object count is correct (2). ''' # - Get a slice that contains any objects after the last object. If this # returns anything, the initially obtained object count was wrong. # - Verify that server responds correctly when more than the available number # of objects are requsted. client = test_client.TestClient(context.node['baseurl']) object_list = client.listObjects(context.TOKEN, start=context.object_total, count=d1_common.const.MAX_LISTOBJECTS) self.assert_counts(object_list, context.object_total, 0, object_list.total) def test_030_get_slices(self): '''Get test object slices. 3 slices are needed, each with 5 objects. They are picked from the beginning, center and end of the available range. ''' client = test_client.TestClient(context.node['baseurl']) for start in (0, context.object_total / 2, context.object_total - 5): object_list = client.listObjects(context.TOKEN, start=start, count=5) # Each slice should be 5 objects, starting at the requested start. self.assert_counts(object_list, start, 5, context.object_total) # Store the slices for later tests. try: context.slices.append(object_list) except AttributeError: context.slices = [object_list] def test_040_invalid_request_negative_start(self): '''Negative 'start' parameter returns InvalidRequest. ''' # It's common to forget to check for negative numbers when validating # indexes. client = test_client.TestClient(context.node['baseurl']) self.assertRaises(d1_common.types.exceptions.InvalidRequest, client.listObjects, context.TOKEN, start=-1, count=d1_common.const.MAX_LISTOBJECTS) def test_050_invalid_request_invalid_count(self): ''''count' parameter higher than MAX_LISTOBJECTS returns InvalidRequest. ''' client = test_client.TestClient(context.node['baseurl']) self.assertRaises(d1_common.types.exceptions.InvalidRequest, client.listObjects, context.TOKEN, count=d1_common.const.MAX_LISTOBJECTS + 1) def test_060_invalid_request_negative_count(self): '''Negative 'count' parameter returns InvalidRequest. ''' client = test_client.TestClient(context.node['baseurl']) self.assertRaises(d1_common.types.exceptions.InvalidRequest, client.listObjects, context.TOKEN, count=-1) def test_070_date_range_1(self): '''startTime and endTime parameters are accepted separately and limit the number of returned objects. ''' # Find two unique datetimes. dates = [] for object_list in context.slices: for object_info in object_list.objectInfo: dates.append(object_info.dateSysMetadataModified) dates.sort() # Check that there are at least two unique timestamps. This test is not # applicable if all objects share the same timestamp. if dates[0] == dates[-1]: context.non_unique_timestamps = True return else: context.non_unique_timestamps = False client = test_client.TestClient(context.node['baseurl']) # It is now known that there are objects with at least two different # timestamps on the node, so filtering on the lowest timestamp must # eliminate at least one object. object_list = client.listObjects(context.TOKEN, startTime=dates[-1]) self.assertTrue(object_list.count < context.object_total) # Filtering on the highest timestamp must eliminate at least one object. object_list = client.listObjects(context.TOKEN, endTime=dates[0]) self.assertTrue(object_list.count < context.object_total) def test_075_date_range_2(self): '''startTime and endTime correctly split the number of returned objects. ''' # Find middle timestamp. dates = [] for object_list in context.slices: for object_info in object_list.objectInfo: dates.append(object_info.dateSysMetadataModified) dates.sort() client = test_client.TestClient(context.node['baseurl']) middle_date = dates[7] # Get object count for objects with timestamps lower than middle_date. low = client.listObjects(context.TOKEN, endTime=middle_date).total # Get object count for objects with timestamps higher or equal to # middle_date. high = client.listObjects(context.TOKEN, startTime=middle_date).total # Check that the separate totals match the total number of objects in the # collection. self.assertEqual(low + high, context.object_total) def test_080_date_range_3(self): '''startTime and endTime parameters are accepted together and limit the number of returned objects. ''' # Find two unique datetimes. dates = [] for object_list in context.slices: for object_info in object_list.objectInfo: dates.append(object_info.dateSysMetadataModified) dates.sort() # A range query between the lowest and highest datetime in the range must # include at last the number of objects that were included in the three # slices. client = test_client.TestClient(context.node['baseurl']) object_list = client.listObjects(context.TOKEN, startTime=dates[0], endTime=dates[-1], count=d1_common.const.MAX_LISTOBJECTS) self.assertTrue(object_list.count >= len(dates))