Check in very rough alpha version of Muse IPC server and ikiwiki test.
[muse-el.git] / contrib / ikiwiki / IkiWiki / Plugin / test.pl
blob8b015a86cee4ee7ba5df95a562909a9ccdd5b655
2 use warnings;
3 use strict;
5 use IO::Select qw();
6 use IO::Socket::INET qw();
8 my %config = (
9 muse_emacs => '/usr/local/bin/emacs',
10 muse_init => '/stuff/proj/personal-site/ikiwiki/muse-init.el',
11 muse_shared_secret => 'foo',
14 my %MUSE_SERVER = ( host => 'localhost' );
16 main();
17 exit 0;
19 # Determine the emacs binary to use
20 sub locate_emacs {
21 my $err = sub {
22 die "Unable to find your emacs binary.\n",
23 " Set muse_emacs config to the right value.\n";
25 if ( $config{muse_emacs} ) {
26 ( -x $config{muse_emacs} ) ? return $config{muse_emacs} : $err->();
28 else {
29 my $emacs = `which emacs`;
30 chomp $emacs;
31 ( $emacs ) ? return $emacs : $err->();
35 # Initialize connection to the Muse IPC server
36 sub start_muse_server {
37 my $secret = $config{muse_shared_secret};
38 my $init_port = $config{muse_init_port} || 0;
39 my $ipc_port = $config{muse_ipc_port};
41 # Perform sanity checks
42 $config{muse_init} or die "Error: muse_init config option not defined.\n";
44 # Start initialization server
45 my $pserver = IO::Socket::INET->new(
46 Proto => 'tcp',
47 LocalAddr => 'localhost',
48 LocalPort => $init_port,
49 Listen => IO::Socket::INET::SOMAXCONN,
50 ) or die "Error: Cannot begin initialization for the Muse IPC server.\n";
51 $pserver->autoflush(1);
52 $init_port = $pserver->sockport();
53 my $select = IO::Select->new($pserver);
55 # Start Emacs
56 defined(my $pid = fork()) or die "Error: Unable to fork.\n";
57 if ( $pid ) {
58 $MUSE_SERVER{pid} = $pid;
60 else {
61 exec locate_emacs(),
62 qw( -q --no-site-file -batch -l ), $config{muse_init},
63 qw( --eval ), "(muse-ikiwiki-start-server \"$init_port\"" .
64 ( $ipc_port ? " \"$ipc_port\"" : '' ) . ")";
65 die "Error: Unable to exec emacs.\n";
68 my $emacs_port = undef;
70 SERVER:
71 # Respond to clients
72 while ( my @ready = $select->can_read() ) {
73 for my $client (@ready) {
74 if ($client == $pserver) {
75 my $new = $pserver->accept();
76 $select->add($new);
77 next;
79 my $line = <$client>;
80 chomp $line if defined $line;
81 if ( defined $line && $line =~ m/^begin (.+)$/s &&
82 $1 eq $secret ) {
83 print $client "ok\n";
84 $line = <$client>;
85 chomp $line if defined $line;
86 if ( defined $line && $line =~ m/^port (.+)$/s ) {
87 $emacs_port = $1;
89 else {
90 print STDERR <<EOF;
91 Error: Invalid response while initializing Muse IPC server.
92 EOF
94 last SERVER;
96 print $client "nok\n" if $line;
97 $select->remove($client);
98 $client->close();
101 $pserver->close();
103 if ( $emacs_port ) {
104 $MUSE_SERVER{port} = $emacs_port;
106 else {
107 kill_muse_server();
111 sub stop_muse_server {
112 my ( $sock ) = @_;
114 if ( $MUSE_SERVER{pid} ) {
115 # Give Muse 3 seconds to stop, presuming that it has already
116 # been sent the "done" command via stop_muse_server.
117 local $SIG{ALRM} = sub {
118 kill 9, $MUSE_SERVER{pid};
119 die "Timeout";
121 eval {
122 alarm 3;
123 print $sock "done\n";
124 $sock->close();
125 waitpid($MUSE_SERVER{pid}, 0);
126 alarm 0;
128 delete $MUSE_SERVER{pid};
130 else {
131 print $sock "done\n";
132 $sock->close();
136 sub kill_muse_server {
137 my @msgs = @_;
139 kill 9, $MUSE_SERVER{pid} if $MUSE_SERVER{pid};
140 die @msgs if @msgs;
143 sub ipc_expect_ok {
144 my ( $sock, $err_msg ) = @_;
145 $err_msg = "Error: Command did not succeed on Muse IPC server.\n";
147 my $line = <$sock>;
148 chomp $line;
149 if ( $line ne 'ok' ) {
150 $sock->close();
151 kill_muse_server $err_msg;
155 sub ipc_connect {
156 my $secret = $config{muse_shared_secret};
157 my $host = $MUSE_SERVER{host};
158 my $port = $MUSE_SERVER{port};
159 $host && $port
160 or kill_muse_server "Error: No Muse IPC server is active.\n";
162 # Start client connection
163 my $sock = IO::Socket::INET->new(
164 Proto => 'tcp',
165 PeerAddr => $host,
166 PeerPort => $port,
167 ) or kill_muse_server "Error: Cannot connect to the Muse IPC server.\n";
168 $sock->autoflush(1);
170 # Authenticate
171 print $sock "begin $secret\n";
172 ipc_expect_ok $sock,
173 "Error: Could not authenticate to the Muse IPC server.\n";
175 return $sock;
178 sub test_name {
179 my ( $sock ) = @_;
181 print $sock "name foobar\n";
182 ipc_expect_ok $sock,
183 "Error: Could not set name of page on Muse IPC server.\n";
186 sub test_title {
187 my ( $sock ) = @_;
189 print $sock "title quux\n";
190 ipc_expect_ok $sock,
191 "Error: Could not set title of page on Muse IPC server.\n";
194 sub main {
195 print "Starting Muse server ...\n";
196 start_muse_server();
198 print "Got port $MUSE_SERVER{port}.\n";
199 my $sock = ipc_connect();
200 test_name($sock);
201 test_title($sock);
203 print "Shutting down ...\n";
204 stop_muse_server($sock);
205 print "Done shutting down.\n";