require "test_helper" class WafPolicyTest < ActiveSupport::TestCase setup do @user = users(:jason) @policy = WafPolicy.new( name: "Block Malicious IPs", policy_type: "country", targets: ["BR", "CN"], policy_action: "deny", user: @user ) end # Validations test "should be valid with all required attributes" do assert @policy.valid? end test "should not be valid without name" do @policy.name = nil assert_not @policy.valid? assert_includes @policy.errors[:name], "can't be blank" end test "should not be valid without unique name" do @policy.name = waf_policies(:one).name assert_not @policy.valid? assert_includes @policy.errors[:name], "has already been taken" end test "should validate policy_type inclusion" do @policy.policy_type = "invalid_type" assert_not @policy.valid? assert_includes @policy.errors[:policy_type], "is not included in the list" end test "should validate policy_action inclusion" do @policy.policy_action = "invalid_action" assert_not @policy.valid? assert_includes @policy.errors[:policy_action], "is not included in the list" end test "should not be valid without targets" do @policy.targets = [] assert_not @policy.valid? assert_includes @policy.errors[:targets], "can't be blank" end test "should validate targets is an array" do @policy.targets = "not an array" assert_not @policy.valid? assert_includes @policy.errors[:targets], "must be an array" end test "should validate country targets format" do @policy.policy_type = "country" # Valid country codes @policy.targets = ["US", "BR", "CN"] assert @policy.valid? # Invalid country codes @policy.targets = ["USA", "123", "B"] assert_not @policy.valid? assert_includes @policy.errors[:targets], "must be valid ISO country codes" end test "should validate ASN targets format" do @policy.policy_type = "asn" # Valid ASNs @policy.targets = [12345, 67890] assert @policy.valid? # Invalid ASNs @policy.targets = ["AS12345", -1, 0] assert_not @policy.valid? assert_includes @policy.errors[:targets], "must be valid ASNs" end test "should validate company targets format" do @policy.policy_type = "company" # Valid company names @policy.targets = ["Google", "Amazon Web Services", "Microsoft"] assert @policy.valid? # Invalid company names @policy.targets = ["", nil, " "] assert_not @policy.valid? assert_includes @policy.errors[:targets], "must be valid company names" end test "should validate network_type targets format" do @policy.policy_type = "network_type" # Valid network types @policy.targets = ["datacenter", "proxy", "vpn", "standard"] assert @policy.valid? # Invalid network types @policy.targets = ["invalid", "malicious", "botnet"] assert_not @policy.valid? assert_includes @policy.errors[:targets], "must be one of: datacenter, proxy, vpn, standard" end test "should validate redirect configuration" do @policy.policy_action = "redirect" # Valid redirect config @policy.additional_data = { "redirect_url" => "https://example.com/blocked" } assert @policy.valid? # Missing redirect URL @policy.additional_data = { "other_config" => "value" } assert_not @policy.valid? assert_includes @policy.errors[:additional_data], "must include 'redirect_url' for redirect action" end test "should validate challenge configuration" do @policy.policy_action = "challenge" # Valid challenge types @policy.additional_data = { "challenge_type" => "captcha" } assert @policy.valid? @policy.additional_data = { "challenge_type" => "javascript" } assert @policy.valid? # Invalid challenge type @policy.additional_data = { "challenge_type" => "invalid" } assert_not @policy.valid? assert_includes @policy.errors[:additional_data], "challenge_type must be one of: captcha, javascript, proof_of_work" # No challenge type (should be valid, uses defaults) @policy.additional_data = {} assert @policy.valid? end # Defaults and Callbacks test "should default to enabled" do @policy.enabled = nil @policy.save! assert @policy.enabled? end test "should default targets to empty array" do policy = WafPolicy.new( name: "Test Policy", policy_type: "country", policy_action: "deny", user: @user ) # before_validation should set defaults policy.valid? assert_equal [], policy.targets end test "should default additional_data to empty hash" do policy = WafPolicy.new( name: "Test Policy", policy_type: "country", targets: ["US"], policy_action: "deny", user: @user ) policy.valid? assert_equal({}, policy.additional_data) end # Policy Type Methods test "policy type predicate methods work correctly" do country_policy = WafPolicy.new(policy_type: "country") assert country_policy.country_policy? assert_not country_policy.asn_policy? assert_not country_policy.company_policy? assert_not country_policy.network_type_policy? asn_policy = WafPolicy.new(policy_type: "asn") assert_not asn_policy.country_policy? assert asn_policy.asn_policy? assert_not asn_policy.company_policy? assert_not asn_policy.network_type_policy? company_policy = WafPolicy.new(policy_type: "company") assert_not company_policy.country_policy? assert_not company_policy.asn_policy? assert company_policy.company_policy? assert_not company_policy.network_type_policy? network_type_policy = WafPolicy.new(policy_type: "network_type") assert_not network_type_policy.country_policy? assert_not network_type_policy.asn_policy? assert_not network_type_policy.company_policy? assert network_type_policy.network_type_policy? end # Action Methods test "action predicate methods work correctly" do allow_policy = WafPolicy.new(policy_action: "allow") assert allow_policy.allow_action? assert_not allow_policy.deny_action? assert_not allow_policy.redirect_action? assert_not allow_policy.challenge_action? deny_policy = WafPolicy.new(policy_action: "deny") assert_not deny_policy.allow_action? assert deny_policy.deny_action? assert_not deny_policy.redirect_action? assert_not deny_policy.challenge_action? redirect_policy = WafPolicy.new(policy_action: "redirect") assert_not redirect_policy.allow_action? assert_not redirect_policy.deny_action? assert redirect_policy.redirect_action? assert_not redirect_policy.challenge_action? challenge_policy = WafPolicy.new(policy_action: "challenge") assert_not challenge_policy.allow_action? assert_not challenge_policy.deny_action? assert_not challenge_policy.redirect_action? assert challenge_policy.challenge_action? end # Policy action methods (to avoid Rails conflicts) test "policy action predicate methods work correctly" do policy = WafPolicy.new(policy_action: "deny") assert policy.deny_policy_action? assert_not policy.allow_policy_action? assert_not policy.redirect_policy_action? assert_not policy.challenge_policy_action? end # Lifecycle Methods test "active? works correctly" do # Active policy active_policy = WafPolicy.new(enabled: true, expires_at: nil) assert active_policy.active? # Enabled but expired expired_policy = WafPolicy.new(enabled: true, expires_at: 1.day.ago) assert_not expired_policy.active? # Disabled with future expiration disabled_policy = WafPolicy.new(enabled: false, expires_at: 1.day.from_now) assert_not disabled_policy.active? # Disabled with no expiration disabled_no_exp = WafPolicy.new(enabled: false, expires_at: nil) assert_not disabled_no_exp.active? # Enabled with future expiration future_exp = WafPolicy.new(enabled: true, expires_at: 1.day.from_now) assert future_exp.active? end test "expired? works correctly" do assert_not WafPolicy.new(expires_at: nil).expired? assert_not WafPolicy.new(expires_at: 1.day.from_now).expired? assert WafPolicy.new(expires_at: 1.day.ago).expired? assert WafPolicy.new(expires_at: Time.current).expired? end test "activate! enables policy" do @policy.enabled = false @policy.save! @policy.activate! assert @policy.reload.enabled? end test "deactivate! disables policy" do @policy.enabled = true @policy.save! @policy.deactivate! assert_not @policy.reload.enabled? end test "expire! sets expiration to now" do @policy.expire! assert @policy.reload.expires_at <= Time.current end # Scopes test "enabled scope returns only enabled policies" do enabled_policy = WafPolicy.create!( name: "Enabled Policy", policy_type: "country", targets: ["US"], policy_action: "deny", user: @user, enabled: true ) disabled_policy = WafPolicy.create!( name: "Disabled Policy", policy_type: "country", targets: ["US"], policy_action: "deny", user: @user, enabled: false ) enabled_policies = WafPolicy.enabled assert_includes enabled_policies, enabled_policy assert_not_includes enabled_policies, disabled_policy end test "active scope returns only active policies" do active_policy = WafPolicy.create!( name: "Active Policy", policy_type: "country", targets: ["US"], policy_action: "deny", user: @user, enabled: true, expires_at: 1.day.from_now ) expired_policy = WafPolicy.create!( name: "Expired Policy", policy_type: "country", targets: ["US"], policy_action: "deny", user: @user, enabled: true, expires_at: 1.day.ago ) disabled_policy = WafPolicy.create!( name: "Disabled Policy", policy_type: "country", targets: ["US"], policy_action: "deny", user: @user, enabled: false ) active_policies = WafPolicy.active assert_includes active_policies, active_policy assert_not_includes active_policies, expired_policy assert_not_includes active_policies, disabled_policy end # Class Factory Methods test "create_country_policy works correctly" do policy = WafPolicy.create_country_policy( ["US", "CA"], policy_action: "deny", user: @user, name: "Custom Name" ) assert policy.persisted? assert_equal "Custom Name", policy.name assert_equal "country", policy.policy_type assert_equal "deny", policy.policy_action assert_equal ["US", "CA"], policy.targets assert_equal @user, policy.user end test "create_asn_policy works correctly" do policy = WafPolicy.create_asn_policy( [12345, 67890], policy_action: "challenge", user: @user ) assert policy.persisted? assert_equal "challenge ASNs 12345, 67890", policy.name assert_equal "asn", policy.policy_type assert_equal "challenge", policy.policy_action assert_equal [12345, 67890], policy.targets end test "create_company_policy works correctly" do policy = WafPolicy.create_company_policy( ["Google", "Amazon"], policy_action: "deny", user: @user ) assert policy.persisted? assert_equal "deny Google, Amazon", policy.name assert_equal "company", policy.policy_type assert_equal ["Google", "Amazon"], policy.targets end test "create_network_type_policy works correctly" do policy = WafPolicy.create_network_type_policy( ["datacenter", "proxy"], policy_action: "redirect", user: @user, additional_data: { redirect_url: "https://example.com/blocked" } ) assert policy.persisted? assert_equal "redirect datacenter, proxy", policy.name assert_equal "network_type", policy.policy_type assert_equal ["datacenter", "proxy"], policy.targets end # Redirect/Challenge Specific Methods test "redirect_url and redirect_status methods work" do policy = WafPolicy.new( policy_action: "redirect", additional_data: { "redirect_url" => "https://example.com/blocked", "redirect_status" => 301 } ) assert_equal "https://example.com/blocked", policy.redirect_url assert_equal 301, policy.redirect_status # Default status policy.additional_data = { "redirect_url" => "https://example.com/blocked" } assert_equal 302, policy.redirect_status end test "challenge_type and challenge_message methods work" do policy = WafPolicy.new( policy_action: "challenge", additional_data: { "challenge_type" => "javascript", "challenge_message" => "Please verify you are human" } ) assert_equal "javascript", policy.challenge_type assert_equal "Please verify you are human", policy.challenge_message # Default challenge type policy.additional_data = {} assert_equal "captcha", policy.challenge_type end # Statistics test "generated_rules_count works" do @policy.save! # Initially no rules assert_equal 0, @policy.generated_rules_count # Create some rules network_range = NetworkRange.create!(ip_range: "192.168.1.0/24") @policy.create_rule_for_network_range(network_range) assert_equal 1, @policy.generated_rules_count end test "effectiveness_stats returns correct data" do @policy.save! stats = @policy.effectiveness_stats assert_equal 0, stats[:total_rules_generated] assert_equal 0, stats[:active_rules] assert_equal 0, stats[:rules_last_7_days] assert_equal "country", stats[:policy_type] assert_equal "deny", stats[:policy_action] assert_equal 2, stats[:targets_count] end # String representations test "to_s returns name" do assert_equal @policy.name, @policy.to_s end test "to_param parameterizes name" do @policy.name = "Block Brazil & China" expected = "block-brazil-china" assert_equal expected, @policy.to_param end end