SQL Lab - A multi-tab SQL editor (#514)

* Carapal react mockup

This is really just a mock up written in React to try different
components. It could become scaffolding to build a prototype, or not.

* Merging in Alanna's theme tweaks for SQL lab

* Tweak the display of the alert message in navbar

* Sketching the middleware refresh for Queries

* Adjustments

* Implement timer sync.

* CTAS

* Refactor the queries to be stored as a dict. (#994)

* Download csv endpoint. (#992)

* CSV download engdpoint.

* Use lower case booleans.

* Replcate loop with the object lookup by key.

* First changes for the sync

* Address comments

* Fix query deletions. Update only the queries from the store.

* Sync queries using tmp_id.

* simplify

* Fix the tests in the carapal. (#1023)

* Sync queries using tmp_id.

* Fix the unit tests

* Bux fixes. Pass 2.

* Tweakin' & linting

* Adding alpha label to the SQL LAb navbar entry

* Fixing the python unit tests
This commit is contained in:
Maxime Beauchemin
2016-08-29 21:55:31 -07:00
committed by GitHub
parent f17cfcbfa2
commit 38b8db8051
62 changed files with 4271 additions and 563 deletions

93
tests/base_tests.py Normal file
View File

@@ -0,0 +1,93 @@
"""Unit tests for Caravel"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import os
import unittest
from flask_appbuilder.security.sqla import models as ab_models
import caravel
from caravel import app, db, models, utils, appbuilder
os.environ['CARAVEL_CONFIG'] = 'tests.caravel_test_config'
'''
app.config['TESTING'] = True
app.config['CSRF_ENABLED'] = False
app.config['SECRET_KEY'] = 'thisismyscretkey'
app.config['WTF_CSRF_ENABLED'] = False
app.config['PUBLIC_ROLE_LIKE_GAMMA'] = True
'''
BASE_DIR = app.config.get("BASE_DIR")
class CaravelTestCase(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(CaravelTestCase, self).__init__(*args, **kwargs)
self.client = app.test_client()
utils.init(caravel)
admin = appbuilder.sm.find_user('admin')
if not admin:
appbuilder.sm.add_user(
'admin', 'admin', ' user', 'admin@fab.org',
appbuilder.sm.find_role('Admin'),
password='general')
gamma = appbuilder.sm.find_user('gamma')
if not gamma:
appbuilder.sm.add_user(
'gamma', 'gamma', 'user', 'gamma@fab.org',
appbuilder.sm.find_role('Gamma'),
password='general')
alpha = appbuilder.sm.find_user('alpha')
if not alpha:
appbuilder.sm.add_user(
'alpha', 'alpha', 'user', 'alpha@fab.org',
appbuilder.sm.find_role('Alpha'),
password='general')
utils.init(caravel)
def login(self, username='admin', password='general'):
resp = self.client.post(
'/login/',
data=dict(username=username, password=password),
follow_redirects=True)
assert 'Welcome' in resp.data.decode('utf-8')
def get_query_by_sql(self, sql):
session = db.create_scoped_session()
query = session.query(models.Query).filter_by(sql=sql).first()
session.close()
return query
def logout(self):
self.client.get('/logout/', follow_redirects=True)
def test_welcome(self):
self.login()
resp = self.client.get('/caravel/welcome')
assert 'Welcome' in resp.data.decode('utf-8')
def setup_public_access_for_dashboard(self, table_name):
public_role = appbuilder.sm.find_role('Public')
perms = db.session.query(ab_models.PermissionView).all()
for perm in perms:
if (perm.permission.name == 'datasource_access' and
perm.view_menu and table_name in perm.view_menu.name):
appbuilder.sm.add_permission_role(public_role, perm)
def revoke_public_access(self, table_name):
public_role = appbuilder.sm.find_role('Public')
perms = db.session.query(ab_models.PermissionView).all()
for perm in perms:
if (perm.permission.name == 'datasource_access' and
perm.view_menu and table_name in perm.view_menu.name):
appbuilder.sm.del_permission_role(public_role, perm)

View File

@@ -9,3 +9,23 @@ CARAVEL_WEBSERVER_PORT = 8081
# continuous integration
if 'CARAVEL__SQLALCHEMY_DATABASE_URI' in os.environ:
SQLALCHEMY_DATABASE_URI = os.environ.get('CARAVEL__SQLALCHEMY_DATABASE_URI')
SQL_CELERY_DB_FILE_PATH = os.path.join(DATA_DIR, 'celerydb.sqlite')
SQL_CELERY_RESULTS_DB_FILE_PATH = os.path.join(DATA_DIR, 'celery_results.sqlite')
SQL_SELECT_AS_CTA = True
SQL_MAX_ROW = 666
TESTING = True
CSRF_ENABLED = False
SECRET_KEY = 'thisismyscretkey'
WTF_CSRF_ENABLED = False
PUBLIC_ROLE_LIKE_GAMMA = True
class CeleryConfig(object):
BROKER_URL = 'sqla+sqlite:///' + SQL_CELERY_DB_FILE_PATH
CELERY_IMPORTS = ('caravel.sql_lab', )
CELERY_RESULT_BACKEND = 'db+sqlite:///' + SQL_CELERY_RESULTS_DB_FILE_PATH
CELERY_ANNOTATIONS = {'sql_lab.add': {'rate_limit': '10/s'}}
CONCURRENCY = 1
CELERY_CONFIG = CeleryConfig

View File

@@ -5,112 +5,47 @@ from __future__ import print_function
from __future__ import unicode_literals
from datetime import datetime
import csv
import doctest
import json
import imp
import os
import json
import io
import unittest
from mock import Mock, patch
from flask import escape
from flask_appbuilder.security.sqla import models as ab_models
import caravel
from caravel import app, db, models, utils, appbuilder, sm
from caravel.models import DruidCluster, DruidDatasource
from caravel.models import DruidDatasource
os.environ['CARAVEL_CONFIG'] = 'tests.caravel_test_config'
from .base_tests import CaravelTestCase
app.config['TESTING'] = True
app.config['CSRF_ENABLED'] = False
app.config['SECRET_KEY'] = 'thisismyscretkey'
app.config['WTF_CSRF_ENABLED'] = False
app.config['PUBLIC_ROLE_LIKE_GAMMA'] = True
BASE_DIR = app.config.get("BASE_DIR")
cli = imp.load_source('cli', BASE_DIR + "/bin/caravel")
class CaravelTestCase(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(CaravelTestCase, self).__init__(*args, **kwargs)
self.client = app.test_client()
utils.init(caravel)
admin = appbuilder.sm.find_user('admin')
if not admin:
appbuilder.sm.add_user(
'admin', 'admin',' user', 'admin@fab.org',
appbuilder.sm.find_role('Admin'),
password='general')
gamma = appbuilder.sm.find_user('gamma')
if not gamma:
appbuilder.sm.add_user(
'gamma', 'gamma', 'user', 'gamma@fab.org',
appbuilder.sm.find_role('Gamma'),
password='general')
alpha = appbuilder.sm.find_user('alpha')
if not alpha:
appbuilder.sm.add_user(
'alpha', 'alpha', 'user', 'alpha@fab.org',
appbuilder.sm.find_role('Alpha'),
password='general')
utils.init(caravel)
def login(self, username='admin', password='general'):
resp = self.client.post(
'/login/',
data=dict(username=username, password=password),
follow_redirects=True)
assert 'Welcome' in resp.data.decode('utf-8')
def logout(self):
self.client.get('/logout/', follow_redirects=True)
def test_welcome(self):
self.login()
resp = self.client.get('/caravel/welcome')
assert 'Welcome' in resp.data.decode('utf-8')
def setup_public_access_for_dashboard(self, table_name):
public_role = appbuilder.sm.find_role('Public')
perms = db.session.query(ab_models.PermissionView).all()
for perm in perms:
if ( perm.permission.name == 'datasource_access' and
perm.view_menu and table_name in perm.view_menu.name):
appbuilder.sm.add_permission_role(public_role, perm)
def revoke_public_access(self, table_name):
public_role = appbuilder.sm.find_role('Public')
perms = db.session.query(ab_models.PermissionView).all()
for perm in perms:
if ( perm.permission.name == 'datasource_access' and
perm.view_menu and table_name in perm.view_menu.name):
appbuilder.sm.del_permission_role(public_role, perm)
class CoreTests(CaravelTestCase):
def __init__(self, *args, **kwargs):
# Load examples first, so that we setup proper permission-view relations
# for all example data sources.
# Load examples first, so that we setup proper permission-view
# relations for all example data sources.
super(CoreTests, self).__init__(*args, **kwargs)
@classmethod
def setUpClass(cls):
cli.load_examples(load_test_data=True)
utils.init(caravel)
cls.table_ids = {tbl.table_name: tbl.id for tbl in (
cls.table_ids = {tbl.table_name: tbl.id for tbl in (
db.session
.query(models.SqlaTable)
.all()
)}
def setUp(self):
pass
db.session.query(models.Query).delete()
def tearDown(self):
pass
@@ -126,7 +61,12 @@ class CoreTests(CaravelTestCase):
copy_name = "Test Sankey Save"
tbl_id = self.table_ids.get('energy_usage')
url = "/caravel/explore/table/{}/?viz_type=sankey&groupby=source&groupby=target&metric=sum__value&row_limit=5000&where=&having=&flt_col_0=source&flt_op_0=in&flt_eq_0=&slice_id={}&slice_name={}&collapsed_fieldsets=&action={}&datasource_name=energy_usage&datasource_id=1&datasource_type=table&previous_viz_type=sankey"
url = (
"/caravel/explore/table/{}/?viz_type=sankey&groupby=source&"
"groupby=target&metric=sum__value&row_limit=5000&where=&having=&"
"flt_col_0=source&flt_op_0=in&flt_eq_0=&slice_id={}&slice_name={}&"
"collapsed_fieldsets=&action={}&datasource_name=energy_usage&"
"datasource_id=1&datasource_type=table&previous_viz_type=sankey")
db.session.commit()
resp = self.client.get(
@@ -146,6 +86,8 @@ class CoreTests(CaravelTestCase):
for slc in db.session.query(Slc).all():
urls += [
(slc.slice_name, 'slice_url', slc.slice_url),
(slc.slice_name, 'slice_id_endpoint', '/caravel/slices/{}'.
format(slc.id)),
(slc.slice_name, 'json_endpoint', slc.viz.json_endpoint),
(slc.slice_name, 'csv_endpoint', slc.viz.csv_endpoint),
]
@@ -210,13 +152,20 @@ class CoreTests(CaravelTestCase):
def test_shortner(self):
self.login(username='admin')
data = "//caravel/explore/table/1/?viz_type=sankey&groupby=source&groupby=target&metric=sum__value&row_limit=5000&where=&having=&flt_col_0=source&flt_op_0=in&flt_eq_0=&slice_id=78&slice_name=Energy+Sankey&collapsed_fieldsets=&action=&datasource_name=energy_usage&datasource_id=1&datasource_type=table&previous_viz_type=sankey"
data = (
"//caravel/explore/table/1/?viz_type=sankey&groupby=source&"
"groupby=target&metric=sum__value&row_limit=5000&where=&having=&"
"flt_col_0=source&flt_op_0=in&flt_eq_0=&slice_id=78&slice_name="
"Energy+Sankey&collapsed_fieldsets=&action=&datasource_name="
"energy_usage&datasource_id=1&datasource_type=table&"
"previous_viz_type=sankey")
resp = self.client.post('/r/shortner/', data=data)
assert '/r/' in resp.data.decode('utf-8')
def test_save_dash(self, username='admin'):
self.login(username=username)
dash = db.session.query(models.Dashboard).filter_by(slug="births").first()
dash = db.session.query(models.Dashboard).filter_by(
slug="births").first()
positions = []
for i, slc in enumerate(dash.slices):
d = {
@@ -237,18 +186,24 @@ class CoreTests(CaravelTestCase):
def test_add_slices(self, username='admin'):
self.login(username=username)
dash = db.session.query(models.Dashboard).filter_by(slug="births").first()
new_slice = db.session.query(models.Slice).filter_by(slice_name="Mapbox Long/Lat").first()
existing_slice = db.session.query(models.Slice).filter_by(slice_name="Name Cloud").first()
dash = db.session.query(models.Dashboard).filter_by(
slug="births").first()
new_slice = db.session.query(models.Slice).filter_by(
slice_name="Mapbox Long/Lat").first()
existing_slice = db.session.query(models.Slice).filter_by(
slice_name="Name Cloud").first()
data = {
"slice_ids": [new_slice.data["slice_id"], existing_slice.data["slice_id"]]
"slice_ids": [new_slice.data["slice_id"],
existing_slice.data["slice_id"]]
}
url = '/caravel/add_slices/{}/'.format(dash.id)
resp = self.client.post(url, data=dict(data=json.dumps(data)))
assert "SLICES ADDED" in resp.data.decode('utf-8')
dash = db.session.query(models.Dashboard).filter_by(slug="births").first()
new_slice = db.session.query(models.Slice).filter_by(slice_name="Mapbox Long/Lat").first()
dash = db.session.query(models.Dashboard).filter_by(
slug="births").first()
new_slice = db.session.query(models.Slice).filter_by(
slice_name="Mapbox Long/Lat").first()
assert new_slice in dash.slices
assert len(set(dash.slices)) == len(dash.slices)
@@ -256,7 +211,10 @@ class CoreTests(CaravelTestCase):
self.login(username=username)
url = '/slicemodelview/add'
resp = self.client.get(url, follow_redirects=True)
assert "Click on a table link to create a Slice" in resp.data.decode('utf-8')
assert (
"Click on a table link to create a Slice" in
resp.data.decode('utf-8')
)
def test_add_slice_redirect_to_druid(self, username='admin'):
datasource = DruidDatasource(
@@ -268,7 +226,10 @@ class CoreTests(CaravelTestCase):
self.login(username=username)
url = '/slicemodelview/add'
resp = self.client.get(url, follow_redirects=True)
assert "Click on a datasource link to create a Slice" in resp.data.decode('utf-8')
assert (
"Click on a datasource link to create a Slice"
in resp.data.decode('utf-8')
)
db.session.delete(datasource)
db.session.commit()
@@ -281,41 +242,42 @@ class CoreTests(CaravelTestCase):
resp = self.client.get('/dashboardmodelview/list/')
assert "List Dashboard" in resp.data.decode('utf-8')
def run_sql(self, sql, user_name):
def run_sql(self, sql, user_name, client_id='not_used'):
self.login(username=user_name)
dbid = (
db.session.query(models.Database)
.filter_by(database_name="main")
.filter_by(database_name='main')
.first().id
)
resp = self.client.post(
'/caravel/sql_json/',
data=dict(database_id=dbid, sql=sql),
data=dict(database_id=dbid, sql=sql, select_as_create_as=False, client_id=client_id),
)
self.logout()
return json.loads(resp.data.decode('utf-8'))
def test_sql_json_no_access(self):
self.assertRaises(
utils.CaravelSecurityException,
self.run_sql, "SELECT * FROM ab_user", 'gamma')
def test_sql_json(self):
data = self.run_sql('SELECT * FROM ab_user', 'admin')
assert len(data['data']) > 0
data = self.run_sql('SELECT * FROM unexistant_table', 'admin')
assert len(data['error']) > 0
def test_sql_json_has_access(self):
main_db = (
db.session.query(models.Database).filter_by(database_name="main")
.first()
db.session.query(models.Database).filter_by(database_name="main").first()
)
utils.merge_perm(sm, 'database_access', main_db.perm)
db.session.commit()
main_db_permission_view = (
db.session.query(ab_models.PermissionView)
.join(ab_models.ViewMenu)
.filter(ab_models.ViewMenu.name == '[main].(id:1)')
.first()
.join(ab_models.ViewMenu)
.filter(ab_models.ViewMenu.name == '[main].(id:1)')
.first()
)
astronaut = sm.add_role("Astronaut")
sm.add_permission_role(astronaut, main_db_permission_view)
# Astronaut role is Gamme + main db permissions
# Astronaut role is Gamma + main db permissions
for gamma_perm in sm.find_role('Gamma').permissions:
sm.add_permission_role(astronaut, gamma_perm)
@@ -326,14 +288,54 @@ class CoreTests(CaravelTestCase):
appbuilder.sm.find_role('Astronaut'),
password='general')
data = self.run_sql('SELECT * FROM ab_user', 'gagarin')
db.session.query(models.Query).delete()
db.session.commit()
assert len(data['data']) > 0
def test_sql_json(self):
data = self.run_sql("SELECT * FROM ab_user", 'admin')
assert len(data['data']) > 0
def test_csv_endpoint(self):
sql = "SELECT first_name, last_name FROM ab_user " \
"where first_name='admin'"
self.run_sql(sql, 'admin')
data = self.run_sql("SELECT * FROM unexistant_table", 'admin')
assert len(data['error']) > 0
query1_id = self.get_query_by_sql(sql).id
self.login('admin')
resp = self.client.get('/caravel/csv/{}'.format(query1_id))
data = csv.reader(io.StringIO(resp.data.decode('utf-8')))
expected_data = csv.reader(io.StringIO(
"first_name,last_name\nadmin, user\n"))
self.assertEqual(list(expected_data), list(data))
self.logout()
def test_queries_endpoint(self):
resp = self.client.get('/caravel/queries/{}'.format(0))
self.assertEquals(403, resp.status_code)
self.login('admin')
resp = self.client.get('/caravel/queries/{}'.format(0))
data = json.loads(resp.data.decode('utf-8'))
self.assertEquals(0, len(data))
self.logout()
self.run_sql("SELECT * FROM ab_user", 'admin', client_id='client_id_1')
self.run_sql("SELECT * FROM ab_user1", 'admin', client_id='client_id_2')
self.login('admin')
resp = self.client.get('/caravel/queries/{}'.format(0))
data = json.loads(resp.data.decode('utf-8'))
self.assertEquals(2, len(data))
query = db.session.query(models.Query).filter_by(
sql='SELECT * FROM ab_user').first()
query.changed_on = utils.EPOCH
db.session.commit()
resp = self.client.get('/caravel/queries/{}'.format(123456000))
data = json.loads(resp.data.decode('utf-8'))
self.assertEquals(1, len(data))
self.logout()
resp = self.client.get('/caravel/queries/{}'.format(0))
self.assertEquals(403, resp.status_code)
def test_public_user_dashboard_access(self):
# Try access before adding appropriate permissions.
@@ -365,6 +367,10 @@ class CoreTests(CaravelTestCase):
assert 'Births' in data
# Confirm that public doesn't have access to other datasets.
resp = self.client.get('/slicemodelview/list/')
data = resp.data.decode('utf-8')
assert 'wb_health_population</a>' not in data
resp = self.client.get('/dashboardmodelview/list/')
data = resp.data.decode('utf-8')
assert "/caravel/dashboard/world_health/" not in data
@@ -398,108 +404,6 @@ class CoreTests(CaravelTestCase):
db.session.commit()
self.test_save_dash('alpha')
SEGMENT_METADATA = [{
"id": "some_id",
"intervals": [ "2013-05-13T00:00:00.000Z/2013-05-14T00:00:00.000Z" ],
"columns": {
"__time": {
"type": "LONG", "hasMultipleValues": False,
"size": 407240380, "cardinality": None, "errorMessage": None },
"dim1": {
"type": "STRING", "hasMultipleValues": False,
"size": 100000, "cardinality": 1944, "errorMessage": None },
"dim2": {
"type": "STRING", "hasMultipleValues": True,
"size": 100000, "cardinality": 1504, "errorMessage": None },
"metric1": {
"type": "FLOAT", "hasMultipleValues": False,
"size": 100000, "cardinality": None, "errorMessage": None }
},
"aggregators": {
"metric1": {
"type": "longSum",
"name": "metric1",
"fieldName": "metric1" }
},
"size": 300000,
"numRows": 5000000
}]
GB_RESULT_SET = [
{
"version": "v1",
"timestamp": "2012-01-01T00:00:00.000Z",
"event": {
"name": 'Canada',
"sum__num": 12345678,
}
},
{
"version": "v1",
"timestamp": "2012-01-01T00:00:00.000Z",
"event": {
"name": 'USA',
"sum__num": 12345678 / 2,
}
},
]
class DruidTests(CaravelTestCase):
"""Testing interactions with Druid"""
def __init__(self, *args, **kwargs):
super(DruidTests, self).__init__(*args, **kwargs)
@patch('caravel.models.PyDruid')
def test_client(self, PyDruid):
self.login(username='admin')
instance = PyDruid.return_value
instance.time_boundary.return_value = [
{'result': {'maxTime': '2016-01-01'}}]
instance.segment_metadata.return_value = SEGMENT_METADATA
cluster = (
db.session
.query(DruidCluster)
.filter_by(cluster_name='test_cluster')
.first()
)
if cluster:
db.session.delete(cluster)
db.session.commit()
cluster = DruidCluster(
cluster_name='test_cluster',
coordinator_host='localhost',
coordinator_port=7979,
broker_host='localhost',
broker_port=7980,
metadata_last_refreshed=datetime.now())
db.session.add(cluster)
cluster.get_datasources = Mock(return_value=['test_datasource'])
cluster.get_druid_version = Mock(return_value='0.9.1')
cluster.refresh_datasources()
datasource_id = cluster.datasources[0].id
db.session.commit()
resp = self.client.get('/caravel/explore/druid/{}/'.format(datasource_id))
assert "[test_cluster].[test_datasource]" in resp.data.decode('utf-8')
nres = [
list(v['event'].items()) + [('timestamp', v['timestamp'])]
for v in GB_RESULT_SET]
nres = [dict(v) for v in nres]
import pandas as pd
df = pd.DataFrame(nres)
instance.export_pandas.return_value = df
instance.query_dict = {}
instance.query_builder.last_query.query_dict = {}
resp = self.client.get('/caravel/explore/druid/{}/?viz_type=table&granularity=one+day&druid_time_origin=&since=7+days+ago&until=now&row_limit=5000&include_search=false&metrics=count&groupby=name&flt_col_0=dim1&flt_op_0=in&flt_eq_0=&slice_id=&slice_name=&collapsed_fieldsets=&action=&datasource_name=test_datasource&datasource_id={}&datasource_type=druid&previous_viz_type=table&json=true&force=true'.format(datasource_id, datasource_id))
assert "Canada" in resp.data.decode('utf-8')
if __name__ == '__main__':
unittest.main()

129
tests/druid_tests.py Normal file
View File

@@ -0,0 +1,129 @@
"""Unit tests for Caravel"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from datetime import datetime
import unittest
from mock import Mock, patch
from caravel import db
from caravel.models import DruidCluster
from .base_tests import CaravelTestCase
SEGMENT_METADATA = [{
"id": "some_id",
"intervals": ["2013-05-13T00:00:00.000Z/2013-05-14T00:00:00.000Z"],
"columns": {
"__time": {
"type": "LONG", "hasMultipleValues": False,
"size": 407240380, "cardinality": None, "errorMessage": None},
"dim1": {
"type": "STRING", "hasMultipleValues": False,
"size": 100000, "cardinality": 1944, "errorMessage": None},
"dim2": {
"type": "STRING", "hasMultipleValues": True,
"size": 100000, "cardinality": 1504, "errorMessage": None},
"metric1": {
"type": "FLOAT", "hasMultipleValues": False,
"size": 100000, "cardinality": None, "errorMessage": None}
},
"aggregators": {
"metric1": {
"type": "longSum",
"name": "metric1",
"fieldName": "metric1"}
},
"size": 300000,
"numRows": 5000000
}]
GB_RESULT_SET = [
{
"version": "v1",
"timestamp": "2012-01-01T00:00:00.000Z",
"event": {
"name": 'Canada',
"sum__num": 12345678,
}
},
{
"version": "v1",
"timestamp": "2012-01-01T00:00:00.000Z",
"event": {
"name": 'USA',
"sum__num": 12345678 / 2,
}
},
]
class DruidTests(CaravelTestCase):
"""Testing interactions with Druid"""
def __init__(self, *args, **kwargs):
super(DruidTests, self).__init__(*args, **kwargs)
@patch('caravel.models.PyDruid')
def test_client(self, PyDruid):
self.login(username='admin')
instance = PyDruid.return_value
instance.time_boundary.return_value = [
{'result': {'maxTime': '2016-01-01'}}]
instance.segment_metadata.return_value = SEGMENT_METADATA
cluster = (
db.session
.query(DruidCluster)
.filter_by(cluster_name='test_cluster')
.first()
)
if cluster:
db.session.delete(cluster)
db.session.commit()
cluster = DruidCluster(
cluster_name='test_cluster',
coordinator_host='localhost',
coordinator_port=7979,
broker_host='localhost',
broker_port=7980,
metadata_last_refreshed=datetime.now())
db.session.add(cluster)
cluster.get_datasources = Mock(return_value=['test_datasource'])
cluster.get_druid_version = Mock(return_value='0.9.1')
cluster.refresh_datasources()
datasource_id = cluster.datasources[0].id
db.session.commit()
resp = self.client.get('/caravel/explore/druid/{}/'.format(
datasource_id))
assert "[test_cluster].[test_datasource]" in resp.data.decode('utf-8')
nres = [
list(v['event'].items()) + [('timestamp', v['timestamp'])]
for v in GB_RESULT_SET]
nres = [dict(v) for v in nres]
import pandas as pd
df = pd.DataFrame(nres)
instance.export_pandas.return_value = df
instance.query_dict = {}
instance.query_builder.last_query.query_dict = {}
resp = self.client.get(
'/caravel/explore/druid/{}/?viz_type=table&granularity=one+day&'
'druid_time_origin=&since=7+days+ago&until=now&row_limit=5000&'
'include_search=false&metrics=count&groupby=name&flt_col_0=dim1&'
'flt_op_0=in&flt_eq_0=&slice_id=&slice_name=&collapsed_fieldsets=&'
'action=&datasource_name=test_datasource&datasource_id={}&'
'datasource_type=druid&previous_viz_type=table&json=true&'
'force=true'.format(datasource_id, datasource_id))
assert "Canada" in resp.data.decode('utf-8')
if __name__ == '__main__':
unittest.main()

View File

@@ -5,15 +5,14 @@ import unittest
class UtilsTestCase(unittest.TestCase):
def test_json_int_dttm_ser(self):
today = date.today()
now = datetime.now()
ms = utils.json_int_dttm_ser(today)
deser = (utils.EPOCH + timedelta(milliseconds=ms)).date()
assert today == deser, "Serialization error: %s is not %s" % (str(today), str(deser))
ms = utils.json_int_dttm_ser(now)
deser = (utils.EPOCH + timedelta(milliseconds=ms))
assert now == deser, "Serialization error: %s is not %s" % (str(now), str(deser))
dttm = datetime(2020, 1, 1)
ts = 1577836800000.0
json_int_dttm_ser = utils.json_int_dttm_ser
assert json_int_dttm_ser(dttm) == ts
assert json_int_dttm_ser(date(2020, 1, 1)) == ts
assert json_int_dttm_ser(datetime(1970, 1, 1)) == 0
assert json_int_dttm_ser(date(1970, 1, 1)) == 0
assert json_int_dttm_ser(dttm + timedelta(milliseconds=1)) == (ts + 1)
with self.assertRaises(TypeError):
utils.json_int_dttm_ser("this is not a date")