Example #1
0
    def setUp(self):
        with patch('ceres.isdir', new=Mock(return_value=True)):
            with patch('ceres.exists', new=Mock(return_value=True)):
                self.ceres_tree = CeresTree('/graphite/storage/ceres')
                self.ceres_node = CeresNode(
                    self.ceres_tree, 'sample_metric',
                    '/graphite/storage/ceres/sample_metric')
                self.ceres_node.timeStep = 60

        slice_configs = [(1200, 1800, 60), (600, 1200, 60)]

        self.ceres_slices = []
        for start, end, step in slice_configs:
            slice_mock = make_slice_mock(start, end, step)
            self.ceres_slices.append(slice_mock)
Example #2
0
    def find_nodes(self, query):
        # translate query pattern if it is tagged
        tagged = not query.pattern.startswith('_tagged.') and ';' in query.pattern
        if tagged:
            # tagged series are stored in ceres using encoded names, so to retrieve them we need to
            # encode the query pattern using the same scheme used in carbon when they are written.
            variants = [
                TaggedSeries.encode(query.pattern, hash_only=True),
                TaggedSeries.encode(query.pattern, hash_only=False),
            ]
        else:
            variants = extract_variants(query.pattern)

        for variant in variants:
            for fs_path in glob(self.tree.getFilesystemPath(variant)):
                metric_path = self.tree.getNodePath(fs_path)

                if CeresNode.isNodeDir(fs_path):
                    ceres_node = self.tree.getNode(metric_path)

                    if ceres_node.hasDataForInterval(query.startTime, query.endTime):
                        real_metric_path = get_real_metric_path(fs_path, metric_path)
                        reader = CeresReader(ceres_node, real_metric_path)
                        # if we're finding by tag, return the proper metric path
                        if tagged:
                            metric_path = query.pattern
                        yield LeafNode(metric_path, reader)

                elif os.path.isdir(fs_path):
                    yield BranchNode(metric_path)
Example #3
0
    def find_nodes(self, query):

        # translate query pattern if it is tagged
        tagged = not query.pattern.startswith(
            '_tagged.') and ';' in query.pattern
        if tagged:
            # tagged series are stored in ceres using encoded names, so to retrieve them we need to encode the
            # query pattern using the same scheme used in carbon when they are written.
            variants = [TaggedSeries.encode(query.pattern)]
        else:
            variants = extract_variants(query.pattern)

        for variant in variants:
            for fs_path in glob(self.tree.getFilesystemPath(variant)):
                metric_path = self.tree.getNodePath(fs_path)

                if CeresNode.isNodeDir(fs_path):
                    ceres_node = self.tree.getNode(metric_path)

                    if ceres_node.hasDataForInterval(query.startTime,
                                                     query.endTime):
                        real_metric_path = get_real_metric_path(
                            fs_path, metric_path)
                        reader = CeresReader(ceres_node, real_metric_path)
                        # if we're finding by tag, return the proper metric path
                        if tagged:
                            metric_path = query.pattern
                        yield LeafNode(metric_path, reader)

                elif os.path.isdir(fs_path):
                    yield BranchNode(metric_path)
Example #4
0
 def setUp(self):
     with patch('ceres.isdir', new=Mock(return_value=True)):
         with patch('ceres.exists', new=Mock(return_value=True)):
             self.ceres_tree = CeresTree('/graphite/storage/ceres')
             self.ceres_node = CeresNode(
                 self.ceres_tree, 'sample_metric',
                 '/graphite/storage/ceres/sample_metric')
Example #5
0
    def find_nodes(self, query):
        for fs_path in glob(self.tree.getFilesystemPath(query.pattern)):
            metric_path = self.tree.getNodePath(fs_path)

            if CeresNode.isNodeDir(fs_path):
                ceres_node = self.tree.getNode(metric_path)

                if ceres_node.hasDataForInterval(query.startTime, query.endTime):
                    real_metric_path = get_real_metric_path(fs_path, metric_path)
                    reader = CeresReader(ceres_node, real_metric_path)
                    yield LeafNode(metric_path, reader)

            elif os.path.isdir(fs_path):
                yield BranchNode(metric_path)
Example #6
0
    def find_nodes(self, query):
        for fs_path in glob( self.tree.getFilesystemPath(query.pattern) ):
            metric_path = self.tree.getNodePath(fs_path)

            if CeresNode.isNodeDir(fs_path):
                ceres_node = self.tree.getNode(metric_path)

                if ceres_node.hasDataForInterval(query.startTime, query.endTime):
                    real_metric_path = get_real_metric_path(fs_path, metric_path)
                    reader = CeresReader(ceres_node, real_metric_path)
                    yield LeafNode(metric_path, reader)

            elif os.path.isdir(fs_path):
                yield BranchNode(metric_path)
Example #7
0
  def setUp(self):
    with patch('ceres.isdir', new=Mock(return_value=True)):
      with patch('ceres.exists', new=Mock(return_value=True)):
        self.ceres_tree = CeresTree('/graphite/storage/ceres')
        self.ceres_node = CeresNode(
            self.ceres_tree,
            'sample_metric',
            '/graphite/storage/ceres/sample_metric')
        self.ceres_node.timeStep = 60

    slice_configs = [
      (1200, 1800, 60),
      (600, 1200, 60)]

    self.ceres_slices = []
    for start, end, step in slice_configs:
      slice_mock = make_slice_mock(start, end, step)
      self.ceres_slices.append(slice_mock)
Example #8
0
  def find_nodes(self, query):

    variants = extract_variants(query.pattern)

    for variant in variants:
      for fs_path in glob( self.tree.getFilesystemPath(variant)):
        metric_path = self.tree.getNodePath(fs_path)

        if CeresNode.isNodeDir(fs_path):
          ceres_node = self.tree.getNode(metric_path)

          if ceres_node.hasDataForInterval(query.startTime, query.endTime):
            relative_path = fs_path[len(self.directory):].lstrip('/')
            real_metric_path = get_real_metric_path(fs_path, relative_path)
            reader = CeresReader(ceres_node, real_metric_path)
            yield LeafNode(metric_path, reader)

        elif os.path.isdir(fs_path):
          yield BranchNode(metric_path)
Example #9
0
 def test_create_sets_a_default_timestep(self, write_metadata_mock):
     CeresNode.create(self.ceres_tree, 'sample_metric')
     write_metadata_mock.assert_called_with(dict(timeStep=DEFAULT_TIMESTEP))
Example #10
0
 def test_init_sets_default_cache_behavior(self):
     ceres_node = CeresNode(self.ceres_tree, 'sample_metric',
                            '/graphite/storage/ceres/sample_metric')
     self.assertEqual(DEFAULT_SLICE_CACHING_BEHAVIOR,
                      ceres_node.sliceCachingBehavior)
