test("claimTask requires scopes", async () => {
    var taskId = slugid.v4();

    await helper.queue.createTask(taskId, taskDef);

    // leave out a required scope
    helper.scopes(
      'assume:worker-type:no-provisioner/test-worker',
      'assume:worker-id:my-worker-group/my-worker'
    );
    // First runId is always 0, so we should be able to claim it here
    await helper.queue.claimTask(taskId, 0, {
      workerGroup:    'my-worker-group',
      workerId:       'my-worker'
    }).then(() => {
      throw new Error("Expected an authentication error");
    }, (err) => {
      debug("Got expected authentiation error: %s", err);
    });

    // leave out a required scope
    helper.scopes(
      'queue:claim-task',
      'assume:worker-id:my-worker-group/my-worker'
    );
    // First runId is always 0, so we should be able to claim it here
    await helper.queue.claimTask(taskId, 0, {
      workerGroup:    'my-worker-group',
      workerId:       'my-worker'
    }).then(() => {
      throw new Error("Expected an authentication error");
    }, (err)  => {
      debug("Got expected authentiation error: %s", err);
    });

    // leave out a required scope
    helper.scopes(
      'queue:claim-task',
      'assume:worker-type:no-provisioner/test-worker'
    );
    // First runId is always 0, so we should be able to claim it here
    await helper.queue.claimTask(taskId, 0, {
      workerGroup:    'my-worker-group',
      workerId:       'my-worker'
    }).then(() => {
      throw new Error("Expected an authentication error");
    }, (err) => {
      debug("Got expected authentiation error: %s", err);
    });
  });
 test('Expiring Namespace', async function() {
   // Create expiration
   var expiry = new Date();
   var myns     = slugid.v4();
   var taskId   = slugid.v4();
   var taskId2  = slugid.v4();
   await helper.index.insertTask(myns+'.one-ns.my-task', {
     taskId:     taskId,
     rank:       41,
     data:       {hello: 'world'},
     expires:    expiry.toJSON(),
   });
   let result = await helper.index.findTask(myns + '.one-ns.my-task');
   assert(result.taskId === taskId, 'Wrong taskId');
   expiry.setDate(expiry.getDate() - 2);
   await helper.index.insertTask(myns + '.another-ns.my-task', {
     taskId:     taskId2,
     rank:       42,
     data:       {hello: 'world two'},
     expires:    expiry.toJSON(),
   });
   result = await helper.index.findTask(myns + '.another-ns.my-task');
   assert(result.taskId === taskId2, 'Wrong taskId');
   // Set now to one day in the past 
   var now = taskcluster.fromNow('- 1 day');
   
   debug('Expiring namespace at: %s, from before %s', new Date(), now);
   await helper.handlers.Namespace.expireEntries(now);
   
   result = await helper.index.listNamespaces(myns, {});
   assert.equal(result.namespaces.length, 1, 'Expected 1 namespace');
   assert(result.namespaces.some(function(ns) {
     return ns.name === 'one-ns';
   }), 'Expected to find one-ns');
   
 });
  test("upload w. generateWriteSAS", function() {
    var key = slugid.v4();
    var expiry = new Date();
    expiry.setMinutes(expiry.getMinutes() + 20);
    var sas = blobstore.generateWriteSAS(key, {expiry: expiry});
    assert(sas, "Failed to generate a signature");

    // Create BlobUploader
    var uploader = new BlobUploader(sas);
    var block1 = slugid.v4();
    var block2 = slugid.v4();

    return Promise.all([
      uploader.putBlock(block1, '{"block1_says": "Hello world",\n'),
      uploader.putBlock(block2, '"block2_says": "Hello Again"}\n')
    ]).then(function() {
      return uploader.putBlockList([block1, block2], 'application/json');
    }).then(function() {
      return blobstore.get(key);
    }).then(function(result) {
      assert(result.block1_says === 'Hello world', "block 1 incorrect");
      assert(result.block2_says === 'Hello Again', "block 2 incorrect");
    });
  });
  test("abort task while pulling image", async () => {
    // Purposely using a large image that would take awhile to download.  Also,
    // this might need to be adjusted later to have a meaningful test.  If an
    // image is removed but the intermediate layers are used elsewhere, the image
    // is just untagged.  When pull image happens, the layers are there so there is
    // nothing to downloading causing the node termination notice to not happen
    // until after the task has started usually.
    let image = 'ubuntu:12.10';
    await dockerUtils.removeImageIfExists(docker, image);
    let task = {
      payload: {
        image: image,
        command: [
          '/bin/bash', '-c', 'echo "Hello"; sleep 15; echo "done";'
        ],
        maxRunTime: 60 * 60
      }
    };
    let taskId = slugid.v4();
    worker = new TestWorker(DockerWorker);
    worker.on('ensure image', (msg) => {
      if (msg.image.name === image) { settings.nodeTermination(); }
    });
    let launch = await worker.launch();
    let result = await worker.postToQueue(task, taskId);
    let taskStatus = await worker.queue.status(taskId);

    assert.equal(taskStatus.status.runs[0].state, 'exception',
      'First run should have been marked as exception on worker-shutdown'
    );

    assert.equal(taskStatus.status.runs[0].reasonResolved, 'worker-shutdown',
      'First run should be resolved with a reason of "worker-shutdown"'
    );

    let log = await getArtifact(
      { taskId: taskId, runId: 0 }, 'public/logs/live_backing.log'
    );

    assert.equal(log.indexOf('Artifact not found'), -1,
      'Backing log should have been created when task was aborted'
    );

    assert.equal(log.indexOf('Hello'), -1, 'Task should not have started after being aborted.')
    assert.notEqual(log.indexOf('Task has been aborted prematurely. Reason: worker-shutdown'), -1,
      'Log should indicate that task was aborted with a reason of "worker-shutdown"'
    );
  });
