Example #1
0
 def test_parseMemo__json_error(self):
     # parseMemo() returns None for formally invalid JSON strings.
     resultset = self.makeStormResultSet()
     range_factory = StormRangeFactory(resultset, self.logError)
     self.assertIs(None, range_factory.parseMemo('foo'))
     self.assertEqual(
         ['memo is not a valid JSON string.'], self.error_messages)
Example #2
0
 def test_parseMemo__json_no_sequence(self):
     # parseMemo() accepts only JSON representations of lists.
     resultset = self.makeStormResultSet()
     range_factory = StormRangeFactory(resultset, self.logError)
     self.assertIs(None, range_factory.parseMemo(simplejson.dumps(1)))
     self.assertEqual(['memo must be the JSON representation of a list.'],
                      self.error_messages)
Example #3
0
 def test_parseMemo__descending_sort_order(self):
     # Validation of a memo string against a descending sort order works.
     resultset = self.makeStormResultSet()
     resultset.order_by(Desc(Person.id))
     range_factory = StormRangeFactory(resultset, self.logError)
     self.assertEqual(
         [1], range_factory.parseMemo(simplejson.dumps([1])))
Example #4
0
 def test_getOrderValuesFor__decorated_result_set(self):
     # getOrderValuesFor() knows how to retrieve SQL sort values
     # from DecoratedResultSets.
     resultset = self.makeDecoratedStormResultSet()
     range_factory = StormRangeFactory(resultset)
     self.assertEqual(
         [resultset[0].id], range_factory.getOrderValuesFor(resultset[0]))
Example #5
0
 def test_getSlice__returns_ShadowedList(self):
     # getSlice() returns lists.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.id)
     range_factory = StormRangeFactory(resultset)
     sliced_result = range_factory.getSlice(3)
     self.assertIsInstance(sliced_result, ShadowedList)
Example #6
0
 def test_limitsGroupedByOrderDirection(self):
     # limitsGroupedByOrderDirection() returns a sequence of
     # (expressions, memos), where expressions is a list of
     # ORDER BY expressions which either are all instances of
     # PropertyColumn, or are all instances of Desc(PropertyColumn).
     # memos are the related limit values.
     resultset = self.makeStormResultSet()
     range_factory = StormRangeFactory(resultset, self.logError)
     order_by = [
         Person.id, Person.datecreated, Person.name, Person.display_name
     ]
     limits = [1, datetime(2011, 7, 25, 0, 0, 0), 'foo', 'bar']
     result = range_factory.limitsGroupedByOrderDirection(order_by, limits)
     self.assertEqual([(order_by, limits)], result)
     order_by = [
         Desc(Person.id),
         Desc(Person.datecreated),
         Desc(Person.name),
         Desc(Person.display_name)
     ]
     result = range_factory.limitsGroupedByOrderDirection(order_by, limits)
     self.assertEqual([(order_by, limits)], result)
     order_by = [
         Person.id, Person.datecreated,
         Desc(Person.name),
         Desc(Person.display_name)
     ]
     result = range_factory.limitsGroupedByOrderDirection(order_by, limits)
     self.assertEqual([(order_by[:2], limits[:2]),
                       (order_by[2:], limits[2:])], result)
Example #7
0
 def test_getSlice__forward_without_memo(self):
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.name, Person.id)
     all_results = list(resultset)
     range_factory = StormRangeFactory(resultset)
     sliced_result = range_factory.getSlice(3)
     self.assertEqual(all_results[:3], list(sliced_result))
Example #8
0
 def test_getOrderValuesFor__two_sort_columns(self):
     # Sorting by more than one column is supported.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.displayname, Person.name)
     range_factory = StormRangeFactory(resultset)
     order_values = range_factory.getOrderValuesFor(resultset[0])
     self.assertEqual(
         [resultset[0].displayname, resultset[0].name], order_values)
Example #9
0
 def test_getOrderValuesFor__descending_sort_order(self):
     # getOrderValuesFor() can retrieve values from reverse sorted
     # columns.
     resultset = self.makeStormResultSet()
     resultset = resultset.order_by(Desc(Person.id))
     range_factory = StormRangeFactory(resultset)
     self.assertEqual(
         [resultset[0].id], range_factory.getOrderValuesFor(resultset[0]))
