def test_search_index(self): response = self.app.get("/metrics/search", query_string={"query": "collectd.*"}) self.assertJSON(response, {"metrics": []}) parent = os.path.join(WHISPER_DIR, "collectd") os.makedirs(parent) for metric in ["load", "memory", "cpu"]: db = os.path.join(parent, "{0}.wsp".format(metric)) whisper.create(db, [(1, 60)]) response = self.app.put("/index") self.assertJSON(response, {"success": True, "entries": 3}) response = self.app.get("/metrics/search", query_string={"query": "collectd.*"}) self.assertJSON( response, { "metrics": [ {"is_leaf": False, "path": None}, {"is_leaf": True, "path": "collectd.cpu"}, {"is_leaf": True, "path": "collectd.load"}, {"is_leaf": True, "path": "collectd.memory"}, ] }, )
def test_metrics_index(self): url = '/metrics/index.json' response = self.app.get(url) self.assertJSON(response, []) self.assertEqual(response.headers['Content-Type'], 'application/json') response = self.app.get(url, query_string={'jsonp': 'foo'}) self.assertEqual(response.data, b'foo([])') self.assertEqual(response.headers['Content-Type'], 'text/javascript') parent = os.path.join(WHISPER_DIR, 'collectd') os.makedirs(parent) for metric in ['load', 'memory', 'cpu']: db = os.path.join(parent, '{0}.wsp'.format(metric)) whisper.create(db, [(1, 60)]) response = self.app.get(url) self.assertJSON(response, [ u'collectd.cpu', u'collectd.load', u'collectd.memory', ]) response = self.app.get(url, query_string={'jsonp': 'bar'}) self.assertEqual( response.data, b'bar(["collectd.cpu", "collectd.load", "collectd.memory"])')
def test_gzipped_whisper_finder(self, scandir_mocked): for db in ( ('gzwhisper_finder', 'foo.wsp'), ('gzwhisper_finder', 'foo', 'bar', 'baz.wsp'), ('gzwhisper_finder', 'bar', 'baz', 'baz.wsp'), ): db_path = os.path.join(WHISPER_DIR, *db) if not os.path.exists(os.path.dirname(db_path)): os.makedirs(os.path.dirname(db_path)) whisper.create(db_path, [(1, 60)]) with open(db_path, 'rb') as f_in: f_out = gzip.open("%s.gz" % db_path, 'wb') shutil.copyfileobj(f_in, f_out) f_out.close() os.remove(db_path) try: store = app.config['GRAPHITE']['store'] scandir_mocked.call_count = 0 nodes = store.find('gzwhisper_finder.foo') self.assertEqual(len(list(nodes)), 2) self.assertEqual(scandir_mocked.call_count, 0) scandir_mocked.call_count = 0 nodes = store.find('gzwhisper_finder.foo{}.bar.baz') self.assertEqual(len(list(nodes)), 1) self.assertEqual(scandir_mocked.call_count, 1) finally: scandir_mocked.call_count = 0
def create_db(self): whisper.create(self.db, [(1, 60)]) self.ts = int(time.time()) whisper.update(self.db, 0.5, self.ts - 2) whisper.update(self.db, 0.4, self.ts - 1) whisper.update(self.db, 0.6, self.ts)
def test_whisper_finder(self, scandir_mocked): for db in ( ('whisper_finder', 'foo.wsp'), ('whisper_finder', 'foo', 'bar', 'baz.wsp'), ('whisper_finder', 'bar', 'baz', 'baz.wsp'), ): db_path = os.path.join(WHISPER_DIR, *db) if not os.path.exists(os.path.dirname(db_path)): os.makedirs(os.path.dirname(db_path)) whisper.create(db_path, [(1, 60)]) try: store = app.config['GRAPHITE']['store'] scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.foo') self.assertEqual(len(list(nodes)), 2) self.assertEqual(scandir_mocked.call_count, 0) scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.foo.bar.baz') self.assertEqual(len(list(nodes)), 1) self.assertEqual(scandir_mocked.call_count, 0) scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.*.ba?.{baz,foo}') self.assertEqual(len(list(nodes)), 2) self.assertEqual(scandir_mocked.call_count, 5) finally: scandir_mocked.call_count = 0
def _create_dbs(self): for db in ( ('test', 'foo.wsp'), ('test', 'wat', 'welp.wsp'), ('test', 'bar', 'baz.wsp'), ): db_path = os.path.join(WHISPER_DIR, *db) os.makedirs(os.path.dirname(db_path)) whisper.create(db_path, [(1, 60)])
def test_index(self): parent = os.path.join(WHISPER_DIR, 'collectd') os.makedirs(parent) for metric in ['load', 'memory', 'cpu']: db = os.path.join(parent, '{0}.wsp'.format(metric)) whisper.create(db, [(1, 60)]) response = self.app.put('/index') self.assertJSON(response, {'success': True, 'entries': 3})
def test_jsonp(self): whisper.create(self.db, [(1, 60)]) start = int(time.time()) - 59 response = self.app.get(self.url, query_string={"format": "json", "jsonp": "foo", "target": "test"}) data = response.data.decode("utf-8") self.assertTrue(data.startswith("foo(")) data = json.loads(data[4:-1]) try: self.assertEqual(data, [{"datapoints": [[None, start + i] for i in range(60)], "target": "test"}]) except AssertionError: # Race condition when time overlaps a second self.assertEqual(data, [{"datapoints": [[None, start + i + 1] for i in range(60)], "target": "test"}])
def _create_dbs(self, ts=None): ts = ts or int(time.time()) for db in ( ('test', 'foo.wsp'), ('test', 'wat', 'welp.wsp'), ('test', 'bar', 'baz.wsp'), ): db_path = os.path.join(WHISPER_DIR, *db) os.makedirs(os.path.dirname(db_path)) whisper.create(db_path, [(1, 60)]) whisper.update(db_path, 1, ts) whisper.update(db_path, 2, ts)
def write_series(self, series, retentions=[(1, 180)]): file_name = os.path.join( WHISPER_DIR, '{0}.wsp'.format(series.pathExpression.replace('.', os.sep))) dir_name = os.path.dirname(file_name) if not os.path.isdir(dir_name): os.makedirs(dir_name) whisper.create(file_name, retentions) data = [] for index, value in enumerate(series): if value is None: continue data.append((series.start + index * series.step, value)) whisper.update_many(file_name, data)
def test_raw_data(self): whisper.create(self.db, [(1, 60)]) response = self.app.get(self.url, query_string={"rawData": "1", "target": "test"}) info, data = response.data.decode("utf-8").strip().split("|", 1) path, start, stop, step = info.split(",") datapoints = data.split(",") try: self.assertEqual(datapoints, ["None"] * 60) self.assertEqual(int(stop) - int(start), 60) except AssertionError: self.assertEqual(datapoints, ["None"] * 59) self.assertEqual(int(stop) - int(start), 59) self.assertEqual(path, "test") self.assertEqual(int(step), 1)
def test_raw_data(self): whisper.create(self.db, [(1, 60)]) response = self.app.get(self.url, query_string={'rawData': '1', 'target': 'test'}) info, data = response.data.decode('utf-8').strip().split('|', 1) path, start, stop, step = info.split(',') datapoints = data.split(',') try: self.assertEqual(datapoints, ['None'] * 60) self.assertEqual(int(stop) - int(start), 60) except AssertionError: self.assertEqual(datapoints, ['None'] * 59) self.assertEqual(int(stop) - int(start), 59) self.assertEqual(path, 'test') self.assertEqual(int(step), 1)
def test_terminal_globstar(self): store = app.config['GRAPHITE']['store'] query = "z.**" hits = ["z._", "z._._", "z._._._"] misses = ["z", "o._", "o.z._", "o._.z"] for path in hits + misses: db_path = os.path.join(WHISPER_DIR, path.replace(".", os.sep)) if not os.path.exists(os.path.dirname(db_path)): os.makedirs(os.path.dirname(db_path)) whisper.create(db_path + '.wsp', [(1, 60)]) paths = [node.path for node in store.find(query, local=True)] for hit in hits: self.assertIn(hit, paths) for miss in misses: self.assertNotIn(miss, paths)
def test_jsonp(self): whisper.create(self.db, [(1, 60)]) start = int(time.time()) - 59 response = self.app.get(self.url, query_string={'format': 'json', 'jsonp': 'foo', 'target': 'test'}) data = response.data.decode('utf-8') self.assertTrue(data.startswith('foo(')) data = json.loads(data[4:-1]) try: self.assertEqual(data, [{'datapoints': [ [None, start + i] for i in range(60) ], 'target': 'test'}]) except AssertionError: # Race condition when time overlaps a second self.assertEqual(data, [{'datapoints': [ [None, start + i + 1] for i in range(60) ], 'target': 'test'}])
def test_metrics_index(self): url = "/metrics/index.json" response = self.app.get(url) self.assertJSON(response, []) self.assertEqual(response.headers["Content-Type"], "application/json") response = self.app.get(url, query_string={"jsonp": "foo"}) self.assertEqual(response.data, b"foo([])") self.assertEqual(response.headers["Content-Type"], "text/javascript") parent = os.path.join(WHISPER_DIR, "collectd") os.makedirs(parent) for metric in ["load", "memory", "cpu"]: db = os.path.join(parent, "{0}.wsp".format(metric)) whisper.create(db, [(1, 60)]) response = self.app.get(url) self.assertJSON(response, [u"collectd.cpu", u"collectd.load", u"collectd.memory"]) response = self.app.get(url, query_string={"jsonp": "bar"}) self.assertEqual(response.data, b'bar(["collectd.cpu", "collectd.load", "collectd.memory"])')
def test_templates(self): ts = int(time.time()) value = 1 for db in ( ('hosts', 'worker1', 'cpu.wsp'), ('hosts', 'worker2', 'cpu.wsp'), ): db_path = os.path.join(WHISPER_DIR, *db) if not os.path.exists(os.path.dirname(db_path)): os.makedirs(os.path.dirname(db_path)) whisper.create(db_path, [(1, 60)]) whisper.update(db_path, value, ts) value += 1 for query, expected in [ ({'target': 'template(hosts.worker1.cpu)'}, 'hosts.worker1.cpu'), ({'target': 'template(constantLine($1),12)'}, '12'), ({'target': 'template(constantLine($1))', 'template[1]': '12'}, '12.0'), ({'target': 'template(constantLine($num),num=12)'}, '12'), ({'target': 'template(constantLine($num))', 'template[num]': '12'}, '12.0'), ({'target': 'template(time($1),"nameOfSeries")'}, 'nameOfSeries'), ({'target': 'template(time($1))', 'template[1]': 'nameOfSeries'}, 'nameOfSeries'), ({'target': 'template(time($name),name="nameOfSeries")'}, 'nameOfSeries'), ({'target': 'template(time($name))', 'template[name]': 'nameOfSeries'}, 'nameOfSeries'), ({'target': 'template(sumSeries(hosts.$1.cpu),"worker1")'}, 'sumSeries(hosts.worker1.cpu)'), ({'target': 'template(sumSeries(hosts.$1.cpu))', 'template[1]': 'worker*'}, 'sumSeries(hosts.worker*.cpu)'), ({'target': 'template(sumSeries(hosts.$host.cpu))', 'template[host]': 'worker*'}, 'sumSeries(hosts.worker*.cpu)'), ]: query['format'] = 'json' response = self.app.get(self.url, query_string=query) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data[0]['target'], expected)
def test_sorted(self): for db in ( ('test', 'foo.wsp'), ('test', 'welp.wsp'), ('test', 'baz.wsp'), ): db_path = os.path.join(WHISPER_DIR, *db) if not os.path.exists(os.path.dirname(db_path)): os.makedirs(os.path.dirname(db_path)) whisper.create(db_path, [(1, 60)]) response = self.app.get(self.url, query_string={'rawData': '1', 'target': 'test.*'}) dses = response.data.decode('utf-8').strip().split("\n") paths = [] for ds in dses: info, data = ds.strip().split('|', 1) path, start, stop, step = info.split(',') paths.append(path) self.assertEqual(paths, ['test.baz', 'test.foo', 'test.welp'])
def test_search_index(self): response = self.app.get('/metrics/search', query_string={'query': 'collectd.*'}) self.assertJSON(response, {'metrics': []}) parent = os.path.join(WHISPER_DIR, 'collectd') os.makedirs(parent) for metric in ['load', 'memory', 'cpu']: db = os.path.join(parent, '{0}.wsp'.format(metric)) whisper.create(db, [(1, 60)]) response = self.app.put('/index') self.assertJSON(response, {'success': True, 'entries': 3}) response = self.app.get('/metrics/search', query_string={'query': 'collectd.*'}) self.assertJSON(response, {'metrics': [ {'is_leaf': False, 'path': None}, {'is_leaf': True, 'path': 'collectd.cpu'}, {'is_leaf': True, 'path': 'collectd.load'}, {'is_leaf': True, 'path': 'collectd.memory'}, ]})
def test_search_index(self): response = self.app.get('/metrics/search', query_string={'query': 'collectd.*'}) self.assertJSON(response, {'metrics': []}) parent = os.path.join(WHISPER_DIR, 'collectd') os.makedirs(parent) for metric in ['load', 'memory', 'cpu']: db = os.path.join(parent, '{0}.wsp'.format(metric)) whisper.create(db, [(1, 60)]) response = self.app.put('/index') self.assertJSON(response, {'success': True, 'entries': 3}) response = self.app.get('/metrics/search', query_string={'query': 'collectd.*'}) self.assertJSON( response, { 'metrics': [ { 'is_leaf': False, 'path': None }, { 'is_leaf': True, 'path': 'collectd.cpu' }, { 'is_leaf': True, 'path': 'collectd.load' }, { 'is_leaf': True, 'path': 'collectd.memory' }, ] })
def test_whisper_finder(self): for db in ( ('whisper_finder', 'foo.wsp'), ('whisper_finder', 'foo', 'bar', 'baz.wsp'), ('whisper_finder', 'bar', 'baz', 'baz.wsp'), ): db_path = os.path.join(WHISPER_DIR, *db) if not os.path.exists(os.path.dirname(db_path)): os.makedirs(os.path.dirname(db_path)) whisper.create(db_path, [(1, 60)]) def listdir_mock(d): self._listdir_counter += 1 return self._original_listdir(d) try: os.listdir = listdir_mock store = app.config['GRAPHITE']['store'] self._listdir_counter = 0 nodes = store.find('whisper_finder.foo') self.assertEqual(len(list(nodes)), 2) self.assertEqual(self._listdir_counter, 0) self._listdir_counter = 0 nodes = store.find('whisper_finder.foo.bar.baz') self.assertEqual(len(list(nodes)), 1) self.assertEqual(self._listdir_counter, 0) self._listdir_counter = 0 nodes = store.find('whisper_finder.*.ba?.{baz,foo}') self.assertEqual(len(list(nodes)), 2) self.assertEqual(self._listdir_counter, 5) finally: os.listdir = self._original_listdir
def test_render_validation(self): whisper.create(self.db, [(1, 60)]) response = self.app.get(self.url) self.assertJSON(response, {"errors": {"target": "This parameter is required."}}, status_code=400) response = self.app.get(self.url, query_string={"graphType": "foo", "target": "test"}) self.assertJSON( response, {"errors": {"graphType": "Invalid graphType 'foo', must be one of 'line', " "'pie'."}}, status_code=400, ) response = self.app.get(self.url, query_string={"maxDataPoints": "foo", "target": "test"}) self.assertJSON(response, {"errors": {"maxDataPoints": "Must be an integer."}}, status_code=400) response = self.app.get( self.url, query_string={"from": "21:2020140313", "until": "21:2020140313", "target": "test"} ) self.assertJSON( response, {"errors": {"from": "Invalid empty time range", "until": "Invalid empty time range"}}, status_code=400, ) response = self.app.get( self.url, query_string={ "target": "foo", "width": 100, "thickness": "1.5", "fontBold": "true", "fontItalic": "default", }, ) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={"target": "foo", "tz": "Europe/Lausanne"}) self.assertJSON(response, {"errors": {"tz": "Unknown timezone: 'Europe/Lausanne'."}}, status_code=400) response = self.app.get(self.url, query_string={"target": "test:aa", "graphType": "pie"}) self.assertJSON(response, {"errors": {"target": "Invalid target: 'test:aa'."}}, status_code=400) response = self.app.get(self.url, query_string={"target": ["test", "foo:1.2"], "graphType": "pie"}) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={"target": ["test", ""]}) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={"target": "test", "format": "csv"}) lines = response.data.decode("utf-8").strip().split("\n") self.assertEqual(len(lines), 60) self.assertFalse(any([l.strip().split(",")[2] for l in lines])) response = self.app.get(self.url, query_string={"target": "test", "format": "svg", "jsonp": "foo"}) jsonpsvg = response.data.decode("utf-8") self.assertTrue(jsonpsvg.startswith('foo("<?xml version=\\"1.0\\"')) self.assertTrue(jsonpsvg.endswith('</script>\\n</svg>")')) response = self.app.get(self.url, query_string={"target": "test", "format": "svg"}) svg = response.data.decode("utf-8") self.assertTrue(svg.startswith('<?xml version="1.0"')) response = self.app.get(self.url, query_string={"target": "sum(test)"}) self.assertEqual(response.status_code, 200) response = self.app.get( self.url, query_string={ "target": [ 'sinFunction("a test", 2)', 'sinFunction("other test", 2.1)', 'sinFunction("other test", 2e1)', ] }, ) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={"target": ['percentileOfSeries(sin("foo bar"), 95, true)']}) self.assertEqual(response.status_code, 200)
def test_render_validation(self): whisper.create(self.db, [(1, 60)]) response = self.app.get(self.url) self.assertJSON(response, {'errors': { 'target': 'This parameter is required.'}}, status_code=400) response = self.app.get(self.url, query_string={'graphType': 'foo', 'target': 'test'}) self.assertJSON(response, {'errors': { 'graphType': "Invalid graphType 'foo', must be one of 'line', " "'pie'."}}, status_code=400) response = self.app.get(self.url, query_string={'maxDataPoints': 'foo', 'target': 'test'}) self.assertJSON(response, {'errors': { 'maxDataPoints': 'Must be an integer.'}}, status_code=400) response = self.app.get(self.url, query_string={ 'from': '21:2020140313', 'until': '21:2020140313', 'target': 'test'}) self.assertJSON(response, {'errors': { 'from': 'Invalid empty time range', 'until': 'Invalid empty time range', }}, status_code=400) response = self.app.get(self.url, query_string={ 'target': 'foo', 'width': 100, 'thickness': '1.5', 'fontBold': 'true', 'fontItalic': 'default', }) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={ 'target': 'foo', 'tz': 'Europe/Lausanne'}) self.assertJSON(response, {'errors': { 'tz': "Unknown timezone: 'Europe/Lausanne'.", }}, status_code=400) response = self.app.get(self.url, query_string={'target': 'test:aa', 'graphType': 'pie'}) self.assertJSON(response, {'errors': { 'target': "Invalid target: 'test:aa'.", }}, status_code=400) response = self.app.get(self.url, query_string={ 'target': ['test', 'foo:1.2'], 'graphType': 'pie'}) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={'target': ['test', '']}) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={'target': 'test', 'format': 'csv'}) lines = response.data.decode('utf-8').strip().split('\n') self.assertEqual(len(lines), 60) self.assertFalse(any([l.strip().split(',')[2] for l in lines])) response = self.app.get(self.url, query_string={'target': 'test', 'format': 'svg', 'jsonp': 'foo'}) jsonpsvg = response.data.decode('utf-8') self.assertTrue(jsonpsvg.startswith('foo("<?xml version=\\"1.0\\"')) self.assertTrue(jsonpsvg.endswith('</script>\\n</svg>")')) response = self.app.get(self.url, query_string={'target': 'test', 'format': 'svg'}) svg = response.data.decode('utf-8') self.assertTrue(svg.startswith('<?xml version="1.0"')) response = self.app.get(self.url, query_string={'target': 'inexisting', 'format': 'svg'}) self.assertEqual(response.status_code, 200) svg = response.data.decode('utf-8') self.assertTrue(svg.startswith('<?xml version="1.0"')) response = self.app.get(self.url, query_string={ 'target': 'sum(test)', }) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={ 'target': ['sinFunction("a test", 2)', 'sinFunction("other test", 2.1)', 'sinFunction("other test", 2e1)'], }) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={ 'target': ['percentileOfSeries(sin("foo bar"), 95, true)'] }) self.assertEqual(response.status_code, 200)
def test_render_options(self): self.create_db() db2 = os.path.join(WHISPER_DIR, 'foo.wsp') whisper.create(db2, [(1, 60)]) ts = int(time.time()) whisper.update(db2, 0.5, ts - 2) for qs in [ {'logBase': 'e'}, {'logBase': 1}, {'logBase': 0.5}, {'margin': -1}, {'colorList': 'orange,green,blue,#0f0'}, {'bgcolor': 'orange'}, {'bgcolor': 'aaabbb'}, {'bgcolor': '#aaabbb'}, {'bgcolor': '#aaabbbff'}, {'fontBold': 'true'}, {'title': 'Hellò'}, {'title': 'true'}, {'vtitle': 'Hellò'}, {'title': 'Hellò', 'yAxisSide': 'right'}, {'uniqueLegend': 'true', '_expr': 'secondYAxis({0})'}, {'uniqueLegend': 'true', 'vtitleRight': 'foo', '_expr': 'secondYAxis({0})'}, {'graphOnly': 'true', 'yUnitSystem': 'si'}, {'lineMode': 'staircase'}, {'lineMode': 'slope'}, {'lineMode': 'connected'}, {'min': 1, 'max': 1, 'thickness': 2, 'yUnitSystem': 'welp'}, {'yMax': 5, 'yLimit': 0.5, 'yStep': 0.1}, {'yMax': 'max', 'yUnitSystem': 'binary'}, {'areaMode': 'stacked', '_expr': 'stacked({0})'}, {'lineMode': 'staircase', '_expr': 'stacked({0})'}, {'areaMode': 'first', '_expr': 'stacked({0})'}, {'areaMode': 'all', '_expr': 'stacked({0})'}, {'areaMode': 'stacked', 'areaAlpha': 0.5, '_expr': 'stacked({0})'}, {'areaMode': 'stacked', 'areaAlpha': 'a', '_expr': 'stacked({0})'}, {'_expr': 'dashed(lineWidth({0}, 5))'}, {'target': 'areaBetween(*)'}, {'drawNullAsZero': 'true'}, {'_expr': 'drawAsInfinite({0})'}, {'graphType': 'pie', 'pieMode': 'average', 'title': 'Pie'}, {'graphType': 'pie', 'pieMode': 'average', 'hideLegend': 'true'}, {'graphType': 'pie', 'pieMode': 'average', 'valueLabels': 'none'}, {'graphType': 'pie', 'pieMode': 'average', 'valueLabels': 'number'}, {'graphType': 'pie', 'pieMode': 'average', 'pieLabels': 'rotated'}, {'noCache': 'true'}, {'cacheTimeout': 5}, {'cacheTimeout': 5}, # cache hit ]: if qs.setdefault('target', ['foo', 'test']) == ['foo', 'test']: if '_expr' in qs: expr = qs.pop('_expr') qs['target'] = [expr.format(t) for t in qs['target']] response = self.app.get(self.url, query_string=qs) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers['Content-Type'], 'image/png') if Cache is None or qs.get('noCache'): self.assertEqual(response.headers['Pragma'], 'no-cache') self.assertEqual(response.headers['Cache-Control'], 'no-cache') self.assertFalse('Expires' in response.headers) else: self.assertEqual(response.headers['Cache-Control'], 'max-age={0}'.format( qs.get('cacheTimeout', 60))) self.assertNotEqual(response.headers['Cache-Control'], 'no-cache') self.assertFalse('Pragma' in response.headers) for qs in [ {'bgcolor': 'foo'}, ]: qs['target'] = 'test' with self.assertRaises(ValueError): response = self.app.get(self.url, query_string=qs) for qs in [ {'lineMode': 'stacked'}, ]: qs['target'] = 'test' with self.assertRaises(AssertionError): response = self.app.get(self.url, query_string=qs)
def test_whisper_finder(self, scandir_mocked): for db in ( ('whisper_finder', 'foo.wsp'), ('whisper_finder', 'foo', 'bar', 'baz.wsp'), ('whisper_finder', 'bar', 'baz', 'baz.wsp'), ): db_path = os.path.join(WHISPER_DIR, *db) if not os.path.exists(os.path.dirname(db_path)): os.makedirs(os.path.dirname(db_path)) whisper.create(db_path, [(1, 60)]) try: store = app.config['GRAPHITE']['store'] scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.foo') self.assertEqual(len(list(nodes)), 2) self.assertEqual(scandir_mocked.call_count, 0) scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.foo.bar.baz') self.assertEqual(len(list(nodes)), 1) self.assertEqual(scandir_mocked.call_count, 0) scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.*.ba?.{baz,foo}') self.assertEqual(len(list(nodes)), 2) self.assertEqual(scandir_mocked.call_count, 5) scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.{foo,bar}.{baz,bar}.{baz,foo}') self.assertEqual(len(list(nodes)), 2) self.assertEqual(scandir_mocked.call_count, 5) scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.{foo}.bar.*') self.assertEqual(len(list(nodes)), 1) self.assertEqual(scandir_mocked.call_count, 2) scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.foo.{ba{r,z},baz}.baz') self.assertEqual(len(list(nodes)), 1) self.assertEqual(scandir_mocked.call_count, 1) scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.{foo,garbage}.bar.baz') self.assertEqual(len(list(nodes)), 1) self.assertEqual(scandir_mocked.call_count, 1) scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.{fo{o}}.bar.baz') self.assertEqual(len(list(nodes)), 1) self.assertEqual(scandir_mocked.call_count, 1) scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.foo{}.bar.baz') self.assertEqual(len(list(nodes)), 1) self.assertEqual(scandir_mocked.call_count, 1) scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.{fo,ba}{o}.bar.baz') self.assertEqual(len(list(nodes)), 1) self.assertEqual(scandir_mocked.call_count, 1) scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.{fo,ba}{o,o}.bar.baz') self.assertEqual(len(list(nodes)), 1) self.assertEqual(scandir_mocked.call_count, 1) scandir_mocked.call_count = 0 nodes = store.find('whisper_finder.{fo,ba}{o,z}.bar.baz') self.assertEqual(len(list(nodes)), 1) self.assertEqual(scandir_mocked.call_count, 1) finally: scandir_mocked.call_count = 0
def test_render_options(self): self.create_db() db2 = os.path.join(WHISPER_DIR, 'foo.wsp') whisper.create(db2, [(1, 60)]) ts = int(time.time()) whisper.update(db2, 0.5, ts - 2) for qs in [ {'logBase': 'e'}, {'logBase': 1}, {'logBase': 0.5}, {'margin': -1}, {'colorList': 'orange,green,blue,#0f0'}, {'bgcolor': 'orange'}, {'bgcolor': 'aaabbb'}, {'bgcolor': '#aaabbb'}, {'bgcolor': '#aaabbbff'}, {'fontBold': 'true'}, {'title': 'Hellò'}, {'title': 'true'}, {'vtitle': 'Hellò'}, {'title': 'Hellò', 'yAxisSide': 'right'}, {'uniqueLegend': 'true', '_expr': 'secondYAxis({0})'}, {'uniqueLegend': 'true', 'vtitleRight': 'foo', '_expr': 'secondYAxis({0})'}, {'graphOnly': 'true', 'yUnitSystem': 'si'}, {'lineMode': 'staircase'}, {'lineMode': 'slope'}, {'lineMode': 'connected'}, {'min': 1, 'max': 1, 'thickness': 2, 'yUnitSystem': 'welp'}, {'yMax': 5, 'yLimit': 0.5, 'yStep': 0.1}, {'yMax': 'max', 'yUnitSystem': 'binary'}, {'areaMode': 'stacked', '_expr': 'stacked({0})'}, {'lineMode': 'staircase', '_expr': 'stacked({0})'}, {'areaMode': 'first', '_expr': 'stacked({0})'}, {'areaMode': 'all', '_expr': 'stacked({0})'}, {'areaMode': 'stacked', 'areaAlpha': 0.5, '_expr': 'stacked({0})'}, {'areaMode': 'stacked', 'areaAlpha': 'a', '_expr': 'stacked({0})'}, {'_expr': 'dashed(lineWidth({0}, 5))'}, {'target': 'areaBetween(*)'}, {'drawNullAsZero': 'true'}, {'_expr': 'drawAsInfinite({0})'}, {'graphType': 'pie', 'pieMode': 'average', 'title': 'Pie'}, {'graphType': 'pie', 'pieMode': 'average', 'hideLegend': 'true'}, {'graphType': 'pie', 'pieMode': 'average', 'valueLabels': 'none'}, {'graphType': 'pie', 'pieMode': 'average', 'valueLabels': 'number'}, {'graphType': 'pie', 'pieMode': 'average', 'pieLabels': 'rotated'}, {'noCache': 'true'}, {'cacheTimeout': 5}, {'cacheTimeout': 5}, # cache hit ]: if qs.setdefault('target', ['foo', 'test']) == ['foo', 'test']: if '_expr' in qs: expr = qs.pop('_expr') qs['target'] = [expr.format(t) for t in qs['target']] response = self.app.get(self.url, query_string=qs) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers['Content-Type'], 'image/png') for qs in [ {'bgcolor': 'foo'}, ]: qs['target'] = 'test' with self.assertRaises(ValueError): response = self.app.get(self.url, query_string=qs) for qs in [ {'lineMode': 'stacked'}, ]: qs['target'] = 'test' with self.assertRaises(AssertionError): response = self.app.get(self.url, query_string=qs)
def test_render_validation(self): whisper.create(self.db, [(1, 60)]) response = self.app.get(self.url) self.assertJSON(response, {'errors': { 'target': 'This parameter is required.'}}, status_code=400) response = self.app.get(self.url, query_string={'graphType': 'foo', 'target': 'test'}) self.assertJSON(response, {'errors': { 'graphType': "Invalid graphType 'foo', must be one of 'line', " "'pie'."}}, status_code=400) response = self.app.get(self.url, query_string={'maxDataPoints': 'foo', 'target': 'test'}) self.assertJSON(response, {'errors': { 'maxDataPoints': 'Must be an integer.'}}, status_code=400) response = self.app.get(self.url, query_string={ 'from': '21:2020140313', 'until': '21:2020140313', 'target': 'test'}) self.assertJSON(response, {'errors': { 'from': 'Invalid empty time range', 'until': 'Invalid empty time range', }}, status_code=400) response = self.app.get(self.url, query_string={ 'target': 'foo', 'width': 100, 'thickness': '1.5', 'fontBold': 'true', 'fontItalic': 'default', }) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={ 'target': 'foo', 'tz': 'Europe/Lausanne'}) self.assertJSON(response, {'errors': { 'tz': "Unknown timezone: 'Europe/Lausanne'.", }}, status_code=400) response = self.app.get(self.url, query_string={'target': 'test:aa', 'graphType': 'pie'}) self.assertJSON(response, {'errors': { 'target': "Invalid target: 'test:aa'.", }}, status_code=400) response = self.app.get(self.url, query_string={ 'target': ['test', 'foo:1.2'], 'graphType': 'pie'}) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={'target': ['test', '']}) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={'target': 'test', 'format': 'csv'}) lines = response.data.decode('utf-8').strip().split('\n') self.assertEqual(len(lines), 60) self.assertFalse(any([l.strip().split(',')[2] for l in lines])) response = self.app.get(self.url, query_string={'target': 'test', 'format': 'svg', 'jsonp': 'foo'}) jsonpsvg = response.data.decode('utf-8') self.assertTrue(jsonpsvg.startswith('foo("<?xml version=\\"1.0\\"')) self.assertTrue(jsonpsvg.endswith('</script>\\n</svg>")')) response = self.app.get(self.url, query_string={'target': 'test', 'format': 'svg'}) svg = response.data.decode('utf-8') self.assertTrue(svg.startswith('<?xml version="1.0"')) response = self.app.get(self.url, query_string={ 'target': 'sum(test)', }) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={ 'target': ['sinFunction("a test", 2)', 'sinFunction("other test", 2.1)', 'sinFunction("other test", 2e1)'], }) self.assertEqual(response.status_code, 200) response = self.app.get(self.url, query_string={ 'target': ['percentileOfSeries(sin("foo bar"), 95, true)'] }) self.assertEqual(response.status_code, 200)
def test_render_options(self): self.create_db() db2 = os.path.join(WHISPER_DIR, 'foo.wsp') whisper.create(db2, [(1, 60)]) ts = int(time.time()) whisper.update(db2, 0.5, ts - 2) for qs in [ { 'logBase': 'e' }, { 'logBase': 1 }, { 'logBase': 0.5 }, { 'logBase': 10 }, { 'margin': -1 }, { 'colorList': 'orange,green,blue,#0f00f0' }, { 'bgcolor': 'orange' }, { 'bgcolor': '000000' }, { 'bgcolor': '#000000' }, { 'bgcolor': '123456' }, { 'bgcolor': '#123456' }, { 'bgcolor': '#12345678' }, { 'bgcolor': 'aaabbb' }, { 'bgcolor': '#aaabbb' }, { 'bgcolor': '#aaabbbff' }, { 'fontBold': 'true' }, { 'title': 'Hellò' }, { 'title': 'true' }, { 'vtitle': 'Hellò' }, { 'title': 'Hellò', 'yAxisSide': 'right' }, { 'uniqueLegend': 'true', '_expr': 'secondYAxis({0})' }, { 'uniqueLegend': 'true', 'vtitleRight': 'foo', '_expr': 'secondYAxis({0})' }, { 'rightWidth': '1', '_expr': 'secondYAxis({0})' }, { 'rightDashed': '1', '_expr': 'secondYAxis({0})' }, { 'rightColor': 'black', '_expr': 'secondYAxis({0})' }, { 'leftWidth': '1', 'target': ['secondYAxis(foo)', 'test'] }, { 'leftDashed': '1', 'target': ['secondYAxis(foo)', 'test'] }, { 'leftColor': 'black', 'target': ['secondYAxis(foo)', 'test'] }, { 'width': '10', '_expr': 'secondYAxis({0})' }, { 'logBase': 'e', 'target': ['secondYAxis(foo)', 'test'] }, { 'graphOnly': 'true', 'yUnitSystem': 'si' }, { 'graphOnly': 'true', 'yUnitSystem': 'wat' }, { 'lineMode': 'staircase' }, { 'lineMode': 'slope' }, { 'lineMode': 'slope', 'from': '-1s' }, { 'lineMode': 'connected' }, { 'min': 1, 'max': 2, 'thickness': 2, 'yUnitSystem': 'none' }, { 'yMax': 5, 'yLimit': 0.5, 'yStep': 0.1 }, { 'yMax': 'max', 'yUnitSystem': 'binary' }, { 'yMaxLeft': 5, 'yLimitLeft': 0.5, 'yStepLeft': 0.1, '_expr': 'secondYAxis({0})' }, { 'yMaxRight': 5, 'yLimitRight': 0.5, 'yStepRight': 0.1, '_expr': 'secondYAxis({0})' }, { 'yMin': 0, 'yLimit': 0.5, 'yStep': 0.1 }, { 'yMinLeft': 0, 'yLimitLeft': 0.5, 'yStepLeft': 0.1, '_expr': 'secondYAxis({0})' }, { 'yMinRight': 0, 'yLimitRight': 0.5, 'yStepRight': 0.1, '_expr': 'secondYAxis({0})' }, { 'areaMode': 'stacked', '_expr': 'stacked({0})' }, { 'lineMode': 'staircase', '_expr': 'stacked({0})' }, { 'areaMode': 'first', '_expr': 'stacked({0})' }, { 'areaMode': 'all', '_expr': 'stacked({0})' }, { 'areaMode': 'all', 'areaAlpha': 0.5, '_expr': 'secondYAxis({0})' }, { 'areaMode': 'all', 'areaAlpha': 0.5, 'target': ['secondYAxis(foo)', 'test'] }, { 'areaMode': 'stacked', 'areaAlpha': 0.5, '_expr': 'stacked({0})' }, { 'areaMode': 'stacked', 'areaAlpha': 'a', '_expr': 'stacked({0})' }, { 'areaMode': 'stacked', '_expr': 'drawAsInfinite({0})' }, { '_expr': 'dashed(lineWidth({0}, 5))' }, { 'target': 'areaBetween(*)' }, { 'drawNullAsZero': 'true' }, { '_expr': 'drawAsInfinite({0})' }, { 'graphType': 'pie', 'pieMode': 'average', 'title': 'Pie' }, { 'graphType': 'pie', 'pieMode': 'maximum', 'title': 'Pie' }, { 'graphType': 'pie', 'pieMode': 'minimum', 'title': 'Pie' }, { 'graphType': 'pie', 'pieMode': 'average', 'hideLegend': 'true' }, { 'graphType': 'pie', 'pieMode': 'average', 'valueLabels': 'none' }, { 'graphType': 'pie', 'pieMode': 'average', 'valueLabels': 'number' }, { 'graphType': 'pie', 'pieMode': 'average', 'pieLabels': 'rotated' }, { 'graphType': 'pie', 'pieMode': 'average', 'areaAlpha': '0.1' }, { 'graphType': 'pie', 'pieMode': 'average', 'areaAlpha': 'none' }, { 'graphType': 'pie', 'pieMode': 'average', 'valueLabelsColor': 'white' }, { 'noCache': 'true' }, { 'cacheTimeout': 5 }, { 'cacheTimeout': 5 }, # cache hit { 'tz': 'Europe/Berlin' }, ]: if qs.setdefault('target', ['foo', 'test']) == ['foo', 'test']: if '_expr' in qs: expr = qs.pop('_expr') qs['target'] = [expr.format(t) for t in qs['target']] response = self.app.get(self.url, query_string=qs) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers['Content-Type'], 'image/png') if Cache is None or qs.get('noCache'): self.assertEqual(response.headers['Pragma'], 'no-cache') self.assertEqual(response.headers['Cache-Control'], 'no-cache') self.assertFalse('Expires' in response.headers) else: self.assertEqual( response.headers['Cache-Control'], 'max-age={0}'.format(qs.get('cacheTimeout', 60))) self.assertNotEqual(response.headers['Cache-Control'], 'no-cache') self.assertFalse('Pragma' in response.headers) for qs in [ { 'bgcolor': 'foo' }, ]: qs['target'] = 'test' with self.assertRaises(ValueError): response = self.app.get(self.url, query_string=qs) for qs in [ { 'lineMode': 'stacked' }, ]: qs['target'] = 'test' with self.assertRaises(AssertionError): response = self.app.get(self.url, query_string=qs)
def test_render_options(self): self.create_db() db2 = os.path.join(WHISPER_DIR, "foo.wsp") whisper.create(db2, [(1, 60)]) ts = int(time.time()) whisper.update(db2, 0.5, ts - 2) for qs in [ {"logBase": "e"}, {"logBase": 1}, {"logBase": 0.5}, {"margin": -1}, {"colorList": "orange,green,blue,#0f0"}, {"bgcolor": "orange"}, {"bgcolor": "aaabbb"}, {"bgcolor": "#aaabbb"}, {"bgcolor": "#aaabbbff"}, {"fontBold": "true"}, {"title": "Hellò"}, {"title": "true"}, {"vtitle": "Hellò"}, {"title": "Hellò", "yAxisSide": "right"}, {"uniqueLegend": "true", "_expr": "secondYAxis({0})"}, {"uniqueLegend": "true", "vtitleRight": "foo", "_expr": "secondYAxis({0})"}, {"graphOnly": "true", "yUnitSystem": "si"}, {"lineMode": "staircase"}, {"lineMode": "slope"}, {"lineMode": "connected"}, {"min": 1, "max": 1, "thickness": 2, "yUnitSystem": "welp"}, {"yMax": 5, "yLimit": 0.5, "yStep": 0.1}, {"yMax": "max", "yUnitSystem": "binary"}, {"areaMode": "stacked", "_expr": "stacked({0})"}, {"lineMode": "staircase", "_expr": "stacked({0})"}, {"areaMode": "first", "_expr": "stacked({0})"}, {"areaMode": "all", "_expr": "stacked({0})"}, {"areaMode": "stacked", "areaAlpha": 0.5, "_expr": "stacked({0})"}, {"areaMode": "stacked", "areaAlpha": "a", "_expr": "stacked({0})"}, {"_expr": "dashed(lineWidth({0}, 5))"}, {"target": "areaBetween(*)"}, {"drawNullAsZero": "true"}, {"_expr": "drawAsInfinite({0})"}, {"graphType": "pie", "pieMode": "average", "title": "Pie"}, {"graphType": "pie", "pieMode": "average", "hideLegend": "true"}, {"graphType": "pie", "pieMode": "average", "valueLabels": "none"}, {"graphType": "pie", "pieMode": "average", "valueLabels": "number"}, {"graphType": "pie", "pieMode": "average", "pieLabels": "rotated"}, {"noCache": "true"}, {"cacheTimeout": 5}, {"cacheTimeout": 5}, # cache hit ]: if qs.setdefault("target", ["foo", "test"]) == ["foo", "test"]: if "_expr" in qs: expr = qs.pop("_expr") qs["target"] = [expr.format(t) for t in qs["target"]] response = self.app.get(self.url, query_string=qs) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers["Content-Type"], "image/png") for qs in [{"bgcolor": "foo"}]: qs["target"] = "test" with self.assertRaises(ValueError): response = self.app.get(self.url, query_string=qs) for qs in [{"lineMode": "stacked"}]: qs["target"] = "test" with self.assertRaises(AssertionError): response = self.app.get(self.url, query_string=qs)
def _create_dbs(self): for db in (("test", "foo.wsp"), ("test", "wat", "welp.wsp"), ("test", "bar", "baz.wsp")): db_path = os.path.join(WHISPER_DIR, *db) os.makedirs(os.path.dirname(db_path)) whisper.create(db_path, [(1, 60)])