Merge lp:~xnox/upstart/overrides into lp:upstart

Proposed by Dimitri John Ledkov on 2013-01-04
Status: Merged
Merged at revision: 1423
Proposed branch: lp:~xnox/upstart/overrides
Merge into: lp:upstart
Diff against target: 814 lines (+484/-160)
4 files modified
ChangeLog (+8/-0)
init/conf.c (+212/-157)
init/tests/test_conf.c (+119/-1)
init/tests/test_conf_static.c (+145/-2)
To merge this branch: bzr merge lp:~xnox/upstart/overrides
Reviewer Review Type Date Requested Status
James Hunt 2013-01-04 Approve on 2013-01-08
Review via email: mp+141914@code.launchpad.net

Description of the change

This branch implements override files from any directory as specified here [1].

Instead of checking for a known path to .override file, a helper function `conf_get_best_override' is used that iterates across conf_sources and looks for the first .override file.

Next, I refactored another helper function conf_load_path_with_override that: loads a conf file, finds best override file for it & if found, applies it.

For the handlers we now have the following logic:
- if a .conf file is created/modified: simply call conf_load_path_with_override.
- if a .override file is created/modified/deleted: iterate across all conf_sources, check for "matching" .conf file and reload it with conf_load_path_with_override.
- if a .conf file is deleted: the behaviour is the same, unref the file from the ConfSource.

For system init, there shouldn't be much performance impact since there is only one directory to do lookups in.

For session init, most jobs will be in the lowest priority config_source. Thus resulting in lstat call in each config_source for each job to check for an .override file. But in practice, those higher priority config_sources may not even exist and lstat calls on non-existing directories is cheap. Potentially this can be micro-optimised by storing hashes of all found .override files while walking the config_sources and then instead of lstat check do a hash lookup...

[1] https://wiki.ubuntu.com/FoundationsTeam/Specs/RaringUpstartUserSessions#Configuration_Files_for_User_Jobs

To post a comment you must log in.
James Hunt (jamesodhunt) wrote :

Hi Dmitrijs,

* Changelog: Need extra indent for 'priority' and 'correctly'.
* init/conf.c:
  - Might just as well add ',2013' to copyright now :)
  - conf_to_job_name():
    - Typo: 'ConfigSource' should be 'ConfSource'.
    - Typo: 'from then' should be 'from the'.
    - You could drop the braces for the final if/else test, but they
      were there originally I guess :)
  - conf_get_best_override():
    - Typo: '& finds the' should be '& find the'.
    - Typo: 'for override file' should be 'for override files'.
    - Typo: 'ConfigSource' should be 'ConfSource'.
    - @name and @last_source are not asserted.
    - Using lstat(2) seems correct since we don't support symlinks on
      purpose, but conf_source_reload_file() is still using stat(2) so
      there is a discrepancy.
  - conf_load_path_with_override():
    - Need space around '=' in initial assignments.
    - 'if (override_path)' at line 818 technically redundant since we already know it
      cannot be NULL.
  - conf_create_modify_handler():
    - Missing check on return from nih_sprintf().
  - conf_delete_handler():
    - Typo: 'overide' rather than 'override'.

Regarding your comments on the lstat issue, we need to keep an eye on this. As you say, the impact should not be great, but it would still be worth performing some tests on a slow system to see if the new code makes any appreciable difference to performance.

review: Needs Fixing
lp:~xnox/upstart/overrides updated on 2013-01-08
1424. By Dimitri John Ledkov on 2013-01-08

Review comments

Dimitri John Ledkov (xnox) wrote :

Addressed all comments.
Checking return status of nih_sprintf with NIH_MUST.
Converted conf_source_reload_file to use lstat as well.

lp:~xnox/upstart/overrides updated on 2013-01-08
1425. By Dimitri John Ledkov on 2013-01-08

;

James Hunt (jamesodhunt) wrote :

Thanks. LGTM - merged!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ChangeLog'
2--- ChangeLog 2012-12-18 09:02:24 +0000
3+++ ChangeLog 2013-01-08 16:18:21 +0000
4@@ -1,3 +1,11 @@
5+2013-01-04 Dmitrijs Ledkovs <xnox@ubuntu.com>
6+
7+ * init/conf.c: add ability to apply override files from higher
8+ priority configuration sources.
9+ * init/tests/test_conf.c: test that multiple override files are
10+ correctly applied and removed.
11+ * init/tests/test_conf_static.c: test override file detection.
12+
13 2012-12-17 James Hunt <james.hunt@ubuntu.com>
14
15 * init/man/init.5: Document that User Jobs are not supported
16
17=== modified file 'init/conf.c'
18--- init/conf.c 2012-12-19 12:46:46 +0000
19+++ init/conf.c 2013-01-08 16:18:21 +0000
20@@ -2,7 +2,7 @@
21 *
22 * conf.c - configuration management
23 *
24- * Copyright © 2009,2010,2011 Canonical Ltd.
25+ * Copyright © 2009,2010,2011,2012,2013 Canonical Ltd.
26 * Author: Scott James Remnant <scott@netsplit.com>.
27 *
28 * This program is free software; you can redistribute it and/or modify
29@@ -86,6 +86,14 @@
30 static inline char *toggle_conf_name (const void *parent, const char *path)
31 __attribute__ ((warn_unused_result, malloc));
32
33+static inline char * conf_to_job_name (const char *source_path,
34+ const char *conf_path)
35+ __attribute__ ((malloc, warn_unused_result));
36+
37+static char * conf_get_best_override (const char *name,
38+ const ConfSource *last_source)
39+ __attribute__ ((malloc, warn_unused_result));
40+
41 /**
42 * conf_sources:
43 *
44@@ -110,6 +118,8 @@
45 static inline int
46 is_conf_file_std (const char *path)
47 {
48+ nih_assert (path != NULL);
49+
50 char *ptr = strrchr (path, '.');
51
52 if (ptr && IS_CONF_EXT_STD (ptr))
53@@ -132,6 +142,8 @@
54 static inline int
55 is_conf_file_override (const char *path)
56 {
57+ nih_assert (path != NULL);
58+
59 char *ptr = strrchr (path, '.');
60
61 if (ptr && IS_CONF_EXT_OVERRIDE (ptr))
62@@ -154,6 +166,8 @@
63 static inline int
64 is_conf_file (const char *path)
65 {
66+ nih_assert (path != NULL);
67+
68 char *ptr = strrchr (path, '.');
69
70 if (ptr && (ptr > path) && (ptr[-1] != '/') && IS_CONF_EXT (ptr))
71@@ -163,6 +177,99 @@
72 }
73
74 /**
75+ * conf_to_job_name:
76+ * @source_path: path to ConfSource
77+ * @conf_path: path to configuration file
78+ *
79+ * Constructs the job name for a given @conf_path. Removes
80+ * @source_path directory name from the front of @conf_path and
81+ * extension from the end.
82+ *
83+ * Returns: newly-allocated name.
84+ *
85+ **/
86+static inline char *
87+conf_to_job_name (const char * source_path, const char * conf_path)
88+{
89+ const char *start, *end;
90+ char *name = NULL;
91+ int source_len;
92+
93+ nih_assert (source_path != NULL);
94+ nih_assert (conf_path != NULL);
95+
96+ start = conf_path;
97+ source_len = strlen (source_path);
98+
99+ if (! strncmp (start, source_path, source_len))
100+ start += source_len;
101+
102+ while (*start == '/')
103+ start++;
104+
105+ end = strrchr (start, '.');
106+ if (end && IS_CONF_EXT (end))
107+ name = NIH_MUST (nih_strndup (NULL, start, end - start));
108+ else
109+ name = NIH_MUST (nih_strdup (NULL, start));
110+
111+ return name;
112+}
113+
114+
115+/**
116+ * conf_get_best_override:
117+ * @conf_file: conf_file object
118+ *
119+ * Given a @conf_file iterate over all config sources & find the
120+ * first applicable override file. It will not look for override files
121+ * beyond the @conf_file's ConfSource.
122+ *
123+ * Returns: newly allocated path to override file or NULL.
124+ **/
125+static char *
126+conf_get_best_override (const char *name, const ConfSource *last_source)
127+{
128+ char *try_path=NULL;
129+ struct stat statbuf;
130+
131+ nih_assert (name != NULL);
132+ nih_assert (last_source != NULL);
133+
134+ NIH_LIST_FOREACH (conf_sources, iter) {
135+
136+ ConfSource *source = (ConfSource *)iter;
137+
138+ /* Look at directories only */
139+ if (source->type == CONF_FILE)
140+ continue;
141+
142+ /* Reclaim memory */
143+ if (try_path)
144+ nih_free (try_path);
145+
146+ /* construct path */
147+ try_path = NIH_MUST (nih_sprintf (NULL, "%s/%s%s", source->path, name, CONF_EXT_OVERRIDE));
148+
149+ /* Found it! */
150+ if (lstat (try_path, &statbuf) == 0 && S_ISREG (statbuf.st_mode))
151+ return try_path;
152+
153+ /* Warning, you have reached the end of the conveyor!
154+ * Ignore overrides beyond .conf itself.
155+ */
156+ if (source == last_source)
157+ break;
158+ }
159+
160+ if (try_path)
161+ nih_free (try_path);
162+
163+ return NULL;
164+}
165+
166+
167+/**
168 * Convert a configuration file name to an override file name and vice
169 * versa.
170 *
171@@ -511,7 +618,7 @@
172
173 override_path = toggle_conf_name (NULL, source->path);
174
175- if (stat (override_path, &statbuf) != 0)
176+ if (lstat (override_path, &statbuf) != 0)
177 return 0;
178
179 nih_debug ("Updating configuration for %s from %s",
180@@ -670,6 +777,66 @@
181 }
182
183 /**
184+ * conf_load_path_with_override:
185+ * @source: configuration source
186+ * @conf_path: path to config file
187+ *
188+ * Loads given @conf_path as a config file in a given @source. Then it
189+ * finds an override file. If an override file is found it applies it
190+ * as well.
191+ **/
192+static void
193+conf_load_path_with_override (ConfSource *source,
194+ const char *conf_path)
195+{
196+ int ret = 0;
197+ const char *error_path = NULL;
198+ char *override_path = NULL;
199+ nih_local char *job_name = NULL;
200+
201+ nih_assert (source != NULL);
202+ nih_assert (conf_path != NULL);
203+
204+ /* reload conf file */
205+ nih_debug ("Loading configuration file %s", conf_path);
206+ ret = conf_reload_path (source, conf_path, NULL);
207+ if (ret < 0) {
208+ error_path = conf_path;
209+ goto error;
210+ }
211+
212+ job_name = conf_to_job_name (source->path, conf_path);
213+ override_path = conf_get_best_override (job_name, source);
214+ if (! override_path)
215+ return;
216+
217+ /* overlay override settings */
218+ nih_debug ("Loading override file %s for %s", conf_path, override_path);
219+ ret = conf_reload_path (source, conf_path, override_path);
220+ if (ret < 0) {
221+ error_path = override_path;
222+ goto error;
223+ }
224+ nih_free (override_path);
225+ return;
226+
227+error:
228+ {
229+ NihError *err;
230+
231+ err = nih_error_get ();
232+ nih_error ("%s: %s: %s", error_path,
233+ _("Error while loading configuration file"),
234+ err->message);
235+ nih_free (err);
236+ if (override_path)
237+ nih_free (override_path);
238+ return;
239+ }
240+}
241+
242+
243+/**
244 * conf_create_modify_handler:
245 * @source: configuration source,
246 * @watch: NihWatch for source,
247@@ -693,85 +860,45 @@
248 struct stat *statbuf)
249 {
250 ConfFile *file = NULL;
251- const char *error_path = path;
252- nih_local char *new_path = NULL;
253- int ret;
254+ char *config_path = NULL;
255+ nih_local char *job_name = NULL;
256
257 nih_assert (source != NULL);
258 nih_assert (watch != NULL);
259 nih_assert (path != NULL);
260- nih_assert (statbuf != NULL);
261
262 /* note that symbolic links are ignored */
263- if (! S_ISREG (statbuf->st_mode))
264- return;
265-
266- new_path = toggle_conf_name (NULL, path);
267- file = (ConfFile *)nih_hash_lookup (source->files, new_path);
268-
269- if (is_conf_file_override (path)) {
270- if (! file) {
271- /* override file has no corresponding conf file */
272- nih_debug ("Ignoring orphan override file %s", path);
273- return;
274- }
275-
276- /* reload conf file */
277- nih_debug ("Loading configuration file %s", new_path);
278- ret = conf_reload_path (source, new_path, NULL);
279- if (ret < 0) {
280- error_path = new_path;
281- goto error;
282- }
283-
284- /* overlay override settings */
285- nih_debug ("Loading override file %s for %s", path, new_path);
286- ret = conf_reload_path (source, new_path, path);
287- if (ret < 0) {
288- error_path = path;
289- goto error;
290- }
291- } else {
292- nih_debug ("Loading configuration and override files for %s", path);
293-
294- /* load conf file */
295- nih_debug ("Loading configuration file %s", path);
296- ret = conf_reload_path (source, path, NULL);
297- if (ret < 0) {
298- error_path = path;
299- goto error;
300- }
301-
302- /* ensure we ignore directory changes (which won't have overrides. */
303- if (is_conf_file_std (path)) {
304- struct stat st;
305- if (stat (new_path, &st) == 0) {
306- /* overlay override settings */
307- nih_debug ("Loading override file %s for %s", new_path, path);
308- ret = conf_reload_path (source, path, new_path);
309- if (ret < 0) {
310- error_path = new_path;
311- goto error;
312- }
313- }
314-
315- }
316+ if (statbuf && ! S_ISREG (statbuf->st_mode))
317+ return;
318+
319+ /* ignore non-config file changes */
320+ if (! is_conf_file (path))
321+ return;
322+
323+ /* For config file, load it and it's override file */
324+ if (is_conf_file_std (path)) {
325+ conf_load_path_with_override (source, path);
326+ return;
327+ }
328+
329+ /* For override files, reload all matching conf+override combos */
330+ job_name = conf_to_job_name (source->path, path);
331+ NIH_LIST_FOREACH (conf_sources, iter) {
332+ ConfSource *source = (ConfSource *)iter;
333+
334+ if (source->type == CONF_FILE)
335+ continue;
336+
337+ config_path = NIH_MUST (nih_sprintf (NULL, "%s/%s%s", source->path, job_name, CONF_EXT_STD));
338+ file = (ConfFile *)nih_hash_lookup (source->files, config_path);
339+ if (file) {
340+ /* Find its override file and reload both */
341+ conf_load_path_with_override (source, config_path);
342+ }
343+ nih_free (config_path);
344 }
345
346 return;
347-
348-error:
349- {
350- NihError *err;
351-
352- err = nih_error_get ();
353- nih_error ("%s: %s: %s", error_path,
354- _("Error while loading configuration file"),
355- err->message);
356- nih_free (err);
357- if (file)
358- nih_unref (file, source);
359- }
360 }
361
362 /**
363@@ -823,28 +950,19 @@
364
365 /* non-override files (and directories) are the simple case, so handle
366 * them and leave.
367- */
368+ */
369 if (! is_conf_file_override (path)) {
370 nih_unref (file, source);
371 return;
372 }
373
374- /* if an override file is deleted for which there is a corresponding
375- * conf file, reload the conf file to remove any modifications
376- * introduced by the override file.
377+ /* Deleting override file is about the same as changing one.
378+ * We need to iterate across all matching jobs and reload them
379+ * with new "best" override file, if any.
380 */
381- new_path = toggle_conf_name (NULL, path);
382- file = (ConfFile *)nih_hash_lookup (source->files, new_path);
383-
384- if (file) {
385- nih_debug ("Reloading configuration for %s on deletion of overide (%s)",
386- new_path, path);
387-
388- if ( conf_reload_path (source, new_path, NULL) < 0 ) {
389- nih_warn ("%s: %s", new_path,
390- _("Unable to reload configuration after override deletion"));
391- }
392- }
393+ nih_debug ("Reloading configuration for matching configs on deletion of override (%s)",
394+ path);
395+ conf_create_modify_handler (source, watch, path, NULL);
396 }
397
398 /**
399@@ -867,64 +985,18 @@
400 const char *path,
401 struct stat *statbuf)
402 {
403- ConfFile *file = NULL;
404- nih_local char *new_path = NULL;
405-
406 nih_assert (source != NULL);
407 nih_assert (dirname != NULL);
408 nih_assert (path != NULL);
409 nih_assert (statbuf != NULL);
410
411- /* We assume that CONF_EXT_STD files are visited before
412- * CONF_EXT_OVERRIDE files. Happily, this assumption is currently
413- * valid since CONF_EXT_STD comes before CONF_EXT_OVERRIDE if ordered
414- * alphabetically.
415- *
416- * If this were ever to change (for example if we decided to
417- * rename the CONF_EXT_OVERRIDE files to end in ".abc", say), the logic
418- * in this function would be erroneous since it would never be possible when
419- * visiting an override file (before a conf file) to lookup a conf file
420- * in the hash, since the conf file would not yet have been seen and thus would
421- * not exist in the hash (yet).
422- */
423- nih_assert (CONF_EXT_STD[1] < CONF_EXT_OVERRIDE[1]);
424-
425 if (! S_ISREG (statbuf->st_mode))
426 return 0;
427
428- if (is_conf_file_std (path)) {
429- if (conf_reload_path (source, path, NULL) < 0) {
430- NihError *err;
431-
432- err = nih_error_get ();
433- nih_error ("%s: %s: %s", path,
434- _("Error while loading configuration file"),
435- err->message);
436- nih_free (err);
437- }
438- return 0;
439- }
440-
441- new_path = toggle_conf_name (NULL, path);
442- file = (ConfFile *)nih_hash_lookup (source->files, new_path);
443-
444- if (file) {
445- /* we're visiting an override file with an associated conf file that
446- * has already been loaded, so just overlay the override file. If
447- * there is no corresponding conf file, we ignore the override file.
448- */
449- if (conf_reload_path (source, new_path, path) < 0) {
450- NihError *err;
451-
452- err = nih_error_get ();
453- nih_error ("%s: %s: %s", new_path,
454- _("Error while reloading configuration file"),
455- err->message);
456- nih_free (err);
457- }
458- }
459-
460- return 0;
461+ if (is_conf_file_std (path))
462+ conf_load_path_with_override (source, path);
463+
464+ return 0;
465 }
466
467
468@@ -957,7 +1029,6 @@
469 {
470 ConfFile *file = NULL;
471 nih_local char *buf = NULL;
472- const char *start, *end;
473 nih_local char *name = NULL;
474 size_t len, pos, lineno;
475 NihError *err = NULL;
476@@ -1014,23 +1085,8 @@
477
478 break;
479 case CONF_JOB_DIR:
480- /* Construct the job name by taking the path and removing
481- * the directory name from the front and the extension
482- * from the end.
483- */
484- start = path;
485- if (! strncmp (start, source->path, strlen (source->path)))
486- start += strlen (source->path);
487-
488- while (*start == '/')
489- start++;
490-
491- end = strrchr (start, '.');
492- if (end && IS_CONF_EXT (end)) {
493- name = NIH_MUST (nih_strndup (NULL, start, end - start));
494- } else {
495- name = NIH_MUST (nih_strdup (NULL, start));
496- }
497+
498+ name = conf_to_job_name (source->path, path);
499
500 /* Create a new job item and parse the buffer to produce
501 * the job definition.
502@@ -1388,4 +1444,3 @@
503 }
504
505 #endif /* DEBUG */
506-
507
508=== modified file 'init/tests/test_conf.c'
509--- init/tests/test_conf.c 2012-12-19 12:46:46 +0000
510+++ init/tests/test_conf.c 2013-01-08 16:18:21 +0000
511@@ -2424,7 +2424,8 @@
512 FILE *f;
513 int ret, fd[4096], i = 0;
514 char dirname[PATH_MAX];
515- char filename[PATH_MAX], override[PATH_MAX];
516+ char filename[PATH_MAX], override[PATH_MAX], override2[PATH_MAX];
517+ char *dir;
518 JobClass *job;
519 NihError *err;
520
521@@ -3424,6 +3425,123 @@
522 unlink (filename);
523 TEST_EQ (rmdir (dirname), 0);
524
525+ TEST_FEATURE ("create two watches, two overrides, conf, then delete override files one by one");
526+ TEST_ENSURE_CLEAN_ENV ();
527+ TEST_FILENAME (dirname);
528+ TEST_EQ (mkdir (dirname, 0755), 0);
529+
530+ strcpy (override, dirname);
531+ strcat (override, "/peter/foo.override");
532+ strcpy (override2, dirname);
533+ strcat (override2, "/paul/foo.override");
534+ strcpy (filename, dirname);
535+ strcat (filename, "/paul/foo.conf");
536+
537+ const char *sources[] = {"peter", "paul", NULL};
538+
539+ for (const char **src = sources; *src; src++) {
540+ dir = nih_sprintf (NULL, "%s/%s", dirname, *src);
541+ TEST_EQ (mkdir (dir, 0755), 0);
542+ source = conf_source_new (NULL, dir, CONF_JOB_DIR);
543+ TEST_NE_P (source, NULL);
544+ ret = conf_source_reload (source);
545+ TEST_EQ (ret, 0);
546+ nih_free (dir);
547+ }
548+
549+ TEST_FORCE_WATCH_UPDATE();
550+
551+ /* create override */
552+ f = fopen (override, "w");
553+ TEST_NE_P (f, NULL);
554+ fprintf (f, "manual\n");
555+ fprintf (f, "author \"peter\"\n");
556+ fclose (f);
557+
558+ TEST_FORCE_WATCH_UPDATE();
559+
560+ /* create override */
561+ f = fopen (override2, "w");
562+ TEST_NE_P (f, NULL);
563+ fprintf (f, "manual\n");
564+ fprintf (f, "author \"paul\"\n");
565+ fprintf (f, "env wibble=wobble\n");
566+ fclose (f);
567+
568+ TEST_FORCE_WATCH_UPDATE();
569+
570+ /* create conf */
571+ f = fopen (filename, "w");
572+ TEST_NE_P (f, NULL);
573+ fprintf (f, "start on started\n");
574+ fprintf (f, "emits hello\n");
575+ fprintf (f, "author \"mary\"\n");
576+ fclose (f);
577+
578+ TEST_FORCE_WATCH_UPDATE();
579+
580+ /* ensure conf loaded */
581+ file = (ConfFile *)nih_hash_lookup (source->files, filename);
582+ TEST_NE_P (file, NULL);
583+ job = (JobClass *)nih_hash_lookup (job_classes, "foo");
584+ TEST_NE_P (job, NULL);
585+ TEST_EQ_P (file->job, job);
586+ TEST_EQ_STR ((job->emits)[0], "hello");
587+
588+ /* should pick up the top-priority override, *NOT* conf */
589+ TEST_EQ_P (job->start_on, NULL);
590+ TEST_EQ_STR (job->author, "peter");
591+
592+ /* delete override */
593+ unlink (override);
594+
595+ TEST_FORCE_WATCH_UPDATE();
596+
597+ /* ensure conf reloaded and updated with the second override */
598+ file = (ConfFile *)nih_hash_lookup (source->files, filename);
599+ TEST_NE_P (file, NULL);
600+ job = (JobClass *)nih_hash_lookup (job_classes, "foo");
601+ TEST_NE_P (job, NULL);
602+ TEST_EQ_P (file->job, job);
603+ TEST_EQ_STR ((job->emits)[0], "hello");
604+
605+ /* should pick up the second override, *NOT* conf */
606+ TEST_EQ_P (job->start_on, NULL);
607+ TEST_EQ_STR (job->author, "paul");
608+ TEST_EQ_STR ((job->env)[0], "wibble=wobble");
609+
610+ TEST_FORCE_WATCH_UPDATE();
611+
612+ /* delete override */
613+ unlink (override2);
614+
615+ TEST_FORCE_WATCH_UPDATE();
616+
617+ /* ensure conf loaded */
618+ file = (ConfFile *)nih_hash_lookup (source->files, filename);
619+ TEST_NE_P (file, NULL);
620+ job = (JobClass *)nih_hash_lookup (job_classes, "foo");
621+ TEST_NE_P (job, NULL);
622+ TEST_EQ_P (file->job, job);
623+ TEST_EQ_STR (job->author, "mary");
624+ TEST_EQ_STR ((job->emits)[0], "hello");
625+ TEST_NE_P (job->start_on, NULL);
626+ TEST_EQ_P (job->env, NULL);
627+
628+ unlink (filename);
629+
630+ for (const char **src = sources; *src; src++) {
631+ dir = nih_sprintf (NULL, "%s/%s", dirname, *src);
632+ TEST_EQ (rmdir (dir), 0);
633+ nih_free (dir);
634+ }
635+
636+ TEST_EQ (rmdir (dirname), 0);
637+
638+ NIH_LIST_FOREACH_SAFE (conf_sources, iter) {
639+ ConfSource *source = (ConfSource *)iter;
640+ nih_free (source);
641+ }
642
643 TEST_FEATURE ("create conf, watch, then create invalid override, delete override");
644 TEST_ENSURE_CLEAN_ENV ();
645
646=== modified file 'init/tests/test_conf_static.c'
647--- init/tests/test_conf_static.c 2012-12-19 12:46:46 +0000
648+++ init/tests/test_conf_static.c 2013-01-08 16:18:21 +0000
649@@ -34,8 +34,8 @@
650 char *f;
651 char *p;
652
653- TEST_FUNCTION_FEATURE ("toggle_conf_name",
654- "changing conf to override");
655+ TEST_FUNCTION ("toggle_conf_name");
656+ TEST_FEATURE ("changing conf to override");
657
658 TEST_FILENAME (dirname);
659 strcpy (filename, dirname);
660@@ -71,11 +71,154 @@
661 nih_free (job);
662 }
663
664+void
665+test_conf_to_job_name (void)
666+{
667+ char dirname[PATH_MAX];
668+ char *filename;
669+ char *name;
670+
671+ TEST_FUNCTION ("conf_to_job_name");
672+ TEST_FEATURE ("with .conf file");
673+ TEST_FILENAME (dirname);
674+ filename = nih_sprintf (NULL, "%s/foo.conf", dirname);
675+ name = conf_to_job_name (dirname, filename);
676+ TEST_EQ_STR (name, "foo");
677+ nih_free (filename);
678+ nih_free (name);
679+
680+ TEST_FEATURE ("with .override file");
681+ filename = nih_sprintf (NULL, "%s/foo.override", dirname);
682+ name = conf_to_job_name (dirname, filename);
683+ TEST_EQ_STR (name, "foo");
684+ nih_free (filename);
685+ nih_free (name);
686+
687+ TEST_FEATURE ("with .conf in a sub-directory");
688+ filename = nih_sprintf (NULL, "%s/foo/bar.conf", dirname);
689+ name = conf_to_job_name (dirname, filename);
690+ TEST_EQ_STR (name, "foo/bar");
691+ nih_free (filename);
692+ nih_free (name);
693+
694+ TEST_FEATURE ("without extension");
695+ filename = nih_sprintf (NULL, "%s/foo", dirname);
696+ name = conf_to_job_name (dirname, filename);
697+ TEST_EQ_STR (name, "foo");
698+ nih_free (filename);
699+ nih_free (name);
700+
701+}
702+
703+void
704+test_conf_get_best_override (void)
705+{
706+ const char *sources[] = {"peter", "paul", "mary", NULL};
707+ FILE *f;
708+ char dirname[PATH_MAX];
709+ char *dir;
710+ char *expected;
711+ char *path;
712+
713+ TEST_FUNCTION ("conf_get_best_override");
714+
715+ TEST_FILENAME (dirname);
716+ mkdir (dirname, 0755);
717+
718+ for (const char **src = sources; *src; src++) {
719+ dir = nih_sprintf (NULL, "%s/%s", dirname, *src);
720+ TEST_EQ (mkdir (dir, 0755), 0);
721+ NIH_MUST (conf_source_new (NULL, dir, CONF_JOB_DIR));
722+ nih_free (dir);
723+ }
724+
725+ TEST_FEATURE ("with no overrides");
726+ NIH_LIST_FOREACH (conf_sources, iter) {
727+ ConfSource *source = (ConfSource *)iter;
728+ path = conf_get_best_override ("foo", source);
729+ TEST_EQ_P (path, NULL);
730+ }
731+
732+ TEST_FEATURE ("with single highest priority override");
733+ expected = nih_sprintf (NULL, "%s/%s/foo.override", dirname, sources[0]);
734+ f = fopen (expected, "w");
735+ TEST_NE_P (f, NULL);
736+ TEST_EQ (fclose (f), 0);
737+
738+ NIH_LIST_FOREACH (conf_sources, iter) {
739+ ConfSource *source = (ConfSource *)iter;
740+ path = conf_get_best_override ("foo", source);
741+ TEST_EQ_STR (path, expected);
742+ nih_free (path);
743+ }
744+ TEST_EQ (unlink (expected), 0);
745+
746+ TEST_FEATURE ("with single middle priority override");
747+ expected = nih_sprintf (NULL, "%s/%s/foo.override", dirname, sources[1]);
748+ f = fopen (expected, "w");
749+ TEST_NE_P (f, NULL);
750+ TEST_EQ (fclose (f), 0);
751+
752+ NIH_LIST_FOREACH (conf_sources, iter) {
753+ ConfSource *source = (ConfSource *)iter;
754+ path = conf_get_best_override ("foo", source);
755+
756+ /* Poor-man's basename(1) */
757+ dir = conf_to_job_name (dirname, source->path);
758+ if (strcmp (dir, sources[0]) == 0) {
759+ TEST_EQ_P (path, NULL);
760+ } else {
761+ TEST_EQ_STR (path, expected);
762+ nih_free (path);
763+ }
764+ nih_free (dir);
765+ }
766+ TEST_EQ (unlink (expected), 0);
767+
768+ TEST_FEATURE ("with single lowest priority override");
769+ expected = nih_sprintf (NULL, "%s/%s/foo.override", dirname, sources[2]);
770+ f = fopen (expected, "w");
771+ TEST_NE_P (f, NULL);
772+ TEST_EQ (fclose (f), 0);
773+
774+ NIH_LIST_FOREACH (conf_sources, iter) {
775+ ConfSource *source = (ConfSource *)iter;
776+ path = conf_get_best_override ("foo", source);
777+
778+ /* Poor-man's basename(1) */
779+ dir = conf_to_job_name (dirname, source->path);
780+ if (strcmp (dir, sources[2]) == 0) {
781+ TEST_EQ_STR (path, expected);
782+ nih_free (path);
783+ } else {
784+ TEST_EQ_P (path, NULL);
785+ }
786+ nih_free (dir);
787+ }
788+ TEST_EQ (unlink (expected), 0);
789+
790+ /* Clean up */
791+ for (const char **src = sources; *src; src++) {
792+ dir = nih_sprintf (NULL, "%s/%s", dirname, *src);
793+ TEST_EQ (rmdir (dir), 0);
794+ nih_free (dir);
795+ }
796+
797+ TEST_EQ (rmdir (dirname), 0);
798+
799+ NIH_LIST_FOREACH_SAFE (conf_sources, iter) {
800+ ConfSource *source = (ConfSource *)iter;
801+ nih_free (source);
802+ }
803+}
804+
805 int
806 main (int argc,
807 char *argv[])
808 {
809 test_toggle_conf_name ();
810+ test_conf_to_job_name ();
811+ test_conf_get_best_override ();
812
813 return 0;
814 }

Subscribers

People subscribed via source and target branches