mirror of
https://github.com/getredash/redash.git
synced 2025-12-19 17:37:19 -05:00
* Snapshot: 23.11.0-dev * dataframe_to_result function moved outside python query runner * added yandex disk query runner * moved file_extension check * skip unsupported extensions in schema * removed unused variable * added support for xlsx with multiple sheets * moved pandas-converters to utils file * added tests * fixed backend tests * fixed pandas to redash type conversion * added more tests * added tests for pandas * added tests for pandas converter and yandex disk * added tests for read_file and multiple sheets * pandas: do not load if lib is not installed * added test for yaml read * fixed test for yaml read --------- Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: Guido Petri <18634426+guidopetri@users.noreply.github.com>
163 lines
5.0 KiB
Python
163 lines
5.0 KiB
Python
from collections import namedtuple
|
|
from unittest import TestCase
|
|
|
|
import pytest
|
|
|
|
from redash import create_app
|
|
from redash.query_runner import (
|
|
TYPE_BOOLEAN,
|
|
TYPE_DATE,
|
|
TYPE_DATETIME,
|
|
TYPE_FLOAT,
|
|
TYPE_INTEGER,
|
|
TYPE_STRING,
|
|
)
|
|
from redash.utils import (
|
|
build_url,
|
|
collect_parameters_from_request,
|
|
filter_none,
|
|
generate_token,
|
|
json_dumps,
|
|
render_template,
|
|
)
|
|
from redash.utils.pandas import pandas_installed
|
|
|
|
DummyRequest = namedtuple("DummyRequest", ["host", "scheme"])
|
|
|
|
skip_condition = pytest.mark.skipif(not pandas_installed, reason="pandas is not installed")
|
|
|
|
if pandas_installed:
|
|
import numpy as np
|
|
import pandas as pd
|
|
|
|
from redash.utils.pandas import get_column_types_from_dataframe, pandas_to_result
|
|
|
|
|
|
class TestBuildUrl(TestCase):
|
|
def test_simple_case(self):
|
|
self.assertEqual(
|
|
"http://example.com/test",
|
|
build_url(DummyRequest("", "http"), "example.com", "/test"),
|
|
)
|
|
|
|
def test_uses_current_request_port(self):
|
|
self.assertEqual(
|
|
"http://example.com:5000/test",
|
|
build_url(DummyRequest("example.com:5000", "http"), "example.com", "/test"),
|
|
)
|
|
|
|
def test_uses_current_request_schema(self):
|
|
self.assertEqual(
|
|
"https://example.com/test",
|
|
build_url(DummyRequest("example.com", "https"), "example.com", "/test"),
|
|
)
|
|
|
|
def test_skips_port_for_default_ports(self):
|
|
self.assertEqual(
|
|
"https://example.com/test",
|
|
build_url(DummyRequest("example.com:443", "https"), "example.com", "/test"),
|
|
)
|
|
self.assertEqual(
|
|
"http://example.com/test",
|
|
build_url(DummyRequest("example.com:80", "http"), "example.com", "/test"),
|
|
)
|
|
self.assertEqual(
|
|
"https://example.com:80/test",
|
|
build_url(DummyRequest("example.com:80", "https"), "example.com", "/test"),
|
|
)
|
|
self.assertEqual(
|
|
"http://example.com:443/test",
|
|
build_url(DummyRequest("example.com:443", "http"), "example.com", "/test"),
|
|
)
|
|
|
|
|
|
class TestCollectParametersFromRequest(TestCase):
|
|
def test_ignores_non_prefixed_values(self):
|
|
self.assertEqual({}, collect_parameters_from_request({"test": 1}))
|
|
|
|
def test_takes_prefixed_values(self):
|
|
self.assertDictEqual(
|
|
{"test": 1, "something_else": "test"},
|
|
collect_parameters_from_request({"p_test": 1, "p_something_else": "test"}),
|
|
)
|
|
|
|
|
|
class TestSkipNones(TestCase):
|
|
def test_skips_nones(self):
|
|
d = {"a": 1, "b": None}
|
|
|
|
self.assertDictEqual(filter_none(d), {"a": 1})
|
|
|
|
|
|
class TestJsonDumps(TestCase):
|
|
def test_handles_binary(self):
|
|
self.assertEqual(json_dumps(memoryview(b"test")), '"74657374"')
|
|
|
|
|
|
class TestGenerateToken(TestCase):
|
|
def test_format(self):
|
|
token = generate_token(40)
|
|
self.assertRegex(token, r"[a-zA-Z0-9]{40}")
|
|
|
|
|
|
class TestRenderTemplate(TestCase):
|
|
def test_render(self):
|
|
app = create_app()
|
|
with app.app_context():
|
|
d = {
|
|
"failures": [
|
|
{
|
|
"id": 1,
|
|
"name": "Failure Unit Test",
|
|
"failed_at": "May 04, 2021 02:07PM UTC",
|
|
"failure_reason": "",
|
|
"failure_count": 1,
|
|
"comment": None,
|
|
}
|
|
]
|
|
}
|
|
html, text = [render_template("emails/failures.{}".format(f), d) for f in ["html", "txt"]]
|
|
self.assertIn("Failure Unit Test", html)
|
|
self.assertIn("Failure Unit Test", text)
|
|
|
|
|
|
@pytest.fixture
|
|
@skip_condition
|
|
def mock_dataframe():
|
|
df = pd.DataFrame(
|
|
{
|
|
"boolean_col": [True, False],
|
|
"integer_col": [1, 2],
|
|
"float_col": [1.1, 2.2],
|
|
"date_col": [np.datetime64("2020-01-01"), np.datetime64("2020-05-05")],
|
|
"datetime_col": [np.datetime64("2020-01-01 12:00:00"), np.datetime64("2020-05-05 14:30:00")],
|
|
"string_col": ["A", "B"],
|
|
}
|
|
)
|
|
return df
|
|
|
|
|
|
@skip_condition
|
|
def test_get_column_types_from_dataframe(mock_dataframe):
|
|
result = get_column_types_from_dataframe(mock_dataframe)
|
|
expected_output = [
|
|
{"name": "boolean_col", "friendly_name": "boolean_col", "type": TYPE_BOOLEAN},
|
|
{"name": "integer_col", "friendly_name": "integer_col", "type": TYPE_INTEGER},
|
|
{"name": "float_col", "friendly_name": "float_col", "type": TYPE_FLOAT},
|
|
{"name": "date_col", "friendly_name": "date_col", "type": TYPE_DATE},
|
|
{"name": "datetime_col", "friendly_name": "datetime_col", "type": TYPE_DATETIME},
|
|
{"name": "string_col", "friendly_name": "string_col", "type": TYPE_STRING},
|
|
]
|
|
|
|
assert result == expected_output
|
|
|
|
|
|
@skip_condition
|
|
def test_pandas_to_result(mock_dataframe):
|
|
result = pandas_to_result(mock_dataframe)
|
|
|
|
assert "columns" in result
|
|
assert "rows" in result
|
|
|
|
assert mock_dataframe.equals(pd.DataFrame(result["rows"]))
|