Example #11
0
class CeresNodeTest(TestCase):
    def setUp(self):
        with patch('ceres.isdir', new=Mock(return_value=True)):
            with patch('ceres.exists', new=Mock(return_value=True)):
                self.ceres_tree = CeresTree('/graphite/storage/ceres')
                self.ceres_node = CeresNode(
                    self.ceres_tree, 'sample_metric',
                    '/graphite/storage/ceres/sample_metric')
                self.ceres_node.timeStep = 60

        slice_configs = [(1200, 1800, 60), (600, 1200, 60)]

        self.ceres_slices = []
        for start, end, step in slice_configs:
            slice_mock = make_slice_mock(start, end, step)
            self.ceres_slices.append(slice_mock)

    def test_init_sets_default_cache_behavior(self):
        ceres_node = CeresNode(self.ceres_tree, 'sample_metric',
                               '/graphite/storage/ceres/sample_metric')
        self.assertEqual(DEFAULT_SLICE_CACHING_BEHAVIOR,
                         ceres_node.sliceCachingBehavior)

    @patch('ceres.os.makedirs', new=Mock())
    @patch('ceres.CeresNode.writeMetadata')
    def test_create_sets_a_default_timestep(self, write_metadata_mock):
        CeresNode.create(self.ceres_tree, 'sample_metric')
        write_metadata_mock.assert_called_with(dict(timeStep=DEFAULT_TIMESTEP))

    @patch('ceres.os.makedirs', new=Mock())
    @patch('ceres.CeresNode.writeMetadata', new=Mock())
    def test_create_returns_new_ceres_node(self):
        ceres_node = CeresNode.create(self.ceres_tree, 'sample_metric')
        self.assertTrue(isinstance(ceres_node, CeresNode))

    def test_write_metadata(self):
        import json

        open_mock = mock_open()
        metadata = dict(timeStep=60, aggregationMethod='avg')
        with patch.object(builtins, 'open', open_mock):
            self.ceres_node.writeMetadata(metadata)
        self.assertEquals(json.dumps(metadata),
                          fetch_mock_open_writes(open_mock))

    def test_read_metadata_sets_timestep(self):
        import json

        metadata = dict(timeStep=60, aggregationMethod='avg')
        json_metadata = json.dumps(metadata)
        open_mock = mock_open(read_data=json_metadata)
        with patch.object(builtins, 'open', open_mock):
            self.ceres_node.readMetadata()
        open_mock().read.assert_called_once()
        self.assertEqual(60, self.ceres_node.timeStep)

    def test_read_metadata_returns_corrupt_if_json_error(self):
        with patch.object(builtins, 'open', mock_open()):
            self.assertRaises(CorruptNode, self.ceres_node.readMetadata)

    def test_set_slice_caching_behavior_validates_names(self):
        self.ceres_node.setSliceCachingBehavior('none')
        self.assertEquals('none', self.ceres_node.sliceCachingBehavior)
        self.ceres_node.setSliceCachingBehavior('all')
        self.assertEquals('all', self.ceres_node.sliceCachingBehavior)
        self.ceres_node.setSliceCachingBehavior('latest')
        self.assertEquals('latest', self.ceres_node.sliceCachingBehavior)
        self.assertRaises(ValueError, self.ceres_node.setSliceCachingBehavior,
                          'foo')
        # Assert unchanged
        self.assertEquals('latest', self.ceres_node.sliceCachingBehavior)

    def test_slices_is_a_generator(self):
        from types import GeneratorType

        self.assertTrue(isinstance(self.ceres_node.slices, GeneratorType))

    def test_slices_returns_cached_set_when_behavior_is_all(self):
        def mock_slice():
            return Mock(spec=CeresSlice)

        self.ceres_node.setSliceCachingBehavior('all')
        cached_contents = [mock_slice for c in range(4)]
        self.ceres_node.sliceCache = cached_contents
        with patch('ceres.CeresNode.readSlices') as read_slices_mock:
            slice_list = list(self.ceres_node.slices)
            self.assertFalse(read_slices_mock.called)

        self.assertEquals(cached_contents, slice_list)

    def test_slices_returns_first_cached_when_behavior_is_latest(self):
        self.ceres_node.setSliceCachingBehavior('latest')
        cached_contents = Mock(spec=CeresSlice)
        self.ceres_node.sliceCache = cached_contents

        read_slices_mock = Mock(return_value=[])
        with patch('ceres.CeresNode.readSlices', new=read_slices_mock):
            slice_iter = self.ceres_node.slices
            self.assertEquals(cached_contents, next(slice_iter))
            # We should be yielding cached before trying to read
            self.assertFalse(read_slices_mock.called)

    def test_slices_reads_remaining_when_behavior_is_latest(self):
        self.ceres_node.setSliceCachingBehavior('latest')
        cached_contents = Mock(spec=CeresSlice)
        self.ceres_node.sliceCache = cached_contents

        read_slices_mock = Mock(return_value=[(0, 60)])
        with patch('ceres.CeresNode.readSlices', new=read_slices_mock):
            slice_iter = self.ceres_node.slices
            next(slice_iter)

            # *now* we expect to read from disk
            try:
                while True:
                    next(slice_iter)
            except StopIteration:
                pass

        read_slices_mock.assert_called_once_with()

    def test_slices_reads_from_disk_when_behavior_is_none(self):
        self.ceres_node.setSliceCachingBehavior('none')
        read_slices_mock = Mock(return_value=[(0, 60)])
        with patch('ceres.CeresNode.readSlices', new=read_slices_mock):
            slice_iter = self.ceres_node.slices
            next(slice_iter)

        read_slices_mock.assert_called_once_with()

    def test_slices_reads_from_disk_when_cache_empty_and_behavior_all(self):
        self.ceres_node.setSliceCachingBehavior('all')
        read_slices_mock = Mock(return_value=[(0, 60)])
        with patch('ceres.CeresNode.readSlices', new=read_slices_mock):
            slice_iter = self.ceres_node.slices
            next(slice_iter)

        read_slices_mock.assert_called_once_with()

    def test_slices_reads_from_disk_when_cache_empty_and_behavior_latest(self):
        self.ceres_node.setSliceCachingBehavior('all')
        read_slices_mock = Mock(return_value=[(0, 60)])
        with patch('ceres.CeresNode.readSlices', new=read_slices_mock):
            slice_iter = self.ceres_node.slices
            next(slice_iter)

        read_slices_mock.assert_called_once_with()

    @patch('ceres.exists', new=Mock(return_value=False))
    def test_read_slices_raises_when_node_doesnt_exist(self):
        self.assertRaises(NodeDeleted, self.ceres_node.readSlices)

    @patch('ceres.exists', new=Mock(return_Value=True))
    def test_read_slices_ignores_not_slices(self):
        listdir_mock = Mock(return_value=['*****@*****.**', '*****@*****.**', 'foo'])
        with patch('ceres.os.listdir', new=listdir_mock):
            self.assertEquals(2, len(self.ceres_node.readSlices()))

    @patch('ceres.exists', new=Mock(return_Value=True))
    def test_read_slices_parses_slice_filenames(self):
        listdir_mock = Mock(return_value=['*****@*****.**', '*****@*****.**'])
        with patch('ceres.os.listdir', new=listdir_mock):
            slice_infos = self.ceres_node.readSlices()
            self.assertTrue((0, 60) in slice_infos)
            self.assertTrue((0, 300) in slice_infos)

    @patch('ceres.exists', new=Mock(return_Value=True))
    def test_read_slices_reverse_sorts_by_time(self):
        listdir_mock = Mock(return_value=[
            '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**',
            '*****@*****.**'
        ])

        with patch('ceres.os.listdir', new=listdir_mock):
            slice_infos = self.ceres_node.readSlices()
            slice_timestamps = [s[0] for s in slice_infos]
            self.assertEqual([600, 320, 120, 0, 0], slice_timestamps)

    def test_no_data_exists_if_no_slices_exist(self):
        with patch('ceres.CeresNode.readSlices', new=Mock(return_value=[])):
            self.assertFalse(self.ceres_node.hasDataForInterval(0, 60))

    def test_no_data_exists_if_no_slices_exist_and_no_time_specified(self):
        with patch('ceres.CeresNode.readSlices', new=Mock(return_value=[])):
            self.assertFalse(self.ceres_node.hasDataForInterval(None, None))

    def test_data_exists_if_slices_exist_and_no_time_specified(self):
        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.assertTrue(self.ceres_node.hasDataForInterval(None, None))

    def test_data_exists_if_slice_covers_interval_completely(self):
        with patch('ceres.CeresNode.slices', new=[self.ceres_slices[0]]):
            self.assertTrue(self.ceres_node.hasDataForInterval(1200, 1800))

    def test_data_exists_if_slice_covers_interval_end(self):
        with patch('ceres.CeresNode.slices', new=[self.ceres_slices[0]]):
            self.assertTrue(self.ceres_node.hasDataForInterval(600, 1260))

    def test_data_exists_if_slice_covers_interval_start(self):
        with patch('ceres.CeresNode.slices', new=[self.ceres_slices[0]]):
            self.assertTrue(self.ceres_node.hasDataForInterval(1740, 2100))

    def test_no_data_exists_if_slice_touches_interval_end(self):
        with patch('ceres.CeresNode.slices', new=[self.ceres_slices[0]]):
            self.assertFalse(self.ceres_node.hasDataForInterval(600, 1200))

    def test_no_data_exists_if_slice_touches_interval_start(self):
        with patch('ceres.CeresNode.slices', new=[self.ceres_slices[0]]):
            self.assertFalse(self.ceres_node.hasDataForInterval(1800, 2100))

    def test_compact_returns_empty_if_passed_empty(self):
        self.assertEqual([], self.ceres_node.compact([]))

    def test_compact_filters_null_values(self):
        self.assertEqual([], self.ceres_node.compact([(60, None)]))

    def test_compact_rounds_timestamps_down_to_step(self):
        self.assertEqual([[(600, 0)]], self.ceres_node.compact([(605, 0)]))

    def test_compact_drops_duplicate_timestamps(self):
        datapoints = [(600, 0), (600, 0)]
        compacted = self.ceres_node.compact(datapoints)
        self.assertEqual([[(600, 0.0)]], compacted)

    def test_compact_keeps_last_seen_duplicate_timestamp(self):
        datapoints = [(600, 0), (600, 1), (660, 1), (660, 0)]
        compacted = self.ceres_node.compact(datapoints)
        self.assertEqual([[(600, 1.0), (660, 0.0)]], compacted)

    def test_compact_groups_contiguous_points(self):
        datapoints = [(600, 0), (660, 0), (840, 0)]
        compacted = self.ceres_node.compact(datapoints)
        self.assertEqual([[(600, 0), (660, 0)], [(840, 0)]], compacted)

    def test_write_noops_if_no_datapoints(self):
        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.ceres_node.write([])
            self.assertFalse(self.ceres_slices[0].write.called)

    def test_write_within_first_slice(self):
        datapoints = [(1200, 0.0), (1260, 1.0), (1320, 2.0)]

        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.ceres_node.write(datapoints)
            self.ceres_slices[0].write.assert_called_once_with(datapoints)

    @patch('ceres.CeresSlice.create')
    def test_write_within_first_slice_doesnt_create(self, slice_create_mock):
        datapoints = [(1200, 0.0), (1260, 1.0), (1320, 2.0)]

        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.ceres_node.write(datapoints)
            self.assertFalse(slice_create_mock.called)

    @patch('ceres.CeresSlice.create', new=Mock())
    def test_write_within_first_slice_with_gaps(self):
        datapoints = [(1200, 0.0), (1320, 2.0)]

        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.ceres_node.write(datapoints)

            # sorted most recent first
            calls = [call.write([datapoints[1]]), call.write([datapoints[0]])]
            self.ceres_slices[0].assert_has_calls(calls)

    @patch('ceres.CeresSlice.create', new=Mock())
    def test_write_within_previous_slice(self):
        datapoints = [(720, 0.0), (780, 2.0)]

        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.ceres_node.write(datapoints)

            # 2nd slice has this range
            self.ceres_slices[1].write.assert_called_once_with(datapoints)

    @patch('ceres.CeresSlice.create')
    def test_write_within_previous_slice_doesnt_create(self,
                                                       slice_create_mock):
        datapoints = [(720, 0.0), (780, 2.0)]

        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.ceres_node.write(datapoints)
            self.assertFalse(slice_create_mock.called)

    @patch('ceres.CeresSlice.create', new=Mock())
    def test_write_within_previous_slice_with_gaps(self):
        datapoints = [(720, 0.0), (840, 2.0)]

        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.ceres_node.write(datapoints)

            calls = [call.write([datapoints[1]]), call.write([datapoints[0]])]
            self.ceres_slices[1].assert_has_calls(calls)

    @patch('ceres.CeresSlice.create', new=Mock())
    def test_write_across_slice_boundaries(self):
        datapoints = [(1080, 0.0), (1140, 1.0), (1200, 2.0), (1260, 3.0)]

        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.ceres_node.write(datapoints)
            self.ceres_slices[0].write.assert_called_once_with(datapoints[2:4])
            self.ceres_slices[1].write.assert_called_once_with(datapoints[0:2])

    @patch('ceres.CeresSlice.create')
    def test_write_before_earliest_slice_creates_new(self, slice_create_mock):
        datapoints = [(300, 0.0)]
        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.ceres_node.write(datapoints)
            slice_create_mock.assert_called_once_with(self.ceres_node, 300, 60)

    @patch('ceres.CeresSlice.create')
    def test_write_before_earliest_slice_writes_to_new_one(
            self, slice_create_mock):
        datapoints = [(300, 0.0)]
        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.ceres_node.write(datapoints)
            slice_create_mock.return_value.write.assert_called_once_with(
                datapoints)

    @patch('ceres.CeresSlice.create')
    def test_write_before_earliest_slice_writes_next_slice_too(
            self, slice_create_mock):
        # slice 0 starts at 600
        datapoints = [(540, 0.0), (600, 0.0)]
        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.ceres_node.write(datapoints)
            self.ceres_slices[1].write.assert_called_once_with([datapoints[1]])

    @patch('ceres.CeresSlice.create')
    def test_create_during_write_clears_slice_cache(self, slice_create_mock):
        self.ceres_node.setSliceCachingBehavior('all')
        self.ceres_node.sliceCache = self.ceres_slices
        datapoints = [(300, 0.0)]
        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.ceres_node.write(datapoints)
            self.assertEquals(None, self.ceres_node.sliceCache)

    @patch('ceres.CeresSlice.create')
    def test_write_past_max_gap_size_creates(self, slice_create_mock):
        datapoints = [(6000, 0.0)]
        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            with patch.object(self.ceres_slices[0],
                              'write',
                              side_effect=SliceGapTooLarge):
                self.ceres_node.write(datapoints)

    @patch('ceres.CeresSlice.create')
    def test_write_different_timestep_creates(self, slice_create_mock):
        datapoints = [(600, 0.0)]
        with patch('ceres.CeresNode.slices', new=self.ceres_slices):
            self.ceres_node.timeStep = 10
            self.ceres_node.write(datapoints)
            slice_create_mock.assert_called_once_with(self.ceres_node, 600, 10)