Example #10
0
 def test_whereExpressions__asc(self):
     """For ascending sort order, whereExpressions() returns the
     WHERE clause expression > memo.
     """
     resultset = self.makeStormResultSet()
     range_factory = StormRangeFactory(resultset, self.logError)
     [where_clause] = range_factory.whereExpressions([Person.id], [1])
     self.assertEquals('(Person.id) > (1)', compile(where_clause))
Example #11
0
 def test_getSlice__forward_with_memo(self):
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.name, Person.id)
     all_results = list(resultset)
     memo = simplejson.dumps([all_results[0].name, all_results[0].id])
     range_factory = StormRangeFactory(resultset)
     sliced_result = range_factory.getSlice(3, memo)
     self.assertEqual(all_results[1:4], list(sliced_result))
 def test_parseMemo__json_no_sequence(self):
     # parseMemo() accepts only JSON representations of lists.
     resultset = self.makeStormResultSet()
     range_factory = StormRangeFactory(resultset, self.logError)
     self.assertIs(None, range_factory.parseMemo(simplejson.dumps(1)))
     self.assertEqual(
         ['memo must be the JSON representation of a list.'],
         self.error_messages)
Example #13
0
 def test_getOrderValuesFor__one_sort_column(self):
     # StormRangeFactory.getOrderValuesFor() returns the values
     # of the fields used in order_by expresssions for a given
     # result row.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.id)
     range_factory = StormRangeFactory(resultset)
     order_values = range_factory.getOrderValuesFor(resultset[0])
     self.assertEqual([resultset[0].id], order_values)
Example #14
0
 def test_getSlice__backward_without_memo(self):
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.name, Person.id)
     all_results = list(resultset)
     expected = all_results[-3:]
     expected.reverse()
     range_factory = StormRangeFactory(resultset)
     sliced_result = range_factory.getSlice(3, forwards=False)
     self.assertEqual(expected, list(sliced_result))
Example #15
0
 def test_getOrderValuesFor__value_from_second_element_of_result_row(self):
     # getOrderValuesFor() can retrieve values from attributes
     # of any Storm table class instance which appear in a result row.
     resultset = self.makeDecoratedStormResultSet()
     resultset = resultset.order_by(LibraryFileAlias.id)
     plain_resultset = resultset.get_plain_result_set()
     range_factory = StormRangeFactory(resultset)
     self.assertEqual([plain_resultset[0][1].id],
                      range_factory.getOrderValuesFor(plain_resultset[0]))
Example #16
0
 def test_parseMemo__invalid_iso_timestamp_value(self):
     # An ISO timestamp with an invalid date is rejected as a memo
     # string.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.datecreated)
     range_factory = StormRangeFactory(resultset, self.logError)
     invalid_timestamp_json = '["2011-05-35T11:30:30"]'
     self.assertIs(None, range_factory.parseMemo(invalid_timestamp_json))
     self.assertEqual(["Invalid datetime value: '2011-05-35T11:30:30'"],
                      self.error_messages)
Example #17
0
 def test_getSlice__decorated_resultset(self):
     resultset = self.makeDecoratedStormResultSet()
     resultset.order_by(LibraryFileAlias.id)
     all_results = list(resultset)
     plain_results = list(resultset.get_plain_result_set())
     memo = simplejson.dumps([resultset.get_plain_result_set()[0][1].id])
     range_factory = StormRangeFactory(resultset)
     sliced_result = range_factory.getSlice(3, memo)
     self.assertEqual(all_results[1:4], list(sliced_result))
     self.assertEqual(plain_results[1:4], sliced_result.shadow_values)
 def test_getOrderValuesFor__value_from_second_element_of_result_row(self):
     # getOrderValuesFor() can retrieve values from attributes
     # of any Storm table class instance which appear in a result row.
     resultset = self.makeDecoratedStormResultSet()
     resultset = resultset.order_by(LibraryFileAlias.id)
     plain_resultset = resultset.get_plain_result_set()
     range_factory = StormRangeFactory(resultset)
     self.assertEqual(
         [plain_resultset[0][1].id],
         range_factory.getOrderValuesFor(plain_resultset[0]))