function route(context) {
  let path = context.url;

  if (path.indexOf(PREFIX) === 0) {
    path = path.slice(PREFIX.length);
  }

  switch (path) {
  case '/generate-secrets': {
    context.app.secretToken = slugid.v4();
    context.app.provisionerBaseUrl = PROVISIONER_BASE_URL;
    let payload = JSON.stringify({
      url: PROVISIONER_BASE_URL,
      token: context.app.secretToken
    });
    return payload;
  }
  case '/meta-data/public-hostname':
    return 'publichost';
  case '/meta-data/public-ipv4':
    return '22.33.44.252';
  case '/meta-data/local-ipv4':
    return '169.254.1.2';
  case '/user-data':
    return new Buffer(JSON.stringify({
      capacity: 1,
      provisionerBaseUrl: context.app.provisionerBaseUrl,
      securityToken: context.app.secretToken,
      workerType: 'ami-333333',
      provisionerId: 'aws-provisioner',
      data: {
        dockerConfig: {
          allowPrivileged: true
        }
      }
    }));
  case '/meta-data/ami-id':
    return 'ami-333333';
  case '/meta-data/instance-type':
    return 'c3.xlarge';
  case '/meta-data/placement/availability-zone':
    return 'us-west-2d';
  case '/meta-data/instance-id':
    return 'i-123456';
  default:
    throw new Error('unknown path: ' + path);
  }
}
  test('listen for task (bind early)', function() {
    // Decide taskId upfront
    var taskId = slugid.v4();

    // Create listener
    var listener = new taskcluster.WebListener({baseUrl: baseUrl});

    // Listen for message
    var gotMessage = new Promise(function(accept) {
      listener.on('message', function(message) {
        if (message.payload.status.taskId === taskId) {
          accept();
        }
      });
    });

    // Bind to queue events
    var queueEvents = new taskcluster.QueueEvents();
    return listener.bind(queueEvents.taskDefined({taskId: taskId})).then(function() {
      // Connect listener
      return listener.connect();
    }).then(function() {
      // Submit a test task
      var queue = new taskcluster.Queue({
        credentials:  cfg.get('taskcluster:credentials')
      });
      var deadline = new Date();
      deadline.setHours(deadline.getHours() + 2);
      return queue.defineTask(taskId, {
        provisionerId:    "dummy-test-provisioner",
        workerType:       "dummy-test-worker-type",
        schedulerId:      "dummy-test-scheduler",
        created:          (new Date()).toJSON(),
        deadline:         deadline.toJSON(),
        payload:          {},
        metadata: {
          name:           "Print `'Hello World'` Once",
          description:    "This task will prìnt `'Hello World'` **once**!",
          owner:          "*****@*****.**",
          source:         "https://github.com/taskcluster/taskcluster-events"
        }
      });
    }).then(function() {
      return gotMessage;
    }).then(function() {
      return listener.close();
    });
  });
 beforeEach(async function() {
   wName = slugid.v4();
   wType = await subject.create(wName, makeWorkerType({
     maxPrice: 6,
     lastModified: new Date(),
     regions: [
       makeRegion({region: 'region1'}),
       makeRegion({region: 'region2'}),
       makeRegion({region: 'region3'}),
     ],
     instanceTypes: [
       makeInstanceType({instanceType: 'type1', capacity: 1, utility: 1}),
       makeInstanceType({instanceType: 'type2', capacity: 2, utility: 2}),
     ],
   }));
 });
 test("createSignedGetUrl", function() {
   var key = slugid.v4();
   return blobstore.put(key, {message: "Hello"}).then(function() {
     var expiry = new Date();
     expiry.setMinutes(expiry.getMinutes() + 5);
     var url = blobstore.createSignedGetUrl(key, {expiry: expiry});
     return request
               .get(url)
               .end()
               .then(function(res) {
                 assert(res.ok, "Request failed");
                 assert(res.body.message === 'Hello',
                        "message didn't message");
               });
   });
 });
