home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / perl5 / Net / DBus / Test / MockConnection.pm next >
Encoding:
Perl POD Document  |  2006-02-19  |  9.0 KB  |  353 lines

  1. # -*- perl -*-
  2. #
  3. # Copyright (C) 2004-2005 Daniel P. Berrange
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18. #
  19. # $Id: MockConnection.pm,v 1.5 2006/02/03 13:30:14 dan Exp $
  20.  
  21. =pod
  22.  
  23. =head1 NAME
  24.  
  25. Net::DBus::Test::MockConnection - Fake a connection to the bus unit testing
  26.  
  27. =head1 SYNOPSIS
  28.  
  29.   use Net::DBus;
  30.  
  31.   my $bus = Net::DBus->test
  32.  
  33.   # Register a service, and the objec to be tested
  34.   use MyObject
  35.   my $service = $bus->export_service("org.example.MyService");
  36.   my $object = MyObject->new($service);
  37.  
  38.  
  39.   # Acquire the service & do tests
  40.   my $remote_service = $bus->get_service('org.example.MyService');
  41.   my $remote_object = $service->get_object("/org/example/MyObjct");
  42.  
  43.   # This traverses the mock connection, eventually
  44.   # invoking 'testSomething' on the $object above.
  45.   $remote_object->testSomething()
  46.  
  47. =head1 DESCRIPTION
  48.  
  49. This object provides a fake implementation of the L<Net::DBus::Binding::Connection>
  50. enabling a pure 'in-memory' message bus to be mocked up. This is intended to
  51. facilitate creation of unit tests for services which would otherwise need to 
  52. call out to other object on a live message bus. It is used as a companion to
  53. the L<Net::DBus::Test::MockObject> module which is how fake objects are to be
  54. provided on the fake bus.
  55.  
  56. =head1 METHODS
  57.  
  58. =over 4
  59.  
  60. =cut
  61.  
  62. package Net::DBus::Test::MockConnection;
  63.  
  64. use strict;
  65. use warnings;
  66.  
  67. use Net::DBus::Binding::Message::MethodReturn;
  68.  
  69. =item my $con = Net::DBus::Test::MockConnection->new()
  70.  
  71. Create a new mock connection object instance. It is not usually
  72. neccessary to create instances of this object directly, instead
  73. the C<test> method on the L<Net::DBus> object can be used to
  74. get a handle to a test bus.
  75.  
  76. =cut
  77.  
  78. sub new {
  79.     my $class = shift;
  80.     my $self = {};
  81.     
  82.     $self->{replies} = [];
  83.     $self->{signals} = [];
  84.     $self->{objects} = {};
  85.     $self->{objectTrees} = {};
  86.     $self->{filters} = [];
  87.     
  88.     bless $self, $class;
  89.     
  90.     return $self;
  91. }
  92.  
  93. =item $con->send($message)
  94.  
  95. Send a message over the mock connection. If the message is
  96. a method call, it will be dispatched straight to any corresponding
  97. mock object registered. If the mesage is an error or method return
  98. it will be made available as a return value for the C<send_with_reply_and_block>
  99. method. If the message is a signal it will be queued up for processing
  100. by the C<dispatch> method. 
  101.  
  102. =cut
  103.  
  104.  
  105. sub send {
  106.     my $self = shift;
  107.     my $msg = shift;
  108.     
  109.     if ($msg->isa("Net::DBus::Binding::Message::MethodCall")) {
  110.     $self->_call_method($msg);
  111.     } elsif ($msg->isa("Net::DBus::Binding::Message::MethodReturn") ||
  112.          $msg->isa("Net::DBus::Binding::Message::Error")) {
  113.     push @{$self->{replies}}, $msg;
  114.     } elsif ($msg->isa("Net::DBus::Binding::Message::Signal")) {
  115.     push @{$self->{signals}}, $msg;
  116.     } else {
  117.     die "unhandled type of message " . ref($msg);
  118.     }
  119. }
  120.  
  121.  
  122. =item $bus->request_name($service_name)
  123.  
  124. Pretend to send a request to the bus registering the well known 
  125. name specified in the C<$service_name> parameter. In reality
  126. this is just a no-op giving the impression that the name was
  127. successfully registered.
  128.  
  129. =cut
  130.  
  131. sub request_name {
  132.     my $self = shift;
  133.     my $name = shift;
  134.     my $flags = shift;
  135.     
  136.     # XXX do we care about this for test cases? probably not...
  137.     # ....famous last words
  138. }
  139.  
  140. =item my $reply = $con->send_with_reply_and_block($msg)
  141.  
  142. Send a message over the mock connection and wait for a
  143. reply. The C<$msg> should be an instance of C<Net::DBus::Binding::Message::MethodCall>
  144. and the return C<$reply> will be an instance of C<Net::DBus::Binding::Message::MethodReturn>.
  145. It is also possible that an error will be thrown, with
  146. the thrown error being blessed into the C<Net::DBus::Error>
  147. class.
  148.  
  149. =cut
  150.  
  151. sub send_with_reply_and_block {
  152.     my $self = shift;
  153.     my $msg = shift;
  154.     my $timeout = shift;
  155.     
  156.     $self->send($msg);
  157.     
  158.     if ($#{$self->{replies}} == -1) {
  159.     die "no reply for " . $msg->get_path . "->" . $msg->get_member . " received within timeout";
  160.     }
  161.     
  162.     my $reply = shift @{$self->{replies}};
  163.     if ($#{$self->{replies}} != -1) {
  164.     die "too many replies received";
  165.     }
  166.  
  167.     if (ref($reply) eq "Net::DBus::Binding::Message::Error") {
  168.     my $iter = $reply->iterator;
  169.     my $desc = $iter->get_string;
  170.     my $err = { name => $reply->get_error_name,
  171.             message => $desc };
  172.     bless $err, "Net::DBus::Error";
  173.     die $err;
  174.     }
  175.     return $reply;
  176. }
  177.  
  178. =item $con->dispatch;
  179.  
  180. Dispatches any pending messages in the incoming queue
  181. to their message handlers. This method should be called
  182. by test suites whenever they anticipate that there are
  183. pending signals to be dealt with.
  184.  
  185. =cut
  186.  
  187. sub dispatch {
  188.     my $self = shift;
  189.     
  190.     my @signals = @{$self->{signals}};
  191.     $self->{signals} = [];
  192.     foreach my $msg (@signals) {
  193.     foreach my $cb (@{$self->{filters}}) {
  194.         # XXX we should worry about return value...
  195.         &$cb($self, $msg);
  196.     }
  197.     }
  198. }
  199.  
  200. =item $con->add_filter($coderef);
  201.  
  202. Adds a filter to the connection which will be invoked whenever a
  203. message is received. The C<$coderef> should be a reference to a
  204. subroutine, which returns a true value if the message should be
  205. filtered out, or a false value if the normal message dispatch
  206. should be performed.
  207.  
  208. =cut
  209.  
  210. sub add_filter {
  211.     my $self = shift;
  212.     my $cb = shift;
  213.     
  214.     push @{$self->{filters}}, $cb;
  215. }
  216.  
  217. =item $bus->add_match($rule)
  218.  
  219. Register a signal match rule with the bus controller, allowing
  220. matching broadcast signals to routed to this client. In reality
  221. this is just a no-op giving the impression that the match was
  222. successfully registered.
  223.  
  224. =cut
  225.  
  226. sub add_match {
  227.     my $self = shift;
  228.     my $rule = shift;
  229.     
  230.     # XXX do we need to implement anything ? probably not 
  231.     # nada
  232. }
  233.  
  234. =item $bus->remove_match($rule)
  235.  
  236. Unregister a signal match rule with the bus controller, preventing
  237. further broadcast signals being routed to this client. In reality
  238. this is just a no-op giving the impression that the match was
  239. successfully unregistered.
  240.  
  241. =cut
  242.  
  243. sub remove_match {
  244.     my $self = shift;
  245.     my $rule = shift;
  246.     
  247.     # XXX do we need to implement anything ? probably not 
  248.     # nada
  249. }
  250.  
  251.  
  252. =item $con->register_object_path($path, \&handler)
  253.  
  254. Registers a handler for messages whose path matches
  255. that specified in the C<$path> parameter. The supplied
  256. code reference will be invoked with two parameters, the
  257. connection object on which the message was received,
  258. and the message to be processed (an instance of the
  259. C<Net::DBus::Binding::Message> class).
  260.  
  261. =cut
  262.  
  263. sub register_object_path {
  264.     my $self = shift;
  265.     my $path = shift;
  266.     my $code = shift;
  267.     
  268.     $self->{objects}->{$path} = $code;
  269. }
  270.  
  271. =item $con->register_fallback($path, \&handler)
  272.  
  273. Registers a handler for messages whose path starts with 
  274. the prefix specified in the C<$path> parameter. The supplied
  275. code reference will be invoked with two parameters, the
  276. connection object on which the message was received,
  277. and the message to be processed (an instance of the
  278. C<Net::DBus::Binding::Message> class).
  279.  
  280. =cut
  281.  
  282. sub register_fallback {
  283.     my $self = shift;
  284.     my $path = shift;
  285.     my $code = shift;
  286.     
  287.     $self->{objects}->{$path} = $code;
  288.     $self->{objectTrees}->{$path} = $code;
  289. }
  290.  
  291. =item $con->unregister_object_path($path)
  292.  
  293. Unregisters the handler associated with the object path C<$path>. The
  294. handler would previously have been registered with the C<register_object_path>
  295. or C<register_fallback> methods.
  296.  
  297. =cut
  298.  
  299. sub unregister_object_path {
  300.     my $self = shift;
  301.     my $path = shift;
  302.     
  303.     delete $self->{objects}->{$path};
  304. }
  305.  
  306. sub _call_method {
  307.     my $self = shift;
  308.     my $msg = shift;
  309.  
  310.     if (exists $self->{objects}->{$msg->get_path}) {
  311.     my $cb = $self->{objects}->{$msg->get_path};
  312.     &$cb($self, $msg);
  313.     } else {
  314.     foreach my $path (reverse sort { $a cmp $b } keys %{$self->{objectTrees}}) {
  315.         if ((index $msg->get_path, $path) == 0) {
  316.         my $cb = $self->{objects}->{$path};
  317.         &$cb($self, $msg);
  318.         return;
  319.         }
  320.     }
  321.     if ($msg->get_path eq "/org/freedesktop/DBus") {
  322.         if ($msg->get_member eq "GetNameOwner") {
  323.         my $reply = Net::DBus::Binding::Message::MethodReturn->new(call => $msg);
  324.         my $iter = $reply->iterator(1);
  325.         $iter->append(":1.1");
  326.         $self->send($reply);
  327.         }
  328.     }
  329.     }
  330. }
  331.  
  332. 1;
  333.  
  334. =pod
  335.  
  336. =back
  337.  
  338. =head1 BUGS
  339.  
  340. It doesn't completely replicate the API of L<Net::DBus::Binding::Connection>, 
  341. merely enough to make the high level bindings work in a test scenario.
  342.  
  343. =head1 SEE ALSO
  344.  
  345. L<Net::DBus>, L<Net::DBus::Test::MockObject>, L<Net::DBus::Binding::Connection>,
  346. L<http://www.mockobjects.com/Faq.html>
  347.  
  348. =head1 COPYRIGHT
  349.  
  350. Copyright 2005 Daniel Berrange <dan@berrange.com>
  351.  
  352. =cut
  353.