1#!/usr/bin/perl -T 2 3use lib '.'; use lib 't'; 4use SATest; sa_t_init("mkrules"); 5use Test::More tests => 97; 6use File::Copy; 7use File::Path; 8 9# --------------------------------------------------------------------------- 10print " script runs, even with nothing to do\n\n"; 11 12my $tdir = "$workdir/mkrules_t"; 13 14mkpath ([$tdir, "$tdir/rulesrc", "$tdir/rules"]); 15 16write_file("$tdir/MANIFEST", [ ]); 17write_file("$tdir/MANIFEST.SKIP", [ "foo2\n" ]); 18write_file("$tdir/rules/active.list", [ "" ]); 19 20ok (mkrun ("--src $tdir/rulesrc --out $tdir/rules --manifest $tdir/MANIFEST --manifestskip $tdir/MANIFEST.SKIP --active $tdir/rules/active.list", \&patterns_run_cb)); 21ok ok_all_patterns(); 22save_tdir(); 23 24# --------------------------------------------------------------------------- 25print " promotion of an active rule\n\n"; 26 27%patterns = ( 28 '72_active.cf: WARNING: not listed in manifest file' => manif_found, 29 "body GOOD /foo/" => rule_line_1, 30 "describe GOOD desc_found" => rule_line_2, 31); 32%anti_patterns = ( 33 "describe T_GOOD desc_found" => rule_line_2, 34); 35 36mkpath ([ "$tdir/rulesrc/sandbox/foo", "$tdir/rules" ]); 37 38write_file("$tdir/MANIFEST", [ ]); 39write_file("$tdir/MANIFEST.SKIP", [ "foo2\n" ]); 40write_file("$tdir/rules/active.list", [ "GOOD\n" ]); 41write_file("$tdir/rulesrc/sandbox/foo/20_foo.cf", [ 42 "body GOOD /foo/\n", 43 "describe GOOD desc_found\n" 44]); 45 46ok (mkrun ("--src $tdir/rulesrc --out $tdir/rules --manifest $tdir/MANIFEST --manifestskip $tdir/MANIFEST.SKIP --active $tdir/rules/active.list 2>&1", \&patterns_run_cb)); 47checkfile("$tdir/rules/72_active.cf", \&patterns_run_cb); 48checkfile("$tdir/rules/70_sandbox.cf", \&patterns_run_cb); 49ok ok_all_patterns(); 50save_tdir(); 51 52# --------------------------------------------------------------------------- 53print " non-promotion of an inactive rule\n\n"; 54 55%patterns = ( 56 '70_sandbox.cf: WARNING: not listed in manifest file' => manif_found, 57 "body T_GOOD /foo/" => rule_line_1, 58 "describe T_GOOD desc_found" => rule_line_2, 59); 60%anti_patterns = ( 61 "describe GOOD desc_found" => rule_line_2, 62); 63 64mkpath ([ "$tdir/rulesrc/sandbox/foo", "$tdir/rules" ]); 65 66write_file("$tdir/MANIFEST", [ ]); 67write_file("$tdir/MANIFEST.SKIP", [ "foo2\n" ]); 68write_file("$tdir/rules/active.list", [ "NOT_GOOD\n" ]); 69write_file("$tdir/rulesrc/sandbox/foo/20_foo.cf", [ 70 "body GOOD /foo/\n", 71 "describe GOOD desc_found\n" 72]); 73 74ok (mkrun ("--src $tdir/rulesrc --out $tdir/rules --manifest $tdir/MANIFEST --manifestskip $tdir/MANIFEST.SKIP --active $tdir/rules/active.list 2>&1", \&patterns_run_cb)); 75checkfile("$tdir/rules/72_active.cf", \&patterns_run_cb); 76checkfile("$tdir/rules/70_sandbox.cf", \&patterns_run_cb); 77ok ok_all_patterns(); 78save_tdir(); 79 80# --------------------------------------------------------------------------- 81print " non-promotion of an inactive rule with score set\n\n"; 82 83%patterns = ( 84 '70_sandbox.cf: WARNING: not listed in manifest file' => manif_found, 85 "body T_GOOD /foo/" => rule_line_1, 86 "describe T_GOOD desc_found" => rule_line_2, 87 "#score T_GOOD 4.0" => score_good, 88); 89%anti_patterns = ( 90 "describe GOOD desc_found" => rule_line_2, 91 "score GOOD 4.0" => 'score', 92); 93 94mkpath ([ "$tdir/rulesrc/sandbox/foo", "$tdir/rules" ]); 95 96write_file("$tdir/MANIFEST", [ ]); 97write_file("$tdir/MANIFEST.SKIP", [ "foo2\n" ]); 98write_file("$tdir/rules/active.list", [ "NOT_GOOD\n" ]); 99write_file("$tdir/rulesrc/sandbox/foo/20_foo.cf", [ 100 "body GOOD /foo/\n", 101 "score GOOD 4.0\n", 102 "describe GOOD desc_found\n" 103]); 104 105ok (mkrun ("--src $tdir/rulesrc --out $tdir/rules --manifest $tdir/MANIFEST --manifestskip $tdir/MANIFEST.SKIP --active $tdir/rules/active.list 2>&1", \&patterns_run_cb)); 106checkfile("$tdir/rules/72_active.cf", \&patterns_run_cb); 107checkfile("$tdir/rules/70_sandbox.cf", \&patterns_run_cb); 108ok ok_all_patterns(); 109save_tdir(); 110 111# --------------------------------------------------------------------------- 112print " non-promotion of a broken rule\n\n"; 113 114%patterns = ( 115 '70_sandbox.cf: WARNING: not listed in manifest file' => manif_found, 116 'LINT FAILED' => lint_failed, 117); 118%anti_patterns = ( 119 "body GOOD" => rule_line_1, 120 "describe GOOD desc_found" => rule_line_2, 121); 122 123mkpath ([ "$tdir/rulesrc/sandbox/foo", "$tdir/rules" ]); 124 125write_file("$tdir/MANIFEST", [ ]); 126write_file("$tdir/MANIFEST.SKIP", [ "foo2\n" ]); 127write_file("$tdir/rules/active.list", [ "GOOD\n" ]); 128write_file("$tdir/rulesrc/sandbox/foo/20_foo.cf", [ 129 "body GOOD /***\n", 130 "describe GOOD desc_found\n" 131]); 132 133ok (mkrun ("--src $tdir/rulesrc --out $tdir/rules --manifest $tdir/MANIFEST --manifestskip $tdir/MANIFEST.SKIP --active $tdir/rules/active.list 2>&1", \&patterns_run_cb)); 134checkfile("$tdir/rules/70_sandbox.cf", \&patterns_run_cb); 135ok (-f "$tdir/rules/72_active.cf"); 136ok (-s "$tdir/rules/72_active.cf" == 0); 137ok ok_all_patterns(); 138save_tdir(); 139 140# --------------------------------------------------------------------------- 141print " promotion of an active meta rule\n\n"; 142 143%patterns = ( 144 '70_sandbox.cf: WARNING: not listed in manifest file' => manif_found, 145 '20_foo.cf: 1 active rules, 1 other' => 'foundrule', 146 "body __GOOD /foo/" => rule_line_1, 147 "meta GOOD (__GOOD)" => rule_line_1a, 148 "describe GOOD desc_found" => rule_line_2, 149); 150%anti_patterns = ( 151 "describe T_GOOD desc_found" => rule_line_2, 152); 153 154mkpath ([ "$tdir/rulesrc/sandbox/foo", "$tdir/rules" ]); 155 156write_file("$tdir/MANIFEST", [ ]); 157write_file("$tdir/MANIFEST.SKIP", [ "foo2\n" ]); 158write_file("$tdir/rules/active.list", [ "GOOD\n" ]); 159write_file("$tdir/rulesrc/sandbox/foo/20_foo.cf", [ 160 "body __GOOD /foo/\n", 161 "meta GOOD (__GOOD)\n", 162 "describe GOOD desc_found\n" 163]); 164 165ok (mkrun ("--src $tdir/rulesrc --out $tdir/rules --manifest $tdir/MANIFEST --manifestskip $tdir/MANIFEST.SKIP --active $tdir/rules/active.list 2>&1", \&patterns_run_cb)); 166checkfile("$tdir/rules/72_active.cf", \&patterns_run_cb); 167checkfile("$tdir/rules/70_sandbox.cf", \&patterns_run_cb); 168ok ok_all_patterns(); 169save_tdir(); 170 171# --------------------------------------------------------------------------- 172print " inactive meta rule\n\n"; 173 174%patterns = ( 175 '70_sandbox.cf: WARNING: not listed in manifest file' => manif_found, 176 '20_foo.cf: 0 active rules, 2 other' => 'foundrule', 177 "body __GOOD /foo/" => rule_line_1, 178 "meta T_GOOD (__GOOD)" => rule_line_1a, 179 "describe T_GOOD desc_found" => rule_line_2, 180); 181%anti_patterns = ( 182 "describe GOOD desc_found" => rule_line_2, 183); 184 185mkpath ([ "$tdir/rulesrc/sandbox/foo", "$tdir/rules" ]); 186 187write_file("$tdir/MANIFEST", [ ]); 188write_file("$tdir/MANIFEST.SKIP", [ "foo2\n" ]); 189write_file("$tdir/rules/active.list", [ "NOT_GOOD\n" ]); 190write_file("$tdir/rulesrc/sandbox/foo/20_foo.cf", [ 191 "body __GOOD /foo/\n", 192 "meta GOOD (__GOOD)\n", 193 "describe GOOD desc_found\n" 194]); 195 196ok (mkrun ("--src $tdir/rulesrc --out $tdir/rules --manifest $tdir/MANIFEST --manifestskip $tdir/MANIFEST.SKIP --active $tdir/rules/active.list 2>&1", \&patterns_run_cb)); 197checkfile("$tdir/rules/72_active.cf", \&patterns_run_cb); 198checkfile("$tdir/rules/70_sandbox.cf", \&patterns_run_cb); 199ok ok_all_patterns(); 200save_tdir(); 201 202# --------------------------------------------------------------------------- 203print " active plugin in sandbox\n\n"; 204 205%patterns = ( 206 '70_sandbox.cf: WARNING: not listed in manifest file' => manif_found, 207 "loadplugin Good plugin.pm" => loadplugin_found, 208 "body GOOD eval:check_foo()" => rule_line_1, 209 "describe GOOD desc_found" => rule_line_2, 210 "ifplugin Good" => if1, 211 "endif" => endif_found, 212); 213%anti_patterns = ( 214 "describe T_GOOD desc_found" => rule_line_2, 215); 216 217mkpath ([ "$tdir/rulesrc/sandbox/foo", "$tdir/rules" ]); 218 219write_file("$tdir/MANIFEST", [ "rulesrc/sandbox/foo/20_foo.cf\n", "rulesrc/sandbox/foo/plugin.pm\n" ]); 220write_file("$tdir/MANIFEST.SKIP", [ "foo2\n" ]); 221write_file("$tdir/rules/active.list", [ "GOOD\n" ]); 222write_file("$tdir/rulesrc/sandbox/foo/20_foo.cf", [ 223 "loadplugin Good plugin.pm\n", 224 "ifplugin Good\n", 225 "body GOOD eval:check_foo()\n", 226 "describe GOOD desc_found\n", 227 "endif\n", 228]); 229write_file("$tdir/rulesrc/sandbox/foo/plugin.pm", [ 230 'package Good;', 231 'use Mail::SpamAssassin::Plugin; our @ISA = qw(Mail::SpamAssassin::Plugin);', 232 'sub new { my ($class, $m) = @_; $class = ref($class) || $class;', 233 'my $self = bless $class->SUPER::new($m), $class;', 234 '$self->register_eval_rule("check_foo"); return $self; }', 235 'sub check_foo { my ($self, $pms) = @_; return 1; }', 236]); 237 238ok (mkrun ("--src $tdir/rulesrc --out $tdir/rules --manifest $tdir/MANIFEST --manifestskip $tdir/MANIFEST.SKIP --active $tdir/rules/active.list 2>&1", \&patterns_run_cb)); 239# checkfile("$tdir/rules/72_active.cf", \&patterns_run_cb); 240checkfile("$tdir/rules/70_sandbox.cf", \&patterns_run_cb); 241ok (-f "$tdir/rules/plugin.pm"); 242ok ok_all_patterns(); 243save_tdir(); 244 245# --------------------------------------------------------------------------- 246print " inactive plugin\n\n"; 247 248%patterns = ( 249 '70_sandbox.cf: WARNING: not listed in manifest file' => manif_found, 250 # "WARNING: GOOD: renamed as T_GOOD due to missing T_ prefix" => warning_seen, 251 "loadplugin Good plugin.pm" => loadplugin_found, 252 "body T_GOOD eval:check_foo()" => rule_line_1, 253 "describe T_GOOD desc_found" => rule_line_2, 254 "ifplugin Good" => if1, 255 "endif" => endif_found, 256); 257%anti_patterns = ( 258 "describe GOOD desc_found" => rule_line_2, 259); 260 261mkpath ([ "$tdir/rulesrc/sandbox/foo", "$tdir/rules" ]); 262 263write_file("$tdir/MANIFEST", [ "rulesrc/sandbox/foo/20_foo.cf\n", "rulesrc/sandbox/foo/plugin.pm\n" ]); 264write_file("$tdir/MANIFEST.SKIP", [ "foo2\n" ]); 265write_file("$tdir/rules/active.list", [ "NOT_GOOD\n" ]); 266write_file("$tdir/rulesrc/sandbox/foo/20_foo.cf", [ 267 "loadplugin Good plugin.pm\n", 268 "ifplugin Good\n", 269 "body GOOD eval:check_foo()\n", 270 "describe GOOD desc_found\n", 271 "endif\n", 272]); 273write_file("$tdir/rulesrc/sandbox/foo/plugin.pm", [ 274 'package Good;', 275 'use Mail::SpamAssassin::Plugin; our @ISA = qw(Mail::SpamAssassin::Plugin);', 276 'sub new { my ($class, $m) = @_; $class = ref($class) || $class;', 277 'my $self = bless $class->SUPER::new($m), $class;', 278 '$self->register_eval_rule("check_foo"); return $self; }', 279 'sub check_foo { my ($self, $pms) = @_; return 1; }', 280]); 281 282ok (mkrun ("--src $tdir/rulesrc --out $tdir/rules --manifest $tdir/MANIFEST --manifestskip $tdir/MANIFEST.SKIP --active $tdir/rules/active.list 2>&1", \&patterns_run_cb)); 283# checkfile("$tdir/rules/72_active.cf", \&patterns_run_cb); 284checkfile("$tdir/rules/70_sandbox.cf", \&patterns_run_cb); 285ok (-f "$tdir/rules/plugin.pm"); 286ok ok_all_patterns(); 287save_tdir(); 288 289 290# --------------------------------------------------------------------------- 291print " active plugin, but the .pm file is AWOL\n\n"; 292 293%patterns = ( 294 "body GOOD eval:check_foo()" => rule_line_1, 295 "describe GOOD desc_found" => rule_line_2, 296 "ifplugin Good" => if1, 297 "endif" => endif_found, 298 "rulesrc/sandbox/foo/20_foo.cf: WARNING: plugin code file '$workdir/mkrules_t/rulesrc/sandbox/foo/plugin.pm' not found, line ignored: loadplugin Good plugin.pm" => plugin_not_found, 299); 300%anti_patterns = ( 301 "describe T_GOOD desc_found" => rule_line_2, 302); 303 304rmtree([ $tdir ]); mkpath ([ "$tdir/rulesrc/sandbox/foo", "$tdir/rules" ]); 305 306write_file("$tdir/MANIFEST", [ "rulesrc/sandbox/foo/20_foo.cf\n", "rulesrc/sandbox/foo/plugin.pm\n" ]); 307write_file("$tdir/MANIFEST.SKIP", [ "foo2\n" ]); 308write_file("$tdir/rules/active.list", [ "GOOD\n" ]); 309write_file("$tdir/rulesrc/sandbox/foo/20_foo.cf", [ 310 "loadplugin Good plugin.pm\n", 311 "ifplugin Good\n", 312 "body GOOD eval:check_foo()\n", 313 "describe GOOD desc_found\n", 314 "endif\n", 315]); 316 317ok (mkrun ("--src $tdir/rulesrc --out $tdir/rules --manifest $tdir/MANIFEST --manifestskip $tdir/MANIFEST.SKIP --active $tdir/rules/active.list 2>&1", \&patterns_run_cb)); 318checkfile("$tdir/rules/72_active.cf", \&patterns_run_cb); 319# checkfile("$tdir/rules/70_sandbox.cf", \&patterns_run_cb); 320ok (!-f "$tdir/rules/plugin.pm"); 321ok ok_all_patterns(); 322save_tdir(); 323 324# --------------------------------------------------------------------------- 325print " active plugin, but the .pm file is not in MANIFEST\n\n"; 326 327%patterns = ( 328 "body GOOD eval:check_foo()" => rule_line_1, 329 "describe GOOD desc_found" => rule_line_2, 330 "ifplugin Good" => if1, 331 "endif" => endif_found, 332 "tryplugin Good plugin.pm" => 'tryplugin', 333 "$workdir/mkrules_t/rulesrc/sandbox/foo/20_foo.cf: WARNING: '$workdir/mkrules_t/rules/plugin.pm' not listed in manifest file, making 'tryplugin': loadplugin Good plugin.pm" => not_found_in_manifest_warning 334); 335%anti_patterns = ( 336); 337 338rmtree([ $tdir ]); mkpath ([ "$tdir/rulesrc/sandbox/foo", "$tdir/rules" ]); 339 340write_file("$tdir/MANIFEST", [ "rulesrc/sandbox/foo/20_foo.cf\n" ]); 341write_file("$tdir/MANIFEST.SKIP", [ ]); 342write_file("$tdir/rules/active.list", [ "GOOD\n" ]); 343write_file("$tdir/rulesrc/sandbox/foo/20_foo.cf", [ 344 "loadplugin Good plugin.pm\n", 345 "ifplugin Good\n", 346 "body GOOD eval:check_foo()\n", 347 "describe GOOD desc_found\n", 348 "endif\n", 349]); 350write_file("$tdir/rulesrc/sandbox/foo/plugin.pm", [ 351 'package Good;', 352 'use Mail::SpamAssassin::Plugin; our @ISA = qw(Mail::SpamAssassin::Plugin);', 353 'sub new { my ($class, $m) = @_; $class = ref($class) || $class;', 354 'my $self = bless $class->SUPER::new($m), $class;', 355 '$self->register_eval_rule("check_foo"); return $self; }', 356 'sub check_foo { my ($self, $pms) = @_; return 1; }', 357]); 358 359ok (mkrun ("--src $tdir/rulesrc --out $tdir/rules --manifest $tdir/MANIFEST --manifestskip $tdir/MANIFEST.SKIP --active $tdir/rules/active.list 2>&1", \&patterns_run_cb)); 360# checkfile("$tdir/rules/72_active.cf", \&patterns_run_cb); 361checkfile("$tdir/rules/70_sandbox.cf", \&patterns_run_cb); 362ok (-f "$tdir/rules/plugin.pm"); 363ok ok_all_patterns(); 364save_tdir(); 365 366# --------------------------------------------------------------------------- 367print "meta rule depends on unpromoted subrule in lexically-earlier file\n\n"; 368# (see mail from Sidney of Oct 16 2006, rules HS_INDEX_PARAM and HS_PHARMA_1) 369 370%patterns = ( 371 "header T_GOOD_SUB" => rule_line_1, 372 "header T_BAD_SUB" => rule_line_2, 373 "meta GOOD (T_GOOD_SUB && !T_BAD_SUB)" => meta_found 374); 375%anti_patterns = ( 376); 377 378rmtree([ $tdir ]); mkpath ([ "$tdir/rulesrc/sandbox/foo", "$tdir/rules" ]); 379 380write_file("$tdir/MANIFEST", [ "rules/72_active.cf\n" ]); 381write_file("$tdir/MANIFEST.SKIP", [ ]); 382write_file("$tdir/rules/active.list", [ "GOOD\n" ]); 383write_file("$tdir/rulesrc/sandbox/foo/20_aaa.cf", [ 384 "meta GOOD (GOOD_SUB && !BAD_SUB)\n", 385]); 386write_file("$tdir/rulesrc/sandbox/foo/20_bbb.cf", [ 387 "header GOOD_SUB Foo =~ /good/\n", 388 "header BAD_SUB Foo =~ /bad/\n", 389]); 390 391ok (mkrun ("--src $tdir/rulesrc --out $tdir/rules --manifest $tdir/MANIFEST --manifestskip $tdir/MANIFEST.SKIP --active $tdir/rules/active.list 2>&1", \&patterns_run_cb)); 392checkfile("$tdir/rules/72_active.cf", \&patterns_run_cb); 393ok ok_all_patterns(); 394save_tdir(); 395 396# --------------------------------------------------------------------------- 397print " nested conditionals\n\n"; 398 399%patterns = ( 400 '72_active.cf: WARNING: not listed in manifest file' => manif_found, 401 "body GOOD /foo/" => rule_line_1, 402 "describe GOOD desc_found" => rule_line_2, 403 "ifplugin Mail::SpamAssassin::Plugin::DKIM" => 'ifplugin', 404 "if (version >= 3.002000)" => 'ifversion', 405); 406%anti_patterns = ( 407 "describe T_GOOD desc_found" => rule_line_2, 408); 409 410mkpath ([ "$tdir/rulesrc/sandbox/foo", "$tdir/rules" ]); 411 412write_file("$tdir/MANIFEST", [ ]); 413write_file("$tdir/MANIFEST.SKIP", [ "foo2\n" ]); 414write_file("$tdir/rules/active.list", [ "GOOD\n" ]); 415write_file("$tdir/rulesrc/sandbox/foo/20_foo.cf", [ 416 "ifplugin Mail::SpamAssassin::Plugin::DKIM\n", 417 "if (version >= 3.002000)\n", 418 "body GOOD /foo/\n", 419 "describe GOOD desc_found\n", 420 "endif\n", 421 "endif\n", 422]); 423 424ok (mkrun ("--src $tdir/rulesrc --out $tdir/rules --manifest $tdir/MANIFEST --manifestskip $tdir/MANIFEST.SKIP --active $tdir/rules/active.list 2>&1", \&patterns_run_cb)); 425checkfile("$tdir/rules/72_active.cf", \&patterns_run_cb); 426checkfile("$tdir/rules/70_sandbox.cf", \&patterns_run_cb); 427ok ok_all_patterns(); 428save_tdir(); 429 430# --------------------------------------------------------------------------- 431 432exit; 433 434sub write_file { 435 my $file = shift; 436 my $linesref = shift; 437 open (O, ">$file") or die "cannot write to $file"; 438 print O @$linesref; 439 close O or die "cannot save $file"; 440} 441 442 443sub mkrun { 444 my $args = shift; 445 my $read_sub = shift; 446 447 my $post_redir = ''; 448 $args =~ s/ 2\>\&1$// and $post_redir = ' 2>&1'; 449 450 rmtree ("$workdir/outputdir.tmp"); # some tests use this 451 mkdir ("$workdir/outputdir.tmp", 0755); 452 453 clear_pattern_counters(); 454 455 my $scrargs = "$perl_path -I../lib ../build/mkrules $args"; 456 print ("\t$scrargs\n"); 457 my $test_number = test_number(); 458 untaint_system ("$scrargs > $workdir/$testname.$test_number $post_redir"); 459 $mk_exitcode = ($?>>8); 460 if ($mk_exitcode != 0) { return undef; } 461 &checkfile ("$workdir/$testname.$test_number", $read_sub) if (defined $read_sub); 462 1; 463} 464 465sub save_tdir { 466 my $test_number = test_number(); 467 468 rmtree("$tdir.$test_number"); 469 if (move( "$tdir", "$tdir.$test_number")) { 470 print "\ttest output tree copied to $tdir.$test_number\n"; 471 } 472} 473 474