Example #19
0
 def test_parseMemo__valid_data(self):
     # If a memo string contains valid data, parseMemo returns this data.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.datecreated, Person.name, Person.id)
     range_factory = StormRangeFactory(resultset, self.logError)
     valid_memo = [
         datetime(2011, 7, 25, 11, 30, 30, 45, tzinfo=pytz.UTC), 'foo', 1]
     json_data = simplejson.dumps(valid_memo, cls=DateTimeJSONEncoder)
     self.assertEqual(valid_memo, range_factory.parseMemo(json_data))
     self.assertEqual(0, len(self.error_messages))
Example #20
0
 def test_parseMemo__memo_type_check(self):
     # parseMemo() accepts only lists containing values that can
     # be used in sort expression of the given result set.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.datecreated, Person.name, Person.id)
     range_factory = StormRangeFactory(resultset, self.logError)
     invalid_memo = [datetime(2011, 7, 25, 11, 30, 30, 45), 'foo', 'bar']
     json_data = simplejson.dumps(invalid_memo, cls=DateTimeJSONEncoder)
     self.assertIs(None, range_factory.parseMemo(json_data))
     self.assertEqual(["Invalid parameter: 'bar'"], self.error_messages)
Example #21
0
 def test_getSlice_backward_with_memo(self):
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.name, Person.id)
     all_results = list(resultset)
     expected = all_results[1:4]
     expected.reverse()
     memo = simplejson.dumps([all_results[4].name, all_results[4].id])
     range_factory = StormRangeFactory(resultset)
     sliced_result = range_factory.getSlice(3, memo, forwards=False)
     self.assertEqual(expected, list(sliced_result))
Example #22
0
 def test_parseMemo__wrong_list_length(self):
     # parseMemo() accepts only lists which have as many elements
     # as the number of sort expressions used in the SQL query of
     # the result set.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.name, Person.id)
     range_factory = StormRangeFactory(resultset, self.logError)
     self.assertIs(None, range_factory.parseMemo(simplejson.dumps([1])))
     expected_message = (
         'Invalid number of elements in memo string. Expected: 2, got: 1')
     self.assertEqual([expected_message], self.error_messages)
Example #23
0
 def test_parseMemo__short_iso_timestamp_with_tzoffset(self):
     # An ISO timestamp with fractions of a second and a time zone
     # offset (YYYY-MM-DDThh:mm:ss.ffffff+hh:mm) is a valid value
     # for columns which store datetime values.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.datecreated)
     range_factory = StormRangeFactory(resultset, self.logError)
     valid_long_timestamp_json = '["2011-07-25T11:30:30-01:00"]'
     self.assertEqual([datetime(2011, 7, 25, 12, 30, 30, tzinfo=pytz.UTC)],
                      range_factory.parseMemo(valid_long_timestamp_json))
     self.assertEqual(0, len(self.error_messages))
Example #24
0
 def test_parseMemo__nonsensical_iso_timestamp_value(self):
     # A memo string is rejected when an ISO timespamp is expected
     # but a nonsensical string is provided.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.datecreated)
     range_factory = StormRangeFactory(resultset, self.logError)
     nonsensical_timestamp_json = '["bar"]'
     self.assertIs(None,
                   range_factory.parseMemo(nonsensical_timestamp_json))
     self.assertEqual(["Invalid datetime value: 'bar'"],
                      self.error_messages)
Example #25
0
 def test_reverseSortOrder(self):
     # reverseSortOrder() wraps a plain PropertyColumn instance into
     # Desc(), and it returns the plain PropertyCOlumn for a Desc()
     # expression.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.id, Desc(Person.name))
     range_factory = StormRangeFactory(resultset, self.logError)
     reverse_person_id, person_name = range_factory.reverseSortOrder()
     self.assertTrue(isinstance(reverse_person_id, Desc))
     self.assertIs(Person.id, reverse_person_id.expr)
     self.assertIs(Person.name, person_name)
