/*
 * storage-object-test.js: Tests for Rackspace Cloudfiles containers
 *
 * (C) 2010 Nodejitsu Inc.
 * MIT LICENSE
 *
 */

var fs = require('fs'),
  should = require('should'),
  helpers = require('../../helpers'),
  async = require('async'),
  http = require('http'),
  hock = require('hock'),
  File = require('../../../lib/pkgcloud/core/storage/file').File,
  mock = !!process.env.MOCK,
  Buffer = require('buffer').Buffer;

if (!mock) {
  return; // these tests are disabled when running for real
}

describe('pkgcloud/rackspace/storage/storage-object', function () {
  describe('The pkgcloud Rackspace Storage client', function () {

    var client, hockInstance, authHockInstance, server, authServer;

    /**
     * Generates a container file list response of specified size for large container tests.
     * Results remain alphabetical by appending incrementing numbers to the file names, e.g. FILE00000, FILE019999.
     * @param start
     * @param end
     * @returns {Array}
     */
    var generateFilesResponse = function (start, end) {
      var files = [];
      function padToFive(number) {
        if (number<=99999) { number = ('0000'+number).slice(-5); }
        return number;
      }

      for (var i = start; i < end; i++) {
        files.push({
          hash: 'cb5c530452af82fb875dc0fb1a00a2c4',
          last_modified: '2013-05-20T22:48:08.059180',
          bytes: 2027,
          name: 'FILE' + padToFive(i),
          content_type: 'application/octet-stream'
        });
      }

      return files;
    };

    before(function (done) {
      client = helpers.createClient('rackspace', 'storage');

      if (!mock) {
        return done();
      }

      hockInstance = hock.createHock({ throwOnUnmatched: false });
      authHockInstance = hock.createHock();

      server = http.createServer(hockInstance.handler);
      authServer = http.createServer(authHockInstance.handler);

      async.parallel([
        function (next) {
          server.listen(12345, next);
        },
        function (next) {
          authServer.listen(12346, next);
        }
      ], done);
    });

    it('getFiles should return a list of files', function (done) {

      if (mock) {
        authHockInstance
          .post('/v2.0/tokens', {
            auth: {
              'RAX-KSKEY:apiKeyCredentials': {
                username: 'MOCK-USERNAME',
                apiKey: 'MOCK-API-KEY'
              }
            }
          })
          .reply(200, helpers.getRackspaceAuthResponse());

        hockInstance
          .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/0.1.7-215?format=json')
          .replyWithFile(200, __dirname + '/../../fixtures/rackspace/getFiles.json');
      }

      client.getFiles('0.1.7-215', function (err, files) {
        should.not.exist(err);
        should.exist(files);
        files.should.have.length(5);
        files.forEach(function (f) {
          f.should.be.instanceof(File);
        });
        authHockInstance && authHockInstance.done();
        hockInstance && hockInstance.done();
        done();
      });
    });

    it('getFiles with undefined limit should return up to 10,000 files', function (done) {

      if (!mock) {
        return done();
      }

      hockInstance
        .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/0.1.7-215?format=json')
        .reply(200, generateFilesResponse(0, 10000));

      client.getFiles('0.1.7-215', function (err, files) {
        should.not.exist(err);
        should.exist(files);
        files.length.should.equal(10000);
        hockInstance && hockInstance.done();
        done();
      });
    });

    it('getFiles with limit should return reduced set', function (done) {

      if (mock) {
        hockInstance
          .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/0.1.7-215?format=json&limit=3')
          .replyWithFile(200, __dirname + '/../../fixtures/rackspace/getContainersLimit.json');
      }

      client.getFiles('0.1.7-215', { limit: 3 }, function (err, files) {
        should.not.exist(err);
        should.exist(files);
        files.should.have.length(3);
        files.forEach(function (f) {
          f.should.be.instanceof(File);
        });
        hockInstance && hockInstance.done();
        done();
      });
    });

    it('getFiles with limit > 10,000 should make multiple requests as necessary', function (done) {

      if (!mock) {
        return done();
      }

      hockInstance
        .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/0.1.7-215?format=json')
        .reply(200, generateFilesResponse(0, 10000))
        .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/0.1.7-215?format=json&marker=FILE09999')
        .reply(200, generateFilesResponse(10000, 20000))
        .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/0.1.7-215?format=json&limit=3400&marker=FILE19999')
        .reply(200, generateFilesResponse(20000, 23400));

      client.getFiles('0.1.7-215', { limit: 23400 }, function (err, files) {
        should.not.exist(err);
        should.exist(files);
        files.should.have.length(23400);
        hockInstance && hockInstance.done();
        done();
      });
    });

    it('getFiles with limit = Infinity should return all files', function (done) {

      if (!mock) {
        return done();
      }

      hockInstance
        .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/0.1.7-215?format=json')
        .reply(200, generateFilesResponse(0, 10000))
        .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/0.1.7-215?format=json&marker=FILE09999')
        .reply(200, generateFilesResponse(10000, 20000))
        .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/0.1.7-215?format=json&marker=FILE19999')
        .reply(200, []);

      client.getFiles('0.1.7-215', { limit: Infinity }, function (err, files) {
        should.not.exist(err);
        should.exist(files);
        files.should.have.length(20000);
        hockInstance && hockInstance.done();
        done();
      });
    });

    it('getFiles with marker should start offset appropriately', function (done) {

      if (mock) {
        hockInstance
          .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/0.1.7-215?format=json&marker=ubuntu-10.04-x86_64%2Fconf%2Fdistributions')
          .replyWithFile(200, __dirname + '/../../fixtures/rackspace/getFilesMarker.json');
      }

      client.getFiles('0.1.7-215', { marker: 'ubuntu-10.04-x86_64/conf/distributions' }, function (err, files) {
        should.not.exist(err);
        should.exist(files);
        files.should.have.length(1);
        files.forEach(function (f) {
          f.should.be.instanceof(File);
        });
        hockInstance && hockInstance.done();
        done();
      });
    });

    it('getFiles with marker and limit should start offset appropriately', function (done) {

      if (mock) {
        hockInstance
          .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/0.1.7-215?format=json&limit=4&marker=CHANGELOG')
          .replyWithFile(200, __dirname + '/../../fixtures/rackspace/getFilesLimitMarker.json');
      }

      client.getFiles('0.1.7-215', { limit: 4, marker: 'CHANGELOG' }, function (err, files) {
        should.not.exist(err);
        should.exist(files);
        files.should.have.length(4);
        files.forEach(function (f) {
          f.should.be.instanceof(File);
        });
        hockInstance && hockInstance.done();
        done();
      });
    });

    it('getFile should URL encode the file name', function (done) {
      if (mock) {
        hockInstance
          .head('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/0.1.7-215/~!%40%23%24%25%5E%26*()_%2B/~!%40%23%24%25%5E%26*()_%2B?format=json')
          .reply(200);
      }

      client.getFile('0.1.7-215', '~!@#$%^&*()_+/~!@#$%^&*()_+', function (err, file) {
        should.not.exist(err);
        should.exist(file);
        file.should.be.instanceof(File);
        hockInstance && hockInstance.done();
        done();
      });
    });

    it('extract should ask server to extract the uploaded tar file', function(done) {
      
      var data = 'H4sIABub81EAA+3TzUrEMBAH8CiIeNKTXvMC1nxuVzx58CiC9uBNam1kQZt1N4X1XXwDX9IJXVi6UDxo6sH/D4akadJOmY7z/owlJkhubTdOulEo040dJpXMTS6tjuuSriTjNnViUbsM5YJztvCPs+atHdxH25wbI6FxOap/9hDqZcjCKqR5RyzwxJjB+iurN/WXiuqvpdGMizTp9P3z+rO94322y9h1WfGbO37P1+IaO6BQFO8U8fqzd/Jo6JGXRXG7nsYTHxSHW1t2NusnlX/Nyvn8pc6KehWumso/zZpnutkGdzq9kNrQv3E+Nb/yudAX+z9t93/f/0LIrf5XNEP/j0H+dQIAAAAAAAAAAAAAAAAAAADwY194ELb5ACgAAA==';
      var tmp = './foo.tar.gz';
      fs.writeFileSync(tmp, new Buffer(data, 'base64'));
      
      if (mock) {
        authHockInstance
          .post('/v2.0/tokens', {
            auth: {
              'RAX-KSKEY:apiKeyCredentials': {
                username: 'MOCK-USERNAME',
                apiKey: 'MOCK-API-KEY'
              }
            }
          })
          .reply(200, helpers.getRackspaceAuthResponse());

        hockInstance
          .put('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00?extract-archive=tar.gz', new Buffer(data, 'base64').toString())
          .replyWithFile(200, __dirname + '/../../fixtures/rackspace/extract.json');
      }
      
      
      
      client.extract({
        local: tmp
      }, function(e, ok, resp) {
        should.not.exist(e);
        should.exist(resp);
        hockInstance && hockInstance.done();
        
        fs.unlinkSync(tmp);
        done();
      });
      
    });

    after(function (done) {
      if (!mock) {
        return done();
      }
      

      async.parallel([
        function (next) {
          server.close(next);
        },
        function (next) {
          authServer.close(next);
        }
      ], done);
    });
  });
});

