forked from cleveragents/cleveragents-core
288 lines
10 KiB
Python
288 lines
10 KiB
Python
"""Step definitions for cloud features identification."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from behave import given, then, when
|
|
|
|
from cleveragents.discovery.cloud_features import CloudFeaturesExtractor
|
|
|
|
|
|
@given("the cloud features extractor is initialized")
|
|
def step_init_cloud_extractor(context):
|
|
"""Initialize the cloud features extractor."""
|
|
plandex_dir = Path(__file__).parent.parent.parent / "plandex"
|
|
context.cloud_extractor = CloudFeaturesExtractor(plandex_dir)
|
|
|
|
|
|
@when("I run the cloud features extraction")
|
|
def step_run_cloud_extraction(context):
|
|
"""Run the cloud features extraction."""
|
|
context.cloud_results = context.cloud_extractor.extract_all()
|
|
|
|
|
|
@when("I scan for billing features")
|
|
def step_scan_billing_features(context):
|
|
"""Scan for billing features."""
|
|
context.cloud_extractor._scan_billing_features()
|
|
context.billing_features = {
|
|
k: v
|
|
for k, v in context.cloud_extractor.cloud_features.items()
|
|
if v.get("category") == "billing"
|
|
}
|
|
|
|
|
|
@when("I scan for telemetry features")
|
|
def step_scan_telemetry_features(context):
|
|
"""Scan for telemetry features."""
|
|
context.cloud_extractor._scan_telemetry_features()
|
|
context.telemetry_features = {
|
|
k: v
|
|
for k, v in context.cloud_extractor.cloud_features.items()
|
|
if v.get("category") == "telemetry"
|
|
}
|
|
|
|
|
|
@when("I scan for managed auth features")
|
|
def step_scan_auth_features(context):
|
|
"""Scan for managed authentication features."""
|
|
context.cloud_extractor._scan_auth_features()
|
|
context.auth_features = {
|
|
k: v
|
|
for k, v in context.cloud_extractor.cloud_features.items()
|
|
if v.get("category") == "managed_auth"
|
|
}
|
|
|
|
|
|
@when("I extract cloud features and generate strategies")
|
|
def step_extract_and_generate_strategies(context):
|
|
"""Extract features and generate replacement strategies."""
|
|
context.cloud_results = context.cloud_extractor.extract_all()
|
|
context.replacement_strategies = context.cloud_results["replacements"]
|
|
|
|
|
|
@when("I extract all cloud features")
|
|
def step_extract_all_cloud_features(context):
|
|
"""Extract all cloud features."""
|
|
context.cloud_results = context.cloud_extractor.extract_all()
|
|
|
|
|
|
@given("I have identified cloud features")
|
|
def step_have_cloud_features(context):
|
|
"""Ensure cloud features are identified."""
|
|
if not hasattr(context, "cloud_results"):
|
|
context.cloud_results = context.cloud_extractor.extract_all()
|
|
|
|
|
|
@when("I save the cloud features results")
|
|
def step_save_cloud_results(context):
|
|
"""Save cloud features results."""
|
|
output_dir = Path("build/test_output/cloud")
|
|
context.json_file, context.yaml_file = context.cloud_extractor.save_results(
|
|
output_dir
|
|
)
|
|
|
|
|
|
@then("I should identify features in all categories")
|
|
def step_check_cloud_categories(context):
|
|
"""Check that features are found in multiple categories."""
|
|
features = context.cloud_results["cloud_features"]
|
|
categories = set(f.get("category") for f in features.values())
|
|
assert len(categories) >= 5, f"Expected multiple categories, got {categories}"
|
|
|
|
|
|
@then("each feature should have an action specified")
|
|
def step_check_feature_actions(context):
|
|
"""Check that each feature has an action."""
|
|
features = context.cloud_results["cloud_features"]
|
|
for feat_id, feature in features.items():
|
|
assert "action" in feature, f"Missing action in {feat_id}"
|
|
assert feature["action"] in ["remove", "replace", "defer"], (
|
|
f"Invalid action in {feat_id}"
|
|
)
|
|
|
|
|
|
@then("each feature should have a priority assigned")
|
|
def step_check_feature_priorities(context):
|
|
"""Check that each feature has a priority."""
|
|
features = context.cloud_results["cloud_features"]
|
|
for feat_id, feature in features.items():
|
|
assert "priority" in feature, f"Missing priority in {feat_id}"
|
|
assert feature["priority"] in ["high", "medium", "low"], (
|
|
f"Invalid priority in {feat_id}"
|
|
)
|
|
|
|
|
|
@then("the statistics should include feature counts")
|
|
def step_check_cloud_statistics(context):
|
|
"""Check cloud feature statistics."""
|
|
stats = context.cloud_results["statistics"]
|
|
assert "total_features" in stats
|
|
assert stats["total_features"] > 0
|
|
assert "by_category" in stats
|
|
assert "by_action" in stats
|
|
assert "by_priority" in stats
|
|
|
|
|
|
@then("I should find {feature_id} feature")
|
|
def step_find_cloud_feature(context, feature_id):
|
|
"""Check that a specific feature exists."""
|
|
# Try to find the feature in the appropriate context attribute
|
|
if hasattr(context, "billing_features") and feature_id in context.billing_features:
|
|
return
|
|
if (
|
|
hasattr(context, "telemetry_features")
|
|
and feature_id in context.telemetry_features
|
|
):
|
|
return
|
|
if hasattr(context, "auth_features") and feature_id in context.auth_features:
|
|
return
|
|
|
|
# If not found in any specific category, check all features
|
|
if hasattr(context, "cloud_extractor"):
|
|
features = context.cloud_extractor.cloud_features
|
|
assert feature_id in features, f"Feature {feature_id} not found"
|
|
else:
|
|
raise AssertionError(f"Feature {feature_id} not found in any category")
|
|
|
|
|
|
@then("each billing feature should have replacement strategy")
|
|
def step_check_billing_replacements(context):
|
|
"""Check billing features have replacements."""
|
|
for feat_id, feature in context.billing_features.items():
|
|
assert "replacement" in feature, f"Missing replacement in {feat_id}"
|
|
|
|
|
|
@then("telemetry should default to opt-in local alternatives")
|
|
def step_check_telemetry_opt_in(context):
|
|
"""Check telemetry is opt-in."""
|
|
for feat_id, feature in context.telemetry_features.items():
|
|
if "replacement" in feature:
|
|
replacement = feature["replacement"].lower()
|
|
assert "opt-in" in replacement or "local" in replacement, (
|
|
f"Telemetry {feat_id} should be opt-in/local"
|
|
)
|
|
|
|
|
|
@then("auth features should have local replacements")
|
|
def step_check_auth_replacements(context):
|
|
"""Check auth features have local replacements."""
|
|
for feat_id, feature in context.auth_features.items():
|
|
assert "replacement" in feature, f"Missing replacement in {feat_id}"
|
|
assert "local" in feature["replacement"].lower(), (
|
|
f"Auth feature {feat_id} should have local replacement"
|
|
)
|
|
|
|
|
|
@then("features should be categorized by action")
|
|
def step_check_action_categories(context):
|
|
"""Check features are categorized by action."""
|
|
assert "remove" in context.replacement_strategies
|
|
assert "replace" in context.replacement_strategies
|
|
|
|
|
|
@then("remove features should be listed")
|
|
def step_check_remove_features(context):
|
|
"""Check remove features are listed."""
|
|
remove_list = context.replacement_strategies["remove"]
|
|
assert isinstance(remove_list, list)
|
|
# We should have at least some features to remove
|
|
assert len(remove_list) > 0
|
|
|
|
|
|
@then("replace features should have alternatives")
|
|
def step_check_replace_alternatives(context):
|
|
"""Check replace features have alternatives."""
|
|
replace_list = context.replacement_strategies["replace"]
|
|
for item in replace_list:
|
|
assert "replacement" in item
|
|
assert item["replacement"] != "None"
|
|
|
|
|
|
@then("strategies should be sorted by priority")
|
|
def step_check_strategy_sorting(context):
|
|
"""Check strategies are sorted by priority."""
|
|
for action_list in context.replacement_strategies.values():
|
|
if len(action_list) > 1:
|
|
priorities = {"high": 0, "medium": 1, "low": 2}
|
|
prev_priority = -1
|
|
for item in action_list:
|
|
curr_priority = priorities.get(item["priority"], 3)
|
|
assert curr_priority >= prev_priority, (
|
|
"Strategies not sorted by priority"
|
|
)
|
|
prev_priority = curr_priority
|
|
|
|
|
|
@then("a JSON file should be created with feature data")
|
|
def step_check_cloud_json_file(context):
|
|
"""Check JSON file creation."""
|
|
assert context.json_file.exists()
|
|
with open(context.json_file) as f:
|
|
data = json.load(f)
|
|
assert "cloud_features" in data
|
|
assert "replacements" in data
|
|
|
|
|
|
@then("a YAML file should be created with feature data")
|
|
def step_check_cloud_yaml_file(context):
|
|
"""Check YAML file creation."""
|
|
assert context.yaml_file.exists()
|
|
|
|
|
|
@then("a cloud features Markdown documentation should be generated")
|
|
def step_check_cloud_markdown_doc(context):
|
|
"""Check Markdown documentation."""
|
|
md_file = context.json_file.parent / "cloud_features.md"
|
|
assert md_file.exists(), f"Markdown file {md_file} does not exist"
|
|
content = md_file.read_text()
|
|
assert "# Cloud-Only Features Analysis" in content
|
|
|
|
|
|
@then("the documentation should include replacement strategies")
|
|
def step_check_cloud_doc_strategies(context):
|
|
"""Check documentation includes strategies."""
|
|
md_file = context.json_file.parent / "cloud_features.md"
|
|
assert md_file.exists()
|
|
content = md_file.read_text()
|
|
assert "Replacement Strategies" in content
|
|
|
|
|
|
@then("the statistics should include total features")
|
|
def step_check_total_features(context):
|
|
"""Check total features statistic."""
|
|
stats = context.cloud_results["statistics"]
|
|
assert stats["total_features"] > 0
|
|
|
|
|
|
@then("the statistics should count features by category")
|
|
def step_check_features_by_category(context):
|
|
"""Check features by category statistic."""
|
|
stats = context.cloud_results["statistics"]
|
|
assert len(stats["by_category"]) > 0
|
|
|
|
|
|
@then("the statistics should count features by action")
|
|
def step_check_features_by_action(context):
|
|
"""Check features by action statistic."""
|
|
stats = context.cloud_results["statistics"]
|
|
assert stats["by_action"]["remove"] >= 0
|
|
assert stats["by_action"]["replace"] >= 0
|
|
|
|
|
|
@then("the statistics should count features by priority")
|
|
def step_check_features_by_priority(context):
|
|
"""Check features by priority statistic."""
|
|
stats = context.cloud_results["statistics"]
|
|
assert stats["by_priority"]["high"] >= 0
|
|
assert stats["by_priority"]["medium"] >= 0
|
|
assert stats["by_priority"]["low"] >= 0
|
|
|
|
|
|
@then("the statistics should count affected Go files")
|
|
def step_check_affected_files(context):
|
|
"""Check affected Go files statistic."""
|
|
stats = context.cloud_results["statistics"]
|
|
assert "go_files_affected" in stats
|
|
assert stats["go_files_affected"] > 0
|