~percona-toolkit-dev/percona-toolkit/fix-password-comma-bug-886077

« back to all changes in this revision

Viewing changes to t/lib/Diskstats.t

  • Committer: Daniel Nichter
  • Date: 2012-02-07 20:10:11 UTC
  • mfrom: (174 2.0)
  • mto: This revision was merged to the branch mainline in revision 189.
  • Revision ID: daniel@percona.com-20120207201011-sok2c1f2ay9qr3gm
Merge trunk r174.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/perl
 
2
 
 
3
BEGIN {
 
4
   die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
 
5
      unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
 
6
   unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
 
7
};
 
8
 
 
9
use strict;
 
10
use warnings FATAL => 'all';
 
11
use English qw(-no_match_vars);
 
12
use Test::More tests => 107;
 
13
 
 
14
use PerconaTest;
 
15
 
 
16
use OptionParser;
 
17
 
 
18
use File::Spec;
 
19
use File::Temp ();
 
20
 
 
21
BEGIN {
 
22
   use_ok "Diskstats";
 
23
   use_ok "DiskstatsGroupByAll";
 
24
   use_ok "DiskstatsGroupByDisk";
 
25
   use_ok "DiskstatsGroupBySample";
 
26
}
 
27
 
 
28
my $o   = new OptionParser(description => 'Diskstats');
 
29
$o->get_specs("$trunk/bin/pt-diskstats");
 
30
$o->get_opts();
 
