ca646e067e945c1b04d73ee0812fef7b0620d107
[debian/amanda] / installcheck / Amanda_IPC_Binary.pl
1 # Copyright (c) 2009 Zmanda, Inc.  All Rights Reserved.
2 #
3 # This program is free software; you can redistribute it and/or modify it
4 # under the terms of the GNU General Public License version 2 as published
5 # by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful, but
8 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
10 # for more details.
11 #
12 # You should have received a copy of the GNU General Public License along
13 # with this program; if not, write to the Free Software Foundation, Inc.,
14 # 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15 #
16 # Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
17 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
18
19 use Test::More tests => 15;
20 use strict;
21 use warnings;
22
23 use lib "@amperldir@";
24 use Installcheck;
25 use Amanda::IPC::Binary;
26 use IO::Handle;
27 use Amanda::Debug;
28 use Data::Dumper;
29 use Carp;
30 use POSIX;
31
32 ##
33 # Define a test protocol
34
35 package TestProtocol;
36 use base "Amanda::IPC::Binary";
37 use Amanda::IPC::Binary;
38
39 # cmd_id's
40 use constant SIMPLE => 1;
41 use constant FOO => 2;
42 use constant BAR => 3;
43
44 # arg_id's
45 use constant NAME => 1;
46 use constant NICKNAME => 2;
47 use constant MANDATORY => 3;
48 use constant OPTIONAL => 4;
49
50 magic(0x1234);
51
52 command(SIMPLE);
53
54 command(FOO,
55     NAME, $IPC_BINARY_STRING,
56     NICKNAME, $IPC_BINARY_STRING);
57
58 command(BAR,
59     MANDATORY, 0,
60     OPTIONAL, $IPC_BINARY_OPTIONAL);
61
62 package main;
63
64 # set up debugging so debug output doesn't interfere with test results
65 Amanda::Debug::dbopen("installcheck");
66 Installcheck::log_test_output();
67
68 # and disable Debug's die() and warn() overrides
69 Amanda::Debug::disable_die_override();
70
71 sub to_bytes {
72     my @result;
73     for my $byte (@_) {
74         if (length($byte) == 1) {
75             push @result, $byte;
76         } else {
77             push @result, chr(hex($byte));
78         }
79     }
80     return join('', @result);
81 }
82
83 sub to_hex {
84     my ($bytes) = @_;
85     my @result;
86     for my $byte (split //, $bytes) {
87         if ((ord($byte) >= ord('a') and ord($byte) <= ord('z')) || $byte eq '-') {
88             push @result, $byte;
89         } else {
90             push @result, sprintf("%02x", ord($byte));
91         }
92     }
93
94     return join(" ", @result);
95 }
96
97 # first, try reading a pre-defined sequence of bytes; this lets us make sure
98 # byte-ordering is right on all platforms.
99 my $fh;
100 my $tmpfile = "$Installcheck::TMP/ipc-binary-test";
101 my ($chan, $msg);
102
103 open($fh, ">", $tmpfile);
104 print $fh to_bytes(
105     qw(12 34), # magic
106     qw(00 01), # cmd_id = SIMPLE
107     qw(00 00 00 0A), # length
108     qw(00 00), # count
109
110     qw(12 34), # magic
111     qw(00 02), # cmd_id = FOO
112     qw(00 00 00 22), # length
113     qw(00 02), # n_args
114     qw(00 00 00 07), # length
115     qw(00 01), # arg_id = NAME
116     qw(n i k o l a s), # data
117     qw(00 00 00 05), # length
118     qw(00 02), # arg_id = NICKNAME
119     qw(a t r u s), # data
120
121     qw(12 34), # magic
122     qw(00 03), # cmd_id = BAR
123     qw(00 00 00 1f), # length
124     qw(00 01), # n_args
125     qw(00 00 00 0f), # length
126     qw(00 03), # arg_id = MANDATORY
127     qw(v e r b o d e n - v r u c h t), # data
128
129     qw(12 34), # magic
130     qw(00 03), # cmd_id = BAR
131     qw(00 00 00 29), # length
132     qw(00 02), # n_args
133     qw(00 00 00 0a), # length
134     qw(00 03), # arg_id = MANDATORY
135     qw(o u d e - g e u z e), # data
136     qw(00 00 00 09), # length
137     qw(00 04), # arg_id = OPTIONAL
138     qw(r o d e n b a c h), # data
139 );
140 close($fh);
141
142 open($fh, "<", $tmpfile);
143
144 $chan = TestProtocol->new();
145
146 $msg = $chan->read_message($fh);
147 is($msg->{'cmd_id'}, TestProtocol::SIMPLE,
148     "got SIMPLE");
149
150 $msg = $chan->read_message($fh);
151 is($msg->{'cmd_id'}, TestProtocol::FOO,
152     "got FOO");
153 is($msg->{'args'}[TestProtocol::NAME], "nikolas",
154     "got NAME arg");
155 is($msg->{'args'}[TestProtocol::NICKNAME], "atrus",
156     "got NICKNAME arg");
157
158 $msg = $chan->read_message($fh);
159 is($msg->{'cmd_id'}, TestProtocol::BAR,
160     "got BAR");
161 is($msg->{'args'}[TestProtocol::MANDATORY], "verboden-vrucht",
162     "got MANDATORY arg");
163 is($msg->{'args'}[TestProtocol::OPTIONAL], undef,
164     "got no OPTIONAL arg");
165
166 $msg = $chan->read_message($fh);
167 is($msg->{'cmd_id'}, TestProtocol::BAR,
168     "got BAR");
169 is($msg->{'args'}[TestProtocol::MANDATORY], "oude-geuze",
170     "got MANDATORY arg");
171 is($msg->{'args'}[TestProtocol::OPTIONAL], "rodenbach",
172     "got OPTIONAL arg");
173
174 $msg = $chan->read_message($fh);
175 is($msg, undef, "no more messages");
176
177 close($fh);
178
179 # now try writing a set of messages, and check that the result is what it should be
180 open($fh, ">", $tmpfile);
181 $chan = TestProtocol->new();
182
183 ok($chan->write_message($fh, $chan->message(
184         TestProtocol::FOO,
185         TestProtocol::NAME, "james",
186         TestProtocol::NICKNAME, "jimmy")),
187     "wrote FOO message");
188
189 ok($chan->write_message($fh, $chan->message(
190         TestProtocol::BAR,
191         TestProtocol::MANDATORY, "absolutely",
192         TestProtocol::OPTIONAL, "maybe")),
193     "wrote BAR message with optional arg");
194
195 ok($chan->write_message($fh, $chan->message(
196         TestProtocol::BAR,
197         TestProtocol::MANDATORY, "yessir")),
198     "wrote BAR message without optional arg");
199
200 $chan->close();
201 close($fh);
202
203 my $bytes_expected = to_bytes(
204     qw(12 34), # magic
205     qw(00 02), # cmd_id = FOO
206     qw(00 00 00 20), # length
207     qw(00 02), # n_args
208     qw(00 00 00 05), # length
209     qw(00 01), # arg_id = NAME
210     qw(j a m e s), # data
211     qw(00 00 00 05), # length
212     qw(00 02), # arg_id = NICKNAME
213     qw(j i m m y), # data
214
215     qw(12 34), # magic
216     qw(00 03), # cmd_id = BAR
217     qw(00 00 00 25), # length
218     qw(00 02), # n_args
219     qw(00 00 00 0a), # length
220     qw(00 03), # arg_id = MANDATORY
221     qw(a b s o l u t e l y), # data
222     qw(00 00 00 05), # length
223     qw(00 04), # arg_id = OPTIONAL
224     qw(m a y b e), # data
225
226     qw(12 34), # magic
227     qw(00 03), # cmd_id = BAR
228     qw(00 00 00 16), # length
229     qw(00 01), # n_args
230     qw(00 00 00 06), # length
231     qw(00 03), # arg_id = MANDATORY
232     qw(y e s s i r), # data
233 );
234
235 # slurp the contents of the temp file and see if it matches
236 open($fh, "<", $tmpfile);
237 my $bytes_written = do { local $/; <$fh> };
238 close($fh);
239
240 is(to_hex($bytes_written),
241    to_hex($bytes_expected),
242     "got the expected bytes");