Example #12
0
 def test_create_sets_a_default_timestep(self, write_metadata_mock):
   CeresNode.create(self.ceres_tree, 'sample_metric')
   write_metadata_mock.assert_called_with(dict(timeStep=DEFAULT_TIMESTEP))
Example #13
0
class CeresNodeTest(TestCase):
  def setUp(self):
    with patch('ceres.isdir', new=Mock(return_value=True)):
      with patch('ceres.exists', new=Mock(return_value=True)):
        self.ceres_tree = CeresTree('/graphite/storage/ceres')
        self.ceres_node = CeresNode(
            self.ceres_tree,
            'sample_metric',
            '/graphite/storage/ceres/sample_metric')
        self.ceres_node.timeStep = 60

    slice_configs = [
      (1200, 1800, 60),
      (600, 1200, 60)]

    self.ceres_slices = []
    for start, end, step in slice_configs:
      slice_mock = make_slice_mock(start, end, step)
      self.ceres_slices.append(slice_mock)

  def test_init_sets_default_cache_behavior(self):
    ceres_node = CeresNode(
        self.ceres_tree,
        'sample_metric',
        '/graphite/storage/ceres/sample_metric')
    self.assertEqual(DEFAULT_SLICE_CACHING_BEHAVIOR, ceres_node.sliceCachingBehavior)

  @patch('ceres.os.makedirs', new=Mock())
  @patch('ceres.CeresNode.writeMetadata')
  def test_create_sets_a_default_timestep(self, write_metadata_mock):
    CeresNode.create(self.ceres_tree, 'sample_metric')
    write_metadata_mock.assert_called_with(dict(timeStep=DEFAULT_TIMESTEP))

  @patch('ceres.os.makedirs', new=Mock())
  @patch('ceres.CeresNode.writeMetadata', new=Mock())
  def test_create_returns_new_ceres_node(self):
    ceres_node = CeresNode.create(self.ceres_tree, 'sample_metric')
    self.assertTrue(isinstance(ceres_node, CeresNode))

  def test_write_metadata(self):
    import json

    open_mock = mock_open()
    metadata = dict(timeStep=60, aggregationMethod='avg')
    with patch.object(builtins, 'open', open_mock):
      self.ceres_node.writeMetadata(metadata)
    self.assertEquals(json.dumps(metadata), fetch_mock_open_writes(open_mock))

  def test_read_metadata_sets_timestep(self):
    import json

    metadata = dict(timeStep=60, aggregationMethod='avg')
    json_metadata = json.dumps(metadata)
    open_mock = mock_open(read_data=json_metadata)
    with patch.object(builtins, 'open', open_mock):
      self.ceres_node.readMetadata()
    open_mock().read.assert_called_once()
    self.assertEqual(60, self.ceres_node.timeStep)

  def test_read_metadata_returns_corrupt_if_json_error(self):
    with patch.object(builtins, 'open', mock_open()):
      self.assertRaises(CorruptNode, self.ceres_node.readMetadata)

  def test_set_slice_caching_behavior_validates_names(self):
    self.ceres_node.setSliceCachingBehavior('none')
    self.assertEquals('none', self.ceres_node.sliceCachingBehavior)
    self.ceres_node.setSliceCachingBehavior('all')
    self.assertEquals('all', self.ceres_node.sliceCachingBehavior)
    self.ceres_node.setSliceCachingBehavior('latest')
    self.assertEquals('latest', self.ceres_node.sliceCachingBehavior)
    self.assertRaises(ValueError, self.ceres_node.setSliceCachingBehavior, 'foo')
    # Assert unchanged
    self.assertEquals('latest', self.ceres_node.sliceCachingBehavior)

  def test_slices_is_a_generator(self):
    from types import GeneratorType

    self.assertTrue(isinstance(self.ceres_node.slices, GeneratorType))

  def test_slices_returns_cached_set_when_behavior_is_all(self):
    def mock_slice():
      return Mock(spec=CeresSlice)

    self.ceres_node.setSliceCachingBehavior('all')
    cached_contents = [mock_slice for c in range(4)]
    self.ceres_node.sliceCache = cached_contents
    with patch('ceres.CeresNode.readSlices') as read_slices_mock:
      slice_list = list(self.ceres_node.slices)
      self.assertFalse(read_slices_mock.called)

    self.assertEquals(cached_contents, slice_list)

  def test_slices_returns_first_cached_when_behavior_is_latest(self):
    self.ceres_node.setSliceCachingBehavior('latest')
    cached_contents = Mock(spec=CeresSlice)
    self.ceres_node.sliceCache = cached_contents

    read_slices_mock = Mock(return_value=[])
    with patch('ceres.CeresNode.readSlices', new=read_slices_mock):
      slice_iter = self.ceres_node.slices
      self.assertEquals(cached_contents, next(slice_iter))
      # We should be yielding cached before trying to read
      self.assertFalse(read_slices_mock.called)

  def test_slices_reads_remaining_when_behavior_is_latest(self):
    self.ceres_node.setSliceCachingBehavior('latest')
    cached_contents = Mock(spec=CeresSlice)
    self.ceres_node.sliceCache = cached_contents

    read_slices_mock = Mock(return_value=[(0, 60)])
    with patch('ceres.CeresNode.readSlices', new=read_slices_mock):
      slice_iter = self.ceres_node.slices
      next(slice_iter)

      # *now* we expect to read from disk
      try:
        while True:
          next(slice_iter)
      except StopIteration:
        pass

    read_slices_mock.assert_called_once_with()

  def test_slices_reads_from_disk_when_behavior_is_none(self):
    self.ceres_node.setSliceCachingBehavior('none')
    read_slices_mock = Mock(return_value=[(0, 60)])
    with patch('ceres.CeresNode.readSlices', new=read_slices_mock):
      slice_iter = self.ceres_node.slices
      next(slice_iter)

    read_slices_mock.assert_called_once_with()

  def test_slices_reads_from_disk_when_cache_empty_and_behavior_all(self):
    self.ceres_node.setSliceCachingBehavior('all')
    read_slices_mock = Mock(return_value=[(0, 60)])
    with patch('ceres.CeresNode.readSlices', new=read_slices_mock):
      slice_iter = self.ceres_node.slices
      next(slice_iter)

    read_slices_mock.assert_called_once_with()

  def test_slices_reads_from_disk_when_cache_empty_and_behavior_latest(self):
    self.ceres_node.setSliceCachingBehavior('all')
    read_slices_mock = Mock(return_value=[(0, 60)])
    with patch('ceres.CeresNode.readSlices', new=read_slices_mock):
      slice_iter = self.ceres_node.slices
      next(slice_iter)

    read_slices_mock.assert_called_once_with()

  @patch('ceres.exists', new=Mock(return_value=False))
  def test_read_slices_raises_when_node_doesnt_exist(self):
    self.assertRaises(NodeDeleted, self.ceres_node.readSlices)

  @patch('ceres.exists', new=Mock(return_Value=True))
  def test_read_slices_ignores_not_slices(self):
    listdir_mock = Mock(return_value=['*****@*****.**', '*****@*****.**', 'foo'])
    with patch('ceres.os.listdir', new=listdir_mock):
      self.assertEquals(2, len(self.ceres_node.readSlices()))

  @patch('ceres.exists', new=Mock(return_Value=True))
  def test_read_slices_parses_slice_filenames(self):
    listdir_mock = Mock(return_value=['*****@*****.**', '*****@*****.**'])
    with patch('ceres.os.listdir', new=listdir_mock):
      slice_infos = self.ceres_node.readSlices()
      self.assertTrue((0, 60) in slice_infos)
      self.assertTrue((0, 300) in slice_infos)

  @patch('ceres.exists', new=Mock(return_Value=True))
  def test_read_slices_reverse_sorts_by_time(self):
    listdir_mock = Mock(return_value=[
      '*****@*****.**',
      '*****@*****.**',
      '*****@*****.**',
      '*****@*****.**',
      '*****@*****.**'])

    with patch('ceres.os.listdir', new=listdir_mock):
      slice_infos = self.ceres_node.readSlices()
      slice_timestamps = [s[0] for s in slice_infos]
      self.assertEqual([600, 320, 120, 0, 0], slice_timestamps)

  def test_no_data_exists_if_no_slices_exist(self):
    with patch('ceres.CeresNode.readSlices', new=Mock(return_value=[])):
      self.assertFalse(self.ceres_node.hasDataForInterval(0, 60))

  def test_no_data_exists_if_no_slices_exist_and_no_time_specified(self):
    with patch('ceres.CeresNode.readSlices', new=Mock(return_value=[])):
      self.assertFalse(self.ceres_node.hasDataForInterval(None, None))

  def test_data_exists_if_slices_exist_and_no_time_specified(self):
    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.assertTrue(self.ceres_node.hasDataForInterval(None, None))

  def test_data_exists_if_slice_covers_interval_completely(self):
    with patch('ceres.CeresNode.slices', new=[self.ceres_slices[0]]):
      self.assertTrue(self.ceres_node.hasDataForInterval(1200, 1800))

  def test_data_exists_if_slice_covers_interval_end(self):
    with patch('ceres.CeresNode.slices', new=[self.ceres_slices[0]]):
      self.assertTrue(self.ceres_node.hasDataForInterval(600, 1260))

  def test_data_exists_if_slice_covers_interval_start(self):
    with patch('ceres.CeresNode.slices', new=[self.ceres_slices[0]]):
      self.assertTrue(self.ceres_node.hasDataForInterval(1740, 2100))

  def test_no_data_exists_if_slice_touches_interval_end(self):
    with patch('ceres.CeresNode.slices', new=[self.ceres_slices[0]]):
      self.assertFalse(self.ceres_node.hasDataForInterval(600, 1200))

  def test_no_data_exists_if_slice_touches_interval_start(self):
    with patch('ceres.CeresNode.slices', new=[self.ceres_slices[0]]):
      self.assertFalse(self.ceres_node.hasDataForInterval(1800, 2100))

  def test_compact_returns_empty_if_passed_empty(self):
    self.assertEqual([], self.ceres_node.compact([]))

  def test_compact_filters_null_values(self):
    self.assertEqual([], self.ceres_node.compact([(60, None)]))

  def test_compact_rounds_timestamps_down_to_step(self):
    self.assertEqual([[(600, 0)]], self.ceres_node.compact([(605, 0)]))

  def test_compact_drops_duplicate_timestamps(self):
    datapoints = [(600, 0), (600, 0)]
    compacted = self.ceres_node.compact(datapoints)
    self.assertEqual([[(600, 0.0)]], compacted)

  def test_compact_keeps_last_seen_duplicate_timestamp(self):
    datapoints = [(600, 0), (600, 1), (660, 1), (660, 0)]
    compacted = self.ceres_node.compact(datapoints)
    self.assertEqual([[(600, 1.0), (660, 0.0)]], compacted)

  def test_compact_groups_contiguous_points(self):
    datapoints = [(600, 0), (660, 0), (840, 0)]
    compacted = self.ceres_node.compact(datapoints)
    self.assertEqual([[(600, 0), (660, 0)], [(840, 0)]], compacted)

  def test_write_noops_if_no_datapoints(self):
    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.ceres_node.write([])
      self.assertFalse(self.ceres_slices[0].write.called)

  def test_write_within_first_slice(self):
    datapoints = [(1200, 0.0), (1260, 1.0), (1320, 2.0)]

    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.ceres_node.write(datapoints)
      self.ceres_slices[0].write.assert_called_once_with(datapoints)

  @patch('ceres.CeresSlice.create')
  def test_write_within_first_slice_doesnt_create(self, slice_create_mock):
    datapoints = [(1200, 0.0), (1260, 1.0), (1320, 2.0)]

    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.ceres_node.write(datapoints)
      self.assertFalse(slice_create_mock.called)

  @patch('ceres.CeresSlice.create', new=Mock())
  def test_write_within_first_slice_with_gaps(self):
    datapoints = [(1200, 0.0), (1320, 2.0)]

    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.ceres_node.write(datapoints)

      # sorted most recent first
      calls = [call.write([datapoints[1]]), call.write([datapoints[0]])]
      self.ceres_slices[0].assert_has_calls(calls)

  @patch('ceres.CeresSlice.create', new=Mock())
  def test_write_within_previous_slice(self):
    datapoints = [(720, 0.0), (780, 2.0)]

    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.ceres_node.write(datapoints)

      # 2nd slice has this range
      self.ceres_slices[1].write.assert_called_once_with(datapoints)

  @patch('ceres.CeresSlice.create')
  def test_write_within_previous_slice_doesnt_create(self, slice_create_mock):
    datapoints = [(720, 0.0), (780, 2.0)]

    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.ceres_node.write(datapoints)
      self.assertFalse(slice_create_mock.called)

  @patch('ceres.CeresSlice.create', new=Mock())
  def test_write_within_previous_slice_with_gaps(self):
    datapoints = [(720, 0.0), (840, 2.0)]

    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.ceres_node.write(datapoints)

      calls = [call.write([datapoints[1]]), call.write([datapoints[0]])]
      self.ceres_slices[1].assert_has_calls(calls)

  @patch('ceres.CeresSlice.create', new=Mock())
  def test_write_across_slice_boundaries(self):
    datapoints = [(1080, 0.0), (1140, 1.0), (1200, 2.0), (1260, 3.0)]

    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.ceres_node.write(datapoints)
      self.ceres_slices[0].write.assert_called_once_with(datapoints[2:4])
      self.ceres_slices[1].write.assert_called_once_with(datapoints[0:2])

  @patch('ceres.CeresSlice.create')
  def test_write_before_earliest_slice_creates_new(self, slice_create_mock):
    datapoints = [(300, 0.0)]
    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.ceres_node.write(datapoints)
      slice_create_mock.assert_called_once_with(self.ceres_node, 300, 60)

  @patch('ceres.CeresSlice.create')
  def test_write_before_earliest_slice_writes_to_new_one(self, slice_create_mock):
    datapoints = [(300, 0.0)]
    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.ceres_node.write(datapoints)
      slice_create_mock.return_value.write.assert_called_once_with(datapoints)

  @patch('ceres.CeresSlice.create')
  def test_write_before_earliest_slice_writes_next_slice_too(self, slice_create_mock):
    # slice 0 starts at 600
    datapoints = [(540, 0.0), (600, 0.0)]
    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.ceres_node.write(datapoints)
      self.ceres_slices[1].write.assert_called_once_with([datapoints[1]])

  @patch('ceres.CeresSlice.create')
  def test_create_during_write_clears_slice_cache(self, slice_create_mock):
    self.ceres_node.setSliceCachingBehavior('all')
    self.ceres_node.sliceCache = self.ceres_slices
    datapoints = [(300, 0.0)]
    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.ceres_node.write(datapoints)
      self.assertEquals(None, self.ceres_node.sliceCache)

  @patch('ceres.CeresSlice.create')
  def test_write_past_max_gap_size_creates(self, slice_create_mock):
    datapoints = [(6000, 0.0)]
    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      with patch.object(self.ceres_slices[0], 'write', side_effect=SliceGapTooLarge):
        self.ceres_node.write(datapoints)

  @patch('ceres.CeresSlice.create')
  def test_write_different_timestep_creates(self, slice_create_mock):
    datapoints = [(600, 0.0)]
    with patch('ceres.CeresNode.slices', new=self.ceres_slices):
      self.ceres_node.timeStep = 10
      self.ceres_node.write(datapoints)
      slice_create_mock.assert_called_once_with(self.ceres_node, 600, 10)