31
 
 
32
{
 
33
my $obj = new Diskstats(OptionParser => $o);
 
34
 
 
35
can_ok( $obj, qw(
 
36
                  columns_regex devices_regex filename
 
37
                  block_size ordered_devs clear_state clear_ordered_devs
 
38
                  stats_for prev_stats_for first_stats_for
 
39
                  has_stats design_print_formats parse_diskstats_line
 
40
                  parse_from print_deltas
 
41
               ) );
 
42
 
 
43
# ############################################################################
 
44
# Testing the constructor.
 
45
# ############################################################################
 
46
for my $attr (
 
47
      [ filename     => (File::Temp::tempfile($0.'diskstats.XXXXXX',
 
48
                                              OPEN=>0, UNLINK=>1))[1] ],
 
49
      [ columns_regex  => qr/!!!/  ],
 
50
      [ devices_regex  => qr/!!!/  ],
 
51
      [ block_size    => 215      ],
 
52
      [ show_inactive => 1        ],
 
53
      [ sample_time   => 1        ],
 
54
      [ interactive   => 1        ],
 
55
   ) {
 
56
   my $attribute   = $attr->[0];
 
57
   my $value       = $attr->[1];
 
58
   my $test_obj    = Diskstats->new( @$attr, OptionParser => $o );
 
59
 
 
60
   is(
 
61
      $test_obj->$attribute(),
 
62
      $value,
 
63
      "Passing an explicit [$attribute] to the constructor works",
 
64
   );
 
65
}
 
66
 
 
67
# ############################################################################
 
68
# parse_diskstats_line
 
69
# ############################################################################
 
70
for my $test (
 
71
   [
 
72
      "104    0 cciss/c0d0 2139885 162788 37361471 8034486 17999682 83425310 811400340 12711047 0 6869437 20744582",
 
73
      [
 
74
         104, 0, "cciss/c0d0",   # major, minor, device
 
75
      
 
76
         2139885,     # reads
 
77
         162788,      # reads_merged
 
78
         37361471,    # read_sectors
 
79
         8034486,     # ms_spent_reading
 
80
      
 
81
         17999682,    # writes
 
82
         83425310,    # writes_merged
 
83
         811400340,   # written_sectors
 
84
         12711047,    # ms_spent_writing
 
85
      
 
86
         0,           # ios_in_progress
 
87
         6869437,     # ms_spent_doing_io
 
88
         20744582,    # ms_weighted
 
89
      
 
90
         18680735.5,  # read_kbs
 
91
         405700170,   # written_kbs
 
92
         103727665,    # ios_requested
 
93
         434566047232,# ios_in_bytes
 
94
      ],
 
95
      "parse_diskstats_line works"
 
96
   ],
 
97
   [
 
98
      "  8 33 sdc1 1572537676 2369344 3687151364 1575056414 2541895139 1708184481 3991989096 121136333 1 982122453 1798311795",
 
99
      [
 
100
          '8', '33', 'sdc1', 1572537676, '2369344', 3687151364,
 
101
          '1575056414', 2541895139, '1708184481', 3991989096,
 
102
          '121136333', '1', '982122453', '1798311795', '1843575682',
 
103
          '1995994548', 5824986640, '3931719915520'
 
104
      ],
 
105
      "parse_diskstats_line works"
 
106
   ],
 
107
   [
 
108
      "  8 33 sdc1 1572537676 2369344 3687151364 1575056414 2541895139 1708184481 3991989096 121136333 1 982122453 1798311795\n",
 
109
      [
 
110
          '8', '33', 'sdc1', 1572537676, '2369344', 3687151364,
 
111
          '1575056414', 2541895139, '1708184481', 3991989096,
 
112
          '121136333', '1', '982122453', '1798311795',
 
113
          '1843575682',
 
114
          '1995994548', 5824986640, '3931719915520'
 
115
      ],
 
116
      "parse_diskstats_line ignores a trailing newline"
 
117
   ],
 
118
   [
 
119
      "  8 33 sdc1 1572537676 2369344 3687151364 1575056414 2541895139 1708184481 3991989096 121136333 1 982122453 \n",
 
120
      undef,
 
121
      "parse_diskstats_line fails on a line without enough fields"
 
122
   ],
 
123
   [
 
124
      "  8 33 sdc1 1572537676 2369344 3687151364 1575056414 2541895139 1708184481 3991989096 121136333 1 982122453 12224123 12312312",
 
125
      undef,
 
126
      "parse_diskstats_line fails on a line with too many fields"
 
127
   ],
 
128
   [
 
129
      "",
 
130
      undef,
 
131
      "parse_diskstats_line returns undef on an empty string",
 
132
   ],
 
133
   [
 
134
      "Malformed line",
 
135
      undef,
 
136
      "parse_diskstats_line returns undef on a malformed line",
 
137
   ],
 
138
) {
 
139
   my ($line, $expected_results, $desc) = @$test;
 
140
   my ($dev, $res) = $obj->parse_diskstats_line($line, $obj->block_size);
 
141
   is_deeply( $res, $expected_results, $desc );
 
142
}
 
143
 
 
144
# For speed, ->parse_diskstats_line doesn't check for undef.
 
145
# In any case, this should never happen, since it's internally
 
146
# used within a readline() loop.
 
147
local $EVAL_ERROR;
 
148
eval { $obj->parse_diskstats_line(undef, $obj->block_size); };
 
149
like(
 
150
   $EVAL_ERROR,
 
151
   qr/Use of uninitialized value/,
 
152
   "parse_diskstats_line should fail on undef",
 
153
);
 
154
 
 
155
 
 
156
# ############################################################################
 
157
# design_print_formats
 
158
# ############################################################################
 
159
 
 
160
my @columns_in_order = @Diskstats::columns_in_order;
 
161
 
 
162
$obj->set_columns_regex(qr/./);
 
163
my ($header, $rows, $cols) = $obj->design_print_formats();
 
164
is_deeply(
 
165
   $cols,
 
166
   [ map { $_->[0] } @columns_in_order ],
 
167
   "design_print_formats: returns the expected columns"
 
168
);
 
169
 
 
170
                  # qr/ \A (?!.*io_s$|\s*[qs]time$) /x
 
171
$obj->set_columns_regex(qr/cnc|rt|busy|prg|[mk]b|[dr]_s|mrg/);
 
172
($header, $rows, $cols) = $obj->design_print_formats();
 
173
is(
 
174
   $header,
 
175
   join(" ", q{%+*s %-6s}, grep { $_ =~ $obj->columns_regex() } map { $_->[0] } @columns_in_order),
 
176
   "design_print_formats: sanity check for defaults"
 
177
);
 
178
 
 
179
$obj->set_columns_regex(qr/./);
 
180
($header, $rows, $cols) = $obj->design_print_formats(max_device_length => 10);
 
181
my $all_columns_format = join(" ", q{%+*s %-10s}, map { $_->[0] } @columns_in_order);
 
182
is(
 
183
   $header,
 
184
   $all_columns_format,
 
185
   "design_print_formats: max_device_length works"
 
186
);
 
187
 
 
188
$obj->set_columns_regex(qr/(?!)/); # Will never match
 
189
($header, $rows, $cols) = $obj->design_print_formats(max_device_length => 10);
 
190
is(
 
191
   $header,
 
192
   q{%+*s %-10s },
 
193
   "design_print_formats respects columns_regex"
 
194
);
 
195
 
 
196
$obj->set_columns_regex(qr/./);
 
197
($header, $rows, $cols) = $obj->design_print_formats(
 
198
                                    max_device_length => 10,
 
199
                                    columns           => []
 
200
                                 );
 
201
is(
 
202
   $header,
 
203
   q{%+*s %-10s },
 
204
   "...unless we pass an explicit column array"
 
205
);
 
206
 
 
207
$obj->set_columns_regex(qr/./);
 
208
($header, $rows, $cols) = $obj->design_print_formats(
 
209
                                 max_device_length => 10,
 
210
                                 columns           => [qw( busy )]
 
211
                           );
 
212
is(
 
213
   $header,
 
214
   q{%+*s %-10s busy},
 
215
   "Header"
 
216
);
 
217
 
 
218
($header, $rows, $cols) = $obj->design_print_formats(
 
219
                                 max_device_length => 10,
 
220
                                 columns           =>
 
221
                                    [ map  { $_->[0] } @columns_in_order ],
 
222
                           );
 
223
is(
 
224
   $header,
 
225
   $all_columns_format,
 
226
   "All columns format"
 
227
);
 
228
 
 
229
throws_ok( sub { $obj->design_print_formats( columns => {} ) },
 
230
        qr/The columns argument to design_print_formats should be an arrayref/,
 
231
        "design_print_formats dies when passed an invalid columns argument");
 
232
 
 
233
# ############################################################################
 
234
# timestamp methods
 
235
# ############################################################################
 
236
for my $method ( qw( curr_ts prev_ts first_ts ) ) {
 
237
   my $setter = "set_$method";
 
238
   ok(!$obj->$method(), "Diskstats->$method is initially false");
 
239
 
 
240
   $obj->$setter(10);
 
241
   is($obj->$method(), 10, "Diskstats->$setter(10) sets it to 10");
 
242
 
 
243
   $obj->$setter(20);
 
244
   $obj->clear_ts();
 
245
   ok(!$obj->$method(), "Diskstats->clear_ts does as advertized");
 
246
}
 
247
 
 
248
# ############################################################################
 
249
# Adding, removing and listing devices.
 
250
# ############################################################################
 
251
is_deeply(
 
252
   [ $obj->ordered_devs() ],
 
253
   [],
 
254
   "ordered_devs starts empty"
 
255
);
 
256
 
 
257
$obj->add_ordered_dev("sda");
 
258
is_deeply(
 
259
   [ $obj->ordered_devs() ],
 
260
   [ qw( sda ) ],
 
261
   "We can add devices just fine,"
 
262
);
 
263
 
 
264
$obj->add_ordered_dev("sda");
 
265
is_deeply(
 
266
   [ $obj->ordered_devs() ],
 
267
   [ qw( sda ) ],
 
268
   "...And duplicates get detected and discarded"
 
269
);
 
270
 
 
271
$obj->clear_ordered_devs();
 
272
is_deeply(
 
273
   [ $obj->ordered_devs() ],
 
274
   [],
 
275
   "clear_ordered_devs does as advertized,"
 
276
);
 
277
$obj->add_ordered_dev("sda");
 
278
is_deeply(
 
279
   [ $obj->ordered_devs() ],
 
280
   [ qw( sda ) ],
 
281
   "...And clears the internal duplicate-checking list"
 
282
);
 
283
 
 
284
# ############################################################################
 
285
# show_inactive -- Whenever it prints inactive devices.
 
286
# ############################################################################
 
287
##
 
288
## show_inactive now functions inside parse_from
 
289
##
 
290
#$obj->set_show_inactive(0);
 
291
#my $print_output = output(
 
292
#   sub {
 
293
#      $obj->print_rows(
 
294
#            "SHOULDN'T PRINT THIS",
 
295
#            [ qw( a b c ) ],
 
296
#            { a => 0, b => 0, c => 0, d => 10 }
 
297
#         );
 
298
#   }
 
299
#);
 
300
#$obj->set_show_inactive(1);
 
301
#
 
302
#is(
 
303
#   $print_output,
 
304
#   "",
 
305
#   "->show_inactive works"
 
306
#);
 
307
 
 
308
# ############################################################################
 
309
# Sane defaults and fatal errors
 
310
# ############################################################################
 
311
for my $method ( qw( delta_against delta_against_ts group_by ) ) {
 
312
   throws_ok(
 
313
      sub { Diskstats->$method() },
 
314
      qr/\QYou must override $method() in a subclass\E/,
 
315
      "->$method has to be overriden"
 
316
   );
 
317
}
 
318
 
 
319
is(
 
320
   $obj->compute_line_ts( first_ts => 0 ),
 
321
   sprintf( "%5.1f", 0 ),
 
322
   "compute_line_ts has a sane default",
 
323
);
 
324
 
 
325
$obj->set_force_header(0);
 
326
 
 
327
is(
 
328
   output( sub { $obj->print_header("asdasdas") } ),
 
329
   "",
 
330
   "force_header works"
 
331
);
 
332
 
 
333
my $output = output(
 
334
   sub { $obj->parse_from( data => "ASMFHNASJNFASKLFLKHNSKD" ); },
 
335
   stderr => 1,
 
336
);
 
337
 
 
338
is(
 
339
   $output,
 
340
   "",
 
341
   "Doesn't die parsing unknown line"
 
342
);
 
343
 
 
344
# ############################################################################
 
345
# _calc* methods
 
346
# ############################################################################
 
347
 
 
348
$obj->clear_state();
 
349
 
 
350
my $prev = {
 
351
   TS   => 1281367519,
 
352
   data => ($obj->parse_diskstats_line(
 
353
"104    0 cciss/c0d0 2139885 162788 37361471 8034486 17999682 83425310 811400340 12711047 0 6869437 20744582", $obj->block_size))[1]
 
354
};
 
355
my $curr = {
 
356
   TS   => 1281367521,
 
357
   data => ($obj->parse_diskstats_line(
 
358
"104    0 cciss/c0d0 2139886 162790 37361478 8034489 17999738 83425580 811402798 12711097 3 6869449 20744632", $obj->block_size))[1]
 
359
};
 
360
 
 
361
$obj->first_ts( $prev->{TS} );
 
362
$obj->prev_ts( $prev->{TS} );
 
363
$obj->curr_ts( $curr->{TS} );
 
364
 
 
365
my $deltas = $obj->_calc_delta_for($curr->{data}, $prev->{data});
 
366
 
 
367
is_deeply(
 
368
   $deltas,
 
369
   {
 
370
      ms_spent_doing_io => 12,
 
371
      ms_spent_reading => 3,
 
372
      ms_spent_writing => 50,
 
373
      ms_weighted => 50,
 
374
      read_kbs => 3.5,
 
375
      read_sectors => 7,
 
376
      reads => 1,
 
377
      reads_merged => 2,
 
378
      writes => 56,
 
379
      writes_merged => 270,
 
380
      written_kbs => 1229,
 
381
      written_sectors => 2458,
 
382
      ios_in_bytes   => 1262080,
 
383
      ios_requested  => 329,
 
384
      ios_in_progress => 3,
 
385
   },
 
386
   "_calc_delta_for works"
 
387
);
 
388
 
 
389
local $EVAL_ERROR;
 
390
eval { $obj->_calc_delta_for($curr->{data}, []) };
 
391
ok(!$EVAL_ERROR, "_calc_delta_for guards against undefined values");
 
392
 
 
393
my %read_stats = $obj->_calc_read_stats(
 
394
   delta_for     => $deltas,
 
395
   elapsed       => $curr->{TS} - $prev->{TS},
 
396
   devs_in_group => 1,
 
397
);
 
398
 
 
399
is_deeply(
 
400
   \%read_stats,
 
401
   {
 
402
      avg_read_sz => '3.5',
 
403
      mbytes_read_sec => '0.001708984375',
 
404
      read_conc => '0.0015',
 
405
      read_merge_pct => '66.6666666666667',
 
406
      read_requests => 3,
 
407
      read_rtime => 1,
 
408
      reads_sec => '0.5'
 
409
   },
 
410
   "_calc_read_stats works"
 
411
);
 
412
 
 
413
my %write_stats = $obj->_calc_write_stats(
 
414
   delta_for     => $deltas,
 
415
   elapsed       => $curr->{TS} - $prev->{TS},
 
416
   devs_in_group => 1,
 
417
);
 
418
 
 
419
is_deeply(
 
420
   \%write_stats,
 
421
   {
 
422
      avg_write_sz => '21.9464285714286',
 
423
      mbytes_written_sec => '0.60009765625',
 
424
      write_conc => '0.025',
 
425
      write_merge_pct => '82.8220858895706',
 
426
      write_requests => 326,
 
427
      write_rtime => '0.153374233128834',
 
428
      writes_sec => '28',
 
429
   },
 
430
   "_calc_write_stats works"
 
431
);
 
432
 
 
433
my %misc_stats = $obj->_calc_misc_stats(
 
434
   delta_for     => $deltas,
 
435
   elapsed       => $curr->{TS} - $prev->{TS},
 
436
   devs_in_group => 1,
 
437
   stats         => { %write_stats, %read_stats },
 
438
);
 
439
 
 
440
is_deeply(
 
441
   \%misc_stats,
 
442
   {
 
443
      busy => '0.6',
 
444
      line_ts => '  0.0',
 
445
      qtime => '0.114128245504816',
 
446
      s_spent_doing_io => '28.5',
 
447
      stime => '0.0364741641337386',
 
448
   },
 
449
   "_calc_misc_stats works"
 
450
);
 
451
 
 
452
$obj->clear_state();
 
453
 
 
454
}
 