describe('provisioner worker type api', () => {

  var id = slugid.v4();
  var workerTypeDefinition = makeWorkerType();
  var workerTypeChanged = _.clone(workerTypeDefinition);
  workerTypeChanged.maxCapacity = 15;

  it('should be able to create a worker (idempotent)', async () => {
    debug('### Create workerType');
    await helper.awsProvisioner.createWorkerType(id, workerTypeDefinition);

    debug('### Create workerType (again)');
    await helper.awsProvisioner.createWorkerType(id, workerTypeDefinition);
  });

  it('should be able to update a worker', async () => {
    debug('### Load workerType');
    var wType = await helper.awsProvisioner.workerType(id);
    assume(wType.maxCapacity).equals(20);

    debug('### Update workerType');
    try {
      await helper.awsProvisioner.updateWorkerType(id, workerTypeChanged);
    } catch (e) {
      console.log(JSON.stringify(e));
      throw e;
    }

    debug('### Load workerType (again)');
    wType = await helper.awsProvisioner.workerType(id);
    assume(wType.maxCapacity).equals(15);
  });

  it('should be able to remove a worker (idempotent)', async () => {
    debug('### Remove workerType');
    await helper.awsProvisioner.removeWorkerType(id);
    await helper.awsProvisioner.removeWorkerType(id);

    debug('### Try to load workerType');
    try {
      await helper.awsProvisioner.workerType(id);
      throw new Error('Expected and error');
    } catch (err) {
      assume(err.statusCode).equals(404);
    }
  });
});
Example #10
0
describe('secrets api', () => {
  let client;

  var token = slugid.v4();
  var secretToAdd = {
    workerType: 'workerType',
    secrets: {
      key1: true,
      key2: 123,
      key3: 'sample',
      key4: {a: 123},
    },
    scopes: ['ascope'],
    token: token,
    expiration: taskcluster.fromNow('1 day'),
  };

  before(async () => {
    client = helper.getClient();
  });

  beforeEach(async () => {
    await main('tableCleaner', {process: 'tableCleaner', profile: 'test'});
  });
  
  it('should be able to create a secret (idempotent)', async () => {
    await client.createSecret(token, secretToAdd);
    await client.createSecret(token, secretToAdd);
  });

  it('should be able to load a secret', async () => {
    await client.createSecret(token, secretToAdd);
    var loadedSecret = await client.getSecret(token);
    assume(loadedSecret.data).to.eql(secretToAdd.secrets);
  });

  it('should be able to remove a secret (idempotent)', async () => {
    await client.removeSecret(token);
    await client.removeSecret(token);

    try {
      await client.getSecret(token);
    } catch (err) {
      assume(err.statusCode).equals(404);
    }
  });
});
  test('does not create multiple taskgraphs', co(function * () {
    // Make a slow taskgraph, which will eventually pass.
    var taskgraphFirstSlow = fs.readFileSync(__dirname + '/fixtures/tc_success/taskgraph.json', 'utf-8');
    taskgraphFirstSlow = jsTemplate(taskgraphFirstSlow, {
      taskId: slugid.v4()
    });
    taskgraphFirstSlow = JSON.parse(taskgraphFirstSlow);
    taskgraphFirstSlow.tasks[0].task.payload.command[2] = "sleep 10s && echo \"Hello World\";"
    taskgraphFirstSlow = JSON.stringify(taskgraphFirstSlow);

    yield commitContent(runtime, 'master', 'taskgraph.json', taskgraphFirstSlow);
    var bug = yield createBug(runtime);

    yield branchFromRef(runtime, 'branch1');
    yield commitContent(runtime, 'branch1', 'foo.txt', 'foo', 'Bug ' + bug.id + ' - add foo.txt');
    var pullSlow = yield createPullRequest(runtime, 'branch1', 'master', 'Bug ' + bug.id + ' - check that we only process once');
    var attachments1 = yield waitForAttachments(runtime, bug.id);
    yield reviewAttachment(runtime, attachments1[0]);
    yield setCheckinNeeded(runtime, bug.id);

    // Wait until the pull request is in a pending state.
    // This way we know that we've already branched to the integration-master branch.
    // This is important so we know we don't have our later commit from master which we use to intentionally ruin the fast-forward.
    yield waitForPullState(runtime, 'autolander', 'autolander-test', 'branch1', 'pending');

    // Add a comment to the bug to see if it's going to cause us to process it twice.
    var addComment = thunkify(runtime.bugzillaApi.addComment.bind(runtime.bugzillaApi));
    yield addComment(bug.id, {
      comment: 'here is a test comment.'
    });

    // Make sure the retry landing looks good.
    yield waitForLandingComment(runtime, bug.id);
    yield waitForCheckinNeededRemoved(runtime, bug.id);
    yield waitForResolvedFixed(runtime, bug.id);

    // We should have two statuses on the pull request.
    var statuses = yield getStatusesFromBranchTip(runtime, 'autolander', 'autolander-test', 'branch1');
    assert.equal(statuses.length, 2);
    assert.equal(statuses[0].state, 'success');
    assert.equal(statuses[1].state, 'pending');

    // The bug should have four comments:
    // The description, attachment, test comment, and landing comment.
    var comments = yield getBugComments(runtime, bug.id);
    assert.equal(comments.length, 4);
  }));
  test("Schedule a task-graph (wrong taskGroupId)", function() {
    // Make task graph
    var taskGraph = makeTaskGraph();
    taskGraph.tasks[0].task.taskGroupId = slugid.v4();

    // Submit taskgraph to scheduler
    debug("### Posting task-graph");
    return subject.scheduler.createTaskGraph(
      taskGraphId,
      taskGraph
    ).then(function(result) {
      assert(false, "This should have failed");
    }, function(err) {
      debug("Expected err: %s, %j", err, err, err.stack);
      assert(err.statusCode === 400, "Expected an error");
    });
  });
  test('createGetUrl', async function() {
    const key = slugid.v4();
    const putUrl = await bucket.createPutUrl(key, {
      contentType: 'application/json',
      expires: 60 * 10,
    });

    let res = await request.put(putUrl).send({message: 'Hello'});
    assert(res.ok, 'put request failed');

    const getUrl = bucket.createGetUrl(key);
    debug('createGetUrl -> %s', getUrl);

    res = await request.get(getUrl);
    assert(res.ok, 'get request failed');
    assert(res.body.message === 'Hello', 'wrong message');
  });
  test('update after a push', async function() {
    let changesets = [
      {
       author: 'Author <*****@*****.**>',
       branch: 'default',
       desc: 'desc',
       files: [
        'xfoobar'
       ],
       node: slugid.v4(),
       tags: []
      },
      {
       author: '*****@*****.**',
       branch: 'default',
       desc: 'desc +tc',
       files: [
        'xfoobar'
       ],
       node: changeset,
       tags: []
      },
    ];

    let lastChangeset = changesets[changesets.length - 1];
    let schedulerEvents = new taskcluster.SchedulerEvents();
    let queueEvents = new taskcluster.QueueEvents();

    await this.pulse.connect();
    let route = `route.testme.try.${lastChangeset.node}`
    this.pulse.bind(queueEvents.taskPending(route));

    monitorSetup.pushlog.push(changesets);

    await this.pulse.resume();
    // Consume the queue now that the event has been sent...
    let [ message ] = await Promise.all([
      eventToPromise(this.pulse, 'message'),
      this.pulse.resume()
    ]);

    let queue = new taskcluster.Queue();
    let task = await queue.getTask(message.payload.status.taskId);
    assert.equal(task.routes[0], route.replace('route.', ''));
  });
  test("can claimTask", async () => {
    var taskId = slugid.v4();

    debug("### Start listening for task running message");
    await helper.events.listenFor('running', helper.queueEvents.taskRunning({
      taskId:   taskId
    }));

    debug("### Creating task");
    await helper.queue.createTask(taskId, taskDef);

    debug("### Claim task");
    // Reduce scopes available to test minimum set of scopes required
    helper.scopes(
      'queue:claim-task',
      'assume:worker-type:no-provisioner/test-worker',
      'assume:worker-id:my-worker-group/my-worker'
    );
    // First runId is always 0, so we should be able to claim it here
    var before = new Date();
    var r1 = await helper.queue.claimTask(taskId, 0, {
      workerGroup:    'my-worker-group',
      workerId:       'my-worker'
    });
    var takenUntil = new Date(r1.takenUntil);
    // Compare to time before the request, because claimTimeout is very small
    // so we can only count on takenUntil being larger than or equal to the
    // time before the request was made
    assume(takenUntil.getTime()).is.greaterThan(before.getTime() - 1);

    debug("### Waiting for task running message");
    var m1 = await helper.events.waitFor('running');
    assume(m1.payload.status).deep.equals(r1.status);

    debug("### Fetch task status");
    var r2 = await helper.queue.status(taskId);
    assume(r2.status).deep.equals(r1.status);

    await base.testing.sleep(100);

    // Again we talking about the first run, so runId must still be 0
    var r3 = await helper.queue.reclaimTask(taskId, 0);
    var takenUntil2 = new Date(r3.takenUntil);
    assume(takenUntil2.getTime()).is.greaterThan(takenUntil.getTime() - 1);
  });
  test('auth with non-root user', async () => {
    let clientId = slugid.v4();
    let result = await helper.apiClient.createClient(clientId, {
      expires:      new Date(3000, 1, 1), // far out in the future
      description:  'Client used by automatic tests, file a bug and delete if' +
                    ' you ever see this client!',
      scopes:       ['myapi:*'],
    });

    let myClient = new helper.TestClient({
      rootUrl: helper.rootUrl,
      credentials: {
        clientId:     result.clientId,
        accessToken:  result.accessToken,
      },
    });
    await myClient.resource();
  });
  test('reportException (superseded) is idempotent', async () => {
    const taskId = slugid.v4();

    debug('### Creating task');
    await helper.queue.createTask(taskId, taskDef);

    debug('### Claiming task');
    // First runId is always 0, so we should be able to claim it here
    let r1 = await helper.queue.claimTask(taskId, 0, {
      workerGroup:    'my-worker-group',
      workerId:       'my-worker',
    });

    debug('### Reporting task exception');
    helper.scopes(
      'queue:resolve-task',
      'assume:worker-id:my-worker-group/my-worker',
    );
    await helper.queue.reportException(taskId, 0, {
      reason:     'superseded',
    });
    helper.checkNextMessage('task-exception', m => {
      assume(m.payload.status.runs[0].state).equals('exception');
      assume(m.payload.status.runs[0].reasonResolved).equals('superseded');
    });

    debug('### Reporting task exception (again)');
    await helper.queue.reportException(taskId, 0, {
      reason:     'superseded',
    });
    helper.checkNextMessage('task-exception');

    debug('### Check status of task');
    const {status: s2} = await helper.queue.status(taskId);
    assume(s2.runs[0].state).equals('exception');
    assume(s2.runs[0].reasonResolved).equals('superseded');

    debug('### Reporting task exception (using temp creds)');
    let queue = new helper.Queue({rootUrl: helper.rootUrl, credentials: r1.credentials});
    await queue.reportException(taskId, 0, {
      reason:     'superseded',
    });
    helper.checkNextMessage('task-exception');
  });
  test("exit $MY_ENV_VAR; with MY_ENV_VAR = 1", function() {
    // Create a taskId
    var taskId = slugid.v4();

    // Start listening for a task-failed message with the generated taskId
    return helper.receiver.listenFor(
      'failed',
      helper.queueEvents.taskFailed({taskId: taskId})
    ).then(function() {
      // Create task
      debug("Submitting task: %s", taskId);
      return helper.queue.createTask(taskId, {
        provisionerId:    'aws-provisioner',
        workerType:       'v2',
        created:          taskcluster.utils.fromNow(),
        deadline:         taskcluster.utils.fromNow('1 hour'),
        payload:          {
          image:          "ubuntu:14.04",
          command:        ["/bin/bash", "-c", "exit $MY_ENV_VAR;"],
          env: {
            MY_ENV_VAR:   '1'
          },
          maxRunTime:     20 * 60
        },
        metadata: {
          name:           "Dummy Test Task",
          description:    "Task for docker-worker that tests environment " +
                          "variables and completes unsuccessfully",
          owner:          "*****@*****.**",
          source:         "https://github.com/taskcluster/taskcluster-diagnostics"
        }
      });
    }).then(undefined, function(err) {
      // Print the error
      debug("queue.createTask error: %j", err);
      // Retrow the error
      throw err;
    }).then(function() {
      return helper.receiver.waitFor('failed');
    }).then(function(message) {
      assert(message.payload.status.taskId === taskId,
             "Expected message to have taskId");
    });
  });
 test('createWorkerType', function() {
   var workerType = slugid.v4();
   debug("Trying to create: %s", workerType);
   return request
           .post(baseUrl + '/worker-type/update')
           .send({
             updateOrCreate:       'create',
             workerType:           workerType,
             launchSpecification: {
               ImageId:            'ami-7eaecc4e',
               InstanceType:       't1.micro'
             },
             maxInstances:         1,
             spotBid:              0.2
           }).end().then(function(res) {
             debug("Created workerType: %s", workerType);
             assert(res.ok);
           });
 });
