/* eslint-env mocha */
/* global Config */
'use strict';

const should = require('should');
const Path = require('path');
const fs = require('fs');

const Metadata = require('../lib/source/metadata');
const fakeMetadata = JSON.parse(fs.readFileSync(Path.resolve(__dirname, './data/test-metadata.json')));

const NON_DEFAULT_INTERVAL = 10000;

describe('Metadata source plugin', () => {
  beforeEach(() => {
    this.m = new Metadata();
    this.m.service.host = '127.0.0.1:8080';
  });

  afterEach(() => {
    this.m.shutdown();
  });

  it('creates a Metadata source instance with a non-default timer interval', () => {
    const m = new Metadata({
      interval: NON_DEFAULT_INTERVAL
    });

    m.interval.should.equal(NON_DEFAULT_INTERVAL);
  });

  it('initializes a timer with the set interval', (done) => {
    this.m.on('update', () => {
      this.m._timer.should.have.keys(['_called', '_idleNext', '_idlePrev', '_idleStart', '_idleTimeout',
        '_onTimeout', '_repeat']);
      done();
    });

    this.m.initialize();
  });

  it('munges a set of paths to create a valid data object', (done) => {
    this.m.on('update', () => {
      const instance = this.m.properties.instance;
      const fake = fakeMetadata.latest['meta-data'];
      const creds = JSON.parse(fake.iam['security-credentials']['fake-role-name']);

      instance['ami-id'].should.equal(fake['ami-id']);
      instance.hostname.should.equal(fake.hostname);
      instance.identity.document.should.equal(fakeMetadata.latest.dynamic['instance-identity'].document);
      instance.credentials.lastUpdated.should.equal(creds.LastUpdated);

      done();
    });

    this.m.initialize();
  });

  it('shuts down cleanly', (done) => {
    this.m.on('shutdown', () => {
      const status = this.m.status();

      status.running.should.be.false();
      done();
    });

    this.m.initialize();
    this.m.shutdown();
  });

  it('initialize returns a promise', () => {
    this.m.initialize().should.be.instanceOf(Promise);
  });

  it('clears the sha1 signature when it\'s shutdown', (done) => {
    this.m.on('shutdown', () => {
      should(this.m.signature).be.null();
      done();
    });

    this.m.initialize();
    this.m.shutdown();
  });

  it('doesn\'t update data if the Metadata Service document is the same', (done) => {
    let instanceId = null,
        signature = null,
        secondExecution = false;

    this.m.on('update', () => {
      instanceId = this.m.properties.instance['ami-id'];
      signature = this.m.signature;

      secondExecution = true;

      // This is a terrible hack
      this.m._timer = false;
      this.m.initialize();
    });

    this.m.on('no-update', () => {
      if (secondExecution) {
        this.m.properties.instance['ami-id'].should.equal(instanceId);
        this.m.signature.should.equal(signature);
        done();
      }
    });

    this.m.initialize();
  });

  it('exposes an error when one occurs but continues running', (done) => {
    this.m.service.host = '0.0.0.0';
    this.m.on('error', (err) => {
      const status = this.m.status();

      err.code.should.equal('ECONNREFUSED');
      status.ok.should.be.false();
      status.running.should.be.true();
      done();
    });

    this.m.initialize();
  });

  it('identifies as a \'ec2-metadata\' source plugin', () => {
    this.m.type.should.equal('ec2-metadata');
  });

  after(() => {
    this.m.service.host = '127.0.0.1:8080';
  });
});

@@ -815,32 +815,34 @@
  %7B%0A    this.m.on
+ce
 ('update', () =%3E
@@ -840,24 +840,24 @@
 e', () =%3E %7B%0A
-
       this.m
@@ -1116,32 +1116,34 @@
  %7B%0A    this.m.on
+ce
 ('update', () =%3E
@@ -1720,32 +1720,34 @@
  %7B%0A    this.m.on
+ce
 ('shutdown', () 
@@ -2094,16 +2094,18 @@
 his.m.on
+ce
 ('shutdo
@@ -2423,16 +2423,18 @@
 his.m.on
+ce
 ('update
@@ -2680,16 +2680,18 @@
 his.m.on
+ce
 ('no-upd
@@ -3031,16 +3031,16 @@
 0.0.0';%0A
-
     this
@@ -3044,16 +3044,18 @@
 his.m.on
+ce
 ('error'

Use once not on in tests to avoid multiple firings across cases