455
# ############################################################################
 
456
# The three subclasses
 
457
# ############################################################################
 
458
for my $test (
 
459
      {
 
460
         class               => "DiskstatsGroupByAll",
 
461
         results_file_prefix => "all",
 
462
      },
 
463
      {
 
464
         class               => "DiskstatsGroupByDisk",
 
465
         results_file_prefix => "disk",
 
466
      },
 
467
      {
 
468
         class               => "DiskstatsGroupBySample",
 
469
         results_file_prefix => "sample",
 
470
      }) {
 
471
   my $obj    = $test->{class}->new(OptionParser => $o, show_inactive => 1);
 
472
   my $prefix = $test->{results_file_prefix};
 
473
 
 
474
   $obj->set_columns_regex(qr/./);
 
475
   $obj->set_show_inactive(1);
 
476
   $obj->set_show_timestamps(0);
 
477
   $obj->set_automatic_headers(0);
 
478
   $obj->set_show_line_between_samples(0);
 
479
 
 
480
   for my $filename ( map "diskstats-00$_.txt", 1..5 ) {
 
481
      my $file = File::Spec->catfile( "t", "pt-diskstats", "samples", $filename );
 
482
      my $file_with_trunk = File::Spec->catfile( $trunk, $file );
 
483
 
 
484
      my $expected = load_file( File::Spec->catfile( "t", "pt-diskstats", "expected", "${prefix}_$filename" ) );
 
485
 
 
486
      my $got = output(
 
487
         sub {
 
488
            $obj->group_by(
 
489
               filename => $file_with_trunk,
 
490
            );
 
491
         });
 
492
      
 
493
      is($got, $expected, "group_by $prefix: $filename via filename");
 
494
   
 
495
      $got = output(
 
496
         sub {
 
497
            open my $fh, "<", $file_with_trunk or die $!;
 
498
            $obj->group_by(
 
499
               filehandle => $fh,
 
500
            );
 
501
         });
 
502
   
 
503
      is($got, $expected, "group_by $prefix: $filename via filehandle");
 
504
   
 
505
      $got = output(
 
506
         sub {
 
507
            $obj->group_by(
 
508
               data => "TS 1298130002.073935000\n" . load_file( $file ),
 
509
            );
 
510
         });
 
511
   
 
512
      is($got, $expected, "group_by $prefix: $filename with an extra TS at the top");
 
513
   }
 
514
 
 
515
   my $data = <<'EOF';
 
516
TS 1297205887.156653000
 
517
   1    0 ram0 0 0 0 0 0 0 0 0 0 0 0
 
518
TS 1297205888.161613000
 
519
EOF
 
520
   
 
521
   my $got = output( sub { $obj->group_by(data => $data) }, stderr => 1 );
 
522
   is(
 
523
      $got,
 
524
      '',
 
525
      "group_by $prefix: 1 line of data between two TS lines results in no output"
 
526
   );
 
527
 
 
528
   $obj->set_curr_ts(0);
 
529
   $obj->set_prev_ts(0);
 
530
   $obj->set_first_ts(0);
 
531
 
 
532
   throws_ok(
 
533
      sub { $obj->_calc_deltas() },
 
534
      qr/Time between samples should be > 0, is /,
 
535
      "$test->{class}, ->_calc_deltas fails if the time elapsed is 0"
 
536
   );
 
537
 
 
538
   $obj->set_curr_ts(0);
 
539
   $obj->set_prev_ts(4);
 
540
   $obj->set_first_ts(4);
 
541
 
 
542
   throws_ok(
 
543
      sub { $obj->_calc_deltas() },
 
544
      qr/Time between samples should be > 0, is /,
 
545
      "$test->{class}, ->_calc_deltas fails if the time elapsed is negative"
 
546
   );
 
547
 
 
548
}
 
549
 
 
550
# ###########################################################################
 
551
# Done.
 
552
# ###########################################################################
 
553
exit;