Example #20
0
  constructor(Worker, workerType, workerId) {
    // Load the test time configuration for all the components...
    var config = loadConfig({
      defaults: require('../config/defaults'),
      profile: require('../config/test'),
      filename: 'docker-worker-test'
    });

    this.provisionerId = PROVISIONER_ID;
    this.workerType = workerType || slugid.v4();
    // remove leading underscores because workerId could be used as container name
    // and container names must start with an alphanumeric character.
    this.workerId = workerId || this.workerType.replace(/^[_-]*/, '');
    this.worker = new Worker(PROVISIONER_ID, this.workerType, this.workerId);

    this.pulse = config.get('pulse');

    this.queue = new Queue({
      credentials: config.get('taskcluster')
    });

    this.scheduler = new Scheduler({
      credentials: config.get('taskcluster')
    });

    var deadline = new Date();
    deadline.setMinutes(deadline.getMinutes() + 60);

    this.TaskFactory = Task.extend({
      properties: {
        deadline: deadline,
        workerType: this.workerType,
        provisionerId: PROVISIONER_ID,
        metadata: {
          description: 'jonas damn you',
          owner: '*****@*****.**',
          name: 'Task from docker-worker test suite',
          source: 'http://foobar.com'
        }
      }
    });
    super();
  }
Example #21
0
File: auth.js Project: chasm/wp6
let reset = function *() {
  let email = this.request.body.fields.email
  let id = slugid.v4()

  let result = yield r.db("quoth").table("users").filter({ email: email}).run()

  if (result) {

    let userId = result[ 0 ].id
    let user = {
      resetCode: id,
      resetExpiresAt: moment().add(2, "hours").toDate()
    }

    let updated = yield r.db("quoth").table("users").get(userId).update(user).run()

    if(updated.replaced === 1 ) {
      let sender = "*****@*****.**"
      let subject = "[Quoth] Reset your credentials"
      let body = "Someone requested to reset your Quoth credentials. To change them " +
        "please follow this link: http://localhost:3000/reset/" + id

      let receiver = email

      try {
        let thunk = yield getPostmarkThunk(sender, receiver, subject, body)

        if (thunk) {
          this.type = "application/json"
          this.body = JSON.stringify(thunk)
        } else {
          this.status = 400
        }
      } catch (err) {
        console.log("err", err)
      }
    } else {
      console.log("error updating user")
    }
  } else {
    this.status = 404
  }
}
 var makeTask = (expiration) => {
   var task = {
     provisionerId:    'no-provisioner',
     workerType:       'test-worker',
     created:          taskcluster.fromNowJSON(),
     deadline:         taskcluster.fromNowJSON('1 day'),
                       // Notice that in config/test.js we've configured
                       // expire-tasks to expire 4 days before expires
     expires:          taskcluster.fromNowJSON(expiration),
     retries:          1,
     payload:          {},
     metadata: {
       name:           "Unit testing task",
       description:    "Task created during unit tests",
       owner:          '*****@*****.**',
       source:         'https://github.com/taskcluster/taskcluster-queue'
     }
   };
   return {taskId: slugid.v4(), task};
 }
  test('conflict with reserved environment variable (RUN_ID)', async () => {

    var taskId = slugid.v4();
    var taskPayload = await getTaskPayload(
      [{taskId: taskId,
        name: 'RUN_ID',
        value: secretDataContent1},
      {taskId: taskId,
        name: envVar1,
        value: secretDataContent2}]
    );

    var expected = 'an environment variable conflicts with an existing environment variable';
    var result = await testworker(taskPayload, taskId);
    var log = result.log.replace(/\n/gm, ' ');

    assert.equal(result.run.state, 'failed', 'task should have failed');
    assert.equal(result.run.reasonResolved, 'failed', 'task should have failed');
    assert.ok(log.indexOf(expected) !== -1, 'env is dumped');
  });
  test('duplicate environment variable', async () => {

    var taskId = slugid.v4();
    var taskPayload = await getTaskPayload(
      [{taskId: taskId,
        name: envVar1,
        value: secretDataContent1},
      {taskId: taskId,
        name: envVar1,
        value: secretDataContent2}]
    );

    var expected = 'an environment variable has been duplicated in the task payload';
    var result = await testworker(taskPayload, taskId);
    var log = result.log.replace(/\n/gm, ' ');

    assert.equal(result.run.state, 'failed', 'task should have failed');
    assert.equal(result.run.reasonResolved, 'failed', 'task should have failed');
    assert.ok(log.indexOf(expected) !== -1, 'env is dumped');
  });
 test("Item.create", function() {
   var date  = new Date();
   var id    = slugid.v4();
   return Item.create({
     pk:       id,
     rk:       "row-key",
     str:      "Hello World",
     nb:       1337.2,
     json:     {Hello: "World"},
     ID:       id,
     date:     date
   }).then(function(item) {
     assert(item.pk    === id,             "pk mismatch");
     assert(item.rk    === 'row-key',      "row-key mismatch");
     assert(item.str   === 'Hello World',  "str mismatch");
     assert(item.nb    === 1337.2,         "nb mismatch");
     assert(item.json.Hello  === "World",  "json mismatch");
     assert(item.date  === date,           "Date mismatch");
   });
 });
