root/honeyclient/tags/exp/DOWN1-mbriggs-db/t/honeyclient_agent_integrity_filesystem.t

Revision 507, 11.6 kB (checked in by kindlund, 2 years ago)

Fixed an insidious Registry parsing bug. Fundamentally, the problem existed where we assumed we could directly use the "diff type" output from the diff utility. Diff operates on a per-line basis, when what we really need is the diff utility to operating on a per-directory group basis. As such, if we're given an 'a', 'c', or 'd' diff type, we can't assume that type applies to the entire directory (for example, it could be that you have key data added or deleted, but the key directory still exists). Thus, I had to include additional logic that maps each per-line diff type to a logical per-directory diff type.

Line 
1 #!/usr/bin/perl -w
2
3 use strict;
4 use Test::More 'no_plan';
5 $| = 1;
6
7
8
9 # =begin testing
10 {
11 # Make sure Log::Log4perl loads
12 BEGIN { use_ok('Log::Log4perl', qw(:nowarn))
13         or diag("Can't load Log::Log4perl package. Check to make sure the package library is correctly listed within the path.");
14
15         # Suppress all logging messages, since we need clean output for unit testing.
16         Log::Log4perl->init({
17             "log4perl.rootLogger"                               => "DEBUG, Buffer",
18             "log4perl.appender.Buffer"                          => "Log::Log4perl::Appender::TestBuffer",
19             "log4perl.appender.Buffer.min_level"                => "fatal",
20             "log4perl.appender.Buffer.layout"                   => "Log::Log4perl::Layout::PatternLayout",
21             "log4perl.appender.Buffer.layout.ConversionPattern" => "%d{yyyy-MM-dd HH:mm:ss} %5p [%M] (%F:%L) - %m%n",
22         });
23 }
24 require_ok('Log::Log4perl');
25 use Log::Log4perl qw(:easy);
26
27 # Make sure the module loads properly, with the exportable
28 # functions shared.
29 BEGIN { use_ok('HoneyClient::Util::Config', qw(getVar setVar))
30         or diag("Can't load HoneyClient::Util::Config package.  Check to make sure the package library is correctly listed within the path."); }
31 require_ok('HoneyClient::Util::Config');
32 can_ok('HoneyClient::Util::Config', 'getVar');
33 can_ok('HoneyClient::Util::Config', 'setVar');
34 use HoneyClient::Util::Config qw(getVar setVar);
35
36 # Suppress all logging messages, since we need clean output for unit testing.
37 Log::Log4perl->init({
38     "log4perl.rootLogger"                               => "DEBUG, Buffer",
39     "log4perl.appender.Buffer"                          => "Log::Log4perl::Appender::TestBuffer",
40     "log4perl.appender.Buffer.min_level"                => "fatal",
41     "log4perl.appender.Buffer.layout"                   => "Log::Log4perl::Layout::PatternLayout",
42     "log4perl.appender.Buffer.layout.ConversionPattern" => "%d{yyyy-MM-dd HH:mm:ss} %5p [%M] (%F:%L) - %m%n",
43 });
44
45 # Make sure Data::Dumper loads
46 BEGIN { use_ok('Data::Dumper')
47         or diag("Can't load Data::Dumper package. Check to make sure the package library is correctly listed within the path."); }
48 require_ok('Data::Dumper');
49 use Data::Dumper;
50
51 # Make sure Storable loads
52 BEGIN { use_ok('Storable', qw(nfreeze thaw dclone))
53         or diag("Can't load Storable package. Check to make sure the package library is correctly listed within the path."); }
54 require_ok('Storable');
55 can_ok('Storable', 'nfreeze');
56 can_ok('Storable', 'thaw');
57 can_ok('Storable', 'dclone');
58 use Storable qw(nfreeze thaw dclone);
59
60 # Make sure File::Find loads.
61 BEGIN { use_ok('File::Find', qw(find)) or diag("Can't load File::Find package.  Check to make sure the package library is correctly listed within the path."); }
62 require_ok('File::Find');
63 can_ok('File::Find', 'find');
64 use File::Find;
65
66 # Make sure Filesys::CygwinPaths loads
67 BEGIN { use_ok('Filesys::CygwinPaths')
68         or diag("Can't load Filesys::CygwinPaths package. Check to make sure the package library is correctly listed within the path."); }
69 require_ok('Filesys::CygwinPaths');
70 use Filesys::CygwinPaths qw(:all);
71
72 # Make sure Algorithm::Diff loads.
73 BEGIN { use_ok('Algorithm::Diff') or diag("Can't load Algorithm::Diff package.  Check to make sure the package library is correctly listed within the path."); }
74 require_ok('Algorithm::Diff');
75 use Algorithm::Diff;
76
77 # Make sure File::Basename loads.
78 BEGIN { use_ok('File::Basename', qw(dirname)) or diag("Can't load File::Basename package.  Check to make sure the package library is correctly listed within the path."); }
79 require_ok('File::Basename');
80 can_ok('File::Basename', 'dirname');
81 use File::Basename qw(dirname);
82
83 # Make sure HoneyClient::Agent::Integrity::Filesystem loads.
84 BEGIN { use_ok('HoneyClient::Agent::Integrity::Filesystem') or diag("Can't load HoneyClient::Agent::Integrity::Filesystem package.  Check to make sure the package library is correctly listed within the path."); }
85 require_ok('HoneyClient::Agent::Integrity::Filesystem');
86 use HoneyClient::Agent::Integrity::Filesystem;
87
88 # Make sure DateTime loads.
89 BEGIN { use_ok('DateTime') or diag("Can't load DateTime package.  Check to make sure the package library is correctly listed within the path."); }
90 require_ok('DateTime');
91 use DateTime;
92
93 # Make sure Digest::MD5 loads.
94 BEGIN { use_ok('Digest::MD5') or diag("Can't load Digest::MD5 package.  Check to make sure the package library is correctly listed within the path."); }
95 require_ok('Digest::MD5');
96 use Digest::MD5;
97
98 # Make sure Digest::SHA loads.
99 BEGIN { use_ok('Digest::SHA') or diag("Can't load Digest::SHA package.  Check to make sure the package library is correctly listed within the path."); }
100 require_ok('Digest::SHA');
101 use Digest::SHA;
102
103 # Make sure File::Type loads.
104 BEGIN { use_ok('File::Type') or diag("Can't load File::Type package.  Check to make sure the package library is correctly listed within the path."); }
105 require_ok('File::Type');
106 use File::Type;
107
108 # Make sure IO::File loads.
109 BEGIN { use_ok('IO::File') or diag("Can't load IO::File package.  Check to make sure the package library is correctly listed within the path."); }
110 require_ok('IO::File');
111 use IO::File;
112 }
113
114
115
116 # =begin testing
117 {
118 diag("These tests will create temporary files in /tmp.  Be sure to cleanup this directory, if any of these tests fail.");
119
120 # Create a generic Filesystem object, with test state data.
121 my $filesystem = HoneyClient::Agent::Integrity::Filesystem->new(test => 1, bypass_baseline => 1);
122 is($filesystem->{test}, 1, "new(test => 1, bypass_baseline => 1)") or diag("The new() call failed.");
123 isa_ok($filesystem, 'HoneyClient::Agent::Integrity::Filesystem', "new(test => 1, bypass_baseline => 1)") or diag("The new() call failed.");
124
125 diag("Performing baseline check of the filesystem; this may take some time...");
126
127 # Perform baseline.
128 $filesystem = HoneyClient::Agent::Integrity::Filesystem->new();
129 isa_ok($filesystem, 'HoneyClient::Agent::Integrity::Filesystem', "new()") or diag("The new() call failed.");
130 }
131
132
133
134 # =begin testing
135 {
136 ### Get the test directory to monitor.
137 my $monitor_dir = $ENV{PWD} . "/" . getVar(name      => "monitor_dir",
138                                            namespace => "HoneyClient::Agent::Integrity::Filesystem::Test");
139
140 ### Seed the directory with test data.
141 my $delete_file = $monitor_dir . "/" . "to_delete.txt";
142 my $change_file = $monitor_dir . "/" . "to_change.txt";
143 my $add_file    = $monitor_dir . "/" . "to_add.txt";
144
145 my $delete_string  = "Test string for the file to be deleted.";
146 my $add_string     = "Test string for the added file.";
147 my $change_string1 = "Original test string for the file to be changed.";
148 my $change_string2 = "Final test string for the changed file.";
149
150 my @file_attr;
151
152 open(DELETE_FILE, ">", $delete_file) or BAIL_OUT("Unable to create test file '" . $delete_file . "'.");
153 print DELETE_FILE $delete_string;
154 close DELETE_FILE;
155
156 @file_attr = stat($delete_file);
157 my $delete_file_size  = $file_attr[7];
158 my $delete_file_mtime = $file_attr[9];
159
160 open(CHANGE_FILE, ">", $change_file) or BAIL_OUT("Unable to create test file '" . $change_file . "'.");
161 print CHANGE_FILE $change_string1;
162 close CHANGE_FILE;
163
164 @file_attr = stat($change_file);
165 my $change_file_size1  = $file_attr[7];
166 my $change_file_mtime1 = $file_attr[9];
167
168 # Make sure the $add_file isn't present.
169 unlink($add_file);
170
171 ### Perform baseline.
172 my $filesystem = HoneyClient::Agent::Integrity::Filesystem->new(monitored_directories => [ $monitor_dir ],
173                                                                 ignored_entries       => [ $monitor_dir ]);
174
175 ### Change data in our test directory on the filesystem.
176 # Delete the target test file.
177 if (!unlink($delete_file)) {
178     fail("Unable to delete test file '" . $delete_file . "'.");
179 }
180
181 # Add the target test file.
182 open(ADD_FILE, ">", $add_file) or BAIL_OUT("Unable to create test file '" . $add_file . "'.");
183 print ADD_FILE $add_string;
184 close ADD_FILE;
185
186 my $md5_ctx = Digest::MD5->new();
187 my $sha1_ctx = Digest::SHA->new("1");
188 my $type_ctx = File::Type->new();
189
190 my $add_fh = IO::File->new($add_file, "r");
191 $md5_ctx->addfile($add_fh);
192 my $add_file_md5 = $md5_ctx->hexdigest();
193 seek($add_fh, 0, 0);
194 $sha1_ctx->addfile($add_fh);
195 my $add_file_sha1 = $sha1_ctx->hexdigest();
196 undef $add_fh;
197 my $add_file_type = $type_ctx->mime_type($add_file);
198
199 @file_attr = stat($add_file);
200 my $add_file_size  = $file_attr[7];
201 my $add_file_mtime = $file_attr[9];
202
203 # Change the target test file.
204 open(CHANGE_FILE, ">", $change_file) or BAIL_OUT("Unable to create test file '" . $change_file . "'.");
205 print CHANGE_FILE $change_string2;
206 close CHANGE_FILE;
207
208 my $change_fh = IO::File->new($change_file, "r");
209 $md5_ctx->addfile($change_fh);
210 my $change_file_md5 = $md5_ctx->hexdigest();
211 seek($change_fh, 0, 0);
212 $sha1_ctx->addfile($change_fh);
213 my $change_file_sha1 = $sha1_ctx->hexdigest();
214 undef $change_fh;
215 my $change_file_type = $type_ctx->mime_type($change_file);
216
217 @file_attr = stat($change_file);
218 my $change_file_size2  = $file_attr[7];
219 my $change_file_mtime2 = $file_attr[9];
220
221 ### Perform check.
222 my $foundChanges = $filesystem->check(no_prepare => 1);
223
224 # Uncomment these lines, if you want to see more
225 # detailed information about the changes found.
226 #$Data::Dumper::Terse = 0;
227 #$Data::Dumper::Indent = 1;
228 #diag(Dumper($foundChanges));
229
230 ### Verify changes.
231 my $expectedChanges = [
232   {
233     'status' => $HoneyClient::Agent::Integrity::Filesystem::STATUS_MODIFIED,
234     'new' => {
235         'name'  => $change_file,
236         'size'  => $change_file_size2,
237         'mtime' => $change_file_mtime2,
238     },
239     'old' => {
240         'name'  => $change_file,
241         'size'  => $change_file_size1,
242         'mtime' => $change_file_mtime1,
243     },
244   },
245   {
246     'status' => $HoneyClient::Agent::Integrity::Filesystem::STATUS_ADDED,
247     'new' => {
248         'name'  => $add_file,
249         'size'  => $add_file_size,
250         'mtime' => $add_file_mtime,
251     },
252   },
253   {
254     'status' => $HoneyClient::Agent::Integrity::Filesystem::STATUS_DELETED,
255     'old' => {
256         'name'  => $delete_file,
257         'size'  => $delete_file_size,
258         'mtime' => $delete_file_mtime,
259     },
260   },
261 ];
262
263 is_deeply($foundChanges, $expectedChanges, "check(no_prepare => 1)") or diag("The check() call failed.");
264
265 ### Perform check.
266 $foundChanges = $filesystem->check();
267
268 # Uncomment these lines, if you want to see more
269 # detailed information about the changes found.
270 #$Data::Dumper::Terse = 0;
271 #$Data::Dumper::Indent = 1;
272 #diag(Dumper($foundChanges));
273
274 ### Verify changes.
275 $expectedChanges = [
276   {
277     'status' => $HoneyClient::Agent::Integrity::Filesystem::STATUS_MODIFIED,
278     'name'  => HoneyClient::Agent::Integrity::Filesystem::_convertFilename($change_file),
279     'mtime' => HoneyClient::Agent::Integrity::Filesystem::_convertTime($change_file_mtime2),
280     'content' => {
281         'size'  => $change_file_size2,
282         'type'  => $change_file_type,
283         'sha1'  => $change_file_sha1,
284         'md5'   => $change_file_md5,
285     },
286   },
287   {
288     'status' => $HoneyClient::Agent::Integrity::Filesystem::STATUS_ADDED,
289     'name'  => HoneyClient::Agent::Integrity::Filesystem::_convertFilename($add_file),
290     'mtime' => HoneyClient::Agent::Integrity::Filesystem::_convertTime($add_file_mtime),
291     'content' => {
292         'size'  => $add_file_size,
293         'type'  => $add_file_type,
294         'sha1'  => $add_file_sha1,
295         'md5'   => $add_file_md5,
296     },
297   },
298   {
299     'status' => $HoneyClient::Agent::Integrity::Filesystem::STATUS_DELETED,
300     'name'  => HoneyClient::Agent::Integrity::Filesystem::_convertFilename($delete_file),
301     'mtime' => HoneyClient::Agent::Integrity::Filesystem::_convertTime($delete_file_mtime),
302   },
303 ];
304
305 is_deeply($foundChanges, $expectedChanges, "check()") or diag("The check() call failed.");
306
307 ### Clean up test data.
308 close DELETE_FILE;
309 unlink($delete_file);
310
311 close CHANGE_FILE;
312 unlink($change_file);
313
314 close ADD_FILE;
315 unlink($add_file);
316 }
317
318
319
320
321 1;
Note: See TracBrowser for help on using the browser.