Example #14
0
class CeresArchiveNodeReadTest(TestCase):
    def setUp(self):
        with patch('ceres.isdir', new=Mock(return_value=True)):
            with patch('ceres.exists', new=Mock(return_value=True)):
                self.ceres_tree = CeresTree('/graphite/storage/ceres')
                self.ceres_node = CeresNode(
                    self.ceres_tree, 'sample_metric',
                    '/graphite/storage/ceres/sample_metric')
                self.ceres_node.timeStep = 30

        slice_configs = [(1200, 1800, 30), (600, 1200, 60)]

        self.ceres_slices = []
        for start, end, step in slice_configs:
            slice_mock = make_slice_mock(start, end, step)
            self.ceres_slices.append(slice_mock)

        self.ceres_slices_patch = patch('ceres.CeresNode.slices',
                                        new=iter(self.ceres_slices))
        self.ceres_slices_patch.start()

    def tearDown(self):
        self.ceres_slices_patch.stop()

    def test_archives_read_loads_metadata_if_timestep_unknown(self):
        with patch('ceres.CeresNode.readMetadata', new=Mock(side_effect=Exception))\
          as read_metadata_mock:
            self.ceres_node.timeStep = None
            try:  # Raise Exception as a cheap exit out of the function once we have the call we want
                self.ceres_node.read(600, 660)
            except Exception:
                pass
            read_metadata_mock.assert_called_once_with()

    def test_archives_read_normalizes_from_time(self):
        self.ceres_node.read(1210, 1260)
        self.ceres_slices[0].read.assert_called_once_with(1200, 1260)

    def test_archives_read_normalizes_until_time(self):
        self.ceres_node.read(1200, 1270)
        self.ceres_slices[0].read.assert_called_once_with(1200, 1260)

    def test_archives_read_returns_empty_time_series_if_before_slices(self):
        result = self.ceres_node.read(0, 300)
        self.assertEqual([None] * 10, result.values)

    def test_archives_read_returns_empty_time_series_if_slice_has_no_data(
            self):
        self.ceres_slices[0].read.side_effect = NoData
        result = self.ceres_node.read(1200, 1500)
        self.assertEqual([None] * 10, result.values)

    def test_archives_read_pads_points_missing_before_series(self):
        result = self.ceres_node.read(300, 1200)
        self.assertEqual(None, result.values[0])

    def test_archives_read_pads_points_missing_after_series(self):
        result = self.ceres_node.read(1200, 1860)
        self.assertEqual(None, result.values[-1])

    def test_archives_read_goes_across_slices(self):
        self.ceres_node.read(900, 1500)
        self.ceres_slices[0].read.assert_called_once_with(1200, 1500)
        self.ceres_slices[1].read.assert_called_once_with(900, 1200)

    def test_archives_read_across_slices_merges_results_average(self):
        result = self.ceres_node.read(900, 1470)
        self.assertEqual([0, 1, 2, 3, 4, 0.5, 2.5, 4.5, 6.5, 8], result.values)

    def test_archives_read_across_slices_merges_results_sum(self):
        self.ceres_node.aggregationMethod = 'sum'
        result = self.ceres_node.read(900, 1470)
        self.assertEqual([0, 1, 2, 3, 4, 1, 5, 9, 13, 8], result.values)

    def test_archives_read_across_slices_merges_results_last(self):
        self.ceres_node.aggregationMethod = 'last'
        result = self.ceres_node.read(900, 1470)
        self.assertEqual([0, 1, 2, 3, 4, 1, 3, 5, 7, 8], result.values)

    def test_archives_read_across_slices_merges_results_max(self):
        self.ceres_node.aggregationMethod = 'max'
        result = self.ceres_node.read(900, 1470)
        self.assertEqual([0, 1, 2, 3, 4, 1, 3, 5, 7, 8], result.values)

    def test_archives_read_across_slices_merges_results_min(self):
        self.ceres_node.aggregationMethod = 'min'
        result = self.ceres_node.read(900, 1470)
        self.assertEqual([0, 1, 2, 3, 4, 0, 2, 4, 6, 8], result.values)

    def test_archives_invalid_aggregation_method(self):
        self.ceres_node.aggregationMethod = 'invalid'
        self.assertRaises(InvalidAggregationMethod, self.ceres_node.read, 900,
                          1500)

    def test_archives_read_pads_points_missing_after_series_across_slices(
            self):
        result = self.ceres_node.read(900, 1860)
        self.assertEqual(None, result.values[-1])

    def test_archives_read_pads_points_missing_between_slices(self):
        self.ceres_slices[1] = make_slice_mock(600, 900, 300)
        result = self.ceres_node.read(600, 1500)
        self.assertEqual([0, None, 4.5], result.values)