var generatePayloadAndLaunch = function(matrix, payload) {
    // I might not really need the payload object here...
    // Javascript closures are hard

    if(Object.keys(matrix).length === 0) {
        // Finished applying one set from the matrix
        console.log('Count: ' + count++);
        payload.created = taskcluster.fromNowJSON();
        payload.deadline = taskcluster.fromNowJSON(jobinfo.deadline);
        var taskId = slugid.v4();
        console.log('TaskURL: ' + taskInspectorURL + '#' + taskId);
        console.log();
        console.log(payload);
        queue.createTask(taskId, payload).then(function(result) {
            //console.log(result);
            console.log(result.status);
        }, function(failure) {
            console.log(failure);
            throw new Error('Task could not be created');
        });
        console.log('********************************************************************************');
    }

    // Get an attribute we handle in this function
    var attr = Object.keys(matrix)[0];

    // Values for that attr
    var values = matrix[attr];

    for (var i in values) {
        delete matrix[attr];

        payload.payload[attr] = values[i];
        generatePayloadAndLaunch(matrix, payload);

        // Nasty hack to deal with Javascript object behaviour
        matrix[attr]=values;
    }

    return;
}
  test('success case', async () => {

    var taskId = slugid.v4();
    var taskPayload = await getTaskPayload(
      [{messageVersion: '1',
        taskId: taskId,
        name: envVar1,
        value: secretDataContent1},
      {messageVersion: '1',
        taskId: taskId,
        name: envVar2,
        value: secretDataContent2}]
    );

    var result = await testworker(taskPayload, taskId);

    assert.equal(result.run.state, 'completed', 'task should be successful');
    assert.equal(result.run.reasonResolved, 'completed', 'task should be successful');
    assert.ok(result.log.indexOf(secretDataContent1) !== -1, 'env is dumped');
    assert.ok(result.log.indexOf(secretDataContent2) !== -1, 'env is dumped');
  });
  test("Context properties can provided", async () => {
    // Create test api
    var api = new subject({
      title:        "Test Api",
      description:  "Another test api",
      context:      ['prop1', 'prop2']
    });

    var value = slugid.v4();
    let validate = await validator({
      folder:         path.join(__dirname, 'schemas'),
      baseUrl:        'http://localhost:4321/'
    });
    api.router({
      validator:  validate,
      context: {
        prop1: "value1",
        prop2: "value2"
      }
    });
  });
  test('auth with non-root user (expired)', async () => {
    let clientId = slugid.v4();
    let result = await helper.apiClient.createClient(clientId, {
      expires:      new Date(1998, 1, 1), // far back in the past
      description:  'Client used by automatic tests, file a bug and delete if' +
                    ' you ever see this client!',
      scopes:       ['myapi:*'],
    });

    let myClient = new helper.TestClient({
      rootUrl: helper.rootUrl,
      credentials: {
        clientId:     result.clientId,
        accessToken:  result.accessToken,
      },
    });
    await myClient.resource().then(() => {
      assert(false, 'expected an error!');
    }, err => {
      assert(err.statusCode === 401, 'expected 401');
    });
  });
  test('taskA <- taskA (self-dependency)', helper.runWithFakeTime(async () => {
    let taskIdA = slugid.v4();
    let taskA = _.defaults({
      dependencies: [taskIdA],
    }, taskDef());

    debug('### Create taskA');
    let r1 = await helper.queue.createTask(taskIdA, taskA);
    assume(r1.status.state).equals('unscheduled');
    helper.checkNextMessage('task-defined', m => assert.equal(m.payload.status.taskId, taskIdA));
    helper.checkNoNextMessage('task-pending'); // because of the self-dep

    debug('### scheduleTask');
    await helper.queue.scheduleTask(taskIdA);
    helper.checkNextMessage('task-pending', m => assert.equal(m.payload.status.taskId, taskIdA));

    debug('### claimTask');
    await helper.queue.claimTask(taskIdA, 0, {
      workerGroup:    'my-worker-group',
      workerId:       'my-worker',
    });
  }, mock));