Example #26
0
 def test_lessThanOrGreaterThanExpression__desc(self):
     # beforeOrAfterExpression() returns an expression
     # (col1, col2,..) < (memo1, memo2...) for descending sort order.
     resultset = self.makeStormResultSet()
     range_factory = StormRangeFactory(resultset, self.logError)
     expressions = [Desc(Person.id), Desc(Person.name)]
     limits = [1, 'foo']
     limit_expression = range_factory.lessThanOrGreaterThanExpression(
         expressions, limits)
     self.assertEqual("(Person.id, Person.name) < (1, E'foo')",
                      compile(limit_expression))
 def test_parseMemo__wrong_list_length(self):
     # parseMemo() accepts only lists which have as many elements
     # as the number of sort expressions used in the SQL query of
     # the result set.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.name, Person.id)
     range_factory = StormRangeFactory(resultset, self.logError)
     self.assertIs(
         None, range_factory.parseMemo(simplejson.dumps([1])))
     expected_message = (
         'Invalid number of elements in memo string. Expected: 2, got: 1')
     self.assertEqual([expected_message], self.error_messages)
 def test_lessThanOrGreaterThanExpression__desc(self):
     # beforeOrAfterExpression() returns an expression
     # (col1, col2,..) < (memo1, memo2...) for descending sort order.
     resultset = self.makeStormResultSet()
     range_factory = StormRangeFactory(resultset, self.logError)
     expressions = [Desc(Person.id), Desc(Person.name)]
     limits = [1, 'foo']
     limit_expression = range_factory.lessThanOrGreaterThanExpression(
         expressions, limits)
     self.assertEqual(
         "(Person.id, Person.name) < (1, 'foo')",
         compile(limit_expression))
 def test_parseMemo__nonsensical_iso_timestamp_value(self):
     # A memo string is rejected when an ISO timespamp is expected
     # but a nonsensical string is provided.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.datecreated)
     range_factory = StormRangeFactory(resultset, self.logError)
     nonsensical_timestamp_json = '["bar"]'
     self.assertIs(
         None, range_factory.parseMemo(nonsensical_timestamp_json))
     self.assertEqual(
         ["Invalid datetime value: 'bar'"],
         self.error_messages)
 def test_parseMemo__long_iso_timestamp_with_tzoffset(self):
     # An ISO timestamp with fractions of a second and a time zone
     # offset (YYYY-MM-DDThh:mm:ss.ffffff+hh:mm) is a valid value
     # for columns which store datetime values.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.datecreated)
     range_factory = StormRangeFactory(resultset, self.logError)
     valid_long_timestamp_json = '["2011-07-25T11:30:30.123456+01:00"]'
     self.assertEqual(
         [datetime(2011, 7, 25, 10, 30, 30, 123456, tzinfo=pytz.UTC)],
         range_factory.parseMemo(valid_long_timestamp_json))
     self.assertEqual(0, len(self.error_messages))
 def test_parseMemo__short_iso_timestamp(self):
     # An ISO timestamp without fractions of a second
     # (YYYY-MM-DDThh:mm:ss) is a valid value for columns which
     # store datetime values.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.datecreated)
     range_factory = StormRangeFactory(resultset, self.logError)
     valid_short_timestamp_json = '["2011-07-25T11:30:30"]'
     self.assertEqual(
         [datetime(2011, 7, 25, 11, 30, 30, tzinfo=pytz.UTC)],
         range_factory.parseMemo(valid_short_timestamp_json))
     self.assertEqual(0, len(self.error_messages))
 def test_parseMemo__invalid_iso_timestamp_value(self):
     # An ISO timestamp with an invalid date is rejected as a memo
     # string.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.datecreated)
     range_factory = StormRangeFactory(resultset, self.logError)
     invalid_timestamp_json = '["2011-05-35T11:30:30"]'
     self.assertIs(
         None, range_factory.parseMemo(invalid_timestamp_json))
     self.assertEqual(
         ["Invalid datetime value: '2011-05-35T11:30:30'"],
         self.error_messages)
Example #33
0
 def test_getSliceByIndex__storm_result_set(self):
     # StormRangeFactory.getSliceByIndex() returns a slice of the
     # resultset, wrapped into a ShadowedList. For plain Storm
     # result sets, the main values and the shadow values are both
     # the corresponding elements of the result set.
     resultset = self.makeStormResultSet()
     all_results = list(resultset)
     range_factory = StormRangeFactory(resultset)
     sliced = range_factory.getSliceByIndex(2, 4)
     self.assertIsInstance(sliced, ShadowedList)
     self.assertEqual(all_results[2:4], list(sliced))
     self.assertEqual(all_results[2:4], sliced.shadow_values)
