1 /**
  2  * @fileOverview Live cloud tests.
  3  *
  4  * See full warnings and dev. notes below.
  5  */
  6 
  7 (function () {
  8   var assert = require('assert'),
  9     testCase = require('nodeunit').testCase,
 10     sunny = require("../lib"),
 11     utils = require("../lib/utils"),
 12 
 13     // Tests
 14     ConnectionTests = require("./live/connection").Tests,
 15     ContainerTests = require("./live/container").Tests,
 16     BlobTests = require("./live/blob").Tests,
 17 
 18     // Variables
 19     Tests,
 20     configPath = process.env.SUNNY_LIVE_TEST_CONFIG,
 21     testsConfig,
 22     testsProto;
 23 
 24   /**
 25    * Live cloud tests.
 26    *
 27    * ## Warning - Mutates Datastore!
 28    * This actually **adds/deletes** containers / files on a live cloud
 29    * account. Care has been taken to not collide with any real data, but you
 30    * are strongly advised to **not** run the tests against a production cloud
 31    * storage account.
 32    *
 33    * ## Configuration
 34    * Tests require a configuration in the format of:
 35    *
 36    *     Configuration = [
 37    *       {
 38    *         provider: 'aws',
 39    *         acount: '<ACCOUNT NAME>',
 40    *         secretKey: '<SECRET KEY>',
 41    *         [ssl: false]
 42    *       },
 43    *       {  // ... other providers ...
 44    *       }
 45    *     ];
 46    *
 47    * Taken from a file. Tests are run against each configuration provided.
 48    * Currently supported providers are:
 49    * - 'aws' AWS Simple Storage Service (S3)
 50    * - 'google': Google Storage For Developers
 51    *
 52    * ## Setup/Teardown and Wrappers (Dev)
 53    * The nodeunit tests are wrapped to inject cloud-specific information and
 54    * to run suites against each different cloud configuration. The underlying
 55    * test prototypes look pretty similar to ordinary nodeunit tests, except
 56    * the function signature is:
 57    *
 58    *     function (test, opts)
 59    *
 60    * instead of:
 61    *
 62    *     function (test)
 63    *
 64    * where ``opts`` are injected cloud information.
 65    *
 66    * Several tests use a setup/teardown wrapper that creates a (hopefully)
 67    * unique and non-existent test container, optionally adds blobs, and wipes
 68    * out everything on teardown.  See ``test.live.utils.createTestSetup()``
 69    * for more information.
 70    *
 71    * @exports Tests as test.live
 72    * @namespace
 73    */
 74   Tests = {};
 75 
 76   // Get the configuration.
 77   if (!configPath) {
 78     assert.fail("Live tests require a configuration file.");
 79   }
 80 
 81   try {
 82     testsConfig = require(configPath).Configuration;
 83   } catch (err) {
 84     console.warn(err);
 85     assert.fail("Invalid configuration file / path: " + configPath);
 86   }
 87 
 88   // Define all tests (prototype).
 89   testsProto = utils.extend(
 90     ConnectionTests,
 91     ContainerTests,
 92     BlobTests
 93   );
 94 
 95   /**
 96    * Bind tests to specific configurations.
 97    * @private
 98    */
 99   function bindTests(config, num) {
100     var prefix = config.provider + "(" + num + ")",
101       sunnyOpts,
102       wrapFn,
103       protoKey,
104       proto,
105       testKey,
106       testGroup;
107 
108     sunnyOpts = {
109       config: config,
110       conn: config.connection
111     };
112 
113     /**
114      * Test wrapper that injects options to each test.
115      * @private
116      */
117     wrapFn = function (testFn) {
118       return function (testOrCallback) {
119         return testFn(testOrCallback, sunnyOpts);
120       };
121     };
122 
123     // Create a new test group for config
124     Tests[prefix] = {};
125 
126     // Re-bind test prefix with specific configs.
127     for (protoKey in testsProto) {
128       if (testsProto.hasOwnProperty(protoKey)) {
129         proto = testsProto[protoKey];
130 
131         // Wrap up a test case.
132         testGroup = {};
133         for (testKey in proto) {
134           if (proto.hasOwnProperty(testKey)) {
135             // Wrap up actual test.
136             testGroup[testKey] = wrapFn(proto[testKey]);
137           }
138         }
139         Tests[prefix][protoKey] = testCase(testGroup);
140       }
141     }
142   }
143 
144   // Create tests for each separate config object.
145   testsConfig.forEach(function (options, index) {
146     var config = sunny.Configuration.fromObj(options);
147     bindTests(config, index);
148   });
149 
150   // Bind all tests to exports.
151   module.exports = Tests;
152 }());
153