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

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

Implemented higher level auth message passing (the receiver doesn't
need to know the message length). The client will use this mechanism to
send the private string. This is working with stand alone bbftp client/server.

Embedded bbftpd is broken until I make corresponding
changes to the python API.

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