source: TI05-delivery/trunk/test/test_bbftpd.py @ 1064

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/trunk/test/test_bbftpd.py@1064
Revision 1064, 6.6 KB checked in by spascoe, 13 years ago (diff)

A python module which provides a function to start the daemon can be
built using the setup.py script. This method of invoking the server
has been briefly tested but no test cases yet.

I've taken out the initialisation/finalisation hooks from the auth API because
we shouldn't need them now. They were written assuming the python interpretter
was going to be embedded within bbftpd, but I've inverted the embedding by
wrapping bbftpd.c:main in a python extension function.

  • Property svn:executable set to *
Line 
1#!/usr/bin/env python
2"""
3Tests for the bbftp daemon.
4
5@author: Stephen Pascoe
6@version: $Id$
7"""
8
9import unittest
10import os, signal, time, syslog
11from glob import glob
12import re, tempfile
13
14class ExtendedAPITestCase(unittest.TestCase):
15    """Test the basic bbftp private authentication API with stub extensions.
16
17    This test case runs bbftpd without python embedding and checks the auth API
18    is being called correctly.
19    """
20
21    def setUp(self):
22        self._getPaths()
23        # Check bbftpd isn't running
24        if self._getServerPids():
25            raise RuntimeError, 'A bbftpd process is already running'
26
27        # We want to mark the beginning of this test case in syslog
28        syslog.openlog('test_bbftpd.py', 0, syslog.LOG_LOCAL0)
29        syslog.syslog(syslog.LOG_DEBUG, 'Starting ExtendedAPITestCase')
30       
31    def tearDown(self):
32        syslog.syslog(syslog.LOG_DEBUG, 'Ended ExtendedAPITestCase')
33        syslog.closelog()
34
35    def testStartup(self):
36        """Start and stop the server.
37        """
38        try:
39            self._startServer()
40            pid = self._getServerPid()
41            self._stopServer(pid)
42        except Exception, e:
43            self.fail(e)
44
45    def testStartupWithSyslog(self):
46        """Start and stop the server, check syslog for INFO entries.
47        """
48        try:
49            self._startServer()
50            pid = self._getServerPid()
51            self._stopServer(pid)
52
53            lines = self._readSyslog()
54        except Exception, e:
55            self.fail(e)
56
57        self.assert_(self._findLines(['.*Starting bbftpd in background mode'], lines))
58
59    def testDir(self):
60        """Try connecting the client and listing a directory.
61        """
62
63        self._startServer()
64        pid = self._getServerPid()
65
66        fh = self._runClient('-e "dir %s"' % self.DATADIR)
67        output = fh.read()
68
69        self._stopServer(pid)
70
71        self.assert_(self._findLines([r'dir .*/data', r' d .*/\.', r' d .*/\.\.',
72                                      r' f .*/foo', r' f .*/bar', r' f .*/baz'], output))       
73
74        lines = self._readSyslog()
75        self.assert_(self._findLines(['.*Getting new bbftp connexion.*',
76                                      '.*Received auth message: NDG-bbFTP.*',
77                                      r'.*Authz: MSG_LIST_V2 .*/test/data/\*.*',
78                                      r'.*User  disconnected.*'], lines))
79       
80    def testRetr(self):
81        """Try retrieving a file.
82        """
83
84        self._startServer()
85        pid = self._getServerPid()
86
87        tmp = tempfile.mktemp('test_bbftpd')
88        fh = self._runClient('-e "get %s/foo %s"' % (self.DATADIR, tmp))
89
90        # Check the client output
91        output = fh.read()
92        self.assert_(self._findLines(['get.*nogzip'], output))
93
94        self._stopServer(pid)
95
96        # Check retrieved file
97        self.assert_(os.system('diff --brief %s/foo %s' % (self.DATADIR, tmp)) == 0)
98        os.remove(tmp)
99
100        # Check syslog
101        lines = self._readSyslog()
102        self.assert_(self._findLines(['.*Authz: RETR .*/foo', '.*GET .*/foo.*'], lines))
103
104    def testStore(self):
105        """Try storing a file.
106        """
107
108        self._startServer()
109        pid = self._getServerPid()
110
111        src = '%s/bar' % (self.DATADIR)
112        dest = '%s/new_bar' % (self.DATADIR)
113        os.system('cp %s %s' % (src, dest))
114        fh = self._runClient('-e "put %s %s"' % (src, dest))
115
116        # Check the client output
117        output = fh.read()
118        self.assert_(self._findLines(['put .* nogzip'], output))
119
120        self._stopServer(pid)
121
122        # Check sent file
123        self.assert_(os.system('diff --brief %s %s' % (dest, src)) == 0)
124        os.remove(dest)
125
126        # Check syslog
127        lines = self._readSyslog()
128        self.assert_(self._findLines(['.*Authz: STORE .*/new_bar', '.*PUT .*/new_bar.*'], lines))
129
130    #------------------------------------------------------------------------------
131           
132    def _getPaths(self):
133        """Find the server executable and any other important files.
134        """
135        self.HOME = os.path.abspath(os.getenv('NDG_DELIVERY_HOME', os.curdir))
136        try:
137            self.BBFTPD = glob('%s/src/bbftp-server*/bbftpd/bbftpd' % self.HOME)[0]
138        except IndexError:
139            raise RuntimeError, 'Cannot find bbftpd executable'
140        try:
141            self.BBFTP = glob('%s/src/bbftp-client*/bbftpc/bbftp' % self.HOME)[0]
142        except:
143            raise RuntimeError, 'Cannot find bbftp executable'
144        dd = '%s/test/data' % self.HOME
145        if os.path.exists(dd):
146            self.DATADIR = dd
147        else:
148            raise RuntimeError, 'Cannot find test data directory'
149
150    def _startServer(self):
151        os.system('%s -b -l DEBUG' % self.BBFTPD)
152
153    def _getServerPids(self):
154        pids = os.popen('ps -C bbftpd -o %p --no-headers').readlines()
155        return [int(x.strip()) for x in pids]
156
157    def _getServerPid(self):
158        return self._getServerPids()[0]
159
160    def _stopServer(self, pid):
161        os.kill(pid, signal.SIGTERM)
162        # Wait upto 5 seconds for the server to stop
163        for x in range(10):
164            if pid not in self._getServerPids():
165                return
166            time.sleep(0.5)
167        raise RuntimeError, 'Failed to stop server'
168
169    def _readSyslog(self, logfile="/var/log/bbftpd/bbftpd.log"):
170        """Get all bbftpd messages from syslog for this test case.
171
172        @note: This requires read access to the logfile
173        """
174
175        # Read the logfile into a buffer
176        log = open(logfile).readlines()
177
178        # Find the latest testcase marker
179        start_i = 0
180        for i in xrange(len(log)-1, -1, -1):
181            if re.search('test_bbftpd.py: Starting ExtendedAPITestCase', log[i]):
182                start_i = i+1
183                break
184        if not start_i:
185            raise RuntimeError, "Can't find test case entry in syslog"
186
187        filtered_log = []
188        for line in log[start_i:]:
189            if re.search(r'test_bbftpd.py:|bbftpd .*:', line):
190                filtered_log.append(line)
191
192        return ''.join(filtered_log)
193
194    def _runClient(self, *args):
195        """Run the client with th -m option and return a file handle of the output.
196        """
197        fh = os.popen('%s -m -u testcase %s localhost' % (self.BBFTP, ' '.join(args)))
198        return fh
199
200    def _findLines(self, lines, string):
201        """Look for lines matching each regular expression in lines.
202       
203        @return: True if all lines are found, else False
204        """
205       
206        for line in lines:
207            if not re.search('^%s$' % line, string, re.M):
208                return False
209           
210        return True
211
212
213if __name__ == '__main__':
214    unittest.main()
Note: See TracBrowser for help on using the repository browser.