369 lines
11 KiB
Ruby
369 lines
11 KiB
Ruby
|
|
# frozen_string_literal: true
|
||
|
|
|
||
|
|
require_relative 'test_helper'
|
||
|
|
|
||
|
|
# ─── Enable ───────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
class TestEnable < Minitest::Test
|
||
|
|
include TestHelpers
|
||
|
|
|
||
|
|
def setup
|
||
|
|
setup_temp_dirs
|
||
|
|
end
|
||
|
|
|
||
|
|
def teardown
|
||
|
|
teardown_temp_dirs
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_enable_new_plugin_creates_file_and_adds_entry
|
||
|
|
op = make_operation(PluginConfig::Operations::Enable)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_includes %w[created_and_enabled enabled], result[:status]
|
||
|
|
assert_equal 'test-plugin@test-marketplace', result[:plugin]
|
||
|
|
assert result[:verified], 'Expected verified to be true'
|
||
|
|
assert_includes result[:enabled_plugins], 'test-plugin@test-marketplace'
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_enable_adds_to_existing_settings
|
||
|
|
create_settings('other-plugin@other-marketplace' => true)
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Enable)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'enabled', result[:status]
|
||
|
|
assert_includes result[:enabled_plugins], 'other-plugin@other-marketplace'
|
||
|
|
assert_includes result[:enabled_plugins], 'test-plugin@test-marketplace'
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_enable_already_enabled_returns_already_enabled
|
||
|
|
create_settings('test-plugin@test-marketplace' => true)
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Enable)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'already_enabled', result[:status]
|
||
|
|
assert result[:verified]
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_enabled_plugins_sorted_alphabetically
|
||
|
|
create_settings('z-plugin@z-marketplace' => true, 'a-plugin@a-marketplace' => true)
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Enable)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
expected = ['a-plugin@a-marketplace', 'test-plugin@test-marketplace', 'z-plugin@z-marketplace']
|
||
|
|
assert_equal expected, result[:enabled_plugins]
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_verified_flag_is_true_on_success
|
||
|
|
op = make_operation(PluginConfig::Operations::Enable)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert result[:verified]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
# ─── Disable ──────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
class TestDisable < Minitest::Test
|
||
|
|
include TestHelpers
|
||
|
|
|
||
|
|
def setup
|
||
|
|
setup_temp_dirs
|
||
|
|
end
|
||
|
|
|
||
|
|
def teardown
|
||
|
|
teardown_temp_dirs
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_disable_existing_plugin_removes_entry
|
||
|
|
create_settings('test-plugin@test-marketplace' => true)
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Disable)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'disabled', result[:status]
|
||
|
|
refute_includes result[:remaining_plugins], 'test-plugin@test-marketplace'
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_disable_nonexistent_plugin_returns_not_found
|
||
|
|
create_settings({})
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Disable)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'not_found', result[:status]
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_disable_preserves_other_plugins
|
||
|
|
create_settings(
|
||
|
|
'test-plugin@test-marketplace' => true,
|
||
|
|
'keep-me@other' => true
|
||
|
|
)
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Disable)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'disabled', result[:status]
|
||
|
|
assert_includes result[:remaining_plugins], 'keep-me@other'
|
||
|
|
refute_includes result[:remaining_plugins], 'test-plugin@test-marketplace'
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_verified_flag_confirms_key_absent
|
||
|
|
create_settings('test-plugin@test-marketplace' => true)
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Disable)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert result[:verified]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
# ─── Register ─────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
class TestRegister < Minitest::Test
|
||
|
|
include TestHelpers
|
||
|
|
|
||
|
|
def setup
|
||
|
|
setup_temp_dirs
|
||
|
|
end
|
||
|
|
|
||
|
|
def teardown
|
||
|
|
teardown_temp_dirs
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_register_new_plugin_adds_to_marketplace
|
||
|
|
create_marketplace(plugins: [])
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Register, description: 'A test plugin')
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'registered', result[:status]
|
||
|
|
assert result[:verified]
|
||
|
|
|
||
|
|
data = JSON.parse(File.read(marketplace_path))
|
||
|
|
names = data['plugins'].map { |p| p['name'] }
|
||
|
|
assert_includes names, 'test-plugin'
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_register_already_present_returns_already_registered
|
||
|
|
create_marketplace(plugins: [{ 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }])
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Register)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'already_registered', result[:status]
|
||
|
|
assert result[:verified]
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_plugins_array_sorted_by_name
|
||
|
|
create_marketplace(plugins: [{ 'name' => 'z-plugin', 'source' => './z-plugin', 'description' => '' }])
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Register, plugin: 'a-plugin')
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
data = JSON.parse(File.read(marketplace_path))
|
||
|
|
names = data['plugins'].map { |p| p['name'] }
|
||
|
|
assert_equal %w[a-plugin z-plugin], names
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_description_is_stored_correctly
|
||
|
|
create_marketplace(plugins: [])
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Register, description: 'My description')
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
data = JSON.parse(File.read(marketplace_path))
|
||
|
|
plugin_entry = data['plugins'].find { |p| p['name'] == 'test-plugin' }
|
||
|
|
assert_equal 'My description', plugin_entry['description']
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
# ─── Unregister ───────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
class TestUnregister < Minitest::Test
|
||
|
|
include TestHelpers
|
||
|
|
|
||
|
|
def setup
|
||
|
|
setup_temp_dirs
|
||
|
|
end
|
||
|
|
|
||
|
|
def teardown
|
||
|
|
teardown_temp_dirs
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_unregister_existing_plugin
|
||
|
|
create_marketplace(plugins: [{ 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }])
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Unregister)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'unregistered', result[:status]
|
||
|
|
assert result[:verified]
|
||
|
|
|
||
|
|
data = JSON.parse(File.read(marketplace_path))
|
||
|
|
names = data['plugins'].map { |p| p['name'] }
|
||
|
|
refute_includes names, 'test-plugin'
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_unregister_nonexistent_returns_not_found
|
||
|
|
create_marketplace(plugins: [])
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Unregister)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'not_found', result[:status]
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_unregister_preserves_other_plugins
|
||
|
|
create_marketplace(plugins: [
|
||
|
|
{ 'name' => 'keep-me', 'source' => './keep-me', 'description' => '' },
|
||
|
|
{ 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }
|
||
|
|
])
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::Unregister)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
data = JSON.parse(File.read(marketplace_path))
|
||
|
|
names = data['plugins'].map { |p| p['name'] }
|
||
|
|
assert_includes names, 'keep-me'
|
||
|
|
refute_includes names, 'test-plugin'
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
# ─── Audit ────────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
class TestAudit < Minitest::Test
|
||
|
|
include TestHelpers
|
||
|
|
|
||
|
|
def setup
|
||
|
|
setup_temp_dirs
|
||
|
|
# Create installed_plugins in temp location; override the path
|
||
|
|
@installed_path = File.join(@tmpdir, 'installed_plugins.json')
|
||
|
|
end
|
||
|
|
|
||
|
|
def teardown
|
||
|
|
teardown_temp_dirs
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_clean_state_returns_ok
|
||
|
|
# Create all required files with correct entries
|
||
|
|
create_marketplace(plugins: [{ 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }])
|
||
|
|
create_settings('test-plugin@test-marketplace' => true)
|
||
|
|
|
||
|
|
# Need to stub installed_plugins_path - create a subclass
|
||
|
|
op = make_audit_op_with_installed({ 'test-plugin@test-marketplace' => { 'status' => 'enabled' } })
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'ok', result[:status]
|
||
|
|
assert_empty result[:issues]
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_missing_marketplace_entry_reports_issue_with_fix
|
||
|
|
create_marketplace(plugins: []) # plugin not registered
|
||
|
|
create_settings('test-plugin@test-marketplace' => true)
|
||
|
|
|
||
|
|
op = make_audit_op_with_installed({ 'test-plugin@test-marketplace' => { 'status' => 'enabled' } })
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'issues_found', result[:status]
|
||
|
|
marketplace_check = result[:checks][:marketplace]
|
||
|
|
assert_equal 'issue', marketplace_check[:status]
|
||
|
|
assert marketplace_check[:fix]
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_missing_settings_entry_reports_issue_with_fix
|
||
|
|
create_marketplace(plugins: [{ 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }])
|
||
|
|
create_settings({}) # plugin not enabled
|
||
|
|
|
||
|
|
op = make_audit_op_with_installed({ 'test-plugin@test-marketplace' => { 'status' => 'enabled' } })
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'issues_found', result[:status]
|
||
|
|
settings_check = result[:checks][:settings]
|
||
|
|
assert_equal 'issue', settings_check[:status]
|
||
|
|
assert settings_check[:fix]
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_multiple_issues_all_reported
|
||
|
|
create_marketplace(plugins: []) # not registered
|
||
|
|
create_settings({}) # not enabled
|
||
|
|
|
||
|
|
op = make_audit_op_with_installed({}) # not installed
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'issues_found', result[:status]
|
||
|
|
assert result[:issues].length >= 2, "Expected at least 2 issues, got #{result[:issues].length}"
|
||
|
|
end
|
||
|
|
|
||
|
|
private
|
||
|
|
|
||
|
|
# Create an Audit subclass that overrides installed_plugins_path to use temp dir
|
||
|
|
def make_audit_op_with_installed(installed_plugins)
|
||
|
|
installed_path = @installed_path
|
||
|
|
create_installed_plugins(installed_path, installed_plugins)
|
||
|
|
|
||
|
|
params = {
|
||
|
|
plugin: 'test-plugin',
|
||
|
|
marketplace: 'test-marketplace',
|
||
|
|
project: @project_dir,
|
||
|
|
marketplace_file: marketplace_path
|
||
|
|
}
|
||
|
|
|
||
|
|
op = PluginConfig::Operations::Audit.new(params)
|
||
|
|
# Override the installed_plugins_path method
|
||
|
|
op.define_singleton_method(:installed_plugins_path) { installed_path }
|
||
|
|
op
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
# ─── List ─────────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
class TestList < Minitest::Test
|
||
|
|
include TestHelpers
|
||
|
|
|
||
|
|
def setup
|
||
|
|
setup_temp_dirs
|
||
|
|
end
|
||
|
|
|
||
|
|
def teardown
|
||
|
|
teardown_temp_dirs
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_list_returns_all_enabled_plugins
|
||
|
|
create_settings(
|
||
|
|
'b-plugin@marketplace' => true,
|
||
|
|
'a-plugin@marketplace' => true
|
||
|
|
)
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::List)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'ok', result[:status]
|
||
|
|
assert_equal %w[a-plugin@marketplace b-plugin@marketplace], result[:enabled_plugins]
|
||
|
|
assert_equal 2, result[:count]
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_list_empty_settings_returns_empty_array
|
||
|
|
create_settings({})
|
||
|
|
|
||
|
|
op = make_operation(PluginConfig::Operations::List)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'ok', result[:status]
|
||
|
|
assert_empty result[:enabled_plugins]
|
||
|
|
assert_equal 0, result[:count]
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_list_missing_file_returns_empty_array
|
||
|
|
# Don't create settings file
|
||
|
|
op = make_operation(PluginConfig::Operations::List)
|
||
|
|
result = op.call
|
||
|
|
|
||
|
|
assert_equal 'ok', result[:status]
|
||
|
|
assert_empty result[:enabled_plugins]
|
||
|
|
assert_equal 0, result[:count]
|
||
|
|
end
|
||
|
|
end
|