root/tags/release1_1_2/_mock_ftplib.py

Revision 182, 7.1 kB (checked in by schwa, 7 years ago)
MockSession.dir_contents: added entry for root directory.
  • Property svn:mime-type set to text/python
  • Property svn:eol-style set to native
Line 
1 # Copyright (C) 2001, Stefan Schwarzer
2 # All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
8 # - Redistributions of source code must retain the above copyright
9 #   notice, this list of conditions and the following disclaimer.
10 #
11 # - Redistributions in binary form must reproduce the above copyright
12 #   notice, this list of conditions and the following disclaimer in the
13 #   documentation and/or other materials provided with the distribution.
14 #
15 # - Neither the name of the above author nor the names of the
16 #   contributors to the software may be used to endorse or promote
17 #   products derived from this software without specific prior written
18 #   permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
24 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 # $Id: _mock_ftplib.py,v 1.20 2002/04/03 21:47:41 schwa Exp $
33
34 """
35 This module implements a mock version of the standard libraries
36 ftplib.py module. Some code is taken from there.
37
38 Not all functionality is implemented, only that which is used to
39 run the unit tests.
40 """
41
42 import ftplib
43 import StringIO
44
45 DEBUG = 0
46
47 # Use a global dictionary of the form {path: mock_file, ...}
48 #  to make "volatile" mock files accessible. This is used for
49 #  testing the contents of a file after an FTPHost.upload call.
50 mock_files = {}
51
52 def content_of(path):
53     return mock_files[path].getvalue()
54
55
56 class MockFile(StringIO.StringIO):
57     """
58     Mock class for the file objects _contained in_ _FTPFile
59     objects (not _FTPFile objects themselves!).
60
61     Unless StringIO.StringIO instances, MockFile objects can be
62     queried for their contents after been closed.
63     """
64     def __init__(self, path, content=''):
65         global mock_files
66         mock_files[path] = self
67         StringIO.StringIO.__init__(self, content)
68
69     def getvalue(self):
70         if not self.closed:
71             return StringIO.StringIO.getvalue(self)
72         else:
73             return self._value_after_close
74
75     def close(self):
76         if not self.closed:
77             self._value_after_close = StringIO.StringIO.getvalue(self)
78         StringIO.StringIO.close(self)
79
80
81 class MockSocket:
82     """
83     Mock class which is used to return something from
84     MockSession.transfercmd.
85     """
86     def __init__(self, path, mock_file_content=''):
87         if DEBUG:
88             print 'File content: *%s*' % mock_file_content
89         self.file_path = path
90         self.mock_file_content = mock_file_content
91
92     def makefile(self, mode):
93         return MockFile(self.file_path, self.mock_file_content)
94
95     def close(self):
96         pass
97
98
99 class MockSession:
100     """
101     Mock class which works like ftplib.FTP for the purpose of the
102     unit tests.
103     """
104     # used by MockSession.cwd and MockSession.pwd
105     current_dir = '/home/sschwarzer'
106
107     # used by MockSession.dir
108     dir_contents = {
109           '/': """\
110 drwxr-xr-x   2 45854    200           512 May  4  2000 home""",
111
112           '/home': """\
113 drwxr-sr-x   2 45854    200           512 May  4  2000 sschwarzer
114 -rw-r--r--   1 45854    200          4605 Jan 19  1970 older
115 -rw-r--r--   1 45854    200          4605 Jan 19  2020 newer
116 lrwxrwxrwx   1 45854    200            21 Jan 19  2002 link -> sschwarzer/index.html
117 lrwxrwxrwx   1 45854    200            15 Jan 19  2002 bad_link -> python/bad_link""",
118
119           '/home/python': """\
120 lrwxrwxrwx   1 45854    200             7 Jan 19  2002 link_link -> ../link
121 lrwxrwxrwx   1 45854    200            14 Jan 19  2002 bad_link -> /home/bad_link""",
122
123           '/home/sschwarzer': """\
124 total 14
125 drwxr-sr-x   2 45854    200           512 May  4  2000 chemeng
126 drwxr-sr-x   2 45854    200           512 Jan  3 17:17 download
127 drwxr-sr-x   2 45854    200           512 Jul 30 17:14 image
128 -rw-r--r--   1 45854    200          4604 Jan 19 23:11 index.html
129 drwxr-sr-x   2 45854    200           512 May 29  2000 os2
130 lrwxrwxrwx   2 45854    200             6 May 29  2000 osup -> ../os2
131 drwxr-sr-x   2 45854    200           512 May 25  2000 publications
132 drwxr-sr-x   2 45854    200           512 Jan 20 16:12 python
133 drwxr-sr-x   6 45854    200           512 Sep 20  1999 scios2"""}
134
135     # file content to be used (indirectly) with transfercmd
136     mock_file_content = ''
137
138     def __init__(self, host='', user='', password=''):
139         self.closed = 0
140         # count successful transfercmd invocations to ensure
141         #  that each has a corresponding voidresp
142         self._transfercmds = 0
143
144     def _remove_trailing_slash(self, path):
145         if path != '/' and path.endswith('/'):
146             path = path[:-1]
147         return path
148
149     def voidcmd(self, cmd):
150         if DEBUG:
151             print cmd
152         if cmd == 'STAT':
153             return 'MockSession server awaiting your commands ;-)'
154         elif cmd.startswith('TYPE '):
155             return
156         else:
157             raise ftplib.error_perm
158
159     def pwd(self):
160         return self.current_dir
161
162     def cwd(self, path):
163         path = self._remove_trailing_slash(path)
164         self.current_dir = path
165
166     def dir(self, path, callback=None):
167         "Provide a callback function with each line of a directory listing."
168         if DEBUG:
169             print 'dir: %s' % path
170         path = self._remove_trailing_slash(path)
171         if not self.dir_contents.has_key(path):
172             raise ftplib.error_perm
173         dir_lines = self.dir_contents[path].split('\n')
174         for line in dir_lines:
175             if callback is None:
176                 print line
177             else:
178                 callback(line)
179
180     def voidresp(self):
181         assert self._transfercmds == 1
182         self._transfercmds = self._transfercmds - 1
183         return '2xx'
184
185     def transfercmd(self, cmd):
186         """
187         Return a MockSocket object whose makefile method will return
188         a mock file object.
189         """
190         if DEBUG:
191             print cmd
192         # fail if attempting to read from/write to a directory
193         cmd, path = cmd.split()
194         path = self._remove_trailing_slash(path)
195         if self.dir_contents.has_key(path):
196             raise ftplib.error_perm
197         # fail if path isn't available (this name is hard-coded here
198         #  and has to be used for the corresponding tests)
199         if (cmd, path) == ('RETR', 'notthere'):
200             raise ftplib.error_perm
201         assert self._transfercmds == 0
202         self._transfercmds = self._transfercmds + 1
203         return MockSocket(path, self.mock_file_content)
204
205     def close(self):
206         if not self.closed:
207             self.closed = 1
208             assert self._transfercmds == 0
209
Note: See TracBrowser for help on using the browser.