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 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)
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)
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')
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)
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)
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 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)
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))
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)
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)
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)
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)
def test_create_returns_new_ceres_node(self): ceres_node = CeresNode.create(self.ceres_tree, 'sample_metric') self.assertTrue(isinstance(ceres_node, CeresNode))
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)
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)
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)