Browse Source

Adding tests

Noah 7 years ago
parent
commit
f6bbc28a68
5 changed files with 378 additions and 45 deletions
  1. 6 30
      lib/settings/index.js
  2. 26 0
      lib/settings/load.js
  3. 13 13
      lib/settings/validate-settings.js
  4. 9 2
      lib/settings/validate-themes.js
  5. 324 0
      test/settings-test.js

+ 6 - 30
lib/settings/index.js View File

@@ -1,39 +1,15 @@
1 1
 var _ = require("underscore"),
2 2
     path = require("path"),
3
-    fs = require("fs");
3
+    fs = require("fs"),
4
+    load = require("./load.js");
4 5
 
5
-var settings = tryToLoad("settings/index.js"),
6
-    themes = tryToLoad("settings/themes.json");
6
+var settings = load("settings/index.js"),
7
+    themes = load("settings/themes.json");
7 8
 
8 9
 // Validate settings
9
-require("./validate-settings.js")(settings);
10
+settings = require("./validate-settings.js")(settings);
10 11
 
11 12
 // Validate themes
12
-require("./validate-themes.js")(themes);
13
+themes = require("./validate-themes.js")(themes);
13 14
 
14 15
 module.exports = settings;
15
-
16
-// Try to load modules
17
-function tryToLoad(filename) {
18
-
19
-  var loaded;
20
-
21
-  try {
22
-    loaded = require(path.join(__dirname, "..", "..", filename));
23
-    if (!loaded) {
24
-      throw new Error("Couldn't load contents of " + filename + ".");
25
-    }
26
-  } catch(e) {
27
-    if (e.code === "MODULE_NOT_FOUND") {
28
-      throw new Error("No " + filename + " file found.");
29
-    } else if (e instanceof SyntaxError) {
30
-      console.warn("Error parsing " + filename);
31
-      throw e;
32
-    } else {
33
-      throw e;
34
-    }
35
-  }
36
-
37
-  return loaded;
38
-
39
-}

+ 26 - 0
lib/settings/load.js View File

@@ -0,0 +1,26 @@
1
+var path = require("path");
2
+
3
+// Try to load module
4
+module.exports = function(filename) {
5
+
6
+  var loaded;
7
+
8
+  try {
9
+    loaded = require(path.join(__dirname, "..", "..", filename));
10
+    if (!loaded) {
11
+      throw new Error("Couldn't load contents of " + filename + ".");
12
+    }
13
+  } catch(e) {
14
+    if (e.code === "MODULE_NOT_FOUND") {
15
+      throw new Error("No " + filename + " file found.");
16
+    } else if (e instanceof SyntaxError) {
17
+      console.warn("Error parsing " + filename + ".");
18
+      throw e;
19
+    } else {
20
+      throw e;
21
+    }
22
+  }
23
+
24
+  return loaded;
25
+
26
+}

+ 13 - 13
lib/settings/validate-settings.js View File

@@ -1,12 +1,14 @@
1 1
 var fs = require("fs"),
2 2
     path = require("path"),
3
-    Canvas = require("canvas");
3
+    mkdirp = require("mkdirp"),
4
+    Canvas = require("canvas"),
5
+    _ = require("underscore");
4 6
 
