org.slc.sli.api.service.BasicServiceTest.java Source code

Java tutorial

Introduction

Here is the source code for org.slc.sli.api.service.BasicServiceTest.java

Source

/*
 * Copyright 2012-2013 inBloom, Inc. and its affiliates.
 *
 * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
 */

package org.slc.sli.api.service;

import junit.framework.Assert;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.slc.sli.api.config.BasicDefinitionStore;
import org.slc.sli.api.config.DefinitionFactory;
import org.slc.sli.api.config.EntityDefinition;
import org.slc.sli.api.representation.EntityBody;
import org.slc.sli.api.resources.SecurityContextInjector;
import org.slc.sli.api.security.SLIPrincipal;
import org.slc.sli.api.security.context.APIAccessDeniedException;
import org.slc.sli.api.security.context.ContextValidator;
import org.slc.sli.api.security.roles.EntityRightsFilter;
import org.slc.sli.api.security.roles.RightAccessValidator;
import org.slc.sli.api.service.query.ApiQuery;
import org.slc.sli.api.test.WebContextTestExecutionListener;
import org.slc.sli.api.util.RequestUtil;
import org.slc.sli.api.util.SecurityUtil;
import org.slc.sli.common.constants.EntityNames;
import org.slc.sli.common.constants.ParameterConstants;
import org.slc.sli.domain.*;
import org.slc.sli.domain.enums.Right;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

