Merge lp:~jamesodhunt/upstart/bug-1221466+1222702 into lp:upstart

Proposed by James Hunt
Status: Merged
Merged at revision: 1549
Proposed branch: lp:~jamesodhunt/upstart/bug-1221466+1222702
Merge into: lp:upstart
Diff against target: 327 lines (+191/-43)
3 files modified
ChangeLog (+13/-0)
extra/upstart-file-bridge.c (+32/-8)
scripts/tests/test_pyupstart_session_init.py (+146/-35)
To merge this branch: bzr merge lp:~jamesodhunt/upstart/bug-1221466+1222702
Reviewer Review Type Date Requested Status
Dimitri John Ledkov Approve
Review via email: mp+184829@code.launchpad.net

Description of the change

* extra/upstart-file-bridge.c:
  - create_handler(): Use original_file() for directories
    (LP: #1221466, #1222702).
  - watched_dir_new(): Additional assert.
  - watched_file_new():
    - Additional assert.
    - Store original directory path in file object to ensure reliable
      matching for directories.
* scripts/tests/test_pyupstart_session_init.py: Added file bridge tests
  for directory creation, modification and deletion.

As expected, new tests in this branch fail with current upstart-file-bridge, but pass when using the updated version in this branch.

To post a comment you must log in.
Revision history for this message
Dimitri John Ledkov (xnox) wrote :

lgtm.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'ChangeLog'
--- ChangeLog 2013-08-23 14:49:09 +0000
+++ ChangeLog 2013-09-10 17:00:41 +0000
@@ -1,3 +1,16 @@
12013-09-10 James Hunt <james.hunt@ubuntu.com>
2
3 * extra/upstart-file-bridge.c:
4 - create_handler(): Use original_file() for directories
5 (LP: #1221466, #1222702).
6 - watched_dir_new(): Additional assert.
7 - watched_file_new():
8 - Additional assert.
9 - Store original directory path in file object to ensure reliable
10 matching for directories.
11 * scripts/tests/test_pyupstart_session_init.py: Added file bridge tests
12 for directory creation, modification and deletion.
13
12013-08-23 James Hunt <james.hunt@ubuntu.com>142013-08-23 James Hunt <james.hunt@ubuntu.com>
215
3 * NEWS: Release 1.1016 * NEWS: Release 1.10
417
=== modified file 'extra/upstart-file-bridge.c'
--- extra/upstart-file-bridge.c 2013-07-03 08:26:23 +0000
+++ extra/upstart-file-bridge.c 2013-09-10 17:00:41 +0000
@@ -177,8 +177,9 @@
177 *177 *
178 * @file: WatchedFile:178 * @file: WatchedFile:
179 *179 *
180 * Obtain the appropriate WatchedFile path: either the original if the180 * Obtain the appropriate WatchedFile path: the original if the
181 * path underwent expansion, else the initial unexpanded path.181 * path underwent expansion or is a directory, else the initial
182 * unexpanded path.
182 *183 *
183 * Required for emitting events since jobs need the unexpanded path to184 * Required for emitting events since jobs need the unexpanded path to
184 * allow their start/stop condition to match even if the path has185 * allow their start/stop condition to match even if the path has
@@ -261,6 +262,9 @@
261 * @parent: parent who is watching over us.262 * @parent: parent who is watching over us.
262 *263 *
263 * Details of the file being watched.264 * Details of the file being watched.
265 *
266 * For directories, @original contains the full path specified by the
267 * job and @path will contain @original, less any trailing slashes.
264 **/268 **/
265typedef struct watched_file {269typedef struct watched_file {
266 NihList entry;270 NihList entry;
@@ -855,7 +859,7 @@
855 *859 *
856 * Although technically fraudulent (the file might not have _just860 * Although technically fraudulent (the file might not have _just
857 * been created_ - it may have existed forever), it is necessary861 * been created_ - it may have existed forever), it is necessary
858 * since otherwise jobs will hang around wating for the file to862 * since otherwise jobs will hang around waiting for the file to
859 * be 'freshly-created'. However, although nih_watch_new() has863 * be 'freshly-created'. However, although nih_watch_new() has
860 * been told to run the create handler for pre-existing files864 * been told to run the create handler for pre-existing files
861 * that doesn't help as we don't watch the files, we watch865 * that doesn't help as we don't watch the files, we watch
@@ -986,10 +990,10 @@
986 * was modified.990 * was modified.
987 */991 */
988 if (file->events & IN_MODIFY)992 if (file->events & IN_MODIFY)
989 handle_event (handled, file->path, IN_MODIFY, path);993 handle_event (handled, original_path (file), IN_MODIFY, path);
990 } else if (! strcmp (file->path, path)) {994 } else if (! strcmp (file->path, path)) {
991 /* Directory has been created */995 /* Directory has been created */
992 handle_event (handled, file->path, IN_CREATE, NULL);996 handle_event (handled, original_path (file), IN_CREATE, NULL);
993 add_dir = TRUE;997 add_dir = TRUE;
994 nih_list_add (&entries, &file->entry);998 nih_list_add (&entries, &file->entry);
995 }999 }
@@ -1464,6 +1468,10 @@
14641468
1465 len = strlen (watched_path);1469 len = strlen (watched_path);
14661470
1471 /* Sanity-check */
1472 if (len <= 1)
1473 return NULL;
1474
1467 if (len > 1 && watched_path[len-1] == '/') {1475 if (len > 1 && watched_path[len-1] == '/') {
1468 /* Better to remove a trailing slash before handing to1476 /* Better to remove a trailing slash before handing to
1469 * inotify since although all works as expected, the1477 * inotify since although all works as expected, the
@@ -1570,18 +1578,34 @@
15701578
1571 len = strlen (path);1579 len = strlen (path);
15721580
1581 /* Sanity-check */
1582 if (len <= 1)
1583 return NULL;
1584
1585 /* Determine if the file is a directory */
1573 file->dir = (path[len-1] == '/');1586 file->dir = (path[len-1] == '/');
15741587
1575 /* optionally one or the other, but not both */1588 /* Optionally one or the other, but not both */
1576 if (file->dir || file->glob)1589 if (file->dir || file->glob)
1577 nih_assert (file->dir || file->glob);1590 nih_assert (file->dir || file->glob);
15781591
1579 file->path = nih_strdup (file, path);1592 /* Don't store the trailing slash for directories since that
1593 * confuses the logic and is redundant (due to file->dir).
1594 */
1595 file->path = nih_strndup (file, path, file->dir ? len-1 : len);
1580 if (! file->path)1596 if (! file->path)
1581 goto error;1597 goto error;
15821598
1583 file->original = NULL;1599 file->original = NULL;
1584 if (original) {1600
1601 if (file->dir) {
1602 /* Retain the original directory path to simplify event
1603 * matching.
1604 */
1605 file->original = nih_strndup (file, path, len);
1606 if (! file->original)
1607 goto error;
1608 } else if (original) {
1585 file->original = nih_strdup (file, original);1609 file->original = nih_strdup (file, original);
1586 if (! file->original)1610 if (! file->original)
1587 goto error;1611 goto error;
15881612
=== modified file 'scripts/tests/test_pyupstart_session_init.py'
--- scripts/tests/test_pyupstart_session_init.py 2013-08-06 16:54:28 +0000
+++ scripts/tests/test_pyupstart_session_init.py 2013-09-10 17:00:41 +0000
@@ -158,59 +158,170 @@
158 self.assertIsInstance(pid, int)158 self.assertIsInstance(pid, int)
159 os.kill(pid, 0)159 os.kill(pid, 0)
160160
161 # Create a job that makes use of the file event to watch to a161 target_dir = tempfile.mkdtemp()
162 file = target_dir + os.sep + 'foo'
163 dir = target_dir + os.sep + 'bar'
164
165 # Create a job that makes use of the file event to watch a
162 # file in a newly-created directory.166 # file in a newly-created directory.
163 dir = tempfile.mkdtemp()167 file_msg = 'got file %s' % file
164 file = dir + os.sep + 'foo'
165
166 msg = 'got file %s' % file
167 lines = []168 lines = []
168 lines.append('start on file FILE=%s EVENT=create' % file)169 lines.append('start on file FILE=%s EVENT=create' % file)
169 lines.append('exec echo %s' % msg)170 lines.append('exec echo %s' % file_msg)
170 create_job = self.upstart.job_create('wait-for-file-creation', lines)171 create_file_job = self.upstart.job_create('wait-for-file-creation', lines)
171 self.assertTrue(create_job)172 self.assertTrue(create_file_job)
172173
173 # Create empty file174 # Create job that waits for a file modification
174 open(file, 'w').close()175 lines = []
176 lines.append('start on file FILE=%s EVENT=modify' % file)
177 lines.append('exec echo %s' % file_msg)
178 modify_file_job = self.upstart.job_create('wait-for-file-modify', lines)
179 self.assertTrue(modify_file_job)
175180
176 # Create another job that triggers when the same file is deleted181 # Create another job that triggers when the same file is deleted
177 lines = []182 lines = []
178 lines.append('start on file FILE=%s EVENT=delete' % file)183 lines.append('start on file FILE=%s EVENT=delete' % file)
179 lines.append('exec echo %s' % msg)184 lines.append('exec echo %s' % file_msg)
180 delete_job = self.upstart.job_create('wait-for-file-deletion', lines)185 delete_file_job = self.upstart.job_create('wait-for-file-deletion', lines)
181 self.assertTrue(delete_job)186 self.assertTrue(delete_file_job)
187
188 # Create job that triggers on directory creation
189 dir_msg = 'got directory %s' % dir
190 lines = []
191 # XXX: note the trailing slash to force a directory watch
192 lines.append('start on file FILE=%s/ EVENT=create' % dir)
193 lines.append('exec echo %s' % dir_msg)
194 create_dir_job = self.upstart.job_create('wait-for-dir-creation', lines)
195 self.assertTrue(create_dir_job)
196
197 # Create job that triggers on directory modification
198 lines = []
199 # XXX: note the trailing slash to force a directory watch
200 lines.append('start on file FILE=%s/ EVENT=modify' % dir)
201 lines.append('exec echo %s' % dir_msg)
202 modify_dir_job = self.upstart.job_create('wait-for-dir-modify', lines)
203 self.assertTrue(modify_dir_job)
204
205 # Create job that triggers on directory deletion
206 lines = []
207 # XXX: note the trailing slash to force a directory watch
208 lines.append('start on file FILE=%s/ EVENT=delete' % dir)
209 lines.append('exec echo %s' % dir_msg)
210 delete_dir_job = self.upstart.job_create('wait-for-dir-delete', lines)
211 self.assertTrue(delete_dir_job)
212
213 # Create empty file
214 open(file, 'w').close()
215
216 # Create directory
217 os.mkdir(dir)
182218
183 # No need to start the jobs of course as the file-bridge handles that!219 # No need to start the jobs of course as the file-bridge handles that!
184220
185 # Identify full path to job logfiles221 # Identify full path to job logfiles
186 create_job_logfile = create_job.logfile_name(dbus_encode(''))222 create_file_job_logfile = create_file_job.logfile_name(dbus_encode(''))
187 self.assertTrue(create_job_logfile)223 self.assertTrue(create_file_job_logfile)
188224
189 delete_job_logfile = delete_job.logfile_name(dbus_encode(''))225 modify_file_job_logfile = modify_file_job.logfile_name(dbus_encode(''))
190 self.assertTrue(delete_job_logfile)226 self.assertTrue(modify_file_job_logfile)
191227
192 # Wait for the create job to run and produce output228 delete_file_job_logfile = delete_file_job.logfile_name(dbus_encode(''))
193 self.assertTrue(wait_for_file(create_job_logfile))229 self.assertTrue(delete_file_job_logfile)
194230
195 # Check the output231 create_dir_job_logfile = create_dir_job.logfile_name(dbus_encode(''))
196 with open(create_job_logfile, 'r', encoding='utf-8') as f:232 self.assertTrue(create_dir_job_logfile)
197 lines = f.readlines()233
198 self.assertTrue(len(lines) == 1)234 modify_dir_job_logfile = modify_dir_job.logfile_name(dbus_encode(''))
199 self.assertEqual(msg, lines[0].rstrip())235 self.assertTrue(modify_dir_job_logfile)
200236
201 shutil.rmtree(dir)237 delete_dir_job_logfile = delete_dir_job.logfile_name(dbus_encode(''))
238 self.assertTrue(delete_dir_job_logfile)
239
240 #--------------------
241
242 # Wait for the create file job to run and produce output
243 self.assertTrue(wait_for_file(create_file_job_logfile))
244
245 # Check the output
246 with open(create_file_job_logfile, 'r', encoding='utf-8') as f:
247 lines = f.readlines()
248 self.assertTrue(len(lines) == 1)
249 self.assertEqual(file_msg, lines[0].rstrip())
250
251 #--------------------
252
253 # Wait for the create directory job to run and produce output
254 self.assertTrue(wait_for_file(create_dir_job_logfile))
255
256 # Check the output
257 with open(create_dir_job_logfile, 'r', encoding='utf-8') as f:
258 lines = f.readlines()
259 self.assertTrue(len(lines) == 1)
260 self.assertEqual(dir_msg, lines[0].rstrip())
261
262 #--------------------
263
264 # Modify the file
265 open(file, 'w').close()
266
267 # Wait for the create file job to run and produce output
268 self.assertTrue(wait_for_file(modify_file_job_logfile))
269
270 # Check the output
271 with open(modify_file_job_logfile, 'r', encoding='utf-8') as f:
272 lines = f.readlines()
273 self.assertTrue(len(lines) == 1)
274 self.assertEqual(file_msg, lines[0].rstrip())
275
276 #--------------------
277 # Modify the directory by creating a new file in it.
278
279 dir_file = dir + os.sep + 'baz'
280 open(dir_file, 'w').close()
281
282 # Wait for the modify directory job to run and produce output
283 self.assertTrue(wait_for_file(modify_dir_job_logfile))
284
285 # Check the output
286 with open(modify_dir_job_logfile, 'r', encoding='utf-8') as f:
287 lines = f.readlines()
288 self.assertTrue(len(lines) == 1)
289 self.assertEqual(dir_msg, lines[0].rstrip())
290
291 #--------------------
292
293 os.remove(dir_file)
294 os.rmdir(dir)
295
296 # Wait for the delete directory job to run and produce output
297 self.assertTrue(wait_for_file(delete_dir_job_logfile))
298
299 # Check the output
300 with open(delete_dir_job_logfile, 'r', encoding='utf-8') as f:
301 lines = f.readlines()
302 self.assertTrue(len(lines) == 1)
303 self.assertEqual(dir_msg, lines[0].rstrip())
304 #--------------------
305
306 shutil.rmtree(target_dir)
202307
203 # Wait for the delete job to run and produce output308 # Wait for the delete job to run and produce output
204 self.assertTrue(wait_for_file(delete_job_logfile))309 self.assertTrue(wait_for_file(delete_file_job_logfile))
205310
206 # Check the output311 # Check the output
207 with open(delete_job_logfile, 'r', encoding='utf-8') as f:312 with open(delete_file_job_logfile, 'r', encoding='utf-8') as f:
208 lines = f.readlines()313 lines = f.readlines()
209 self.assertTrue(len(lines) == 1)314 self.assertTrue(len(lines) == 1)
210 self.assertEqual(msg, lines[0].rstrip())315 self.assertEqual(file_msg, lines[0].rstrip())
211316
212 os.remove(create_job_logfile)317 #--------------------
213 os.remove(delete_job_logfile)318
319 os.remove(create_file_job_logfile)
320 os.remove(modify_file_job_logfile)
321 os.remove(delete_file_job_logfile)
322 os.remove(create_dir_job_logfile)
323 os.remove(modify_dir_job_logfile)
324 os.remove(delete_dir_job_logfile)
214325
215 file_bridge.stop()326 file_bridge.stop()
216 self.stop_session_init()327 self.stop_session_init()

Subscribers

People subscribed via source and target branches