Example #15
0
 def test_create_returns_new_ceres_node(self):
     ceres_node = CeresNode.create(self.ceres_tree, 'sample_metric')
     self.assertTrue(isinstance(ceres_node, CeresNode))
Example #16
0
class CeresNodeReadTest(TestCase):
    def setUp(self):
        with patch('ceres.isdir', new=Mock(return_value=True)):
            with patch('ceres.exists', new=Mock(return_value=True)):
                self.ceres_tree = CeresTree('/graphite/storage/ceres')
                self.ceres_node = CeresNode(
                    self.ceres_tree, 'sample_metric',
                    '/graphite/storage/ceres/sample_metric')
                self.ceres_node.timeStep = 60

        slice_configs = [(1200, 1800, 60), (600, 1200, 60)]

        self.ceres_slices = []
        for start, end, step in slice_configs:
            slice_mock = make_slice_mock(start, end, step)
            self.ceres_slices.append(slice_mock)

        self.ceres_slices_patch = patch('ceres.CeresNode.slices',
                                        new=iter(self.ceres_slices))
        self.ceres_slices_patch.start()

    def tearDown(self):
        self.ceres_slices_patch.stop()

    def test_read_loads_metadata_if_timestep_unknown(self):
        with patch('ceres.CeresNode.readMetadata', new=Mock(side_effect=Exception))\
          as read_metadata_mock:
            self.ceres_node.timeStep = None
            try:  # Raise Exception as a cheap exit out of the function once we have the call we want
                self.ceres_node.read(600, 660)
            except Exception:
                pass
            read_metadata_mock.assert_called_once_with()

    def test_read_normalizes_from_time(self):
        self.ceres_node.read(1210, 1260)
        self.ceres_slices[0].read.assert_called_once_with(1200, 1260)

    def test_read_normalizes_until_time(self):
        self.ceres_node.read(1200, 1270)
        self.ceres_slices[0].read.assert_called_once_with(1200, 1260)

    def test_read_returns_empty_time_series_if_before_slices(self):
        result = self.ceres_node.read(0, 300)
        self.assertEqual([None] * 5, result.values)

    def test_read_returns_empty_time_series_if_slice_has_no_data(self):
        self.ceres_slices[0].read.side_effect = NoData
        result = self.ceres_node.read(1200, 1500)
        self.assertEqual([None] * 5, result.values)

    def test_read_pads_points_missing_before_series(self):
        result = self.ceres_node.read(540, 1200)
        self.assertEqual([None] + [0] * 10, result.values)

    def test_read_pads_points_missing_after_series(self):
        result = self.ceres_node.read(1200, 1860)
        self.assertEqual(None, result.values[-1])

    def test_read_goes_across_slices(self):
        self.ceres_node.read(900, 1500)
        self.ceres_slices[0].read.assert_called_once_with(1200, 1500)
        self.ceres_slices[1].read.assert_called_once_with(900, 1200)

    def test_read_across_slices_merges_results(self):
        result = self.ceres_node.read(900, 1500)
        self.assertEqual([0] * 10, result.values)

    def test_read_pads_points_missing_after_series_across_slices(self):
        result = self.ceres_node.read(900, 1860)
        self.assertEqual(None, result.values[-1])

    def test_read_pads_points_missing_between_slices(self):
        self.ceres_slices[1] = make_slice_mock(600, 1140, 60)
        result = self.ceres_node.read(900, 1500)
        self.assertEqual([0] * 4 + [None] + [0] * 5, result.values)
