206 строки
6.6 KiB
Python
206 строки
6.6 KiB
Python
import os
|
|
from unittest.mock import Mock, patch
|
|
|
|
import lkml
|
|
import looker_sdk as _looker_sdk
|
|
import pytest
|
|
|
|
from generator.spoke import generate_directories
|
|
|
|
from .utils import print_and_test
|
|
|
|
|
|
@pytest.fixture()
|
|
def namespaces() -> dict:
|
|
return {
|
|
"glean-app": {
|
|
"pretty_name": "Glean App",
|
|
"glean_app": True,
|
|
"spoke": "looker-spoke-default",
|
|
"views": {
|
|
"baseline": {
|
|
"type": "ping_view",
|
|
"tables": [
|
|
{
|
|
"channel": "release",
|
|
"table": "mozdata.glean_app.baseline",
|
|
}
|
|
],
|
|
}
|
|
},
|
|
"explores": {
|
|
"baseline": {"type": "ping_explore", "views": {"base_view": "baseline"}}
|
|
},
|
|
}
|
|
}
|
|
|
|
|
|
@pytest.fixture
|
|
def custom_namespaces():
|
|
return {
|
|
"custom": {
|
|
"glean_app": False,
|
|
"spoke": "looker-spoke-private",
|
|
"connection": "bigquery-oauth",
|
|
"owners": ["custom-owner@allizom.com", "custom-owner2@allizom.com"],
|
|
"pretty_name": "Custom",
|
|
"views": {
|
|
"baseline": {
|
|
"tables": [
|
|
{"channel": "release", "table": "mozdata.custom.baseline"}
|
|
],
|
|
"type": "ping_view",
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
|
|
@patch("generator.spoke.looker_sdk")
|
|
@patch.dict(os.environ, {"LOOKER_INSTANCE_URI": "https://mozilladev.cloud.looker.com"})
|
|
def test_generate_directories(looker_sdk, namespaces, tmp_path):
|
|
sdk = looker_sdk.init31()
|
|
sdk.search_model_sets.return_value = [Mock(models=["model"], id=1)]
|
|
sdk.lookml_model.side_effect = _looker_sdk.error.SDKError
|
|
looker_sdk.error = Mock(SDKError=_looker_sdk.error.SDKError)
|
|
|
|
generate_directories(namespaces, tmp_path, True)
|
|
dirs = list((tmp_path / "looker-spoke-default").iterdir())
|
|
assert dirs == [tmp_path / "looker-spoke-default" / "glean-app"]
|
|
|
|
app_path = tmp_path / "looker-spoke-default" / "glean-app/"
|
|
sub_dirs = set(app_path.iterdir())
|
|
assert sub_dirs == {
|
|
app_path / "views",
|
|
app_path / "explores",
|
|
app_path / "dashboards",
|
|
app_path / "glean-app.model.lkml",
|
|
}
|
|
|
|
sdk.create_lookml_model.assert_called_once()
|
|
sdk.update_model_set.assert_called_once()
|
|
|
|
|
|
@patch("generator.spoke.looker_sdk")
|
|
def test_generate_directories_no_sdk(looker_sdk, namespaces, tmp_path):
|
|
sdk = looker_sdk.init31()
|
|
sdk.search_model_sets.return_value = [Mock(models=["model"], id=1)]
|
|
|
|
generate_directories(namespaces, tmp_path, False)
|
|
dirs = list((tmp_path / "looker-spoke-default").iterdir())
|
|
assert dirs == [tmp_path / "looker-spoke-default" / "glean-app"]
|
|
|
|
app_path = tmp_path / "looker-spoke-default" / "glean-app"
|
|
sub_dirs = set(app_path.iterdir())
|
|
assert sub_dirs == {
|
|
app_path / "views",
|
|
app_path / "explores",
|
|
app_path / "dashboards",
|
|
app_path / "glean-app.model.lkml",
|
|
}
|
|
|
|
assert (app_path / "dashboards" / ".gitkeep").exists()
|
|
|
|
sdk.create_lookml_model.assert_not_called()
|
|
|
|
|
|
@patch("generator.spoke.looker_sdk")
|
|
@patch.dict(os.environ, {"LOOKER_INSTANCE_URI": "https://mozilladev.cloud.looker.com"})
|
|
def test_existing_dir(looker_sdk, namespaces, tmp_path):
|
|
sdk = looker_sdk.init31()
|
|
sdk.search_model_sets.return_value = [Mock(models=["model"], id=1)]
|
|
|
|
generate_directories(namespaces, tmp_path, True)
|
|
tmp_file = tmp_path / "looker-spoke-default" / "glean-app" / "tmp-file"
|
|
tmp_file.write_text("hello, world")
|
|
|
|
generate_directories(namespaces, tmp_path)
|
|
|
|
# We shouldn't overwrite this dir
|
|
assert tmp_file.is_file()
|
|
|
|
|
|
@patch("generator.spoke.looker_sdk")
|
|
@patch.dict(os.environ, {"LOOKER_INSTANCE_URI": "https://mozilla.cloud.looker.com"})
|
|
def test_generate_model(looker_sdk, namespaces, tmp_path):
|
|
sdk = looker_sdk.init31()
|
|
sdk.search_model_sets.side_effect = [[Mock(models=["model"], id=1)]]
|
|
sdk.lookml_model.side_effect = _looker_sdk.error.SDKError
|
|
looker_sdk.error = Mock(SDKError=_looker_sdk.error.SDKError)
|
|
|
|
write_model = Mock()
|
|
looker_sdk.models.WriteModelSet.return_value = write_model
|
|
|
|
generate_directories(namespaces, tmp_path, True)
|
|
expected = {
|
|
"connection": "telemetry",
|
|
"label": "Glean App",
|
|
"includes": [
|
|
"//looker-hub/glean-app/explores/*",
|
|
"//looker-hub/glean-app/dashboards/*",
|
|
"views/*",
|
|
"explores/*",
|
|
"dashboards/*",
|
|
],
|
|
}
|
|
actual = lkml.load(
|
|
(
|
|
tmp_path / "looker-spoke-default" / "glean-app" / "glean-app.model.lkml"
|
|
).read_text()
|
|
)
|
|
assert expected == actual
|
|
|
|
looker_sdk.models.WriteModelSet.assert_any_call(models=["model", "glean-app"])
|
|
assert looker_sdk.models.WriteModelSet.call_count == 1
|
|
|
|
sdk.update_model_set.assert_any_call(1, write_model)
|
|
|
|
|
|
@patch("generator.spoke.looker_sdk")
|
|
@patch.dict(os.environ, {"LOOKER_INSTANCE_URI": "https://mozilladev.cloud.looker.com"})
|
|
def test_alternate_connection(looker_sdk, custom_namespaces, tmp_path):
|
|
sdk = looker_sdk.init31()
|
|
sdk.search_model_sets.return_value = [Mock(models=["model"], id=1)]
|
|
sdk.lookml_model.side_effect = _looker_sdk.error.SDKError
|
|
looker_sdk.error = Mock(SDKError=_looker_sdk.error.SDKError)
|
|
|
|
write_model = Mock()
|
|
looker_sdk.models.WriteLookmlModel.return_value = write_model
|
|
|
|
generate_directories(custom_namespaces, tmp_path, True)
|
|
dirs = list((tmp_path / "looker-spoke-private").iterdir())
|
|
assert dirs == [tmp_path / "looker-spoke-private" / "custom"]
|
|
|
|
app_path = tmp_path / "looker-spoke-private" / "custom"
|
|
sub_dirs = set(app_path.iterdir())
|
|
assert sub_dirs == {
|
|
app_path / "views",
|
|
app_path / "explores",
|
|
app_path / "dashboards",
|
|
app_path / "custom.model.lkml",
|
|
}
|
|
|
|
expected = {
|
|
"connection": "bigquery-oauth",
|
|
"label": "Custom",
|
|
"includes": [
|
|
"//looker-hub/custom/explores/*",
|
|
"//looker-hub/custom/dashboards/*",
|
|
"views/*",
|
|
"explores/*",
|
|
"dashboards/*",
|
|
],
|
|
}
|
|
actual = lkml.load(
|
|
(tmp_path / "looker-spoke-private" / "custom" / "custom.model.lkml").read_text()
|
|
)
|
|
print_and_test(expected, actual)
|
|
|
|
looker_sdk.models.WriteLookmlModel.assert_called_with(
|
|
allowed_db_connection_names=["bigquery-oauth"],
|
|
name="custom",
|
|
project_name="spoke-private",
|
|
)
|
|
sdk.create_lookml_model.assert_called_with(write_model)
|
|
sdk.update_model_set.assert_called_once()
|