5 7
 module.exports = function(settings) {
6 8
 
7 9
   // Check paths
8 10
   if (typeof settings.workingDirectory !== "string") {
9
-    throw new Error("settings.workingDirectory is required. See https://github.com/nypublicradio/audiogram/blob/master/SERVER.md#all-settings for details.").
11
+    throw new Error("settings.workingDirectory is required. See https://github.com/nypublicradio/audiogram/blob/master/SERVER.md#all-settings for details.");
10 12
   }
11 13
 
12 14
   if (typeof settings.storagePath !== "string" && typeof settings.s3Bucket !== "string") {
@@ -15,14 +17,14 @@ module.exports = function(settings) {
15 17
 
16 18
   // TODO normalize workingDirectory, s3Bucket, and storagePath
17 19
   settings.workingDirectory = normalize(settings.workingDirectory);
18
-  tryToCreate("workingDirectory");
20
+  tryToCreate(settings.workingDirectory, "workingDirectory");
19 21
 
20 22
   if (typeof settings.s3Bucket === "string") {
21 23
 
22 24
     // Remove s3:// and trailing slash, bucket name only
23 25
     settings.s3Bucket = settings.s3Bucket.replace(/^(s3[:]\/\/)|\/$/g, "");
24 26
 
25
-    if (settings.storagePath) {
27
+    if (typeof settings.storagePath === "string") {
26 28
 
27 29
       // No leading slash, one trailing slash
28 30
       settings.storagePath = settings.storagePath.replace(/^\/|\/$/g, "");
@@ -37,7 +39,7 @@ module.exports = function(settings) {
37 39
 
38 40
   } else {
39 41
     settings.storagePath = normalize(settings.storagePath);
40
-    tryToCreate("storagePath");
42
+    tryToCreate(settings.storagePath, "storagePath");
41 43
   }
42 44
 
43 45
   // Check maxUploadSize
@@ -63,24 +65,22 @@ module.exports = function(settings) {
63 65
         fs.accessSync(font.file);
64 66
         Canvas.registerFont(font.file, _.pick(font, "family", "weight", "style"));
65 67
       } catch(e) {
66
-        // TODO catch font registration error
67
-        console.warn(e);
68 68
         return console.warn("Font file " + font.file + " does not exist or is not readable.");
69 69
       }
70 70
 
71 71
     });
72 72
   }
73 73
 
74
+  return settings;
75
+
74 76
 };
75 77
 
76
-function tryToCreate(key) {
78
+function tryToCreate(dir, key) {
77 79
   try {
78
-    mkdirp.sync(settings[key]);
79
-    fs.accessSync(settings[key]);
80
+    mkdirp.sync(dir);
81
+    fs.accessSync(dir);
80 82
   } catch(e) {
81
-    // TODO more helpful msg
82
-    console.warn(e);
83
-    throw e;
83
+    throw new Error("Could not create/access settings." + key + " at " + dir + "");
84 84
   }
85 85
 }
86 86
 

+ 9 - 2
lib/settings/validate-themes.js View File

@@ -5,7 +5,7 @@ var path = require("path"),
5 5
 module.exports = function(themes) {
6 6
 
7 7
   if (!themes || !_.keys(_.omit(themes, "default")).length) {
8
-    throw new Error("No themes found in settings/themes.json. See https://github.com/nypublicradio/audiogram/blob/master/THEMES.md for details.");
8
+    return console.warn("No themes found in settings/themes.json. See https://github.com/nypublicradio/audiogram/blob/master/THEMES.md for details.");
9 9
   }
10 10
 
11 11
   for (var key in themes) {
@@ -14,6 +14,8 @@ module.exports = function(themes) {
14 14
     }
15 15
   }
16 16
 
17
+  return themes;
18
+
17 19
 };
18 20
 
19 21
 function validateTheme(name, options) {
@@ -31,7 +33,12 @@ function validateTheme(name, options) {
31 33
   });
32 34
 
33 35
   if (typeof options.backgroundImage === "string") {
34
-    fullBackgroundImagePath = path.join(__dirname, "..", "..", "settings/backgrounds/", options.backgroundImage);
36
+
37
+    fullBackgroundImagePath = options.backgroundImage;
38
+
39
+    if (!path.isAbsolute(options.backgroundImage)) {
40
+      fullBackgroundImagePath = path.join(__dirname, "..", "..", "settings/backgrounds/", options.backgroundImage);
41
+    }
35 42
 
36 43
     try {
37 44
       fs.accessSync(fullBackgroundImagePath);

+ 324 - 0
test/settings-test.js View File

@@ -0,0 +1,324 @@
1
+var tape = require("tape"),
2
+    path = require("path"),
3
+    validateSettings = require("../lib/settings/validate-settings.js"),
4
+    validateThemes = require("../lib/settings/validate-themes.js"),
5
+    load = require("../lib/settings/load.js");
6
+
7
+tape("Load test", function(test) {
8
+
9
+  test.throws(function(){
10
+    load("settings/blah.js");
11
+  }, /No .+ file found/);
12
+
13
+  test.throws(function(){
14
+    load("README.md");
15
+  }, /SyntaxError/);
16
+
17
+  test.doesNotThrow(function(){
18
+    load("settings/themes.json");
19
+  });
20
+
21
+  test.doesNotThrow(function(){
22
+    load("settings/index.js");
23
+  });
24
+
25
+  test.end();
26
+
27
+});
28
+
29
+tape("Required fields", function(test) {
30
+
31
+  test.throws(function(){
32
+    validateSettings({});
33
+  }, /settings.workingDirectory is required/);
34
+
35
+  test.throws(function(){
36
+    validateSettings({ workingDirectory: 1 });
37
+  }, /settings.workingDirectory is required/);
38
+
39
+  test.throws(function(){
40
+    validateSettings({ workingDirectory: "" });
41
+  }, /settings.storagePath/);
42
+
43
+  test.throws(function(){
44
+    validateSettings({ workingDirectory: "", storagePath: 1 });
45
+  }, /settings.storagePath/);
46
+
47
+  test.doesNotThrow(function(){
48
+    validateSettings({ workingDirectory: path.join(__dirname), storagePath: path.join(__dirname) });
49
+  }, /settings.storagePath/);
50
+
51
+  test.doesNotThrow(function(){
52
+    validateSettings({ workingDirectory: path.join(__dirname), s3Bucket: "bucket" });
53
+  }, /settings.storagePath/);
54
+
55
+  test.end();
56
+
57
+});
58
+
59
+tape("Max upload size", function(test) {
60
+
61
+  test.throws(function(){
62
+    validateSettings({ workingDirectory: path.join(__dirname), storagePath: path.join(__dirname), maxUploadSize: "a lot" });
63
+  }, /settings.maxUploadSize/);
64
+
65
+  test.end();
66
+
67
+});
68
+
69
+tape("Normalizing paths", function(test) {
70
+
71
+  var relative = validateSettings({
72
+    storagePath: "test/",
73
+    workingDirectory: "test/"
74
+  });
75
+
76
+  var absolute = validateSettings({
77
+    storagePath: path.join(__dirname),
78
+    workingDirectory: path.join(__dirname)
79
+  });
80
+
81
+  var relative2 = validateSettings({
82
+    storagePath: "test",
83
+    workingDirectory: "test"
84
+  });
85
+
86
+  test.equal(path.relative(relative.storagePath, absolute.storagePath), "");
87
+  test.equal(path.relative(relative.workingDirectory, absolute.workingDirectory), "");
88
+  test.equal(path.relative(relative2.storagePath, absolute.storagePath), "");
89
+  test.equal(path.relative(relative2.workingDirectory, absolute.workingDirectory), "");
90
+
91
+  test.end();
92
+
93
+});
94
+
95
+tape("Normalize S3 bucket", function(test) {
96
+
97
+  var settings = validateSettings({
98
+    s3Bucket: "bucket",
99
+    workingDirectory: "test/"
100
+  });
101
+
102
+  test.equal(settings.s3Bucket, "bucket");
103
+  test.equal(settings.storagePath, "");
104
+
105
+  var settings = validateSettings({
106
+    s3Bucket: "s3://bucket",
107
+    workingDirectory: "test/"
108
+  });
109
+
110
+  test.equal(settings.s3Bucket, "bucket");
111
+  test.equal(settings.storagePath, "");
112
+
113
+  settings = validateSettings({
114
+    s3Bucket: "s3://bucket/",
115
+    workingDirectory: "test/"
116
+  });
117
+
118
+  test.equal(settings.s3Bucket, "bucket");
119
+  test.equal(settings.storagePath, "");
120
+
121
+  settings = validateSettings({
122
+    s3Bucket: "s3://bucket/",
123
+    storagePath: "/",
124
+    workingDirectory: "test/"
125
+  });
126
+
127
+  test.equal(settings.s3Bucket, "bucket");
128
+  test.equal(settings.storagePath, "");
129
+
130
+  settings = validateSettings({
131
+    s3Bucket: "s3://bucket/",
132
+    storagePath: "dir",
133
+    workingDirectory: "test/"
134
+  });
135
+
136
+  test.equal(settings.s3Bucket, "bucket");
137
+  test.equal(settings.storagePath, "dir/");
138
+
139
+  settings = validateSettings({
140
+    s3Bucket: "s3://bucket/",
141
+    storagePath: "dir/",
142
+    workingDirectory: "test/"
143
+  });
144
+
145
+  test.equal(settings.s3Bucket, "bucket");
146
+  test.equal(settings.storagePath, "dir/");
147
+
148
+  settings = validateSettings({
149
+    s3Bucket: "s3://bucket/",
150
+    storagePath: "/dir/",
151
+    workingDirectory: "test/"
152
+  });
153
+
154
+  test.equal(settings.s3Bucket, "bucket");
155
+  test.equal(settings.storagePath, "dir/");
156
+
157
+  test.end();
158
+
159
+});
160
+
161
+tape("Fonts", function(test) {
162
+
163
+  test.throws(function(){
164
+    validateSettings({
165
+      s3Bucket: "bucket",
166
+      workingDirectory: "test/",
167
+      fonts: 1
168
+    });
169
+  }, /settings.fonts/);
170
+
171
+  test.throws(function(){
172
+    validateSettings({
173
+      s3Bucket: "bucket",
174
+      workingDirectory: "test/",
175
+      fonts: {}
176
+    });
177
+  }, /settings.fonts/);
178
+
179
+  doesWarn(test, function(){
180
+    validateSettings({
181
+      s3Bucket: "bucket",
182
+      workingDirectory: "test/",
183
+      fonts: [
184
+        {}
185
+      ]
186
+    });
187
+  }, /settings.fonts.+missing/);
188
+
189
+  doesWarn(test, function(){
190
+    validateSettings({
191
+      s3Bucket: "bucket",
192
+      workingDirectory: "test/",
193
+      fonts: [
194
+        { family: "" }
195
+      ]
196
+    });
197
+  }, /settings.fonts.+missing/);
198
+
199
+  doesWarn(test, function(){
200
+    validateSettings({
201
+      s3Bucket: "bucket",
202
+      workingDirectory: "test/",
203
+      fonts: [
204
+        { file: "" }
205
+      ]
206
+    });
207
+  }, /settings.fonts.+missing/);
208
+
209
+  doesWarn(test, function(){
210
+    validateSettings({
211
+      s3Bucket: "bucket",
212
+      workingDirectory: "test/",
213
+      fonts: [
214
+        { file: "notarealfont.ttf", family: "fake" }
215
+      ]
216
+    });
217
+  }, /Font file.+does not exist/);
218
+
219
+  doesNotWarn(test, function(){
220
+    validateSettings({
221
+      s3Bucket: "bucket",
222
+      workingDirectory: "test/",
223
+      fonts: [
224
+        { file: "settings/fonts/SourceSansPro-Light.ttf", family: "Source Sans Pro" },
225
+        { file: path.join(__dirname, "..", "settings/fonts/SourceSansPro-Bold.ttf"), family: "Source Sans Pro", weight: "bold" }
226
+      ]
227
+    });
228
+  });
229
+
230
+  test.end();
231
+
232
+});
233
+
234
+tape("Themes", function(test) {
235
+
236
+  doesWarn(test, function(){
237
+    validateThemes({});
238
+  }, /No themes/);
239
+
240
+  doesWarn(test, function(){
241
+    validateThemes([]);
242
+  }, /No themes/);
243
+
244
+  doesWarn(test, function(){
245
+    validateThemes({ "default": {} });
246
+  }, /No themes/);
247
+
248
+  doesNotWarn(test, function(){
249
+    validateThemes({ "default": { width: 0, height: 0, framesPerSecond: 0, samplesPerFrame: 0 }, "theme": {} });
250
+  });
251
+
252
+  doesNotWarn(test, function(){
253
+    validateThemes({ "default": { framesPerSecond: 0, samplesPerFrame: 0 }, "theme": { width: 0, height: 0 } });
254
+  });
255
+
256
+  doesWarn(test, function(){
257
+    validateThemes({ "default": { height: 0, framesPerSecond: 0, samplesPerFrame: 0 }, "theme": {} });
258
+  }, /required property 'width'/);
259
+
260
+  doesWarn(test, function(){
261
+    validateThemes({ "default": { width: 0, framesPerSecond: 0, samplesPerFrame: 0 }, "theme": {} });
262
+  }, /required property 'height'/);
263
+
264
+  doesWarn(test, function(){
265
+    validateThemes({ "default": { width: 0, height: 0, samplesPerFrame: 0 }, "theme": {} });
266
+  }, /required property 'framesPerSecond'/);
267
+
268
+  doesWarn(test, function(){
269
+    validateThemes({ "default": { width: 0, height: 0, framesPerSecond: 0 }, "theme": {} });
270
+  }, /required property 'samplesPerFrame'/);
271
+
272
+  doesWarn(test, function(){
273
+    validateThemes({ "default": { width: 0, height: 0, framesPerSecond: 0, samplesPerFrame: 0 }, "theme": { backgroundImage: "doesnotexist.jpg" } });
274
+  }, /Background image.+does not exist/);
275
+
276
+  doesNotWarn(test, function(){
277
+    validateThemes({ "default": { width: 0, height: 0, framesPerSecond: 0, samplesPerFrame: 0 }, "theme": { backgroundImage: "subway.jpg" } });
278
+  });
279
+
280
+  doesNotWarn(test, function(){
281
+    validateThemes({ "default": { width: 0, height: 0, framesPerSecond: 0, samplesPerFrame: 0 }, "theme": { backgroundImage: path.join(__dirname, "..", "settings/backgrounds/subway.jpg") } });
282
+  });
283
+
284
+  test.end();
285
+
286
+});
287
+
288
+function doesNotWarn(test, fn) {
289
+  doesWarn(test, fn, "");
290
+}
291
+
292
+function doesWarn(test, fn, regexp) {
293
+
294
+  var output = capture();
295
+
296
+  fn();
297
+
298
+  if (arguments.length > 2) {
299
+    if (typeof regexp === "string") {
300
+      test.equal(output(), regexp);
301
+    } else {
302
+      test.assert(regexp.test(output()));
303
+    }
304
+  } else {
305
+    test.assert(output().length);
306
+  }
307
+
308
+}
309
+
310
+function capture(){
311
+
312
+  var write = process.stderr.write,
313
+      out = "";
314
+
315
+  process.stderr.write = function(str) {
316
+    out += str;
317
+  };
318
+
319
+  return function(){
320
+    process.stderr.write = write;
321
+    return out;
322
+  }
323
+
324
+}