Example #17
0
 def test_create_returns_new_ceres_node(self):
   ceres_node = CeresNode.create(self.ceres_tree, 'sample_metric')
   self.assertTrue(isinstance(ceres_node, CeresNode))
Example #18
0
class CeresNodeReadTest(TestCase):
  def setUp(self):
    with patch('ceres.isdir', new=Mock(return_value=True)):
      with patch('ceres.exists', new=Mock(return_value=True)):
        self.ceres_tree = CeresTree('/graphite/storage/ceres')
        self.ceres_node = CeresNode(
            self.ceres_tree,
            'sample_metric',
            '/graphite/storage/ceres/sample_metric')
        self.ceres_node.timeStep = 60

    slice_configs = [
      (1200, 1800, 60),
      (600, 1200, 60)]

    self.ceres_slices = []
    for start, end, step in slice_configs:
      slice_mock = make_slice_mock(start, end, step)
      self.ceres_slices.append(slice_mock)

    self.ceres_slices_patch = patch('ceres.CeresNode.slices', new=iter(self.ceres_slices))
    self.ceres_slices_patch.start()

  def tearDown(self):
    self.ceres_slices_patch.stop()

  def test_read_loads_metadata_if_timestep_unknown(self):
    with patch('ceres.CeresNode.readMetadata', new=Mock(side_effect=Exception))\
      as read_metadata_mock:
      self.ceres_node.timeStep = None
      try:  # Raise Exception as a cheap exit out of the function once we have the call we want
        self.ceres_node.read(600, 660)
      except Exception:
        pass
      read_metadata_mock.assert_called_once_with()

  def test_read_normalizes_from_time(self):
    self.ceres_node.read(1210, 1260)
    self.ceres_slices[0].read.assert_called_once_with(1200, 1260)

  def test_read_normalizes_until_time(self):
    self.ceres_node.read(1200, 1270)
    self.ceres_slices[0].read.assert_called_once_with(1200, 1260)

  def test_read_returns_empty_time_series_if_before_slices(self):
    result = self.ceres_node.read(0, 300)
    self.assertEqual([None] * 5, result.values)

  def test_read_returns_empty_time_series_if_slice_has_no_data(self):
    self.ceres_slices[0].read.side_effect = NoData
    result = self.ceres_node.read(1200, 1500)
    self.assertEqual([None] * 5, result.values)

  def test_read_pads_points_missing_before_series(self):
    result = self.ceres_node.read(540, 1200)
    self.assertEqual([None] + [0] * 10, result.values)

  def test_read_pads_points_missing_after_series(self):
    result = self.ceres_node.read(1200, 1860)
    self.assertEqual(None, result.values[-1])

  def test_read_goes_across_slices(self):
    self.ceres_node.read(900, 1500)
    self.ceres_slices[0].read.assert_called_once_with(1200, 1500)
    self.ceres_slices[1].read.assert_called_once_with(900, 1200)

  def test_read_across_slices_merges_results(self):
    result = self.ceres_node.read(900, 1500)
    self.assertEqual([0] * 10, result.values)

  def test_read_pads_points_missing_after_series_across_slices(self):
    result = self.ceres_node.read(900, 1860)
    self.assertEqual(None, result.values[-1])

  def test_read_pads_points_missing_between_slices(self):
    self.ceres_slices[1] = make_slice_mock(600, 1140, 60)
    result = self.ceres_node.read(900, 1500)
    self.assertEqual([0] * 4 + [None] + [0] * 5, result.values)
