mirror of
https://github.com/apache/superset.git
synced 2026-04-19 16:14:52 +00:00
feat(deck-gl): Enable individual deck.gl layer selection in FilterScope tree (#33769)
Co-authored-by: richardfn <richard.fogaca@appsilon.com> Co-authored-by: amaannawab923 <amaannawab923@gmail.com>
This commit is contained in:
committed by
GitHub
parent
11215b092a
commit
85034b9748
@@ -812,6 +812,620 @@ class TestBaseDeckGLViz(SupersetTestCase):
|
||||
adhoc_filters = test_viz_deckgl.form_data["adhoc_filters"]
|
||||
assert expected_results.get(mock_key) == adhoc_filters
|
||||
|
||||
def test_init_with_layer_filtering_applied(self):
|
||||
"""Test BaseDeckGLViz.__init__ applies layer filtering when conditions are
|
||||
met."""
|
||||
datasource = self.get_datasource_mock()
|
||||
form_data = {
|
||||
"slice_id": 123,
|
||||
"adhoc_filters": [
|
||||
{
|
||||
"clause": "WHERE",
|
||||
"subject": "col1",
|
||||
"operator": "==",
|
||||
"comparator": "value1",
|
||||
"layerFilterScope": [0, 1],
|
||||
"deck_slices": [123, 456],
|
||||
},
|
||||
{
|
||||
"clause": "WHERE",
|
||||
"subject": "col2",
|
||||
"operator": "!=",
|
||||
"comparator": "value2",
|
||||
"layerFilterScope": [1],
|
||||
"deck_slices": [123, 456],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
test_viz = viz.BaseDeckGLViz(datasource, form_data)
|
||||
|
||||
# Should only have the first filter (scoped to layer 0)
|
||||
assert len(test_viz.form_data["adhoc_filters"]) == 1
|
||||
assert test_viz.form_data["adhoc_filters"][0]["subject"] == "col1"
|
||||
|
||||
def test_init_without_layer_filtering(self):
|
||||
"""Test BaseDeckGLViz.__init__ doesn't apply filtering when conditions
|
||||
aren't met."""
|
||||
datasource = self.get_datasource_mock()
|
||||
form_data = {
|
||||
"adhoc_filters": [
|
||||
{
|
||||
"clause": "WHERE",
|
||||
"subject": "col1",
|
||||
"operator": "==",
|
||||
"comparator": "value1",
|
||||
}
|
||||
]
|
||||
}
|
||||
original_filters = form_data["adhoc_filters"].copy()
|
||||
|
||||
test_viz = viz.BaseDeckGLViz(datasource, form_data)
|
||||
|
||||
# Filters should remain unchanged
|
||||
assert test_viz.form_data["adhoc_filters"] == original_filters
|
||||
|
||||
def test_should_apply_layer_filtering_true(self):
|
||||
"""Test _should_apply_layer_filtering returns True when all conditions are
|
||||
met."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {"slice_id": 123, "adhoc_filters": [{"layerFilterScope": [0, 1]}]}
|
||||
|
||||
result = test_viz._should_apply_layer_filtering(form_data)
|
||||
assert result is True
|
||||
|
||||
def test_should_apply_layer_filtering_false_missing_slice_id(self):
|
||||
"""Test _should_apply_layer_filtering returns False when slice_id is missing."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {"adhoc_filters": [{"layerFilterScope": [0, 1]}]}
|
||||
|
||||
result = test_viz._should_apply_layer_filtering(form_data)
|
||||
assert result is False
|
||||
|
||||
def test_should_apply_layer_filtering_false_missing_adhoc_filters(self):
|
||||
"""Test _should_apply_layer_filtering returns False when adhoc_filters is
|
||||
missing."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {"slice_id": 123}
|
||||
|
||||
result = test_viz._should_apply_layer_filtering(form_data)
|
||||
assert result is False
|
||||
|
||||
def test_should_apply_layer_filtering_false_no_layer_scoped_filters(self):
|
||||
"""Test _should_apply_layer_filtering returns False when no layer scoped
|
||||
filters exist."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {
|
||||
"slice_id": 123,
|
||||
"adhoc_filters": [{"clause": "WHERE", "subject": "col1"}],
|
||||
}
|
||||
|
||||
result = test_viz._should_apply_layer_filtering(form_data)
|
||||
assert result is False
|
||||
|
||||
def test_has_layer_scoped_filters_true_with_dict(self):
|
||||
"""Test _has_layer_scoped_filters returns True when filter dict has
|
||||
layerFilterScope."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {
|
||||
"adhoc_filters": [{"layerFilterScope": [0, 1]}, {"clause": "WHERE"}]
|
||||
}
|
||||
|
||||
result = test_viz._has_layer_scoped_filters(form_data)
|
||||
assert result is True
|
||||
|
||||
def test_has_layer_scoped_filters_true_with_non_none_value(self):
|
||||
"""Test _has_layer_scoped_filters returns True when layerFilterScope is not
|
||||
None."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {
|
||||
"adhoc_filters": [
|
||||
{"layerFilterScope": []}, # Empty list is not None
|
||||
{"clause": "WHERE"},
|
||||
]
|
||||
}
|
||||
|
||||
result = test_viz._has_layer_scoped_filters(form_data)
|
||||
assert result is True
|
||||
|
||||
def test_has_layer_scoped_filters_false_none_value(self):
|
||||
"""Test _has_layer_scoped_filters returns False when layerFilterScope is
|
||||
None."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {"adhoc_filters": [{"layerFilterScope": None}, {"clause": "WHERE"}]}
|
||||
|
||||
result = test_viz._has_layer_scoped_filters(form_data)
|
||||
assert result is False
|
||||
|
||||
def test_has_layer_scoped_filters_false_no_scoped_filters(self):
|
||||
"""Test _has_layer_scoped_filters returns False when no filters have
|
||||
layerFilterScope."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {
|
||||
"adhoc_filters": [
|
||||
{"clause": "WHERE", "subject": "col1"},
|
||||
{"clause": "WHERE", "subject": "col2"},
|
||||
]
|
||||
}
|
||||
|
||||
result = test_viz._has_layer_scoped_filters(form_data)
|
||||
assert result is False
|
||||
|
||||
def test_has_layer_scoped_filters_empty_filters(self):
|
||||
"""Test _has_layer_scoped_filters returns False when adhoc_filters is empty."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {"adhoc_filters": []}
|
||||
|
||||
result = test_viz._has_layer_scoped_filters(form_data)
|
||||
assert result is False
|
||||
|
||||
def test_apply_multilayer_filtering_filters_by_layer_scope(self):
|
||||
"""Test _apply_multilayer_filtering correctly filters by layer scope."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {
|
||||
"slice_id": 456, # This is layer index 1
|
||||
"adhoc_filters": [
|
||||
{
|
||||
"subject": "global_filter",
|
||||
"deck_slices": [123, 456],
|
||||
# No layerFilterScope = global filter
|
||||
},
|
||||
{
|
||||
"subject": "layer_0_filter",
|
||||
"layerFilterScope": [0],
|
||||
"deck_slices": [123, 456],
|
||||
},
|
||||
{
|
||||
"subject": "layer_1_filter",
|
||||
"layerFilterScope": [1],
|
||||
"deck_slices": [123, 456],
|
||||
},
|
||||
{
|
||||
"subject": "layer_0_1_filter",
|
||||
"layerFilterScope": [0, 1],
|
||||
"deck_slices": [123, 456],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
result = test_viz._apply_multilayer_filtering(form_data)
|
||||
|
||||
# Should include: global_filter, layer_1_filter, layer_0_1_filter
|
||||
assert len(result["adhoc_filters"]) == 3
|
||||
subjects = [f["subject"] for f in result["adhoc_filters"]]
|
||||
assert "global_filter" in subjects
|
||||
assert "layer_1_filter" in subjects
|
||||
assert "layer_0_1_filter" in subjects
|
||||
assert "layer_0_filter" not in subjects
|
||||
|
||||
def test_apply_multilayer_filtering_no_deck_slices(self):
|
||||
"""Test _apply_multilayer_filtering returns original form_data when no
|
||||
deck_slices."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {"slice_id": 123, "adhoc_filters": [{"subject": "filter1"}]}
|
||||
|
||||
result = test_viz._apply_multilayer_filtering(form_data)
|
||||
|
||||
# Should return original form_data unchanged
|
||||
assert result == form_data
|
||||
|
||||
def test_apply_multilayer_filtering_slice_not_in_deck_slices(self):
|
||||
"""Test _apply_multilayer_filtering returns original when slice_id not in
|
||||
deck_slices."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {
|
||||
"slice_id": 999, # Not in deck_slices
|
||||
"adhoc_filters": [{"subject": "filter1", "deck_slices": [123, 456]}],
|
||||
}
|
||||
|
||||
result = test_viz._apply_multilayer_filtering(form_data)
|
||||
|
||||
# Should return original form_data unchanged
|
||||
assert result == form_data
|
||||
|
||||
def test_get_deck_slices_from_filters_found(self):
|
||||
"""Test _get_deck_slices_from_filters returns deck_slices when found."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {
|
||||
"adhoc_filters": [
|
||||
{"subject": "filter1"},
|
||||
{"subject": "filter2", "deck_slices": [123, 456, 789]},
|
||||
{"subject": "filter3"},
|
||||
]
|
||||
}
|
||||
|
||||
result = test_viz._get_deck_slices_from_filters(form_data)
|
||||
|
||||
assert result == [123, 456, 789]
|
||||
|
||||
def test_get_deck_slices_from_filters_not_found(self):
|
||||
"""Test _get_deck_slices_from_filters returns None when not found."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {"adhoc_filters": [{"subject": "filter1"}, {"subject": "filter2"}]}
|
||||
|
||||
result = test_viz._get_deck_slices_from_filters(form_data)
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_get_deck_slices_from_filters_empty_filters(self):
|
||||
"""Test _get_deck_slices_from_filters returns None when adhoc_filters is
|
||||
empty."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
form_data = {"adhoc_filters": []}
|
||||
|
||||
result = test_viz._get_deck_slices_from_filters(form_data)
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_get_filter_layer_scope_dict(self):
|
||||
"""Test _get_filter_layer_scope with dict filter item."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
filter_item = {"layerFilterScope": [0, 1, 2]}
|
||||
result = test_viz._get_filter_layer_scope(filter_item)
|
||||
|
||||
assert result == [0, 1, 2]
|
||||
|
||||
def test_get_filter_layer_scope_dict_none(self):
|
||||
"""Test _get_filter_layer_scope with dict that has None layerFilterScope."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
filter_item = {"layerFilterScope": None}
|
||||
result = test_viz._get_filter_layer_scope(filter_item)
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_get_filter_layer_scope_dict_missing_key(self):
|
||||
"""Test _get_filter_layer_scope with dict missing layerFilterScope."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
filter_item = {"subject": "col1"}
|
||||
result = test_viz._get_filter_layer_scope(filter_item)
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_get_filter_layer_scope_object_with_attribute(self):
|
||||
"""Test _get_filter_layer_scope with object having layerFilterScope
|
||||
attribute."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
from unittest.mock import Mock
|
||||
|
||||
filter_item = Mock()
|
||||
filter_item.layerFilterScope = [1, 2]
|
||||
|
||||
result = test_viz._get_filter_layer_scope(filter_item)
|
||||
|
||||
assert result == [1, 2]
|
||||
|
||||
def test_get_filter_layer_scope_object_without_attribute(self):
|
||||
"""Test _get_filter_layer_scope with object missing layerFilterScope
|
||||
attribute."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
from unittest.mock import Mock
|
||||
|
||||
filter_item = Mock()
|
||||
del filter_item.layerFilterScope # Remove the attribute
|
||||
|
||||
result = test_viz._get_filter_layer_scope(filter_item)
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_get_filter_layer_scope_non_dict_non_object(self):
|
||||
"""Test _get_filter_layer_scope with non-dict, non-object types."""
|
||||
datasource = self.get_datasource_mock()
|
||||
test_viz = viz.BaseDeckGLViz(datasource, {})
|
||||
|
||||
# Test with string
|
||||
result = test_viz._get_filter_layer_scope("string_filter")
|
||||
assert result is None
|
||||
|
||||
# Test with number
|
||||
result = test_viz._get_filter_layer_scope(123)
|
||||
assert result is None
|
||||
|
||||
# Test with None
|
||||
result = test_viz._get_filter_layer_scope(None)
|
||||
assert result is None
|
||||
|
||||
|
||||
class TestDeckGLMultiLayer(SupersetTestCase):
|
||||
def test_filter_items_by_scope_with_filter_id(self):
|
||||
"""Test _filter_items_by_scope method with items having filterId."""
|
||||
datasource = self.get_datasource_mock()
|
||||
form_data = {}
|
||||
test_viz = viz.DeckGLMultiLayer(datasource, form_data)
|
||||
|
||||
filter_item_1 = Mock()
|
||||
filter_item_1.filterId = "filter_1"
|
||||
filter_item_2 = Mock()
|
||||
filter_item_2.filterId = "filter_2"
|
||||
filter_item_3 = Mock()
|
||||
filter_item_3.filterId = "filter_3"
|
||||
|
||||
items = [filter_item_1, filter_item_2, filter_item_3]
|
||||
layer_index = 0
|
||||
layer_filter_scope = {"filter_1": [0, 1], "filter_2": [1], "filter_3": []}
|
||||
|
||||
result = test_viz._filter_items_by_scope(items, layer_index, layer_filter_scope)
|
||||
|
||||
assert len(result) == 2
|
||||
assert filter_item_1 in result
|
||||
assert filter_item_3 in result
|
||||
assert filter_item_2 not in result
|
||||
|
||||
def test_filter_items_by_scope_without_filter_id(self):
|
||||
"""Test _filter_items_by_scope method with items without filterId."""
|
||||
datasource = self.get_datasource_mock()
|
||||
form_data = {}
|
||||
test_viz = viz.DeckGLMultiLayer(datasource, form_data)
|
||||
|
||||
filter_item_1 = Mock()
|
||||
del filter_item_1.filterId
|
||||
filter_item_2 = Mock()
|
||||
filter_item_2.filterId = None
|
||||
|
||||
items = [filter_item_1, filter_item_2]
|
||||
layer_index = 0
|
||||
layer_filter_scope = {"filter_1": [1]}
|
||||
|
||||
result = test_viz._filter_items_by_scope(items, layer_index, layer_filter_scope)
|
||||
|
||||
assert len(result) == 2
|
||||
assert filter_item_1 in result
|
||||
assert filter_item_2 in result
|
||||
|
||||
def test_process_extra_form_data_filters(self):
|
||||
"""Test _process_extra_form_data_filters method."""
|
||||
datasource = self.get_datasource_mock()
|
||||
form_data = {}
|
||||
test_viz = viz.DeckGLMultiLayer(datasource, form_data)
|
||||
|
||||
layer_index = 0
|
||||
layer_filter_scope = {"filter_1": [0, 1], "filter_2": [1], "filter_3": []}
|
||||
filter_data_mapping = {
|
||||
"filter_1": [{"column": "col1", "op": "==", "val": "value1"}],
|
||||
"filter_2": [{"column": "col2", "op": "!=", "val": "value2"}],
|
||||
"filter_3": [{"column": "col3", "op": ">", "val": 100}],
|
||||
}
|
||||
extra_form_data = {"existing_key": "existing_value"}
|
||||
|
||||
result = test_viz._process_extra_form_data_filters(
|
||||
layer_index, layer_filter_scope, filter_data_mapping, extra_form_data
|
||||
)
|
||||
|
||||
expected_filters = [
|
||||
{"column": "col1", "op": "==", "val": "value1"},
|
||||
{"column": "col3", "op": ">", "val": 100},
|
||||
]
|
||||
assert result["filters"] == expected_filters
|
||||
assert result["existing_key"] == "existing_value"
|
||||
|
||||
def test_process_extra_form_data_filters_empty_inputs(self):
|
||||
"""Test _process_extra_form_data_filters with empty inputs."""
|
||||
datasource = self.get_datasource_mock()
|
||||
form_data = {}
|
||||
test_viz = viz.DeckGLMultiLayer(datasource, form_data)
|
||||
|
||||
result = test_viz._process_extra_form_data_filters(0, {}, {}, {})
|
||||
assert result == {}
|
||||
|
||||
extra_form_data = {"key": "value"}
|
||||
result = test_viz._process_extra_form_data_filters(0, {}, {}, extra_form_data)
|
||||
assert result == extra_form_data
|
||||
|
||||
def test_apply_layer_filtering_without_layer_filter_scope(self):
|
||||
"""Test _apply_layer_filtering when layer_filter_scope is empty."""
|
||||
datasource = self.get_datasource_mock()
|
||||
form_data = {
|
||||
"extra_filters": [Mock(), Mock()],
|
||||
"adhoc_filters": [Mock()],
|
||||
"extra_form_data": {"key": "value"},
|
||||
}
|
||||
test_viz = viz.DeckGLMultiLayer(datasource, form_data)
|
||||
|
||||
layer_form_data = {"viz_type": "deck_scatter"}
|
||||
layer_index = 0
|
||||
|
||||
result = test_viz._apply_layer_filtering(layer_form_data, layer_index)
|
||||
|
||||
assert result["extra_filters"] == form_data["extra_filters"]
|
||||
assert result["adhoc_filters"] == form_data["adhoc_filters"]
|
||||
assert result["extra_form_data"] == form_data["extra_form_data"]
|
||||
|
||||
def test_apply_layer_filtering_with_layer_filter_scope(self):
|
||||
"""Test _apply_layer_filtering with layer_filter_scope."""
|
||||
datasource = self.get_datasource_mock()
|
||||
|
||||
extra_filter_1 = Mock()
|
||||
extra_filter_1.filterId = "filter_1"
|
||||
extra_filter_2 = Mock()
|
||||
extra_filter_2.filterId = "filter_2"
|
||||
|
||||
adhoc_filter_1 = Mock()
|
||||
adhoc_filter_1.filterId = "filter_1"
|
||||
|
||||
form_data = {
|
||||
"layer_filter_scope": {"filter_1": [0], "filter_2": [1]},
|
||||
"filter_data_mapping": {
|
||||
"filter_1": [{"column": "col1", "op": "==", "val": "value1"}]
|
||||
},
|
||||
"extra_filters": [extra_filter_1, extra_filter_2],
|
||||
"adhoc_filters": [adhoc_filter_1],
|
||||
"extra_form_data": {"existing": "data"},
|
||||
}
|
||||
test_viz = viz.DeckGLMultiLayer(datasource, form_data)
|
||||
|
||||
layer_form_data = {"viz_type": "deck_scatter"}
|
||||
layer_index = 0
|
||||
|
||||
result = test_viz._apply_layer_filtering(layer_form_data, layer_index)
|
||||
|
||||
assert len(result["extra_filters"]) == 1
|
||||
assert result["extra_filters"][0].filterId == "filter_1"
|
||||
assert len(result["adhoc_filters"]) == 1
|
||||
assert result["adhoc_filters"][0].filterId == "filter_1"
|
||||
assert result["extra_form_data"]["filters"] == [
|
||||
{"column": "col1", "op": "==", "val": "value1"}
|
||||
]
|
||||
|
||||
@patch("superset.viz.viz_types")
|
||||
@patch("superset.db.session")
|
||||
def test_get_data_with_layer_filtering(self, mock_db_session, mock_viz_types):
|
||||
"""Test get_data method with layer filtering enabled."""
|
||||
datasource = self.get_datasource_mock()
|
||||
|
||||
slice_1 = Mock()
|
||||
slice_1.form_data = {"viz_type": "deck_scatter", "layer_name": "Layer 1"}
|
||||
slice_1.data = {"features": [{"type": "Feature"}]}
|
||||
slice_1.datasource = datasource
|
||||
|
||||
slice_2 = Mock()
|
||||
slice_2.form_data = {"viz_type": "deck_path", "layer_name": "Layer 2"}
|
||||
slice_2.data = {"features": [{"type": "Feature"}]}
|
||||
slice_2.datasource = datasource
|
||||
|
||||
# Mock the database query to return our slice objects
|
||||
mock_db_session.query.return_value.filter.return_value.all.return_value = [
|
||||
slice_1,
|
||||
slice_2,
|
||||
]
|
||||
|
||||
mock_scatter_viz_class = Mock()
|
||||
mock_scatter_viz_instance = Mock()
|
||||
mock_scatter_viz_instance.get_payload.return_value = {
|
||||
"data": {"features": [{"id": 1}]}
|
||||
}
|
||||
mock_scatter_viz_class.return_value = mock_scatter_viz_instance
|
||||
|
||||
mock_path_viz_class = Mock()
|
||||
mock_path_viz_instance = Mock()
|
||||
mock_path_viz_instance.get_payload.return_value = {
|
||||
"data": {"features": [{"id": 2}]}
|
||||
}
|
||||
mock_path_viz_class.return_value = mock_path_viz_instance
|
||||
|
||||
mock_viz_types.get.side_effect = lambda viz_type: {
|
||||
"deck_scatter": mock_scatter_viz_class,
|
||||
"deck_path": mock_path_viz_class,
|
||||
}.get(viz_type)
|
||||
|
||||
form_data = {
|
||||
"layer_filter_scope": {"filter_1": [0], "filter_2": [1]},
|
||||
"filter_data_mapping": {
|
||||
"filter_1": [{"column": "col1", "op": "==", "val": "value1"}],
|
||||
"filter_2": [{"column": "col2", "op": "!=", "val": "value2"}],
|
||||
},
|
||||
"deck_slices": [1, 2], # Use integer IDs instead of Mock objects
|
||||
}
|
||||
|
||||
with patch("superset.viz.config", {"MAPBOX_API_KEY": "test_key"}):
|
||||
test_viz = viz.DeckGLMultiLayer(datasource, form_data)
|
||||
|
||||
test_viz._apply_layer_filtering = Mock(
|
||||
side_effect=lambda form_data, idx: form_data
|
||||
)
|
||||
|
||||
result = test_viz.get_data(pd.DataFrame())
|
||||
|
||||
assert test_viz._apply_layer_filtering.call_count == 2
|
||||
test_viz._apply_layer_filtering.assert_any_call(slice_1.form_data, 0)
|
||||
test_viz._apply_layer_filtering.assert_any_call(slice_2.form_data, 1)
|
||||
|
||||
assert isinstance(result, dict)
|
||||
assert "features" in result
|
||||
assert "mapboxApiKey" in result
|
||||
assert "slices" in result
|
||||
assert result["mapboxApiKey"] == "test_key"
|
||||
|
||||
@patch("superset.viz.viz_types")
|
||||
@patch("superset.db.session")
|
||||
def test_get_data_filters_none_data_slices(self, mock_db_session, mock_viz_types):
|
||||
"""Test get_data method filters out slices with None data."""
|
||||
datasource = self.get_datasource_mock()
|
||||
|
||||
slice_1 = Mock()
|
||||
slice_1.form_data = {"viz_type": "deck_scatter"}
|
||||
slice_1.data = {"features": [{"type": "Feature"}]}
|
||||
slice_1.datasource = datasource
|
||||
|
||||
slice_2 = Mock()
|
||||
slice_2.form_data = {"viz_type": "deck_path"}
|
||||
slice_2.data = None
|
||||
slice_2.datasource = datasource
|
||||
|
||||
# Mock the database query to return our slice objects
|
||||
mock_db_session.query.return_value.filter.return_value.all.return_value = [
|
||||
slice_1,
|
||||
slice_2,
|
||||
]
|
||||
|
||||
mock_viz_class = Mock()
|
||||
mock_viz_instance = Mock()
|
||||
mock_viz_instance.get_payload.return_value = {"data": {"features": []}}
|
||||
mock_viz_class.return_value = mock_viz_instance
|
||||
mock_viz_types.get.return_value = mock_viz_class
|
||||
|
||||
form_data = {"deck_slices": [1, 2]} # Use integer IDs instead of Mock objects
|
||||
|
||||
with patch("superset.viz.config", {"MAPBOX_API_KEY": "test_key"}):
|
||||
test_viz = viz.DeckGLMultiLayer(datasource, form_data)
|
||||
result = test_viz.get_data(pd.DataFrame())
|
||||
|
||||
assert isinstance(result, dict)
|
||||
assert len(result["slices"]) == 1
|
||||
assert result["slices"][0] == slice_1.data
|
||||
|
||||
def test_get_data_empty_deck_slices(self):
|
||||
"""Test get_data method with empty deck_slices."""
|
||||
datasource = self.get_datasource_mock()
|
||||
form_data = {"deck_slices": []}
|
||||
|
||||
with patch("superset.viz.config", {"MAPBOX_API_KEY": "test_key"}):
|
||||
test_viz = viz.DeckGLMultiLayer(datasource, form_data)
|
||||
result = test_viz.get_data(pd.DataFrame())
|
||||
|
||||
assert isinstance(result, dict)
|
||||
assert result["features"] == {}
|
||||
assert result["slices"] == []
|
||||
assert result["mapboxApiKey"] == "test_key"
|
||||
|
||||
|
||||
class TestTimeSeriesViz(SupersetTestCase):
|
||||
def test_timeseries_unicode_data(self):
|
||||
|
||||
Reference in New Issue
Block a user