source: TI05-delivery/trunk/test/test_embedded.py @ 1100

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

Python code on the server will now receive the private string from the
client. This is the basic requirement for doing bbftp authentication
within python.

Slightly higher level message passing functions ndg_message_send/recv are now
bound to python callbacks bbftpd.send and bbftpd.recv.

  • Property svn:executable set to *
Line 
1#!/usr/bin/env python
2"""
3Tests for the bbftp daemon when embedded in Python.
4
5@author: Stephen Pascoe
6@version: $Id$
7"""
8
9import unittest
10import sys, os, signal, time, syslog
11from glob import glob
12import re, tempfile
13
14HOME = os.path.abspath(os.getenv('NDG_DELIVERY_HOME', os.curdir))
15BUILDDIR = glob('%s/build/lib.*' % HOME)[0]
16BBFTP = glob('%s/src/bbftp-client*/bbftpc/bbftp' % HOME)[0]
17DATADIR = '%s/test/data' % HOME
18VERSION = open('%s/VERSION' % HOME).read()
19NDG_MESSAGE_LEN = 256
20
21NDG_HANDSHAKE = "NDG-Delivery-server %s" % VERSION
22
23sys.path.append(BUILDDIR)
24import bbftpd
25       
26class AuthzContext:
27    def __init__(self, version_msg, user):
28        self.version = version_msg
29        self.username = user
30
31class AuthContext:
32    def authorise(self):
33        # Read the auth version message
34        msg = bbftpd.recv()
35        # Trim to first '\0'
36        x = msg.find('\0')
37        if x:
38            msg = msg[:x]
39
40        syslog.syslog(syslog.LOG_DEBUG, 'AuthContext received Auth message: %s' % msg)
41
42        # Send the response
43        msg = NDG_HANDSHAKE + '\0' * (NDG_MESSAGE_LEN - len(NDG_HANDSHAKE))
44        bbftpd.send(msg)
45
46        # Get privatestr
47        privatestr = bbftpd.recv()
48        # Trim to first '\0'
49        x = privatestr.find('\0')
50        if x:
51            privatestr = privatestr[:x]
52        syslog.syslog(syslog.LOG_DEBUG, "AuthContext received privatestr: %s" % privatestr)
53
54        return AuthzContext(msg, "TestCaseUser")
55
56class EmbeddedServerTestCase(unittest.TestCase):
57    """Test the bbftpd module.
58    """
59   
60    def setUp(self):
61        # We want to mark the beginning of this test case in syslog
62        syslog.openlog('test_embedded.py', 0, syslog.LOG_LOCAL0)
63        syslog.syslog(syslog.LOG_DEBUG, 'Starting EmbeddedServerTestCase')
64
65        self._startServer()
66
67    def tearDown(self):
68        self._stopServer()
69        syslog.syslog(syslog.LOG_DEBUG, 'Ended EmbeddedServerTestCase')
70        syslog.closelog()
71
72    def testStartup(self):
73        lines = self._readSyslog()
74        # Give syslog time to flush it's logs.
75        time.sleep(1)
76        self.assert_(self._findLines(['.*Starting bbftpd'], lines))
77
78    def testDir(self):
79        """Try connecting the client and listing a directory.
80        """
81
82
83        fh = self._runClient("dir %s" % DATADIR)
84        output = fh.read()
85
86
87        self.assert_(self._findLines([r'dir .*/data', r' d .*/\.', r' d .*/\.\.',
88                                      r' f .*/foo', r' f .*/bar', r' f .*/baz'], output))       
89
90        lines = self._readSyslog()
91        self.assert_(self._findLines(['.*Getting new bbftp connexion.*',
92                                      r'.*Authz: MSG_LIST_V2 .*/test/data/\*.*',
93                                      r'.*User TestCaseUser disconnected.*'], lines))
94
95
96    def testHandshake(self):
97        """Verify handshake messages are exchanged.
98        """
99
100        fh = self._runClient("dir .", debug=True)
101        output = fh.read()
102
103        self.assert_(self._findLines(['Received Auth handshake: NDG-Delivery-server %s' % VERSION], output))
104
105        lines = self._readSyslog()
106        self.assert_(self._findLines(['.*AuthContext received Auth message: NDG-Delivery-client %s' % VERSION], lines))
107
108    def testPrivateStr(self):
109        """Verify the private string is sent to server.
110        """
111
112        fh = self._runClient("dir .", privatestr="testPrivateStr")
113        output = fh.read()
114
115        lines = self._readSyslog()
116        self.assert_(self._findLines(['.*AuthContext received privatestr: testPrivateStr'], lines))
117
118    def testRetr(self):
119        """Try retrieving a file.
120        """
121
122        tmp = tempfile.mktemp('test_bbftpd')
123        fh = self._runClient("get %s/foo %s" % (DATADIR, tmp))
124
125        # Check the client output
126        output = fh.read()
127        self.assert_(self._findLines(['get.*nogzip'], output))
128
129        # Check retrieved file
130        self.assert_(os.system('diff --brief %s/foo %s' % (DATADIR, tmp)) == 0)
131        os.remove(tmp)
132
133        # Check syslog
134        lines = self._readSyslog()
135        self.assert_(self._findLines(['.*Authz: RETR .*/foo', '.*GET TestCaseUser .*/foo.*'], lines))
136
137    def testStore(self):
138        """Try storing a file.
139        """
140
141
142        src = '%s/bar' % (DATADIR)
143        dest = '%s/new_bar' % (DATADIR)
144        os.system('cp %s %s' % (src, dest))
145        fh = self._runClient("put %s %s" % (src, dest))
146
147        # Check the client output
148        output = fh.read()
149        self.assert_(self._findLines(['put .* nogzip'], output))
150
151
152        # Check sent file
153        self.assert_(os.system('diff --brief %s %s' % (dest, src)) == 0)
154        os.remove(dest)
155
156        # Check syslog
157        lines = self._readSyslog()
158        self.assert_(self._findLines(['.*Authz: STORE .*/new_bar', '.*PUT TestCaseUser .*/new_bar.*'], lines))
159
160
161    #----------------------------------------------------------------------------------
162
163
164    def _startServer(self):
165        # Start the server and store it's PID
166        self.authContext = AuthContext()
167        self.pid = bbftpd.run(self.authContext, ['-l', 'DEBUG'])
168
169    def _stopServer(self):
170        # Stop the server process
171        os.kill(self.pid, signal.SIGTERM)
172        os.waitpid(self.pid, 0)
173        syslog.syslog(syslog.LOG_DEBUG, 'Stopping server')
174
175
176    def _runClient(self, cmd, debug=False, user="testcase", privatestr=None):
177        """Run the client.
178        """
179
180        if debug:
181            f = "-d"
182        else:
183            f = "-m"
184
185        if privatestr == None:
186            p = ""
187        else:
188            p = "-P %s" % repr(privatestr)
189       
190        fh = os.popen('%s %s %s -u %s -e %s localhost' % (BBFTP, f, p, user, repr(cmd)))
191        return fh
192
193
194    def _readSyslog(self, logfile="/var/log/bbftpd/bbftpd.log"):
195        """Get all bbftpd messages from syslog for this test case.
196
197        @note: This requires read access to the logfile
198        """
199
200        # Read the logfile into a buffer
201        log = open(logfile).readlines()
202
203        # Find the latest testcase marker
204        start_i = 0
205        for i in xrange(len(log)-1, -1, -1):
206            if re.search('test_embedded.py: Starting EmbeddedServerTestCase', log[i]):
207                start_i = i+1
208                break
209        if not start_i:
210            raise RuntimeError, "Can't find test case entry in syslog"
211
212        filtered_log = []
213        for line in log[start_i:]:
214            if re.search(r'test_bbftpd.py:|bbftpd .*:', line):
215                filtered_log.append(line)
216
217        return ''.join(filtered_log)
218
219
220    def _findLines(self, lines, string):
221        """Look for lines matching each regular expression in lines.
222       
223        @return: True if all lines are found, else False
224        """
225       
226        for line in lines:
227            if not re.search('^%s$' % line, string, re.M):
228                return False
229           
230        return True
231
232
233if __name__ == '__main__':
234    unittest.main()
Note: See TracBrowser for help on using the repository browser.