From ddc4bc744261ab696df8cdae0ea0341406963813 Mon Sep 17 00:00:00 2001 From: Maxime Quandalle Date: Sat, 4 Oct 2014 18:29:27 +0200 Subject: [PATCH] Complete the appcache test suite * Add a test to verify section header unicity * Add a test to verify NETWORK section content * Simplify the regular expressions used in the manifest content test. --- packages/appcache/appcache_tests-client.js | 96 ++++++++++++++++------ packages/appcache/appcache_tests-server.js | 2 +- packages/appcache/package.js | 6 +- 3 files changed, 74 insertions(+), 30 deletions(-) diff --git a/packages/appcache/appcache_tests-client.js b/packages/appcache/appcache_tests-client.js index 60e286a515..f47947008f 100644 --- a/packages/appcache/appcache_tests-client.js +++ b/packages/appcache/appcache_tests-client.js @@ -1,10 +1,7 @@ var manifestUrl = '/app.manifest'; -var pathRegex = '[a-z0-9_@\\-^:\\?!#$%&+={}/\\[\\]\\.]+'; -var versionRegex = '[a-z0-9]+'; - -var appcacheTest = function(cb) { - return function(test, next) { +var appcacheTest = function(name, cb) { + Tinytest.addAsync('appcache - ' + name, function(test, next) { HTTP.get(manifestUrl, function (err, res) { if (err) { test.fail(err); @@ -13,30 +10,50 @@ var appcacheTest = function(cb) { } next(); }); - }; + }); }; -Tinytest.addAsync('appcache - presence', appcacheTest(function(test, manifest) { + +// Verify that the code status of the HTTP response is "OK" +appcacheTest('presence', function(test, manifest) { test.equal(manifest.statusCode, 200, 'manifest not served'); -})); +}); -Tinytest.addAsync('appcache - content type', - appcacheTest(function(test, manifest) { - test.equal(manifest.headers['content-type'], 'text/cache-manifest'); -})); -Tinytest.addAsync('appcache - validity', appcacheTest(function(test, manifest) { +// Verify the content-type HTTP header +appcacheTest('content type', function(test, manifest) { + test.equal(manifest.headers['content-type'], 'text/cache-manifest'); +}); + + +// Verify that each section header is only set once. +appcacheTest('sections unicity', function(test, manifest) { + var content = manifest.content; + var sectionHeaders = ['CACHE:', 'NETWORK:', 'FALLBACK:', 'SETTINGS']; + _.each(sectionHeaders, function(sectionHeader) { + var globalSearch = new RegExp(sectionHeader, "g"); + var matches = content.match(globalSearch) || []; + test.isTrue(matches.length <= 1, sectionHeader + ' is set twice'); + }); +}); + + +// Verify the content of the header and of each section of the manifest using +// regular expressions. Regular expressions matches malformed URIs but that's +// not what we're trying to catch here (the user is free to add its own content +// in the manifest -- even malformed). +appcacheTest('sections validity', function(test, manifest) { var lines = manifest.content.split('\n'); var i = 0; var currentRegex = null, line = null; var nextLine = function() { return lines[i++]; - } + }; var eof = function() { return i >= lines.length; - } + }; var nextLineMatches = function(expected, n) { n = n || 1; @@ -46,15 +63,10 @@ Tinytest.addAsync('appcache - validity', appcacheTest(function(test, manifest) { }); }; - var regExpConstructor = function(/* arguments */) { - var parts = ['^'].concat(_.toArray(arguments)).concat(['$']); - return new RegExp(parts.join(''), 'i'); - }; - // Verify header validity nextLineMatches('CACHE MANIFEST'); nextLineMatches(''); - nextLineMatches(regExpConstructor('# ', versionRegex), 2); + nextLineMatches(/^# [a-z0-9]+$/i, 2); // Verify body validity @@ -65,12 +77,13 @@ Tinytest.addAsync('appcache - validity', appcacheTest(function(test, manifest) { // A section start with its name suffixed by a colon. When we read a new // section header, we update the currentRegex expression for the next lines // of the section. - // XXX There is also a 'SETTINGS' section, not used by this package. + // XXX There is also a 'SETTINGS' section, not used by this package. If this + // section is used, the test will fail. if (line === 'CACHE:' || line === 'NETWORK:') - currentRegex = regExpConstructor(pathRegex); + currentRegex = /^\S+$/; else if (line === 'FALLBACK:') - currentRegex = regExpConstructor(pathRegex, ' ', pathRegex); + currentRegex = /^\S+ \S+$/; // Blank lines and lines starting with a `#` (comments) are valid else if (line == '' || line.match(/^#.+/)) @@ -89,4 +102,37 @@ Tinytest.addAsync('appcache - validity', appcacheTest(function(test, manifest) { else test.matches(line, currentRegex, 'line ' + i); } -})); +}); + + +// Verify that resources declared on the server with the `onlineOnly` parameter +// are present in the network section of the manifest. The `appcache` package +// also automatically add the manifest (`app.manifest`) add the star symbol to +// this list and therefore we also check the presence of these two elements. +appcacheTest('network section content', function(test, manifest) { + var shouldBePresentInNetworkSection = [ + "/app.manifest", + "/online/", + "/bigimage.jpg", + "/largedata.json", + "*" + ]; + var lines = manifest.content.split('\n'); + var startNetworkSection = lines.indexOf('NETWORK:'); + + // We search the end of the 'NETWORK:' section by looking at the beginning + // of any potential other section. By default we set this value to + // `lines.length - 1` which is the index of the last line. + var otherSections = ['CACHE:', 'FALLBACK:', 'SETTINGS']; + var endNetworkSection = _.reduce(otherSections, function(min, sectionName) { + var position = lines.indexOf(sectionName); + return position > startNetworkSection && position < min ? position : min; + }, lines.length - 1); + + // We remove the first line because it's the 'NETWORK:' header line. + var networkLines = lines.slice(startNetworkSection + 1, endNetworkSection); + + _.each(shouldBePresentInNetworkSection, function(item) { + test.include(networkLines, item); + }); +}); diff --git a/packages/appcache/appcache_tests-server.js b/packages/appcache/appcache_tests-server.js index a66dbdccb6..fdd3772406 100644 --- a/packages/appcache/appcache_tests-server.js +++ b/packages/appcache/appcache_tests-server.js @@ -10,7 +10,7 @@ WebApp.addHtmlAttributeHook(function (request) { }); -// Let's add some file in the 'ONLINE' section +// Let's add some ressources in the 'NETWORK' section Meteor.AppCache.config({ onlineOnly: [ '/online/', diff --git a/packages/appcache/package.js b/packages/appcache/package.js index 3792b2e62d..0a9989eccd 100644 --- a/packages/appcache/package.js +++ b/packages/appcache/package.js @@ -16,11 +16,9 @@ Package.onUse(function (api) { Package.onTest(function (api) { api.use('tinytest'); api.use('appcache'); - + api.use('http', 'client'); + api.use('underscore', 'client'); api.use('webapp', 'server'); api.addFiles('appcache_tests-server.js', 'server'); - - api.use('underscore', 'client'); - api.use('http', 'client'); api.addFiles('appcache_tests-client.js', 'client'); });