mirror of
https://github.com/apache/superset.git
synced 2026-04-07 18:35:15 +00:00
332 lines
10 KiB
Python
332 lines
10 KiB
Python
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from jinja2 import Environment, FileSystemLoader
|
|
|
|
|
|
@pytest.fixture
|
|
def templates_dir():
|
|
"""Get the templates directory path."""
|
|
return (
|
|
Path(__file__).parent.parent / "src" / "superset_extensions_cli" / "templates"
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def jinja_env(templates_dir):
|
|
"""Create a Jinja2 environment for testing templates."""
|
|
return Environment(loader=FileSystemLoader(templates_dir))
|
|
|
|
|
|
@pytest.fixture
|
|
def template_context():
|
|
"""Default template context for testing."""
|
|
return {
|
|
"id": "test_extension",
|
|
"name": "Test Extension",
|
|
"version": "0.1.0",
|
|
"license": "Apache-2.0",
|
|
"include_frontend": True,
|
|
"include_backend": True,
|
|
}
|
|
|
|
|
|
# Extension JSON Template Tests
|
|
@pytest.mark.unit
|
|
def test_extension_json_template_renders_with_both_frontend_and_backend(
|
|
jinja_env, template_context
|
|
):
|
|
"""Test extension.json template renders correctly with both frontend and backend."""
|
|
template = jinja_env.get_template("extension.json.j2")
|
|
rendered = template.render(template_context)
|
|
|
|
# Parse the rendered JSON to ensure it's valid
|
|
parsed = json.loads(rendered)
|
|
|
|
# Verify basic fields
|
|
assert parsed["id"] == "test_extension"
|
|
assert parsed["name"] == "Test Extension"
|
|
assert parsed["version"] == "0.1.0"
|
|
assert parsed["license"] == "Apache-2.0"
|
|
assert parsed["permissions"] == []
|
|
|
|
# Verify frontend section exists
|
|
assert "frontend" in parsed
|
|
frontend = parsed["frontend"]
|
|
assert "contributions" in frontend
|
|
assert "moduleFederation" in frontend
|
|
assert frontend["contributions"] == {"commands": [], "views": {}, "menus": {}}
|
|
assert frontend["moduleFederation"] == {"exposes": ["./index"]}
|
|
|
|
# Verify backend section exists
|
|
assert "backend" in parsed
|
|
backend = parsed["backend"]
|
|
assert backend["entryPoints"] == ["test_extension.entrypoint"]
|
|
assert backend["files"] == ["backend/src/test_extension/**/*.py"]
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.parametrize(
|
|
"include_frontend,include_backend,expected_sections",
|
|
[
|
|
(True, False, ["frontend"]),
|
|
(False, True, ["backend"]),
|
|
(False, False, []),
|
|
],
|
|
)
|
|
def test_extension_json_template_renders_with_different_configurations(
|
|
jinja_env, template_context, include_frontend, include_backend, expected_sections
|
|
):
|
|
"""Test extension.json template renders correctly with different configurations."""
|
|
template_context["include_frontend"] = include_frontend
|
|
template_context["include_backend"] = include_backend
|
|
|
|
template = jinja_env.get_template("extension.json.j2")
|
|
rendered = template.render(template_context)
|
|
|
|
parsed = json.loads(rendered)
|
|
|
|
# Check for expected sections
|
|
for section in expected_sections:
|
|
assert section in parsed, f"Expected section '{section}' not found"
|
|
|
|
# Check that unexpected sections are not present
|
|
all_sections = ["frontend", "backend"]
|
|
for section in all_sections:
|
|
if section not in expected_sections:
|
|
assert section not in parsed, f"Unexpected section '{section}' found"
|
|
|
|
|
|
# Frontend Package JSON Template Tests
|
|
@pytest.mark.unit
|
|
def test_frontend_package_json_template_renders_correctly(jinja_env, template_context):
|
|
"""Test frontend/package.json template renders correctly."""
|
|
template = jinja_env.get_template("frontend/package.json.j2")
|
|
rendered = template.render(template_context)
|
|
|
|
parsed = json.loads(rendered)
|
|
|
|
# Verify basic package info
|
|
assert parsed["name"] == "test_extension"
|
|
assert parsed["version"] == "0.1.0"
|
|
assert parsed["license"] == "Apache-2.0"
|
|
assert parsed["private"] is True
|
|
|
|
# Verify scripts section
|
|
assert "scripts" in parsed
|
|
scripts = parsed["scripts"]
|
|
assert "start" in scripts
|
|
assert "build" in scripts
|
|
assert "webpack" in scripts["build"]
|
|
|
|
# Verify dependencies
|
|
assert "peerDependencies" in parsed
|
|
peer_deps = parsed["peerDependencies"]
|
|
assert "@apache-superset/core" in peer_deps
|
|
assert "react" in peer_deps
|
|
assert "react-dom" in peer_deps
|
|
|
|
# Verify dev dependencies
|
|
assert "devDependencies" in parsed
|
|
dev_deps = parsed["devDependencies"]
|
|
assert "webpack" in dev_deps
|
|
assert "typescript" in dev_deps
|
|
|
|
|
|
# Backend Pyproject TOML Template Tests
|
|
@pytest.mark.unit
|
|
def test_backend_pyproject_toml_template_renders_correctly(jinja_env, template_context):
|
|
"""Test backend/pyproject.toml template renders correctly."""
|
|
template = jinja_env.get_template("backend/pyproject.toml.j2")
|
|
rendered = template.render(template_context)
|
|
|
|
# Basic content verification (without full TOML parsing)
|
|
assert "test_extension" in rendered
|
|
assert "0.1.0" in rendered
|
|
assert "Apache-2.0" in rendered
|
|
|
|
|
|
# Template Rendering with Different Parameters Tests
|
|
@pytest.mark.unit
|
|
@pytest.mark.parametrize(
|
|
"id_,name",
|
|
[
|
|
("simple_extension", "Simple Extension"),
|
|
("MyExtension123", "My Extension 123"),
|
|
("complex_extension_name_123", "Complex Extension Name 123"),
|
|
("ext", "Ext"),
|
|
],
|
|
)
|
|
def test_template_rendering_with_different_ids(jinja_env, id_, name):
|
|
"""Test templates render correctly with various extension ids/names."""
|
|
context = {
|
|
"id": id_,
|
|
"name": name,
|
|
"version": "1.0.0",
|
|
"license": "MIT",
|
|
"include_frontend": True,
|
|
"include_backend": True,
|
|
}
|
|
|
|
# Test extension.json template
|
|
template = jinja_env.get_template("extension.json.j2")
|
|
rendered = template.render(context)
|
|
parsed = json.loads(rendered)
|
|
|
|
assert parsed["id"] == id_
|
|
assert parsed["name"] == name
|
|
assert parsed["backend"]["entryPoints"] == [f"{id_}.entrypoint"]
|
|
assert parsed["backend"]["files"] == [f"backend/src/{id_}/**/*.py"]
|
|
|
|
# Test package.json template
|
|
template = jinja_env.get_template("frontend/package.json.j2")
|
|
rendered = template.render(context)
|
|
parsed = json.loads(rendered)
|
|
|
|
assert parsed["name"] == id_
|
|
|
|
# Test pyproject.toml template
|
|
template = jinja_env.get_template("backend/pyproject.toml.j2")
|
|
rendered = template.render(context)
|
|
|
|
assert id_ in rendered
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.parametrize("version", ["0.1.0", "1.0.0", "2.1.3-alpha", "10.20.30"])
|
|
def test_template_rendering_with_different_versions(jinja_env, version):
|
|
"""Test templates render correctly with various version formats."""
|
|
context = {
|
|
"id": "test_ext",
|
|
"name": "Test Extension",
|
|
"version": version,
|
|
"license": "Apache-2.0",
|
|
"include_frontend": True,
|
|
"include_backend": False,
|
|
}
|
|
|
|
template = jinja_env.get_template("extension.json.j2")
|
|
rendered = template.render(context)
|
|
parsed = json.loads(rendered)
|
|
|
|
assert parsed["version"] == version
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.parametrize(
|
|
"license_type",
|
|
[
|
|
"Apache-2.0",
|
|
"MIT",
|
|
"BSD-3-Clause",
|
|
"GPL-3.0",
|
|
"Custom License",
|
|
],
|
|
)
|
|
def test_template_rendering_with_different_licenses(jinja_env, license_type):
|
|
"""Test templates render correctly with various license types."""
|
|
context = {
|
|
"id": "test_ext",
|
|
"name": "Test Extension",
|
|
"version": "1.0.0",
|
|
"license": license_type,
|
|
"include_frontend": True,
|
|
"include_backend": True,
|
|
}
|
|
|
|
# Test extension.json template
|
|
template = jinja_env.get_template("extension.json.j2")
|
|
rendered = template.render(context)
|
|
parsed = json.loads(rendered)
|
|
|
|
assert parsed["license"] == license_type
|
|
|
|
# Test package.json template
|
|
template = jinja_env.get_template("frontend/package.json.j2")
|
|
rendered = template.render(context)
|
|
parsed = json.loads(rendered)
|
|
|
|
assert parsed["license"] == license_type
|
|
|
|
|
|
# Template Validation Tests
|
|
@pytest.mark.unit
|
|
@pytest.mark.parametrize(
|
|
"template_name", ["extension.json.j2", "frontend/package.json.j2"]
|
|
)
|
|
def test_templates_produce_valid_json(jinja_env, template_context, template_name):
|
|
"""Test that all JSON templates produce valid JSON output."""
|
|
template = jinja_env.get_template(template_name)
|
|
rendered = template.render(template_context)
|
|
|
|
# This will raise an exception if the JSON is invalid
|
|
try:
|
|
json.loads(rendered)
|
|
except json.JSONDecodeError as e:
|
|
pytest.fail(f"Template {template_name} produced invalid JSON: {e}")
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_template_whitespace_handling(jinja_env, template_context):
|
|
"""Test that templates handle whitespace correctly and produce clean output."""
|
|
template = jinja_env.get_template("extension.json.j2")
|
|
rendered = template.render(template_context)
|
|
|
|
# Should not have excessive empty lines
|
|
lines = rendered.split("\n")
|
|
empty_line_count = sum(1 for line in lines if line.strip() == "")
|
|
|
|
# Some empty lines are OK for formatting, but not excessive
|
|
assert empty_line_count < len(lines) / 2, (
|
|
"Too many empty lines in rendered template"
|
|
)
|
|
|
|
# Should be properly formatted JSON
|
|
parsed = json.loads(rendered)
|
|
# Re-serialize to check it's valid structure
|
|
json.dumps(parsed, indent=2)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_template_context_edge_cases(jinja_env):
|
|
"""Test template rendering with edge case contexts."""
|
|
# Test with minimal context
|
|
minimal_context = {
|
|
"id": "minimal",
|
|
"name": "Minimal",
|
|
"version": "1.0.0",
|
|
"license": "MIT",
|
|
"include_frontend": False,
|
|
"include_backend": False,
|
|
}
|
|
|
|
template = jinja_env.get_template("extension.json.j2")
|
|
rendered = template.render(minimal_context)
|
|
parsed = json.loads(rendered)
|
|
|
|
# Should still be valid JSON with basic fields
|
|
assert parsed["id"] == "minimal"
|
|
assert parsed["name"] == "Minimal"
|
|
assert "frontend" not in parsed
|
|
assert "backend" not in parsed
|