Example #34
0
 def test_getSlice__backwards_then_forwards(self):
     # A slice can be retrieved in both directions from one factory.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.id)
     all_results = list(resultset)
     memo = simplejson.dumps([all_results[2].id])
     range_factory = StormRangeFactory(resultset)
     backward_slice = range_factory.getSlice(
         size=2, endpoint_memo=memo, forwards=False)
     backward_slice.reverse()
     self.assertEqual(all_results[:2], list(backward_slice))
     forward_slice = range_factory.getSlice(
         size=2, endpoint_memo=memo, forwards=True)
     self.assertEqual(all_results[3:5], list(forward_slice))
Example #35
0
    def test_whereExpressions__two_sort_columns_desc_desc(self):
        """If the descending sort columns c1, c2 and the memo values
        m1, m2 are specified, whereExpressions() returns a WHERE
        expressions comparing the tuple (c1, c2) with the memo tuple
        (m1, m2):

        (c1, c2) < (m1, m2)
        """
        resultset = self.makeStormResultSet()
        range_factory = StormRangeFactory(resultset, self.logError)
        [where_clause] = range_factory.whereExpressions(
            [Desc(Person.id), Desc(Person.name)], [1, 'foo'])
        self.assertEquals(
            "(Person.id, Person.name) < (1, 'foo')", compile(where_clause))
Example #36
0
 def test_equalsExpressionsFromLimits(self):
     resultset = self.makeStormResultSet()
     range_factory = StormRangeFactory(resultset, self.logError)
     order_by = [
         Person.id, Person.datecreated, Desc(Person.name),
         Desc(Person.displayname)]
     limits = [
         1, datetime(2011, 07, 25, 0, 0, 0, tzinfo=pytz.UTC), 'foo', 'bar']
     limits = range_factory.limitsGroupedByOrderDirection(order_by, limits)
     equals_expressions = range_factory.equalsExpressionsFromLimits(limits)
     equals_expressions = map(compile, equals_expressions)
     self.assertEqual(
         ['Person.id = ?', 'Person.datecreated = ?', 'Person.name = ?',
          'Person.displayname = ?'],
         equals_expressions)
Example #37
0
 def _getBatchNavigator(self, grantees):
     """Return the batch navigator to be used to batch the grantees."""
     return BatchNavigator(grantees,
                           self.request,
                           hide_counts=True,
                           size=config.launchpad.default_batch_size,
                           range_factory=StormRangeFactory(grantees))
Example #38
0
 def test_StormRangeFactory__EmptyResultSet(self):
     # It is possible to create StormRangeFactory instances for
     # EmptyResultSets,
     resultset = EmptyResultSet()
     range_factory = StormRangeFactory(resultset)
     self.assertEqual(0, range_factory.rough_length)
     self.assertEmptyResultSetsWorking(range_factory)
 def test_getEndpointMemos(self):
     # getEndpointMemos() returns JSON representations of the
     # sort fields of the first and last element of a batch.
     resultset = self.makeStormResultSet()
     resultset.order_by(Person.name)
     range_factory = StormRangeFactory(resultset)
     memo_value = range_factory.getOrderValuesFor(resultset[0])
     request = LaunchpadTestRequest(
         QUERY_STRING='memo=%s' % simplejson.dumps(memo_value))
     batchnav = BatchNavigator(
         resultset, request, size=3, range_factory=range_factory)
     first, last = range_factory.getEndpointMemos(batchnav.batch)
     expected_first = simplejson.dumps(
         [resultset[1].name], cls=DateTimeJSONEncoder)
     expected_last = simplejson.dumps(
         [resultset[3].name], cls=DateTimeJSONEncoder)
     self.assertEqual(expected_first, first)
     self.assertEqual(expected_last, last)
 def test_getEndpointMemos__decorated_result_set(self):
     # getEndpointMemos() works for DecoratedResultSet
     # instances too.
     resultset = self.makeDecoratedStormResultSet()
     resultset.order_by(LibraryFileAlias.id)
     range_factory = StormRangeFactory(resultset)
     request = LaunchpadTestRequest()
     batchnav = BatchNavigator(
         resultset, request, size=3, range_factory=range_factory)
     first, last = range_factory.getEndpointMemos(batchnav.batch)
     expected_first = simplejson.dumps(
         [resultset.get_plain_result_set()[0][1].id],
         cls=DateTimeJSONEncoder)
     expected_last = simplejson.dumps(
         [resultset.get_plain_result_set()[2][1].id],
         cls=DateTimeJSONEncoder)
     self.assertEqual(expected_first, first)
     self.assertEqual(expected_last, last)