text: /*
   * Copyright 2014 Apereo Foundation (AF) Licensed under the
   * Educational Community License, Version 2.0 (the "License"); you may
   * not use this file except in compliance with the License. You may
   * obtain a copy of the License at
   *
   *     http://opensource.org/licenses/ECL-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an "AS IS"
   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
   * or implied. See the License for the specific language governing
   * permissions and limitations under the License.
   */
  var _ = require('underscore');
  var assert = require('assert');
  
  var AuthzUtil = require('oae-authz/lib/util');
  var RestAPI = require('oae-rest');
  var RestContext = require('oae-rest/lib/model').RestContext;
  var Context = require('oae-context').Context;
  var TestsUtil = require('oae-tests');
  
  var PrincipalsUtil = require('oae-principals/lib/util');
  var User = require('oae-principals/lib/model').User;
  
  describe('Principals', function() {
  
      // Rest context that can be used every time we need to make a request as a global admin
      var camAdminRestContext = null;
      // Rest context for a user that will be used inside of the tests
      var johnRestContext = null;
  
      /**
       * Function that will fill up the anonymous and the tenant admin context
       */
      before(function(callback) {
          // Fill up global admin rest context
          camAdminRestContext = TestsUtil.createTenantAdminRestContext(global.oaeTests.tenants.cam.host);
  
          // Fill up the rest context for our test user
          TestsUtil.generateTestUsers(camAdminRestContext, 1, function(err, users, john) {
              assert.ok(!err);
              johnRestContext = john.restContext;
              RestAPI.User.getMe(johnRestContext, function(err) {
                  assert.ok(!err);
                  return callback();
              });
          });
      });
  
  
      describe('Utilities', function() {
  
          /**
           * Create a number of users and groups that will be used inside of the tests
           * @param  {Function(principals)}   callback                Standard callback function
           * @param  {Object}                 callback.principals     Object where the keys are identifiers for the created principals and the values are
           *                                                          are the actual group/user context objects
           */
          var createUsersAndGroup = function(callback) {
  
              var createdPrincipals = {};
  
              var createPrincipal = function(type, identifier, metadata) {
                  var principalId = TestsUtil.generateTestUserId(identifier);
                  if (type === 'group') {
                      RestAPI.Group.createGroup(johnRestContext, metadata, metadata, 'public', 'yes', [], [], function(err, groupObj) {
                          assert.ok(!err);
                          createdPrincipals[identifier] = groupObj;
                          if (_.keys(createdPrincipals).length === 7) {
                              callback(createdPrincipals);
                          }
                      });
                  } else {
                      var email = TestsUtil.generateTestEmailAddress(null, global.oaeTests.tenants.cam.emailDomain);
                      RestAPI.User.createUser(camAdminRestContext, principalId, 'password', metadata, email, {}, function(err, userObj) {
                          assert.ok(!err);
                          var userContext = new Context(global.oaeTests.tenants.cam, userObj);
                          createdPrincipals[identifier] = userContext;
                          if (_.keys(createdPrincipals).length === 7) {
                              callback(createdPrincipals);
                          }
                      });
                  }
              };
  
              // Create 4 users
              createPrincipal('user', 'nicolaas', 'Nicolaas Matthijs');
              createPrincipal('user', 'simon', 'Simon Gaeremynck');
              createPrincipal('user', 'bert', 'Bert Pareyn');
              createPrincipal('user', 'branden', 'Branden Visser');
  
              // Create 3 groups
              createPrincipal('group', 'oae-team', 'OAE Team');
              createPrincipal('group', 'backend-team', 'Back-end Team');
              createPrincipal('group', 'ui-team', 'UI Team');
          };
  
  
          /**
           * Test that verifies the working of the getPrincipal utility function
           */
          it('verify get principal', function(callback) {
              createUsersAndGroup(function(createdPrincipals) {
  
                  // Get an existing user
                  PrincipalsUtil.getPrincipal(createdPrincipals['nicolaas'], createdPrincipals['nicolaas'].user().id, function(err, user) {
                      assert.ok(!err);
                      assert.ok(user);
                      assert.equal(user.id, createdPrincipals['nicolaas'].user().id);
                      assert.equal(user.displayName, 'Nicolaas Matthijs');
                      assert.equal(user.resourceType, 'user');
                      assert.equal(user.profilePath, '/user/' + user.tenant.alias + '/' + AuthzUtil.getResourceFromId(user.id).resourceId);
  
                      // Get a non-existing user
                      PrincipalsUtil.getPrincipal(createdPrincipals['nicolaas'], 'non-existing-user', function(err, user) {
                          assert.ok(err);
                          assert.ok(!user);
  
                          // Get an existing group
                          PrincipalsUtil.getPrincipal(createdPrincipals['nicolaas'], createdPrincipals['oae-team'].id, function(err, group) {
                              assert.ok(!err);
                              assert.ok(group);
                              assert.equal(group.id, createdPrincipals['oae-team'].id);
                              assert.equal(group.displayName, 'OAE Team');
                              assert.equal(group.resourceType, 'group');
                              assert.equal(group.profilePath, '/group/' + group.tenant.alias + '/' + AuthzUtil.getResourceFromId(group.id).resourceId);
  
                              // Get a non-existing group
                              PrincipalsUtil.getPrincipal(createdPrincipals['nicolaas'], 'non-existing-group', function(err, group) {
                                  assert.ok(err);
                                  assert.ok(!group);
                                  callback();
                              });
                          });
                      });
                  });
              });
          });
  
          /**
           * Test that verifies the working of the getPrincipals utility function, allowing the retrieval of
           * multiple principals at once
           */
          it('verify get principals', function(callback) {
              createUsersAndGroup(function(createdPrincipals) {
  
                  // Get existing users
                  PrincipalsUtil.getPrincipals(createdPrincipals['nicolaas'], [createdPrincipals['nicolaas'].user().id, createdPrincipals['simon'].user().id, createdPrincipals['bert'].user().id], function(err, users) {
                      assert.ok(!err);
                      assert.ok(users);
                      assert.equal(_.keys(users).length, 3);
                      assert.equal(users[createdPrincipals['nicolaas'].user().id].id, createdPrincipals['nicolaas'].user().id);
                      assert.equal(users[createdPrincipals['simon'].user().id].id, createdPrincipals['simon'].user().id);
                      assert.equal(users[createdPrincipals['bert'].user().id].id, createdPrincipals['bert'].user().id);
  
                      // Get existing groups
                      PrincipalsUtil.getPrincipals(createdPrincipals['nicolaas'], [createdPrincipals['oae-team'].id, createdPrincipals['backend-team'].id], function(err, groups) {
                          assert.ok(!err);
                          assert.ok(groups);
                          assert.equal(_.keys(groups).length, 2);
                          assert.equal(groups[createdPrincipals['oae-team'].id].id, createdPrincipals['oae-team'].id);
                          assert.equal(groups[createdPrincipals['backend-team'].id].id, createdPrincipals['backend-team'].id);
  
                          // Get existing users and groups
                          PrincipalsUtil.getPrincipals(createdPrincipals['nicolaas'], [createdPrincipals['oae-team'].id, createdPrincipals['nicolaas'].user().id, createdPrincipals['simon'].user().id, createdPrincipals['backend-team'].id, createdPrincipals['branden'].user().id], function(err, principals) {
                              assert.ok(!err);
                              assert.ok(principals);
                              assert.equal(_.keys(principals).length, 5);
                              assert.equal(principals[createdPrincipals['nicolaas'].user().id].id, createdPrincipals['nicolaas'].user().id);
                              assert.equal(principals[createdPrincipals['simon'].user().id].id, createdPrincipals['simon'].user().id);
                              assert.equal(principals[createdPrincipals['oae-team'].id].id, createdPrincipals['oae-team'].id);
                              assert.equal(principals[createdPrincipals['backend-team'].id].id, createdPrincipals['backend-team'].id);
                              assert.equal(principals[createdPrincipals['branden'].user().id].id, createdPrincipals['branden'].user().id);
  
                              // Get existing users, of which some don't exist
                              PrincipalsUtil.getPrincipals(createdPrincipals['nicolaas'], [createdPrincipals['nicolaas'].user().id, 'u:cam:non-existing-user', createdPrincipals['simon'].user().id], function(err, users) {
                                  assert.ok(!err);
                                  assert.strictEqual(_.keys(users).length, 2);
  
                                  // Get existing groups, of which some don't exist
                                  PrincipalsUtil.getPrincipals(createdPrincipals['nicolaas'], [createdPrincipals['oae-team'].id, 'u:cam:non-existing-group'], function(err, groups) {
                                      assert.ok(!err);
                                      assert.strictEqual(_.keys(groups).length, 1);
  
                                      // Get existing users/groups, of which some don't exist
                                      PrincipalsUtil.getPrincipals(createdPrincipals['nicolaas'], [createdPrincipals['oae-team'].id, createdPrincipals['nicolaas'].user().id, 'u:cam:non-existing-user', createdPrincipals['simon'].user().id, 'u:cam:non-existing-group'], function(err, principals) {
                                          assert.ok(!err);
                                          assert.strictEqual(_.keys(principals).length, 3);
                                          return callback();
                                      });
                                  });
                              });
                          });
                      });
                  });
              });
          });
  
          /**
           * Test that verifies the function that's used to create a cross-tenant unique principal id
           */
          it('verify principal identifiers', function() {
              var id = AuthzUtil.toId('g', 'cam', 'oae-team');
              assert.ok(PrincipalsUtil.isGroup(id));
  
              id = AuthzUtil.toId('u', 'cam', 'simong');
              assert.ok(PrincipalsUtil.isUser(id));
  
              id = AuthzUtil.toId('c', 'cam', 'foo.doc');
              assert.ok(!PrincipalsUtil.isUser(id));
              assert.ok(!PrincipalsUtil.isUser(id));
          });
  
          /**
           * Test that verifies the createUpdatedUser function
           */
          it('verify createUpdatedUser', function() {
              var source = new User('camtest', 'u:camtest:sourceId', 'sourceDisplayName', 'sourceEmail', {
                  'visibility': 'sourceVisibility',
                  'locale': 'sourceLocale',
                  'publicAlias': 'sourcePublicAlias'
              });
  
              // Verify tenant doesn't change
              var destUpdates = {'tenant': 'destTenant'};
              var dest = PrincipalsUtil.createUpdatedUser(source, destUpdates);
              assert.equal(dest.tenant.alias, 'camtest');
  
              // Verify id doesn't change
              destUpdates = {'id': 'dest'};
              dest = PrincipalsUtil.createUpdatedUser(source, destUpdates);
              assert.equal(dest.id, 'u:camtest:sourceId');
  
              // Verify displayName changes
              destUpdates = {'displayName': 'dest'};
              dest = PrincipalsUtil.createUpdatedUser(source, destUpdates);
              assert.equal(dest.displayName, 'dest');
  
              // Verify visibility changes
              destUpdates = {'visibility': 'dest'};
              dest = PrincipalsUtil.createUpdatedUser(source, destUpdates);
              assert.equal(dest.visibility, 'dest');
  
              // Verify locale changes
              destUpdates = {'locale': 'dest'};
              dest = PrincipalsUtil.createUpdatedUser(source, destUpdates);
              assert.equal(dest.locale, 'dest');
  
              // Verify publicAlias changes
              destUpdates = {'publicAlias': 'dest'};
              dest = PrincipalsUtil.createUpdatedUser(source, destUpdates);
              assert.equal(dest.publicAlias, 'dest');
  
              // Verify admin status for tenant and global are immutable
              destUpdates = {'isGlobalAdmin': true};
              dest = PrincipalsUtil.createUpdatedUser(source, destUpdates);
              assert.ok(!dest.isGlobalAdmin());
  
              destUpdates = {'isTenantAdmin': true};
              dest = PrincipalsUtil.createUpdatedUser(source, destUpdates);
              assert.ok(!dest.isTenantAdmin(source.tenant));
  
              destUpdates = {'admin:global': true};
              dest = PrincipalsUtil.createUpdatedUser(source, destUpdates);
              assert.ok(!dest.isGlobalAdmin());
  
              destUpdates = {'admin:tenant': true};
              dest = PrincipalsUtil.createUpdatedUser(source, destUpdates);
              assert.ok(!dest.isTenantAdmin(source.tenant));
  
          });
  
      });
  });
  