mirror of
https://github.com/apache/superset.git
synced 2026-04-17 23:25:05 +00:00
fix: Rename apache-superset-cli to apache-superset-extensions-cli (#34883)
This commit is contained in:
committed by
GitHub
parent
ebfb14c353
commit
bcf156c969
362
superset-extensions-cli/tests/test_cli_init.py
Normal file
362
superset-extensions-cli/tests/test_cli_init.py
Normal file
@@ -0,0 +1,362 @@
|
||||
# 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
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from superset_extensions_cli.cli import app
|
||||
|
||||
from tests.utils import (
|
||||
assert_directory_exists,
|
||||
assert_directory_structure,
|
||||
assert_file_exists,
|
||||
assert_file_structure,
|
||||
assert_json_content,
|
||||
create_test_extension_structure,
|
||||
load_json_file,
|
||||
)
|
||||
|
||||
|
||||
# Init Command Tests
|
||||
@pytest.mark.cli
|
||||
def test_init_creates_extension_with_both_frontend_and_backend(
|
||||
cli_runner, isolated_filesystem, cli_input_both
|
||||
):
|
||||
"""Test that init creates a complete extension with both frontend and backend."""
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input_both)
|
||||
|
||||
assert result.exit_code == 0, f"Command failed with output: {result.output}"
|
||||
assert (
|
||||
"🎉 Extension Test Extension (ID: test_extension) initialized" in result.output
|
||||
)
|
||||
|
||||
# Verify directory structure
|
||||
extension_path = isolated_filesystem / "test_extension"
|
||||
assert_directory_exists(extension_path, "main extension directory")
|
||||
|
||||
expected_structure = create_test_extension_structure(
|
||||
isolated_filesystem,
|
||||
"test_extension",
|
||||
include_frontend=True,
|
||||
include_backend=True,
|
||||
)
|
||||
|
||||
# Check directories
|
||||
assert_directory_structure(extension_path, expected_structure["expected_dirs"])
|
||||
|
||||
# Check files
|
||||
assert_file_structure(extension_path, expected_structure["expected_files"])
|
||||
|
||||
|
||||
@pytest.mark.cli
|
||||
def test_init_creates_extension_with_frontend_only(
|
||||
cli_runner, isolated_filesystem, cli_input_frontend_only
|
||||
):
|
||||
"""Test that init creates extension with only frontend components."""
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input_frontend_only)
|
||||
|
||||
assert result.exit_code == 0, f"Command failed with output: {result.output}"
|
||||
|
||||
extension_path = isolated_filesystem / "test_extension"
|
||||
assert_directory_exists(extension_path)
|
||||
|
||||
# Should have frontend directory and package.json
|
||||
assert_directory_exists(extension_path / "frontend")
|
||||
assert_file_exists(extension_path / "frontend" / "package.json")
|
||||
|
||||
# Should NOT have backend directory
|
||||
backend_path = extension_path / "backend"
|
||||
assert not backend_path.exists(), (
|
||||
"Backend directory should not exist for frontend-only extension"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.cli
|
||||
def test_init_creates_extension_with_backend_only(
|
||||
cli_runner, isolated_filesystem, cli_input_backend_only
|
||||
):
|
||||
"""Test that init creates extension with only backend components."""
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input_backend_only)
|
||||
|
||||
assert result.exit_code == 0, f"Command failed with output: {result.output}"
|
||||
|
||||
extension_path = isolated_filesystem / "test_extension"
|
||||
assert_directory_exists(extension_path)
|
||||
|
||||
# Should have backend directory and pyproject.toml
|
||||
assert_directory_exists(extension_path / "backend")
|
||||
assert_file_exists(extension_path / "backend" / "pyproject.toml")
|
||||
|
||||
# Should NOT have frontend directory
|
||||
frontend_path = extension_path / "frontend"
|
||||
assert not frontend_path.exists(), (
|
||||
"Frontend directory should not exist for backend-only extension"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.cli
|
||||
def test_init_creates_extension_with_neither_frontend_nor_backend(
|
||||
cli_runner, isolated_filesystem, cli_input_neither
|
||||
):
|
||||
"""Test that init creates minimal extension with neither frontend nor backend."""
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input_neither)
|
||||
|
||||
assert result.exit_code == 0, f"Command failed with output: {result.output}"
|
||||
|
||||
extension_path = isolated_filesystem / "test_extension"
|
||||
assert_directory_exists(extension_path)
|
||||
|
||||
# Should only have extension.json
|
||||
assert_file_exists(extension_path / "extension.json")
|
||||
|
||||
# Should NOT have frontend or backend directories
|
||||
assert not (extension_path / "frontend").exists()
|
||||
assert not (extension_path / "backend").exists()
|
||||
|
||||
|
||||
@pytest.mark.cli
|
||||
@pytest.mark.parametrize(
|
||||
"invalid_name,expected_error",
|
||||
[
|
||||
("test-extension", "must be alphanumeric"),
|
||||
("test extension", "must be alphanumeric"),
|
||||
("test.extension", "must be alphanumeric"),
|
||||
("test@extension", "must be alphanumeric"),
|
||||
("", "must be alphanumeric"),
|
||||
],
|
||||
)
|
||||
def test_init_validates_extension_name(
|
||||
cli_runner, isolated_filesystem, invalid_name, expected_error
|
||||
):
|
||||
"""Test that init validates extension names according to regex pattern."""
|
||||
cli_input = f"{invalid_name}\n0.1.0\nApache-2.0\ny\ny\n"
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input)
|
||||
|
||||
assert result.exit_code == 1, (
|
||||
f"Expected command to fail for invalid name '{invalid_name}'"
|
||||
)
|
||||
assert expected_error in result.output
|
||||
|
||||
|
||||
@pytest.mark.cli
|
||||
def test_init_accepts_numeric_extension_name(cli_runner, isolated_filesystem):
|
||||
"""Test that init accepts numeric extension ids like '123'."""
|
||||
cli_input = "123\n123\n0.1.0\nApache-2.0\ny\ny\n"
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input)
|
||||
|
||||
assert result.exit_code == 0, f"Numeric id '123' should be valid: {result.output}"
|
||||
assert Path("123").exists(), "Directory for '123' should be created"
|
||||
|
||||
|
||||
@pytest.mark.cli
|
||||
@pytest.mark.parametrize(
|
||||
"valid_id", ["test123", "TestExtension", "test_extension_123", "MyExt_1"]
|
||||
)
|
||||
def test_init_with_valid_alphanumeric_names(cli_runner, valid_id):
|
||||
"""Test that init accepts various valid alphanumeric names."""
|
||||
with cli_runner.isolated_filesystem():
|
||||
cli_input = f"{valid_id}\nTest Extension\n0.1.0\nApache-2.0\ny\ny\n"
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input)
|
||||
|
||||
assert result.exit_code == 0, (
|
||||
f"Valid name '{valid_id}' was rejected: {result.output}"
|
||||
)
|
||||
assert Path(valid_id).exists(), f"Directory for '{valid_id}' was not created"
|
||||
|
||||
|
||||
@pytest.mark.cli
|
||||
def test_init_fails_when_directory_already_exists(
|
||||
cli_runner, isolated_filesystem, cli_input_both
|
||||
):
|
||||
"""Test that init fails gracefully when target directory already exists."""
|
||||
# Create the directory first
|
||||
existing_dir = isolated_filesystem / "test_extension"
|
||||
existing_dir.mkdir()
|
||||
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input_both)
|
||||
|
||||
assert result.exit_code == 1, "Command should fail when directory already exists"
|
||||
assert "already exists" in result.output
|
||||
|
||||
|
||||
@pytest.mark.cli
|
||||
def test_extension_json_content_is_correct(
|
||||
cli_runner, isolated_filesystem, cli_input_both
|
||||
):
|
||||
"""Test that the generated extension.json has the correct content."""
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input_both)
|
||||
assert result.exit_code == 0
|
||||
|
||||
extension_path = isolated_filesystem / "test_extension"
|
||||
extension_json_path = extension_path / "extension.json"
|
||||
|
||||
# Verify the JSON structure and values
|
||||
assert_json_content(
|
||||
extension_json_path,
|
||||
{
|
||||
"id": "test_extension",
|
||||
"name": "Test Extension",
|
||||
"version": "0.1.0",
|
||||
"license": "Apache-2.0",
|
||||
"permissions": [],
|
||||
},
|
||||
)
|
||||
|
||||
# Load and verify more complex nested structures
|
||||
content = load_json_file(extension_json_path)
|
||||
|
||||
# Verify frontend section exists and has correct structure
|
||||
assert "frontend" in content
|
||||
frontend = content["frontend"]
|
||||
assert "contributions" in frontend
|
||||
assert "moduleFederation" in frontend
|
||||
assert frontend["contributions"] == {"commands": [], "views": [], "menus": []}
|
||||
assert frontend["moduleFederation"] == {"exposes": ["./index"]}
|
||||
|
||||
# Verify backend section exists and has correct structure
|
||||
assert "backend" in content
|
||||
backend = content["backend"]
|
||||
assert "entryPoints" in backend
|
||||
assert "files" in backend
|
||||
assert backend["entryPoints"] == ["test_extension.entrypoint"]
|
||||
assert backend["files"] == ["backend/src/test_extension/**/*.py"]
|
||||
|
||||
|
||||
@pytest.mark.cli
|
||||
def test_frontend_package_json_content_is_correct(
|
||||
cli_runner, isolated_filesystem, cli_input_both
|
||||
):
|
||||
"""Test that the generated frontend/package.json has the correct content."""
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input_both)
|
||||
assert result.exit_code == 0
|
||||
|
||||
extension_path = isolated_filesystem / "test_extension"
|
||||
package_json_path = extension_path / "frontend" / "package.json"
|
||||
|
||||
# Verify the package.json structure and values
|
||||
assert_json_content(
|
||||
package_json_path,
|
||||
{
|
||||
"name": "test_extension",
|
||||
"version": "0.1.0",
|
||||
"license": "Apache-2.0",
|
||||
},
|
||||
)
|
||||
|
||||
# Verify more complex structures
|
||||
content = load_json_file(package_json_path)
|
||||
assert "scripts" in content
|
||||
assert "build" in content["scripts"]
|
||||
assert "peerDependencies" in content
|
||||
assert "@apache-superset/core" in content["peerDependencies"]
|
||||
|
||||
|
||||
@pytest.mark.cli
|
||||
def test_backend_pyproject_toml_is_created(
|
||||
cli_runner, isolated_filesystem, cli_input_both
|
||||
):
|
||||
"""Test that the generated backend/pyproject.toml file is created."""
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input_both)
|
||||
assert result.exit_code == 0
|
||||
|
||||
extension_path = isolated_filesystem / "test_extension"
|
||||
pyproject_path = extension_path / "backend" / "pyproject.toml"
|
||||
|
||||
assert_file_exists(pyproject_path, "backend pyproject.toml")
|
||||
|
||||
# Basic content verification (without parsing TOML for now)
|
||||
content = pyproject_path.read_text()
|
||||
assert "test_extension" in content
|
||||
assert "0.1.0" in content
|
||||
assert "Apache-2.0" in content
|
||||
|
||||
|
||||
@pytest.mark.cli
|
||||
def test_init_command_output_messages(cli_runner, isolated_filesystem, cli_input_both):
|
||||
"""Test that init command produces expected output messages."""
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input_both)
|
||||
|
||||
assert result.exit_code == 0
|
||||
output = result.output
|
||||
|
||||
# Check for expected success messages
|
||||
assert "✅ Created extension.json" in output
|
||||
assert "✅ Created frontend folder structure" in output
|
||||
assert "✅ Created backend folder structure" in output
|
||||
assert "🎉 Extension Test Extension (ID: test_extension) initialized" in output
|
||||
|
||||
|
||||
@pytest.mark.cli
|
||||
def test_init_with_custom_version_and_license(cli_runner, isolated_filesystem):
|
||||
"""Test init with custom version and license parameters."""
|
||||
cli_input = "my_extension\nMy Extension\n2.1.0\nMIT\ny\nn\n"
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input)
|
||||
|
||||
assert result.exit_code == 0
|
||||
|
||||
extension_path = isolated_filesystem / "my_extension"
|
||||
extension_json_path = extension_path / "extension.json"
|
||||
|
||||
assert_json_content(
|
||||
extension_json_path,
|
||||
{
|
||||
"id": "my_extension",
|
||||
"name": "My Extension",
|
||||
"version": "2.1.0",
|
||||
"license": "MIT",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.cli
|
||||
def test_full_init_workflow_integration(cli_runner, isolated_filesystem):
|
||||
"""Integration test for the complete init workflow."""
|
||||
# Test the complete flow with realistic user input
|
||||
cli_input = "awesome_charts\nAwesome Charts\n1.0.0\nApache-2.0\ny\ny\n"
|
||||
result = cli_runner.invoke(app, ["init"], input=cli_input)
|
||||
|
||||
# Verify success
|
||||
assert result.exit_code == 0
|
||||
|
||||
# Verify complete directory structure
|
||||
extension_path = isolated_filesystem / "awesome_charts"
|
||||
expected_structure = create_test_extension_structure(
|
||||
isolated_filesystem,
|
||||
"awesome_charts",
|
||||
include_frontend=True,
|
||||
include_backend=True,
|
||||
)
|
||||
|
||||
# Comprehensive structure verification
|
||||
assert_directory_structure(extension_path, expected_structure["expected_dirs"])
|
||||
assert_file_structure(extension_path, expected_structure["expected_files"])
|
||||
|
||||
# Verify all generated files have correct content
|
||||
extension_json = load_json_file(extension_path / "extension.json")
|
||||
assert extension_json["id"] == "awesome_charts"
|
||||
assert extension_json["name"] == "Awesome Charts"
|
||||
assert extension_json["version"] == "1.0.0"
|
||||
assert extension_json["license"] == "Apache-2.0"
|
||||
|
||||
package_json = load_json_file(extension_path / "frontend" / "package.json")
|
||||
assert package_json["name"] == "awesome_charts"
|
||||
|
||||
pyproject_content = (extension_path / "backend" / "pyproject.toml").read_text()
|
||||
assert "awesome_charts" in pyproject_content
|
||||
Reference in New Issue
Block a user