/**
 *
 * Unit Tests
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/spring/applicationContext-test.xml" })
@TestExecutionListeners({ WebContextTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
        DirtiesContextTestExecutionListener.class })
public class BasicServiceTest {
    private static final Logger LOG = LoggerFactory.getLogger(BasicServiceTest.class);

    private BasicService service = null; //class under test

    @Autowired
    private ApplicationContext context;

    @Autowired
    private SecurityContextInjector securityContextInjector;

    @Autowired
    private BasicDefinitionStore definitionStore;

    @Autowired
    DefinitionFactory factory;

    @Autowired
    @Qualifier("validationRepo")
    private Repository<Entity> securityRepo;

    private Repository<Entity> mockRepo;

    private EntityRightsFilter mockRightsFilter;

    private List<Treatment> mockTreatments = new ArrayList<Treatment>();

    // For later cleanup.
    private static SecurityUtil.UserContext prevUserContext = SecurityUtil.getUserContext();
    private static SecurityContext prevSecurityContext = SecurityContextHolder.getContext();

    private static final int MAX_RESULT_SIZE = 0;

    class MatchesNotAccessible extends ArgumentMatcher<Entity> {
        Set<String> studentIds = new HashSet<String>(
                Arrays.asList("student1", "student2", "student4", "student5", "student6", "student13", "student14",
                        "student16", "student17", "student18", "student20", "student22", "student23", "student24"));

        @Override
        public boolean matches(Object arg) {
            return !studentIds.contains(((Entity) arg).getEntityId());
        }
    }

    class MatchesNotFieldAccessible extends ArgumentMatcher<Entity> {
        Set<String> studentIds = new HashSet<String>(Arrays.asList("student2", "student3", "student4", "student5",
                "student6", "student7", "student8", "student11", "student12", "student13", "student15", "student16",
                "student17", "student18", "student21", "student22", "student23"));

        @Override
        public boolean matches(Object arg) {
            return !studentIds.contains(((Entity) arg).getEntityId());
        }
    }

    @SuppressWarnings("unchecked")
    @Before
    public void setup()
            throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException {
        service = (BasicService) context.getBean("basicService", "student", null, securityRepo);

        EntityDefinition student = factory.makeEntity("student").exposeAs("students").build();

        service.setDefn(student);

        mockRepo = Mockito.mock(Repository.class);
        Field repo = BasicService.class.getDeclaredField("repo");
        repo.setAccessible(true);
        repo.set(service, mockRepo);

        mockRightsFilter = Mockito.mock(EntityRightsFilter.class);
        Field entityRightsFilter = BasicService.class.getDeclaredField("entityRightsFilter");
        entityRightsFilter.setAccessible(true);
        entityRightsFilter.set(service, mockRightsFilter);

        Field treatments = BasicService.class.getDeclaredField("treatments");
        treatments.setAccessible(true);
        treatments.set(service, mockTreatments);
    }

    @Test
    public void testCheckFieldAccessAdmin() {
        // inject administrator security context for unit testing
        securityContextInjector.setAdminContextWithElevatedRights();

        NeutralQuery query = new NeutralQuery();
        query.addCriteria(new NeutralCriteria("economicDisadvantaged", "=", "true"));

        NeutralQuery query1 = new NeutralQuery(query);

        service.checkFieldAccess(query, false);
        assertTrue("Should match", query1.equals(query));
    }

    @Test(expected = QueryParseException.class)
    public void testCheckFieldAccessEducator() {
        // inject administrator security context for unit testing
        securityContextInjector.setEducatorContext();

        NeutralQuery query = new NeutralQuery();
        query.addCriteria(new NeutralCriteria("economicDisadvantaged", "=", "true"));

        service.checkFieldAccess(query, false);
    }

    @Test
    public void testWriteSelf() {
        BasicService basicService = (BasicService) context.getBean("basicService", "teacher",
                new ArrayList<Treatment>(), securityRepo);
        basicService.setDefn(definitionStore.lookupByEntityType("teacher"));
        securityContextInjector.setEducatorContext("my-id");

        Map<String, Object> body = new HashMap<String, Object>();
        Entity entity = securityRepo.create("teacher", body);

        EntityBody updated = new EntityBody();
        basicService.update(entity.getEntityId(), updated, false);
    }

    @Test
    public void testIsSelf() {
        BasicService basicService = (BasicService) context.getBean("basicService", "teacher",
                new ArrayList<Treatment>(), securityRepo);
        basicService.setDefn(definitionStore.lookupByEntityType("teacher"));
        securityContextInjector.setEducatorContext("my-id");
        assertTrue(basicService
                .isSelf(new NeutralQuery(new NeutralCriteria("_id", NeutralCriteria.OPERATOR_EQUAL, "my-id"))));
        NeutralQuery query = new NeutralQuery(
                new NeutralCriteria("_id", NeutralCriteria.CRITERIA_IN, Arrays.asList("my-id")));
        assertTrue(basicService.isSelf(query));
        query.addCriteria(
                new NeutralCriteria("someOtherProperty", NeutralCriteria.OPERATOR_EQUAL, "somethingElse"));
        assertTrue(basicService.isSelf(query));
        query.addOrQuery(
                new NeutralQuery(new NeutralCriteria("refProperty", NeutralCriteria.OPERATOR_EQUAL, "my-id")));
        assertTrue(basicService.isSelf(query));
        query.addOrQuery(
                new NeutralQuery(new NeutralCriteria("_id", NeutralCriteria.OPERATOR_EQUAL, "someoneElse")));
        assertFalse(basicService.isSelf(query));
        assertFalse(basicService.isSelf(new NeutralQuery(
                new NeutralCriteria("_id", NeutralCriteria.CRITERIA_IN, Arrays.asList("my-id", "someoneElse")))));

    }

    @SuppressWarnings("unchecked")
    @Test
    public void testList()
            throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        securityContextInjector.setEducatorContext();

        RightAccessValidator mockAccessValidator = Mockito.mock(RightAccessValidator.class);
        Field rightAccessValidator = BasicService.class.getDeclaredField("rightAccessValidator");
        rightAccessValidator.setAccessible(true);
        rightAccessValidator.set(service, mockAccessValidator);

        EntityBody entityBody1 = new EntityBody();
        entityBody1.put("studentUniqueStateId", "student1");
        EntityBody entityBody2 = new EntityBody();
        entityBody2.put("studentUniqueStateId", "student2");
        Entity entity1 = new MongoEntity("student", "student1", entityBody1, new HashMap<String, Object>());
        Entity entity2 = new MongoEntity("student", "student2", entityBody2, new HashMap<String, Object>());
        Iterable<Entity> entities = Arrays.asList(entity1, entity2);

        Mockito.when(mockRepo.findAll(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(entities);
        Mockito.when(mockRepo.count(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(2L);

        Mockito.when(mockRightsFilter.makeEntityBody(Mockito.eq(entity1), Mockito.any(List.class),
                Mockito.any(EntityDefinition.class), Mockito.any(Collection.class), Mockito.any(Collection.class)))
                .thenReturn(entityBody1);
        Mockito.when(mockRightsFilter.makeEntityBody(Mockito.eq(entity2), Mockito.any(List.class),
                Mockito.any(EntityDefinition.class), Mockito.any(Collection.class), Mockito.any(Collection.class)))
                .thenReturn(entityBody2);

        RequestUtil.setCurrentRequestId();
        Iterable<EntityBody> listResult = service.list(new NeutralQuery());

        List<EntityBody> bodies = new ArrayList<EntityBody>();
        for (EntityBody body : listResult) {
            bodies.add(body);
        }
        Assert.assertEquals("EntityBody mismatch", entityBody1, bodies.toArray()[0]);
        Assert.assertEquals("EntityBody mismatch", entityBody2, bodies.toArray()[1]);

        long count = service.count(new NeutralQuery());
        Assert.assertEquals(2, count);
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testListBasedOnContextualRoles()
            throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        securityContextInjector.setEducatorContext();
        SecurityUtil.setUserContext(SecurityUtil.UserContext.TEACHER_CONTEXT);
        RightAccessValidator mockAccessValidator = Mockito.mock(RightAccessValidator.class);
        Field rightAccessValidator = BasicService.class.getDeclaredField("rightAccessValidator");
        rightAccessValidator.setAccessible(true);
        rightAccessValidator.set(service, mockAccessValidator);

        Collection<GrantedAuthority> teacherContextRights = new HashSet<GrantedAuthority>(
                Arrays.asList(Right.TEACHER_CONTEXT, Right.READ_PUBLIC, Right.WRITE_PUBLIC));

        EntityBody entityBody1 = new EntityBody();
        entityBody1.put("studentUniqueStateId", "student1");
        EntityBody entityBody2 = new EntityBody();
        entityBody2.put("studentUniqueStateId", "student2");
        Entity entity1 = new MongoEntity("student", "student1", entityBody1, new HashMap<String, Object>());
        Entity entity2 = new MongoEntity("student", "student2", entityBody2, new HashMap<String, Object>());
        Iterable<Entity> entities = Arrays.asList(entity1, entity2);

        Mockito.when(mockRepo.findAll(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(entities);
        Mockito.when(mockRepo.count(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(2L);

        Mockito.when(mockRightsFilter.makeEntityBody(Mockito.eq(entity1), Mockito.any(List.class),
                Mockito.any(EntityDefinition.class), Mockito.anyBoolean(), Mockito.any(Collection.class),
                Mockito.any(SecurityUtil.UserContext.class))).thenReturn(entityBody1);
        Mockito.when(mockRightsFilter.makeEntityBody(Mockito.eq(entity2), Mockito.any(List.class),
                Mockito.any(EntityDefinition.class), Mockito.anyBoolean(), Mockito.any(Collection.class),
                Mockito.any(SecurityUtil.UserContext.class))).thenReturn(entityBody2);

        Mockito.when(mockAccessValidator.getContextualAuthorities(Matchers.eq(false), Matchers.eq(entity1),
                Matchers.eq(SecurityUtil.UserContext.TEACHER_CONTEXT), Matchers.eq(true)))
                .thenReturn(teacherContextRights);

        ContextValidator mockContextValidator = Mockito.mock(ContextValidator.class);
        Field contextValidator = BasicService.class.getDeclaredField("contextValidator");
        contextValidator.setAccessible(true);
        contextValidator.set(service, mockContextValidator);

        Map<String, SecurityUtil.UserContext> studentContext = new HashMap<String, SecurityUtil.UserContext>();
        studentContext.put(entity1.getEntityId(), SecurityUtil.UserContext.TEACHER_CONTEXT);
        studentContext.put(entity2.getEntityId(), SecurityUtil.UserContext.TEACHER_CONTEXT);

        Mockito.when(mockContextValidator.getValidatedEntityContexts(Matchers.any(EntityDefinition.class),
                Matchers.any(Collection.class), Matchers.anyBoolean(), Matchers.anyBoolean()))
                .thenReturn(studentContext);

        NeutralQuery query = new NeutralQuery();
        query.setLimit(ApiQuery.API_QUERY_DEFAULT_LIMIT);
        RequestUtil.setCurrentRequestId();
        Iterable<EntityBody> listResult = service.listBasedOnContextualRoles(query);

        List<EntityBody> bodies = new ArrayList<EntityBody>();
        for (EntityBody body : listResult) {
            bodies.add(body);
        }
        Assert.assertEquals("EntityBody mismatch", entityBody1, bodies.toArray()[0]);
        Assert.assertEquals("EntityBody mismatch", entityBody2, bodies.toArray()[1]);

        long count = service.countBasedOnContextualRoles(new NeutralQuery());
        Assert.assertEquals(2, count);
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testListBasedOnContextualRolesDualContext()
            throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        securityContextInjector.setDualContext();
        SecurityUtil.setUserContext(SecurityUtil.UserContext.DUAL_CONTEXT);

        Collection<GrantedAuthority> teacherContextRights = new HashSet<GrantedAuthority>(
                Arrays.asList(Right.TEACHER_CONTEXT, Right.READ_PUBLIC, Right.WRITE_PUBLIC));
        Collection<GrantedAuthority> staffContextRights = new HashSet<GrantedAuthority>(
                Arrays.asList(Right.STAFF_CONTEXT, Right.READ_GENERAL, Right.WRITE_GENERAL));
        Collection<GrantedAuthority> dualContextRights = new HashSet<GrantedAuthority>(teacherContextRights);
        dualContextRights.addAll(staffContextRights);
        Collection<GrantedAuthority> noContextRights = new HashSet<GrantedAuthority>();

        RightAccessValidator mockAccessValidator = Mockito.mock(RightAccessValidator.class);
        Field rightAccessValidator = BasicService.class.getDeclaredField("rightAccessValidator");
        rightAccessValidator.setAccessible(true);
        rightAccessValidator.set(service, mockAccessValidator);

        List<Entity> entities = new ArrayList<Entity>();
        Map<String, SecurityUtil.UserContext> studentContext = new HashMap<String, SecurityUtil.UserContext>();
        for (int i = 0; i < 30; i++) {
            String id = "student" + i;
            Entity entity = new MongoEntity("student", id, new HashMap<String, Object>(),
                    new HashMap<String, Object>());
            entity.getBody().put("key", "value");
            entities.add(entity);

            EntityBody entityBody = new EntityBody();
            entityBody.put("studentUniqueStateId", id);
            Mockito.when(mockRightsFilter.makeEntityBody(Mockito.eq(entity), Mockito.any(List.class),
                    Mockito.any(EntityDefinition.class), Mockito.anyBoolean(), Mockito.any(Collection.class),
                    Mockito.any(SecurityUtil.UserContext.class))).thenReturn(entityBody);

            if ((i % 12) == 0) {
                studentContext.put(id, SecurityUtil.UserContext.DUAL_CONTEXT);
                Mockito.when(mockAccessValidator.getContextualAuthorities(Matchers.eq(false), Matchers.eq(entity),
                        Matchers.eq(SecurityUtil.UserContext.DUAL_CONTEXT), Matchers.eq(true)))
                        .thenReturn(dualContextRights);
            } else if ((i % 3) == 0) {
                studentContext.put(id, SecurityUtil.UserContext.STAFF_CONTEXT);
                Mockito.when(mockAccessValidator.getContextualAuthorities(Matchers.eq(false), Matchers.eq(entity),
                        Matchers.eq(SecurityUtil.UserContext.STAFF_CONTEXT), Matchers.eq(true)))
                        .thenReturn(staffContextRights);
            } else if ((i % 4) == 0) {
                studentContext.put(id, SecurityUtil.UserContext.TEACHER_CONTEXT);
                Mockito.when(mockAccessValidator.getContextualAuthorities(Matchers.eq(false), Matchers.eq(entity),
                        Matchers.eq(SecurityUtil.UserContext.TEACHER_CONTEXT), Matchers.eq(true)))
                        .thenReturn(teacherContextRights);
            } else {
                studentContext.put(id, SecurityUtil.UserContext.NO_CONTEXT);
                Mockito.when(mockAccessValidator.getContextualAuthorities(Matchers.eq(false), Matchers.eq(entity),
                        Matchers.eq(SecurityUtil.UserContext.NO_CONTEXT), Matchers.eq(true)))
                        .thenReturn(noContextRights);
            }
        }

        NeutralQuery query = new NeutralQuery();
        query.setLimit(ApiQuery.API_QUERY_DEFAULT_LIMIT);

        Mockito.when(mockRepo.findAll(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(entities);
        Mockito.when(mockRepo.count(Mockito.eq("student"), Mockito.eq(query))).thenReturn(50L);

        Mockito.doThrow(new AccessDeniedException("")).when(mockAccessValidator).checkAccess(Mockito.anyBoolean(),
                Mockito.anyBoolean(), Mockito.argThat(new MatchesNotAccessible()), Mockito.anyString(),
                Mockito.eq(staffContextRights));
        Mockito.doThrow(new AccessDeniedException("")).when(mockAccessValidator).checkFieldAccess(
                Mockito.any(NeutralQuery.class), Mockito.argThat(new MatchesNotFieldAccessible()),
                Mockito.anyString(), Mockito.eq(teacherContextRights));
        Mockito.doThrow(new AccessDeniedException("")).when(mockAccessValidator).checkAccess(Mockito.anyBoolean(),
                Mockito.anyBoolean(), Mockito.any(Entity.class), Mockito.anyString(), Mockito.eq(noContextRights));

        ContextValidator mockContextValidator = Mockito.mock(ContextValidator.class);
        Field contextValidator = BasicService.class.getDeclaredField("contextValidator");
        contextValidator.setAccessible(true);
        contextValidator.set(service, mockContextValidator);

        Mockito.when(mockContextValidator.getValidatedEntityContexts(Matchers.any(EntityDefinition.class),
                Matchers.any(Collection.class), Matchers.anyBoolean(), Matchers.anyBoolean()))
                .thenReturn(studentContext);

        RequestUtil.setCurrentRequestId();
        Iterable<EntityBody> listResult = service.listBasedOnContextualRoles(query);

        Iterable<String> expectedResult1 = Arrays.asList("student0", "student4", "student6", "student8",
                "student12", "student16", "student18", "student24");
        assertEntityBodyIdsEqual(expectedResult1.iterator(), listResult.iterator());

        long count = service.countBasedOnContextualRoles(query);
        Assert.assertEquals(8, count);

        // Assure same order and count.

        RequestUtil.setCurrentRequestId();

        listResult = service.listBasedOnContextualRoles(query);

        Iterable<String> expectedResult2 = Arrays.asList("student0", "student4", "student6", "student8",
                "student12", "student16", "student18", "student24");
        assertEntityBodyIdsEqual(expectedResult2.iterator(), listResult.iterator());

        count = service.countBasedOnContextualRoles(query);
        Assert.assertEquals(8, count);
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testCreate()
            throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        securityContextInjector.setEducatorContext();

        //adding this to research "Heisenbug" that may be related to timing of resource initialization, which causes nonrepeatable test failures.
        try {
            Thread.currentThread().sleep(5L); //sleep for 5 ms
        } catch (InterruptedException is) {
            //squish
        }

        RightAccessValidator mockAccessValidator = Mockito.mock(RightAccessValidator.class);
        Field rightAccessValidator = BasicService.class.getDeclaredField("rightAccessValidator");
        rightAccessValidator.setAccessible(true);
        rightAccessValidator.set(service, mockAccessValidator);

        //adding this to research "Heisenbug" that may be related to timing of resource initialization, which causes nonrepeatable test failures.
        try {
            Thread.currentThread().sleep(5L); //sleep for 5 ms
        } catch (InterruptedException is) {
            //squish
        }

        EntityBody entityBody1 = new EntityBody();
        entityBody1.put("studentUniqueStateId", "student1");
        EntityBody entityBody2 = new EntityBody();
        entityBody2.put("studentUniqueStateId", "student2");

        List<EntityBody> entityBodies = Arrays.asList(entityBody1, entityBody2);

        Entity entity1 = new MongoEntity("student", "student1", entityBody1, new HashMap<String, Object>());
        Entity entity2 = new MongoEntity("student", "student2", entityBody2, new HashMap<String, Object>());
        Mockito.when(mockRepo.create(Mockito.eq("student"), Mockito.eq(entityBody1), Mockito.any(Map.class),
                Mockito.eq("student"))).thenReturn(entity1);
        Mockito.when(mockRepo.create(Mockito.eq("student"), Mockito.eq(entityBody2), Mockito.any(Map.class),
                Mockito.eq("student"))).thenReturn(entity2);

        LOG.debug(ToStringBuilder.reflectionToString(entityBodies, ToStringStyle.MULTI_LINE_STYLE));

        //adding this to research "Heisenbug" that may be related to timing of resource initialization, which causes nonrepeatable test failures.
        try {
            Thread.currentThread().sleep(5L); //sleep for 5 ms
        } catch (InterruptedException is) {
            //squish
        }

        List<String> listResult = service.create(entityBodies);

        Assert.assertEquals("EntityBody mismatch", entity1.getEntityId(), listResult.toArray()[0]);
        Assert.assertEquals("EntityBody mismatch", entity2.getEntityId(), listResult.toArray()[1]);
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testCreateBasedOnContextualRoles()
            throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        securityContextInjector.setEducatorContext();

        RightAccessValidator mockAccessValidator = Mockito.mock(RightAccessValidator.class);
        Field rightAccessValidator = BasicService.class.getDeclaredField("rightAccessValidator");
        rightAccessValidator.setAccessible(true);
        rightAccessValidator.set(service, mockAccessValidator);

        EntityBody entityBody1 = new EntityBody();
        entityBody1.put("studentUniqueStateId", "student1");
        EntityBody entityBody2 = new EntityBody();
        entityBody2.put("studentUniqueStateId", "student2");
        List<EntityBody> entityBodies = Arrays.asList(entityBody1, entityBody2);
        Entity entity1 = new MongoEntity("student", "student1", entityBody1, new HashMap<String, Object>());
        Entity entity2 = new MongoEntity("student", "student2", entityBody2, new HashMap<String, Object>());
        Mockito.when(mockRepo.create(Mockito.eq("student"), Mockito.eq(entityBody1), Mockito.any(Map.class),
                Mockito.eq("student"))).thenReturn(entity1);
        Mockito.when(mockRepo.create(Mockito.eq("student"), Mockito.eq(entityBody2), Mockito.any(Map.class),
                Mockito.eq("student"))).thenReturn(entity2);

        List<String> listResult = service.createBasedOnContextualRoles(entityBodies);

        Assert.assertEquals("EntityBody mismatch", entity1.getEntityId(), listResult.toArray()[0]);
        Assert.assertEquals("EntityBody mismatch", entity2.getEntityId(), listResult.toArray()[1]);
    }

    @Test
    public void testUpdateBasedOnContextualRoles()
            throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        securityContextInjector.setStaffContext();
        service = (BasicService) context.getBean("basicService", "student", new ArrayList<Treatment>(),
                securityRepo);
        EntityDefinition studentDef = factory.makeEntity("student").exposeAs("students").build();
        service.setDefn(studentDef);
        EntityBody entityBody1 = new EntityBody();
        entityBody1.put("studentUniqueStateId", "student1");
        Entity student = securityRepo.create(EntityNames.STUDENT, entityBody1);
        EntityBody entityBody2 = new EntityBody();
        entityBody2.put(ParameterConstants.STUDENT_ID, student.getEntityId());
        entityBody2.put(ParameterConstants.SCHOOL_ID, SecurityContextInjector.ED_ORG_ID);
        securityRepo.create(EntityNames.STUDENT_SCHOOL_ASSOCIATION, entityBody2);
        securityRepo.createWithRetries(EntityNames.EDUCATION_ORGANIZATION, SecurityContextInjector.ED_ORG_ID,
                new HashMap<String, Object>(), new HashMap<String, Object>(), EntityNames.EDUCATION_ORGANIZATION,
                1);

        EntityBody putEntity = new EntityBody();
        putEntity.put("studentUniqueStateId", "student1");
        putEntity.put("loginId", "student1");
        boolean result = service.update(student.getEntityId(), putEntity, true);

        Assert.assertTrue(result);
        Entity studentResult = securityRepo.findById(EntityNames.STUDENT, student.getEntityId());
        Assert.assertNotNull(studentResult.getBody());
        Assert.assertNotNull(studentResult.getBody().get("studentUniqueStateId"));
        Assert.assertEquals("student1", studentResult.getBody().get("studentUniqueStateId"));
        Assert.assertNotNull(studentResult.getBody().get("loginId"));
        Assert.assertEquals("student1", studentResult.getBody().get("loginId"));
    }

    @Test(expected = AccessDeniedException.class)
    public void testUpdateBasedOnContextualRolesAccessDenied()
            throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        securityContextInjector.setEducatorContext();
        service = (BasicService) context.getBean("basicService", "student", new ArrayList<Treatment>(),
                securityRepo);
        EntityDefinition studentDef = factory.makeEntity("student").exposeAs("students").build();
        service.setDefn(studentDef);
        EntityBody entityBody1 = new EntityBody();
        entityBody1.put("studentUniqueStateId", "student1");
        Entity student = securityRepo.create(EntityNames.STUDENT, entityBody1);
        EntityBody entityBody2 = new EntityBody();
        entityBody2.put(ParameterConstants.STUDENT_ID, student.getEntityId());
        entityBody2.put(ParameterConstants.SCHOOL_ID, SecurityContextInjector.ED_ORG_ID);
        securityRepo.create(EntityNames.STUDENT_SCHOOL_ASSOCIATION, entityBody2);
        securityRepo.createWithRetries(EntityNames.EDUCATION_ORGANIZATION, SecurityContextInjector.ED_ORG_ID,
                new HashMap<String, Object>(), new HashMap<String, Object>(), EntityNames.EDUCATION_ORGANIZATION,
                1);

        EntityBody putEntity = new EntityBody();
        putEntity.put("studentUniqueStateId", "student1");
        putEntity.put("loginId", "student1");
        boolean result = service.update(student.getEntityId(), putEntity, true);

        Assert.assertFalse(result);
    }

    @Test
    public void testPatchBasedOnContextualRoles()
            throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        securityContextInjector.setStaffContext();
        service = (BasicService) context.getBean("basicService", "student", new ArrayList<Treatment>(),
                securityRepo);
        EntityDefinition studentDef = factory.makeEntity("student").exposeAs("students").build();
        service.setDefn(studentDef);

        EntityBody studentBody = new EntityBody();
        studentBody.put("studentUniqueStateId", "123");
        Entity student = securityRepo.create(EntityNames.STUDENT, studentBody);

        EntityBody ssaBody = new EntityBody();
        ssaBody.put(ParameterConstants.STUDENT_ID, student.getEntityId());
        ssaBody.put(ParameterConstants.SCHOOL_ID, SecurityContextInjector.ED_ORG_ID);
        securityRepo.create(EntityNames.STUDENT_SCHOOL_ASSOCIATION, ssaBody);

        securityRepo.createWithRetries(EntityNames.EDUCATION_ORGANIZATION, SecurityContextInjector.ED_ORG_ID,
                new HashMap<String, Object>(), new HashMap<String, Object>(), EntityNames.EDUCATION_ORGANIZATION,
                1);

        EntityBody putEntity = new EntityBody();
        putEntity.put("studentUniqueStateId", "456");
        putEntity.put("schoolFoodServicesEligibility", "Yes");

        boolean result = service.patch(student.getEntityId(), putEntity, true);

        Assert.assertTrue(result);
        Entity studentResult = securityRepo.findById(EntityNames.STUDENT, student.getEntityId());
        Assert.assertNotNull(studentResult.getBody());
        Assert.assertNotNull(studentResult.getBody().get("studentUniqueStateId"));
        Assert.assertEquals("456", studentResult.getBody().get("studentUniqueStateId"));
        Assert.assertNotNull(studentResult.getBody().get("schoolFoodServicesEligibility"));
        Assert.assertEquals("Yes", studentResult.getBody().get("schoolFoodServicesEligibility"));
    }

    @Test
    public void testPatchBasedOnContextualRolesWithEmptyPatchBody()
            throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        securityContextInjector.setStaffContext();
        service = (BasicService) context.getBean("basicService", "student", new ArrayList<Treatment>(),
                securityRepo);
        EntityDefinition studentDef = factory.makeEntity("student").exposeAs("students").build();
        service.setDefn(studentDef);

        EntityBody studentBody = new EntityBody();
        studentBody.put("studentUniqueStateId", "123");
        Entity student = securityRepo.create(EntityNames.STUDENT, studentBody);

        EntityBody ssaBody = new EntityBody();
        ssaBody.put(ParameterConstants.STUDENT_ID, student.getEntityId());
        ssaBody.put(ParameterConstants.SCHOOL_ID, SecurityContextInjector.ED_ORG_ID);
        securityRepo.create(EntityNames.STUDENT_SCHOOL_ASSOCIATION, ssaBody);

        securityRepo.createWithRetries(EntityNames.EDUCATION_ORGANIZATION, SecurityContextInjector.ED_ORG_ID,
                new HashMap<String, Object>(), new HashMap<String, Object>(), EntityNames.EDUCATION_ORGANIZATION,
                1);

        EntityBody putEntity = new EntityBody();

        boolean result = service.patch(student.getEntityId(), putEntity, true);

        Assert.assertFalse(result);
        Entity studentResult = securityRepo.findById(EntityNames.STUDENT, student.getEntityId());
        Assert.assertNotNull(studentResult.getBody());
        Assert.assertNotNull(studentResult.getBody().get("studentUniqueStateId"));
        Assert.assertEquals("123", studentResult.getBody().get("studentUniqueStateId"));
        Assert.assertNull(studentResult.getBody().get("schoolFoodServicesEligibility"));
    }

    @Test(expected = AccessDeniedException.class)
    public void testPatchBasedOnContextualRolesAccessDenied()
            throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        securityContextInjector.setEducatorContext();
        service = (BasicService) context.getBean("basicService", "student", new ArrayList<Treatment>(),
                securityRepo);

        EntityDefinition studentDef = factory.makeEntity("student").exposeAs("students").build();
        service.setDefn(studentDef);

        EntityBody studentBody = new EntityBody();
        studentBody.put("studentUniqueStateId", "123");
        Entity student = securityRepo.create(EntityNames.STUDENT, studentBody);

        EntityBody ssaBody = new EntityBody();
        ssaBody.put(ParameterConstants.STUDENT_ID, student.getEntityId());
        ssaBody.put(ParameterConstants.SCHOOL_ID, SecurityContextInjector.ED_ORG_ID);
        securityRepo.create(EntityNames.STUDENT_SCHOOL_ASSOCIATION, ssaBody);

        securityRepo.createWithRetries(EntityNames.EDUCATION_ORGANIZATION, SecurityContextInjector.ED_ORG_ID,
                new HashMap<String, Object>(), new HashMap<String, Object>(), EntityNames.EDUCATION_ORGANIZATION,
                1);

        EntityBody putEntity = new EntityBody();
        putEntity.put("studentUniqueStateId", "456");
        putEntity.put("schoolFoodServicesEligibility", "Yes");

        boolean result = service.patch(student.getEntityId(), putEntity, true);

        Assert.assertFalse(result);
    }

    @Test
    public void testgetEntityContextAuthorities() throws SecurityException, NoSuchFieldException,
            IllegalArgumentException, IllegalAccessException, NoSuchMethodException {
        securityContextInjector.setDualContext();

        RightAccessValidator mockAccessValidator = Mockito.mock(RightAccessValidator.class);
        Field rightAccessValidator = BasicService.class.getDeclaredField("rightAccessValidator");
        rightAccessValidator.setAccessible(true);
        rightAccessValidator.set(service, mockAccessValidator);

        boolean isSelf = true;
        boolean isRead = true;

        EntityBody entityBody1 = new EntityBody();
        entityBody1.put("studentUniqueStateId", "student1");
        Entity student = securityRepo.create(EntityNames.STUDENT, entityBody1);

        Collection<GrantedAuthority> staffContextRights = SecurityUtil.getSLIPrincipal().getEdOrgContextRights()
                .get(SecurityContextInjector.ED_ORG_ID).get(SecurityUtil.UserContext.STAFF_CONTEXT);
        Collection<GrantedAuthority> teacherContextRights = SecurityUtil.getSLIPrincipal().getEdOrgContextRights()
                .get(SecurityContextInjector.ED_ORG_ID).get(SecurityUtil.UserContext.TEACHER_CONTEXT);

        Mockito.when(mockAccessValidator.getContextualAuthorities(Matchers.eq(isSelf), Matchers.eq(student),
                Matchers.eq(SecurityUtil.UserContext.STAFF_CONTEXT), Matchers.eq(isRead)))
                .thenReturn(staffContextRights);
        Mockito.when(mockAccessValidator.getContextualAuthorities(Matchers.eq(isSelf), Matchers.eq(student),
                Matchers.eq(SecurityUtil.UserContext.TEACHER_CONTEXT), Matchers.eq(isRead)))
                .thenReturn(teacherContextRights);

        ContextValidator mockContextValidator = Mockito.mock(ContextValidator.class);
        Field contextValidator = BasicService.class.getDeclaredField("contextValidator");
        contextValidator.setAccessible(true);
        contextValidator.set(service, mockContextValidator);

        Map<String, SecurityUtil.UserContext> studentContext = new HashMap<String, SecurityUtil.UserContext>();
        studentContext.put(student.getEntityId(), SecurityUtil.UserContext.STAFF_CONTEXT);

        Mockito.when(mockContextValidator.getValidatedEntityContexts(Matchers.any(EntityDefinition.class),
                Matchers.any(Collection.class), Matchers.anyBoolean(), Matchers.anyBoolean()))
                .thenReturn(studentContext);

        Collection<GrantedAuthority> rights = service.getEntityContextAuthorities(student, isSelf, isRead);

        Assert.assertEquals(staffContextRights, rights);

        securityContextInjector.setEducatorContext();
        rights = service.getEntityContextAuthorities(student, isSelf, isRead);

        Assert.assertEquals(teacherContextRights, rights);

    }

    @Test
    public void testUserHasMultipleContextsOrDifferingRightsDualContext() throws IllegalArgumentException,
            IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException {
        securityContextInjector.setDualContext();

        Method method = BasicService.class.getDeclaredMethod("userHasMultipleContextsOrDifferingRights");
        method.setAccessible(true);
        boolean testCondition = (Boolean) method.invoke(service);

        Assert.assertTrue(testCondition);
    }

    @Test
    public void testUserHasMultipleContextsOrDifferingRightsDifferentRights() throws IllegalArgumentException,
            IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException {
        securityContextInjector.setEducatorContext();

        Set<GrantedAuthority> rights1 = new HashSet<GrantedAuthority>(
                Arrays.asList(Right.TEACHER_CONTEXT, Right.READ_PUBLIC, Right.WRITE_PUBLIC));
        Set<GrantedAuthority> rights2 = new HashSet<GrantedAuthority>(
                Arrays.asList(Right.TEACHER_CONTEXT, Right.READ_PUBLIC, Right.READ_GENERAL, Right.WRITE_PUBLIC));
        Map<String, Collection<GrantedAuthority>> edOrgRights = new HashMap<String, Collection<GrantedAuthority>>();
        edOrgRights.put("edOrg1", rights1);
        edOrgRights.put("edOrg2", rights2);
        SLIPrincipal principal = Mockito.mock(SLIPrincipal.class);
        Mockito.when(principal.getEdOrgRights()).thenReturn(edOrgRights);
        setPrincipalInContext(principal);

        Method method = BasicService.class.getDeclaredMethod("userHasMultipleContextsOrDifferingRights");
        method.setAccessible(true);
        boolean testCondition = (Boolean) method.invoke(service);

        Assert.assertTrue(testCondition);
    }

    @Test
    public void testUserHasMultipleContextsOrDifferingRightsSingleEdOrg() throws IllegalArgumentException,
            IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException {
        securityContextInjector.setEducatorContext();

        Set<GrantedAuthority> rights1 = new HashSet<GrantedAuthority>(
                Arrays.asList(Right.TEACHER_CONTEXT, Right.READ_PUBLIC, Right.WRITE_PUBLIC));
        Map<String, Collection<GrantedAuthority>> edOrgRights = new HashMap<String, Collection<GrantedAuthority>>();
        edOrgRights.put("edOrg1", rights1);
        SLIPrincipal principal = Mockito.mock(SLIPrincipal.class);
        Mockito.when(principal.getEdOrgRights()).thenReturn(edOrgRights);
        setPrincipalInContext(principal);

        Method method = BasicService.class.getDeclaredMethod("userHasMultipleContextsOrDifferingRights");
        method.setAccessible(true);
        boolean testCondition = (Boolean) method.invoke(service);

        Assert.assertFalse(testCondition);
    }

    @Test
    public void testUserHasMultipleContextsOrDifferingRightsSameRights() throws IllegalArgumentException,
            IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException {
        securityContextInjector.setEducatorContext();

        Set<GrantedAuthority> rights1 = new HashSet<GrantedAuthority>(
                Arrays.asList(Right.TEACHER_CONTEXT, Right.READ_PUBLIC, Right.WRITE_PUBLIC));
        Map<String, Collection<GrantedAuthority>> edOrgRights = new HashMap<String, Collection<GrantedAuthority>>();
        edOrgRights.put("edOrg1", rights1);
        edOrgRights.put("edOrg2", rights1);
        SLIPrincipal principal = Mockito.mock(SLIPrincipal.class);
        Mockito.when(principal.getEdOrgRights()).thenReturn(edOrgRights);
        setPrincipalInContext(principal);

        Method method = BasicService.class.getDeclaredMethod("userHasMultipleContextsOrDifferingRights");
        method.setAccessible(true);
        boolean testCondition = (Boolean) method.invoke(service);

        Assert.assertFalse(testCondition);
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testGetResponseEntities() throws SecurityException, NoSuchFieldException, IllegalArgumentException,
            IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        securityContextInjector.setDualContext();
        SecurityUtil.setUserContext(SecurityUtil.UserContext.DUAL_CONTEXT);

        List<Entity> entities = new ArrayList<Entity>();
        Map<String, SecurityUtil.UserContext> studentContext = new HashMap<String, SecurityUtil.UserContext>();
        for (int i = 0; i < 30; i++) {
            String id = "student" + i;
            entities.add(
                    new MongoEntity("student", id, new HashMap<String, Object>(), new HashMap<String, Object>()));
            studentContext.put(id, SecurityUtil.UserContext.DUAL_CONTEXT);
        }

        Mockito.when(mockRepo.findAll(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(entities);
        Mockito.when(mockRepo.count(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(50L);

        ContextValidator mockContextValidator = Mockito.mock(ContextValidator.class);
        Field contextValidator = BasicService.class.getDeclaredField("contextValidator");
        contextValidator.setAccessible(true);
        contextValidator.set(service, mockContextValidator);
        Mockito.when(mockContextValidator.getValidatedEntityContexts(Matchers.any(EntityDefinition.class),
                Matchers.any(Collection.class), Matchers.anyBoolean(), Matchers.anyBoolean()))
                .thenReturn(studentContext);

        RightAccessValidator mockAccessValidator = Mockito.mock(RightAccessValidator.class);
        Field rightAccessValidator = BasicService.class.getDeclaredField("rightAccessValidator");
        rightAccessValidator.setAccessible(true);
        rightAccessValidator.set(service, mockAccessValidator);
        Mockito.when(mockAccessValidator.getContextualAuthorities(Matchers.anyBoolean(), Matchers.any(Entity.class),
                Matchers.eq(SecurityUtil.UserContext.DUAL_CONTEXT), Matchers.anyBoolean()))
                .thenReturn(new HashSet<GrantedAuthority>());
        Mockito.doThrow(new AccessDeniedException("")).when(mockAccessValidator).checkAccess(Mockito.anyBoolean(),
                Mockito.anyBoolean(), Mockito.argThat(new MatchesNotAccessible()), Mockito.anyString(),
                Mockito.anyCollection());
        Mockito.doThrow(new AccessDeniedException("")).when(mockAccessValidator).checkFieldAccess(
                Mockito.any(NeutralQuery.class), Mockito.argThat(new MatchesNotFieldAccessible()),
                Mockito.anyString(), Mockito.anyCollection());

        NeutralQuery query = new NeutralQuery();
        query.setLimit(ApiQuery.API_QUERY_DEFAULT_LIMIT);

        Method method = BasicService.class.getDeclaredMethod("getResponseEntities", NeutralQuery.class,
                boolean.class);
        method.setAccessible(true);

        RequestUtil.setCurrentRequestId();
        Collection<Entity> accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult1 = Arrays.asList("student2", "student4", "student5", "student6",
                "student13", "student16", "student17", "student18", "student22", "student23");
        assertEntityIdsEqual(expectedResult1.iterator(), accessibleEntities.iterator());

        long count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(10, count);

        // Assure same order and count.

        RequestUtil.setCurrentRequestId();

        accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult2 = Arrays.asList("student2", "student4", "student5", "student6",
                "student13", "student16", "student17", "student18", "student22", "student23");
        assertEntityIdsEqual(expectedResult2.iterator(), accessibleEntities.iterator());

        count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(10, count);

        query.setOffset(7);
        RequestUtil.setCurrentRequestId();

        accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult3 = Arrays.asList("student18", "student22", "student23");
        assertEntityIdsEqual(expectedResult3.iterator(), accessibleEntities.iterator());

        count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(10, count);

        // Assure same order and count.

        query.setOffset(7);
        RequestUtil.setCurrentRequestId();

        accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult4 = Arrays.asList("student18", "student22", "student23");
        assertEntityIdsEqual(expectedResult4.iterator(), accessibleEntities.iterator());

        count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(10, count);
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testGetResponseEntitiesPageLimit() throws SecurityException, NoSuchFieldException,
            IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        securityContextInjector.setDualContext();
        SecurityUtil.setUserContext(SecurityUtil.UserContext.DUAL_CONTEXT);

        List<Entity> entities = new ArrayList<Entity>();
        Map<String, SecurityUtil.UserContext> studentContext = new HashMap<String, SecurityUtil.UserContext>();
        for (int i = 0; i < 30; i++) {
            String id = "student" + i;
            entities.add(
                    new MongoEntity("student", id, new HashMap<String, Object>(), new HashMap<String, Object>()));
            studentContext.put(id, SecurityUtil.UserContext.DUAL_CONTEXT);
        }

        Mockito.when(mockRepo.findAll(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(entities);
        Mockito.when(mockRepo.count(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(50L);

        ContextValidator mockContextValidator = Mockito.mock(ContextValidator.class);
        Field contextValidator = BasicService.class.getDeclaredField("contextValidator");
        contextValidator.setAccessible(true);
        contextValidator.set(service, mockContextValidator);
        Mockito.when(mockContextValidator.getValidatedEntityContexts(Matchers.any(EntityDefinition.class),
                Matchers.any(Collection.class), Matchers.anyBoolean(), Matchers.anyBoolean()))
                .thenReturn(studentContext);

        RightAccessValidator mockAccessValidator = Mockito.mock(RightAccessValidator.class);
        Field rightAccessValidator = BasicService.class.getDeclaredField("rightAccessValidator");
        rightAccessValidator.setAccessible(true);
        rightAccessValidator.set(service, mockAccessValidator);
        Mockito.when(mockAccessValidator.getContextualAuthorities(Matchers.anyBoolean(), Matchers.any(Entity.class),
                Matchers.eq(SecurityUtil.UserContext.DUAL_CONTEXT), Matchers.anyBoolean()))
                .thenReturn(new HashSet<GrantedAuthority>());
        Mockito.doThrow(new AccessDeniedException("")).when(mockAccessValidator).checkAccess(Mockito.anyBoolean(),
                Mockito.anyBoolean(), Mockito.argThat(new MatchesNotAccessible()), Mockito.anyString(),
                Mockito.anyCollection());
        Mockito.doThrow(new AccessDeniedException("")).when(mockAccessValidator).checkFieldAccess(
                Mockito.any(NeutralQuery.class), Mockito.argThat(new MatchesNotFieldAccessible()),
                Mockito.anyString(), Mockito.anyCollection());

        NeutralQuery query = new NeutralQuery();
        query.setLimit(5);

        Method method = BasicService.class.getDeclaredMethod("getResponseEntities", NeutralQuery.class,
                boolean.class);
        method.setAccessible(true);

        RequestUtil.setCurrentRequestId();
        Collection<Entity> accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult1 = Arrays.asList("student2", "student4", "student5", "student6",
                "student13");
        assertEntityIdsEqual(expectedResult1.iterator(), accessibleEntities.iterator());

        long count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(10, count);

        // Assure same order and count.

        RequestUtil.setCurrentRequestId();

        accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult2 = Arrays.asList("student2", "student4", "student5", "student6",
                "student13");
        assertEntityIdsEqual(expectedResult2.iterator(), accessibleEntities.iterator());

        count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(10, count);

        query.setOffset(4);
        RequestUtil.setCurrentRequestId();

        accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult3 = Arrays.asList("student13", "student16", "student17", "student18",
                "student22");
        assertEntityIdsEqual(expectedResult3.iterator(), accessibleEntities.iterator());

        count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(10, count);

        // Assure same order and count.

        RequestUtil.setCurrentRequestId();

        accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult4 = Arrays.asList("student13", "student16", "student17", "student18",
                "student22");
        assertEntityIdsEqual(expectedResult4.iterator(), accessibleEntities.iterator());

        count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(10, count);

        query.setOffset(7);
        RequestUtil.setCurrentRequestId();

        accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult5 = Arrays.asList("student18", "student22", "student23");
        assertEntityIdsEqual(expectedResult5.iterator(), accessibleEntities.iterator());

        count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(10, count);

        // Assure same order and count.

        RequestUtil.setCurrentRequestId();

        accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult6 = Arrays.asList("student18", "student22", "student23");
        assertEntityIdsEqual(expectedResult6.iterator(), accessibleEntities.iterator());

        count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(10, count);

        query.setOffset(10);
        RequestUtil.setCurrentRequestId();

        accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Assert.assertEquals(0, accessibleEntities.size());

        count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(10, count);
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testGetAccessibleEntitiesCountLimit() throws SecurityException, NoSuchFieldException,
            IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        securityContextInjector.setDualContext();
        SecurityUtil.setUserContext(SecurityUtil.UserContext.DUAL_CONTEXT);

        List<Entity> entities = new ArrayList<Entity>();
        Map<String, SecurityUtil.UserContext> studentContext = new HashMap<String, SecurityUtil.UserContext>();
        for (int i = 0; i < 30; i++) {
            String id = "student" + i;
            entities.add(
                    new MongoEntity("student", id, new HashMap<String, Object>(), new HashMap<String, Object>()));
            studentContext.put(id, SecurityUtil.UserContext.DUAL_CONTEXT);
        }

        Mockito.when(mockRepo.findAll(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(entities);
        Mockito.when(mockRepo.count(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(50L);

        ContextValidator mockContextValidator = Mockito.mock(ContextValidator.class);
        Field contextValidator = BasicService.class.getDeclaredField("contextValidator");
        contextValidator.setAccessible(true);
        contextValidator.set(service, mockContextValidator);
        Mockito.when(mockContextValidator.getValidatedEntityContexts(Matchers.any(EntityDefinition.class),
                Matchers.any(Collection.class), Matchers.anyBoolean(), Matchers.anyBoolean()))
                .thenReturn(studentContext);

        RightAccessValidator mockAccessValidator = Mockito.mock(RightAccessValidator.class);
        Field rightAccessValidator = BasicService.class.getDeclaredField("rightAccessValidator");
        rightAccessValidator.setAccessible(true);
        rightAccessValidator.set(service, mockAccessValidator);
        Mockito.when(mockAccessValidator.getContextualAuthorities(Matchers.anyBoolean(), Matchers.any(Entity.class),
                Matchers.eq(SecurityUtil.UserContext.DUAL_CONTEXT), Matchers.anyBoolean()))
                .thenReturn(new HashSet<GrantedAuthority>());
        Mockito.doThrow(new AccessDeniedException("")).when(mockAccessValidator).checkAccess(Mockito.anyBoolean(),
                Mockito.anyBoolean(), Mockito.argThat(new MatchesNotAccessible()), Mockito.anyString(),
                Mockito.anyCollection());
        Mockito.doThrow(new AccessDeniedException("")).when(mockAccessValidator).checkFieldAccess(
                Mockito.any(NeutralQuery.class), Mockito.argThat(new MatchesNotFieldAccessible()),
                Mockito.anyString(), Mockito.anyCollection());

        NeutralQuery query = new NeutralQuery();
        query.setLimit(MAX_RESULT_SIZE);

        final long mockCountLimit = 5;
        Field countLimit = BasicService.class.getDeclaredField("countLimit");
        countLimit.setAccessible(true);
        final long prevCountLimit = countLimit.getLong(service);
        countLimit.set(service, mockCountLimit);

        Method method = BasicService.class.getDeclaredMethod("getResponseEntities", NeutralQuery.class,
                boolean.class);
        method.setAccessible(true);

        RequestUtil.setCurrentRequestId();
        Collection<Entity> accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult1 = Arrays.asList("student2", "student4", "student5", "student6",
                "student13");
        assertEntityIdsEqual(expectedResult1.iterator(), accessibleEntities.iterator());

        long count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(5, count);

        // Assure same order and count.

        RequestUtil.setCurrentRequestId();

        accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult2 = Arrays.asList("student2", "student4", "student5", "student6",
                "student13");
        assertEntityIdsEqual(expectedResult2.iterator(), accessibleEntities.iterator());

        count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(5, count);

        countLimit.set(service, prevCountLimit);
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testGetResponseEntitiesBatchLimit() throws SecurityException, NoSuchFieldException,
            IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        securityContextInjector.setDualContext();
        SecurityUtil.setUserContext(SecurityUtil.UserContext.DUAL_CONTEXT);

        List<Entity> entities = new ArrayList<Entity>();
        Map<String, SecurityUtil.UserContext> studentContext = new HashMap<String, SecurityUtil.UserContext>();
        for (int i = 0; i < 30; i++) {
            String id = "student" + i;
            entities.add(
                    new MongoEntity("student", id, new HashMap<String, Object>(), new HashMap<String, Object>()));
            studentContext.put(id, SecurityUtil.UserContext.DUAL_CONTEXT);
        }

        final int mockBatchSize = 10;
        Mockito.when(mockRepo.findAll(Mockito.eq("student"), Mockito.any(NeutralQuery.class)))
                .thenReturn(entities.subList(0, mockBatchSize))
                .thenReturn(entities.subList(mockBatchSize, mockBatchSize * 2))
                .thenReturn(entities.subList(mockBatchSize * 2, mockBatchSize * 3))
                .thenReturn(new ArrayList<Entity>());
        Mockito.when(mockRepo.count(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(50L);

        ContextValidator mockContextValidator = Mockito.mock(ContextValidator.class);
        Field contextValidator = BasicService.class.getDeclaredField("contextValidator");
        contextValidator.setAccessible(true);
        contextValidator.set(service, mockContextValidator);
        Mockito.when(mockContextValidator.getValidatedEntityContexts(Matchers.any(EntityDefinition.class),
                Matchers.any(Collection.class), Matchers.anyBoolean(), Matchers.anyBoolean()))
                .thenReturn(studentContext);

        RightAccessValidator mockAccessValidator = Mockito.mock(RightAccessValidator.class);
        Field rightAccessValidator = BasicService.class.getDeclaredField("rightAccessValidator");
        rightAccessValidator.setAccessible(true);
        rightAccessValidator.set(service, mockAccessValidator);
        Mockito.when(mockAccessValidator.getContextualAuthorities(Matchers.anyBoolean(), Matchers.any(Entity.class),
                Matchers.eq(SecurityUtil.UserContext.DUAL_CONTEXT), Matchers.anyBoolean()))
                .thenReturn(new HashSet<GrantedAuthority>());
        Mockito.doThrow(new AccessDeniedException("")).when(mockAccessValidator).checkAccess(Mockito.anyBoolean(),
                Mockito.anyBoolean(), Mockito.argThat(new MatchesNotAccessible()), Mockito.anyString(),
                Mockito.anyCollection());
        Mockito.doThrow(new AccessDeniedException("")).when(mockAccessValidator).checkFieldAccess(
                Mockito.any(NeutralQuery.class), Mockito.argThat(new MatchesNotFieldAccessible()),
                Mockito.anyString(), Mockito.anyCollection());

        NeutralQuery query = new NeutralQuery();
        query.setLimit(MAX_RESULT_SIZE);

        Field batchSize = BasicService.class.getDeclaredField("batchSize");
        batchSize.setAccessible(true);
        int prevBatchSize = batchSize.getInt(service);
        batchSize.set(service, mockBatchSize);

        Method method = BasicService.class.getDeclaredMethod("getResponseEntities", NeutralQuery.class,
                boolean.class);
        method.setAccessible(true);

        RequestUtil.setCurrentRequestId();
        Mockito.when(mockRepo.findAll(Mockito.eq("student"), Mockito.any(NeutralQuery.class)))
                .thenReturn(entities.subList(0, mockBatchSize))
                .thenReturn(entities.subList(mockBatchSize, mockBatchSize * 2))
                .thenReturn(entities.subList(mockBatchSize * 2, mockBatchSize * 3))
                .thenReturn(new ArrayList<Entity>());

        Collection<Entity> accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult1 = Arrays.asList("student2", "student4", "student5", "student6",
                "student13", "student16", "student17", "student18", "student22", "student23");
        assertEntityIdsEqual(expectedResult1.iterator(), accessibleEntities.iterator());

        long count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(10, count);

        // Assure same order and count.

        RequestUtil.setCurrentRequestId();
        Mockito.when(mockRepo.findAll(Mockito.eq("student"), Mockito.any(NeutralQuery.class)))
                .thenReturn(entities.subList(0, mockBatchSize))
                .thenReturn(entities.subList(mockBatchSize, mockBatchSize * 2))
                .thenReturn(entities.subList(mockBatchSize * 2, mockBatchSize * 3))
                .thenReturn(new ArrayList<Entity>());

        accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Iterable<String> expectedResult2 = Arrays.asList("student2", "student4", "student5", "student6",
                "student13", "student16", "student17", "student18", "student22", "student23");
        assertEntityIdsEqual(expectedResult2.iterator(), accessibleEntities.iterator());

        count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(10, count);

        batchSize.set(service, prevBatchSize);
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testGetResponseEntitiesEmpty() throws SecurityException, NoSuchFieldException,
            IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        securityContextInjector.setDualContext();
        SecurityUtil.setUserContext(SecurityUtil.UserContext.DUAL_CONTEXT);

        Mockito.when(mockRepo.findAll(Mockito.eq("student"), Mockito.any(NeutralQuery.class)))
                .thenReturn(new ArrayList<Entity>());
        Mockito.when(mockRepo.count(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(0L);

        ContextValidator mockContextValidator = Mockito.mock(ContextValidator.class);
        Field contextValidator = BasicService.class.getDeclaredField("contextValidator");
        contextValidator.setAccessible(true);
        contextValidator.set(service, mockContextValidator);

        NeutralQuery query = new NeutralQuery();
        query.setLimit(ApiQuery.API_QUERY_DEFAULT_LIMIT);

        Method method = BasicService.class.getDeclaredMethod("getResponseEntities", NeutralQuery.class,
                boolean.class);
        method.setAccessible(true);

        RequestUtil.setCurrentRequestId();
        Collection<Entity> accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);

        Assert.assertTrue(accessibleEntities.isEmpty());

        long count = service.getAccessibleEntitiesCount("student");
        Assert.assertEquals(0, count);
    }

    @SuppressWarnings({ "unchecked", "unused" })
    @Test
    public void testGetResponseEntitiesNoAccess() throws SecurityException, NoSuchFieldException,
            IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        securityContextInjector.setDualContext();
        SecurityUtil.setUserContext(SecurityUtil.UserContext.DUAL_CONTEXT);

        List<Entity> entities = new ArrayList<Entity>();
        Map<String, SecurityUtil.UserContext> studentContext = new HashMap<String, SecurityUtil.UserContext>();
        for (int i = 0; i < 30; i++) {
            String id = "student" + i;
            entities.add(
                    new MongoEntity("student", id, new HashMap<String, Object>(), new HashMap<String, Object>()));
            studentContext.put(id, SecurityUtil.UserContext.DUAL_CONTEXT);
        }
        Mockito.when(mockRepo.findAll(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(entities);
        Mockito.when(mockRepo.count(Mockito.eq("student"), Mockito.any(NeutralQuery.class))).thenReturn(50L);

        ContextValidator mockContextValidator = Mockito.mock(ContextValidator.class);
        Field contextValidator = BasicService.class.getDeclaredField("contextValidator");
        contextValidator.setAccessible(true);
        contextValidator.set(service, mockContextValidator);
        Mockito.when(mockContextValidator.getValidatedEntityContexts(Matchers.any(EntityDefinition.class),
                Matchers.any(Collection.class), Matchers.anyBoolean(), Matchers.anyBoolean()))
                .thenReturn(studentContext);

        RightAccessValidator mockAccessValidator = Mockito.mock(RightAccessValidator.class);
        Field rightAccessValidator = BasicService.class.getDeclaredField("rightAccessValidator");
        rightAccessValidator.setAccessible(true);
        rightAccessValidator.set(service, mockAccessValidator);
        Mockito.when(mockAccessValidator.getContextualAuthorities(Matchers.anyBoolean(), Matchers.any(Entity.class),
                Matchers.eq(SecurityUtil.UserContext.DUAL_CONTEXT), Matchers.anyBoolean()))
                .thenReturn(new HashSet<GrantedAuthority>());
        Mockito.doThrow(new AccessDeniedException("")).when(mockAccessValidator).checkAccess(Mockito.anyBoolean(),
                Mockito.anyBoolean(), Mockito.any(Entity.class), Mockito.anyString(), Mockito.anyCollection());
        Mockito.doThrow(new AccessDeniedException("")).when(mockAccessValidator).checkFieldAccess(
                Mockito.any(NeutralQuery.class), Mockito.any(Entity.class), Mockito.anyString(),
                Mockito.anyCollection());

        NeutralQuery query = new NeutralQuery();
        query.setLimit(ApiQuery.API_QUERY_DEFAULT_LIMIT);

        Method method = BasicService.class.getDeclaredMethod("getResponseEntities", NeutralQuery.class,
                boolean.class);
        method.setAccessible(true);

        try {
            RequestUtil.setCurrentRequestId();
            Collection<Entity> accessibleEntities = (Collection<Entity>) method.invoke(service, query, false);
        } catch (InvocationTargetException itex) {
            Assert.assertEquals(APIAccessDeniedException.class, itex.getCause().getClass());
            Assert.assertEquals("Access to resource denied.", itex.getCause().getMessage());
        }
    }

    private void setPrincipalInContext(SLIPrincipal principal) {
        Authentication authentication = Mockito.mock(Authentication.class);
        Mockito.when(authentication.getPrincipal()).thenReturn(principal);
        SecurityContext context = Mockito.mock(SecurityContext.class);
        Mockito.when(context.getAuthentication()).thenReturn(authentication);
        SecurityContextHolder.setContext(context);
    }

    private void assertEntityBodyIdsEqual(Iterator<String> expected, Iterator<EntityBody> actual) {
        while (expected.hasNext()) {
            Assert.assertEquals(expected.next(), actual.next().get("studentUniqueStateId"));
        }
        Assert.assertFalse(actual.hasNext());
    }

    private void assertEntityIdsEqual(Iterator<String> expected, Iterator<Entity> actual) {
        while (expected.hasNext()) {
            Assert.assertEquals(expected.next(), actual.next().getEntityId());
        }
        Assert.assertFalse(actual.hasNext());
    }

    @AfterClass
    public static void reset() {
        // Let's be good citizens and clean up after ourselves for the subsequent tests!
        SecurityUtil.setUserContext(prevUserContext);
        SecurityContextHolder.setContext(prevSecurityContext);
    }

}