Example #19
0
class CeresArchiveNodeReadTest(TestCase):
  def setUp(self):
    with patch('ceres.isdir', new=Mock(return_value=True)):
      with patch('ceres.exists', new=Mock(return_value=True)):
        self.ceres_tree = CeresTree('/graphite/storage/ceres')
        self.ceres_node = CeresNode(
            self.ceres_tree,
            'sample_metric',
            '/graphite/storage/ceres/sample_metric')
        self.ceres_node.timeStep = 30

    slice_configs = [
      (1200, 1800, 30),
      (600, 1200, 60)]

    self.ceres_slices = []
    for start, end, step in slice_configs:
      slice_mock = make_slice_mock(start, end, step)
      self.ceres_slices.append(slice_mock)

    self.ceres_slices_patch = patch('ceres.CeresNode.slices', new=iter(self.ceres_slices))
    self.ceres_slices_patch.start()

  def tearDown(self):
    self.ceres_slices_patch.stop()

  def test_archives_read_loads_metadata_if_timestep_unknown(self):
    with patch('ceres.CeresNode.readMetadata', new=Mock(side_effect=Exception))\
      as read_metadata_mock:
      self.ceres_node.timeStep = None
      try:  # Raise Exception as a cheap exit out of the function once we have the call we want
        self.ceres_node.read(600, 660)
      except Exception:
        pass
      read_metadata_mock.assert_called_once_with()

  def test_archives_read_normalizes_from_time(self):
    self.ceres_node.read(1210, 1260)
    self.ceres_slices[0].read.assert_called_once_with(1200, 1260)

  def test_archives_read_normalizes_until_time(self):
    self.ceres_node.read(1200, 1270)
    self.ceres_slices[0].read.assert_called_once_with(1200, 1260)

  def test_archives_read_returns_empty_time_series_if_before_slices(self):
    result = self.ceres_node.read(0, 300)
    self.assertEqual([None] * 10, result.values)

  def test_archives_read_returns_empty_time_series_if_slice_has_no_data(self):
    self.ceres_slices[0].read.side_effect = NoData
    result = self.ceres_node.read(1200, 1500)
    self.assertEqual([None] * 10, result.values)

  def test_archives_read_pads_points_missing_before_series(self):
    result = self.ceres_node.read(300, 1200)
    self.assertEqual(None, result.values[0])

  def test_archives_read_pads_points_missing_after_series(self):
    result = self.ceres_node.read(1200, 1860)
    self.assertEqual(None, result.values[-1])

  def test_archives_read_goes_across_slices(self):
    self.ceres_node.read(900, 1500)
    self.ceres_slices[0].read.assert_called_once_with(1200, 1500)
    self.ceres_slices[1].read.assert_called_once_with(900, 1200)

  def test_archives_read_across_slices_merges_results_average(self):
    result = self.ceres_node.read(900, 1470)
    self.assertEqual([0, 1, 2, 3, 4, 0.5, 2.5, 4.5, 6.5, 8], result.values)

  def test_archives_read_across_slices_merges_results_sum(self):
    self.ceres_node.aggregationMethod = 'sum'
    result = self.ceres_node.read(900, 1470)
    self.assertEqual([0, 1, 2, 3, 4, 1, 5, 9, 13, 8], result.values)

  def test_archives_read_across_slices_merges_results_last(self):
    self.ceres_node.aggregationMethod = 'last'
    result = self.ceres_node.read(900, 1470)
    self.assertEqual([0, 1, 2, 3, 4, 1, 3, 5, 7, 8], result.values)

  def test_archives_read_across_slices_merges_results_max(self):
    self.ceres_node.aggregationMethod = 'max'
    result = self.ceres_node.read(900, 1470)
    self.assertEqual([0, 1, 2, 3, 4, 1, 3, 5, 7, 8], result.values)

  def test_archives_read_across_slices_merges_results_min(self):
    self.ceres_node.aggregationMethod = 'min'
    result = self.ceres_node.read(900, 1470)
    self.assertEqual([0, 1, 2, 3, 4, 0, 2, 4, 6, 8], result.values)

  def test_archives_invalid_aggregation_method(self):
    self.ceres_node.aggregationMethod = 'invalid'
    self.assertRaises(InvalidAggregationMethod, self.ceres_node.read, 900, 1500)

  def test_archives_read_pads_points_missing_after_series_across_slices(self):
    result = self.ceres_node.read(900, 1860)
    self.assertEqual(None, result.values[-1])

  def test_archives_read_pads_points_missing_between_slices(self):
    self.ceres_slices[1] = make_slice_mock(600, 900, 300)
    result = self.ceres_node.read(600, 1500)
    self.assertEqual([0, None, 4.5], result.values)