org.apereo.services.persondir.support.jdbc.MultiRowJdbcPersonAttributeDaoTest.java Source code

Java tutorial

Introduction

Here is the source code for org.apereo.services.persondir.support.jdbc.MultiRowJdbcPersonAttributeDaoTest.java

Source

/**
 * Licensed to Apereo under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Apereo licenses this file to you 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 the following location:
 *
 *   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.apereo.services.persondir.support.jdbc;

import com.google.common.collect.ImmutableMap;
import junit.framework.TestCase;
import org.apereo.services.persondir.support.AbstractDefaultAttributePersonAttributeDao;
import org.apereo.services.persondir.support.SimpleUsernameAttributeProvider;
import org.apereo.services.persondir.util.CaseCanonicalizationMode;
import org.apereo.services.persondir.util.Util;
import org.springframework.jdbc.BadSqlGrammarException;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Test the {@link MultiRowJdbcPersonAttributeDao} against a dummy DataSource.
 *
 * @author andrew.petro@yale.edu
 * @author Eric Dalquist
    
 */
public class MultiRowJdbcPersonAttributeDaoTest extends AbstractCaseSensitivityJdbcPersonAttributeDaoTest {

    @Override
    protected void setUpSchema(final DataSource dataSource) throws SQLException {
        final Connection con = dataSource.getConnection();

        con.prepareStatement(
                "CREATE TABLE user_table " + "(netid VARCHAR, " + "attr_name VARCHAR, " + "attr_val VARCHAR)")
                .execute();

        con.prepareStatement(
                "INSERT INTO user_table " + "(netid, attr_name, attr_val) " + "VALUES ('awp9', 'name', 'Andrew')")
                .execute();
        con.prepareStatement("INSERT INTO user_table " + "(netid, attr_name, attr_val) "
                + "VALUES ('awp9', 'email', 'andrew.petro@yale.edu')").execute();
        con.prepareStatement("INSERT INTO user_table " + "(netid, attr_name, attr_val) "
                + "VALUES ('awp9', 'shirt_color', 'blue')").execute();

        con.prepareStatement("INSERT INTO user_table " + "(netid, attr_name, attr_val) "
                + "VALUES ('edalquist', 'name', 'Eric')").execute();
        con.prepareStatement("INSERT INTO user_table " + "(netid, attr_name, attr_val) "
                + "VALUES ('edalquist', 'email', 'edalquist@unicon.net')").execute();
        con.prepareStatement("INSERT INTO user_table " + "(netid, attr_name, attr_val) "
                + "VALUES ('edalquist', 'shirt_color', 'blue')").execute();

        con.prepareStatement(
                "INSERT INTO user_table " + "(netid, attr_name, attr_val) " + "VALUES ('atest', 'name', 'Andrew')")
                .execute();
        con.prepareStatement("INSERT INTO user_table " + "(netid, attr_name, attr_val) "
                + "VALUES ('atest', 'email', 'andrew.test@test.net')").execute();
        con.prepareStatement("INSERT INTO user_table " + "(netid, attr_name, attr_val) "
                + "VALUES ('atest', 'shirt_color', 'red')").execute();

        con.prepareStatement(
                "INSERT INTO user_table " + "(netid, attr_name, attr_val) " + "VALUES ('susan', 'name', 'Susan')")
                .execute();
        con.prepareStatement("INSERT INTO user_table " + "(netid, attr_name, attr_val) "
                + "VALUES ('susan', 'email', 'susan.test@test.net')").execute();
        con.prepareStatement("INSERT INTO user_table " + "(netid, attr_name, attr_val) "
                + "VALUES ('susan', 'shirt_color', null)").execute();

        con.close();
    }

    @Override
    protected void tearDownSchema(final DataSource dataSource) throws SQLException {
        final Connection con = dataSource.getConnection();

        con.prepareStatement("DROP TABLE user_table").execute();

        con.close();
    }

    @Override
    protected AbstractJdbcPersonAttributeDao<Map<String, Object>> newDao(final DataSource dataSource) {
        final MultiRowJdbcPersonAttributeDao dao = new MultiRowJdbcPersonAttributeDao(dataSource,
                "SELECT netid, attr_name, attr_val FROM user_table WHERE {0}");
        dao.setNameValueColumnMappings(ImmutableMap.of("attr_name", "attr_val"));
        return dao;
    }

    @Override
    protected boolean supportsPerDataAttributeCaseSensitivity() {
        return false;
    }

    @Override
    protected void beforeNonUsernameQuery(final AbstractJdbcPersonAttributeDao<Map<String, Object>> dao) {

        // no processing method for caseInsensitiveResultAttributeMappings b/c
        // the mapping from physical data layer attrib name (attr_val) to
        // logical data layer attrib name has already occurred by the time
        // the case canonicalization kicks in
        processQueryAttributeMappingValues_BeforeNonUsernameQuery(dao);
        processCaseInsensitiveDataAttributeMappingValues_BeforeNonUsernameQuery(dao);
        dao.setUnmappedUsernameAttribute("netid");
    }

    protected void processQueryAttributeMappingValues_BeforeNonUsernameQuery(
            final AbstractJdbcPersonAttributeDao<Map<String, Object>> dao) {
        final Map<String, Set<String>> origMappings = dao.getQueryAttributeMapping();
        if (origMappings == null || origMappings.isEmpty()) {
            return;
        }
        final Map<String, Set<String>> newMappings = new LinkedHashMap<>();
        for (final Map.Entry<String, Set<String>> origMapping : origMappings.entrySet()) {
            final Set<String> newMappingValue = new LinkedHashSet<>();
            // multi-row dao maps all non-username attr values to the same
            // data layer column
            for (final String origMappingValue : origMapping.getValue()) {
                if (!("netid".equals(origMappingValue))) {
                    newMappingValue.add("attr_val");
                } else {
                    newMappingValue.add(origMappingValue);
                }
            }
            newMappings.put(origMapping.getKey(), newMappingValue);
        }
        dao.setQueryAttributeMapping(newMappings);
    }

    protected void processCaseInsensitiveDataAttributeMappingValues_BeforeNonUsernameQuery(
            final AbstractJdbcPersonAttributeDao<Map<String, Object>> dao) {
        final Map<String, CaseCanonicalizationMode> origMappings = dao.getCaseInsensitiveDataAttributes();
        if (origMappings == null || origMappings.isEmpty()) {
            return;
        }
        final Map<String, CaseCanonicalizationMode> newMappings = new LinkedHashMap<>();
        for (final Map.Entry<String, CaseCanonicalizationMode> origMapping : origMappings.entrySet()) {
            // that's right, it's all or nothing for the multi-row DAO w/r/t
            // case sensitivity of non-username attribs b/c the canonicalization
            // is based on data-layer attribute names, which are all the same for
            // this DAO type.
            if (!("netid".equals(origMapping.getKey()))) {
                newMappings.put("attr_val", origMapping.getValue());
            } else {
                newMappings.put(origMapping.getKey(), origMapping.getValue());
            }
        }
        dao.setCaseInsensitiveDataAttributes(newMappings);
    }

    public void testNoQueryAttributeMapping() {
        final MultiRowJdbcPersonAttributeDao impl = new MultiRowJdbcPersonAttributeDao(testDataSource,
                "SELECT netid, attr_name, attr_val FROM user_table WHERE netid = 'awp9'");
        impl.setUseAllQueryAttributes(false);

        impl.setUsernameAttributeProvider(new SimpleUsernameAttributeProvider("uid"));
        impl.setUnmappedUsernameAttribute("netid");

        final Map<String, Object> columnsToAttributes = new LinkedHashMap<>();
        columnsToAttributes.put("name", "firstName");
        final Set<String> emailAttributeNames = new LinkedHashSet<>();
        emailAttributeNames.add("email");
        emailAttributeNames.add("emailAddress");
        columnsToAttributes.put("email", emailAttributeNames);
        columnsToAttributes.put("shirt_color", "dressShirtColor");
        impl.setResultAttributeMapping(columnsToAttributes);

        impl.setNameValueColumnMappings(Collections.singletonMap("attr_name", "attr_val"));

        final Map<String, List<Object>> attribs = impl.getMultivaluedUserAttributes("awp9");
        TestCase.assertEquals(Util.list("andrew.petro@yale.edu"), attribs.get("email"));
        TestCase.assertEquals(Util.list("andrew.petro@yale.edu"), attribs.get("emailAddress"));
        TestCase.assertEquals(Util.list("blue"), attribs.get("dressShirtColor"));
        TestCase.assertNull(attribs.get("shirt_color"));
        TestCase.assertEquals(Util.list("Andrew"), attribs.get("firstName"));
    }

    /**
     * Test that the implementation properly reports the attribute names it
     * expects to map.
     */
    public void testPossibleUserAttributeNames() {
        final MultiRowJdbcPersonAttributeDao impl = new MultiRowJdbcPersonAttributeDao(testDataSource,
                "SELECT attr_name, attr_val FROM user_table WHERE {0}");
        impl.setQueryAttributeMapping(Collections.singletonMap("uid", "netid"));

        final Map<String, Object> columnsToAttributes = new LinkedHashMap<>();
        columnsToAttributes.put("name", "firstName");

        final Set<String> emailAttributeNames = new LinkedHashSet<>();
        emailAttributeNames.add("email");
        emailAttributeNames.add("emailAddress");
        columnsToAttributes.put("email", emailAttributeNames);
        columnsToAttributes.put("shirt_color", "dressShirtColor");
        impl.setResultAttributeMapping(columnsToAttributes);

        final Set<String> expectedAttributeNames = new LinkedHashSet<>();
        expectedAttributeNames.add("firstName");
        expectedAttributeNames.add("email");
        expectedAttributeNames.add("emailAddress");
        expectedAttributeNames.add("dressShirtColor");

        final Set<String> attributeNames = impl.getPossibleUserAttributeNames();
        TestCase.assertEquals(attributeNames, expectedAttributeNames);
    }

    /**
     * Test for a query with a single attribute
     */
    public void testSingleAttrQuery() {
        final MultiRowJdbcPersonAttributeDao impl = new MultiRowJdbcPersonAttributeDao(testDataSource,
                "SELECT netid, attr_name, attr_val FROM user_table WHERE {0}");
        impl.setQueryAttributeMapping(Collections.singletonMap("uid", "netid"));

        impl.setUsernameAttributeProvider(new SimpleUsernameAttributeProvider("uid"));
        impl.setUnmappedUsernameAttribute("netid");

        final Map<String, Object> columnsToAttributes = new LinkedHashMap<>();
        columnsToAttributes.put("name", "firstName");
        final Set<String> emailAttributeNames = new LinkedHashSet<>();
        emailAttributeNames.add("email");
        emailAttributeNames.add("emailAddress");
        columnsToAttributes.put("email", emailAttributeNames);
        columnsToAttributes.put("shirt_color", "dressShirtColor");
        impl.setResultAttributeMapping(columnsToAttributes);

        impl.setNameValueColumnMappings(Collections.singletonMap("attr_name", "attr_val"));

        final Map<String, List<Object>> attribs = impl.getMultivaluedUserAttributes("awp9");
        TestCase.assertEquals(Util.list("andrew.petro@yale.edu"), attribs.get("email"));
        TestCase.assertEquals(Util.list("andrew.petro@yale.edu"), attribs.get("emailAddress"));
        TestCase.assertEquals(Util.list("blue"), attribs.get("dressShirtColor"));
        TestCase.assertNull(attribs.get("shirt_color"));
        TestCase.assertEquals(Util.list("Andrew"), attribs.get("firstName"));
    }

    /**
     * Test for a query with a single attribute
     */
    public void testInvalidColumnName() {
        final MultiRowJdbcPersonAttributeDao impl = new MultiRowJdbcPersonAttributeDao(testDataSource,
                "SELECT netid, attr_name, attr_val FROM user_table WHERE {0}");
        impl.setQueryAttributeMapping(Collections.singletonMap("uid", "netid"));

        impl.setUsernameAttributeProvider(new SimpleUsernameAttributeProvider("uid"));
        impl.setUnmappedUsernameAttribute("netid");

        final Map<String, Object> columnsToAttributes = new LinkedHashMap<>();
        columnsToAttributes.put("name", "firstName");

        columnsToAttributes.put("email", "emailAddress");
        impl.setResultAttributeMapping(columnsToAttributes);

        impl.setNameValueColumnMappings(Collections.singletonMap("attr_nam", "attr_val"));

        try {
            impl.getMultivaluedUserAttributes("awp9");
            TestCase.fail("BadSqlGrammarException expected with invalid attribute mapping key");
        } catch (final BadSqlGrammarException bsge) {
            //expected
        }

        impl.setNameValueColumnMappings(Collections.singletonMap("attr_name", "attr_va"));

        try {
            impl.getMultivaluedUserAttributes("awp9");
            TestCase.fail("BadSqlGrammarException expected with invalid attribute mapping key");
        } catch (final BadSqlGrammarException bsge) {
            //expected
        }
    }

    /**
     * Test for a query with a single attribute
     */
    public void testSetNullAttributeMapping() {
        final MultiRowJdbcPersonAttributeDao impl = new MultiRowJdbcPersonAttributeDao(testDataSource,
                "SELECT netid, attr_name, attr_val FROM user_table WHERE {0}");
        impl.setQueryAttributeMapping(Collections.singletonMap("uid", "netid"));

        impl.setUsernameAttributeProvider(new SimpleUsernameAttributeProvider("uid"));
        impl.setUnmappedUsernameAttribute("netid");

        final Map<String, Object> columnsToAttributes = new LinkedHashMap<>();
        columnsToAttributes.put("name", "firstName");

        final Set<String> emailAttributeNames = new LinkedHashSet<>();
        emailAttributeNames.add("email");
        emailAttributeNames.add("emailAddress");
        columnsToAttributes.put("email", emailAttributeNames);
        columnsToAttributes.put("shirt_color", null);
        impl.setResultAttributeMapping(columnsToAttributes);

        impl.setNameValueColumnMappings(Collections.singletonMap("attr_name", "attr_val"));

        final Map<String, List<Object>> attribs = impl.getMultivaluedUserAttributes("awp9");
        TestCase.assertEquals(Util.list("andrew.petro@yale.edu"), attribs.get("email"));
        TestCase.assertEquals(Util.list("andrew.petro@yale.edu"), attribs.get("emailAddress"));
        TestCase.assertEquals(Util.list("blue"), attribs.get("shirt_color"));
        TestCase.assertEquals(Util.list("Andrew"), attribs.get("firstName"));
    }

    /**
     * Test for a query with a single attribute
     */
    public void testSetNullAttributeName() {
        final MultiRowJdbcPersonAttributeDao impl = new MultiRowJdbcPersonAttributeDao(testDataSource,
                "SELECT netid, attr_name, attr_val FROM user_table WHERE {0}");
        impl.setQueryAttributeMapping(Collections.singletonMap("uid", "netid"));

        impl.setUsernameAttributeProvider(new SimpleUsernameAttributeProvider("uid"));
        impl.setUnmappedUsernameAttribute("netid");

        final Map<String, Object> columnsToAttributes = new LinkedHashMap<>();
        columnsToAttributes.put("", "dressShirtColor");

        try {
            impl.setResultAttributeMapping(columnsToAttributes);
            TestCase.fail("IllegalArgumentException if the ColumnsToAttributes Map has an empty Key");
        } catch (final IllegalArgumentException iae) {
            //expected
        }
    }

    /**
     * Test for a query with a null value attribute
     */
    public void testNullAttrQuery() {
        final MultiRowJdbcPersonAttributeDao impl = new MultiRowJdbcPersonAttributeDao(testDataSource,
                "SELECT netid, attr_name, attr_val FROM user_table WHERE {0}");
        impl.setQueryAttributeMapping(Collections.singletonMap("uid", "netid"));

        impl.setUsernameAttributeProvider(new SimpleUsernameAttributeProvider("uid"));
        impl.setUnmappedUsernameAttribute("netid");

        final Map<String, Object> columnsToAttributes = new LinkedHashMap<>();
        columnsToAttributes.put("name", "firstName");
        columnsToAttributes.put("shirt_color", "dressShirtColor");
        impl.setResultAttributeMapping(columnsToAttributes);

        impl.setNameValueColumnMappings(Collections.singletonMap("attr_name", "attr_val"));

        final Map<String, List<Object>> attribs = impl.getMultivaluedUserAttributes("susan");
        TestCase.assertEquals(Collections.singletonList(null), attribs.get("dressShirtColor"));
        TestCase.assertEquals(Util.list("Susan"), attribs.get("firstName"));
    }

    /**
     * Test case for a query that needs multiple attributes to complete and
     * more attributes than are needed to complete are passed to it.
     */
    public void testMultiAttrQuery() {
        final Map<String, String> queryAttributeMapping = new LinkedHashMap<>();
        queryAttributeMapping.put("uid", "netid");
        queryAttributeMapping.put("shirtColor", "attr_val");

        final MultiRowJdbcPersonAttributeDao impl = new MultiRowJdbcPersonAttributeDao(testDataSource,
                "SELECT netid, attr_name, attr_val FROM user_table WHERE {0}");
        impl.setQueryAttributeMapping(queryAttributeMapping);

        impl.setUsernameAttributeProvider(new SimpleUsernameAttributeProvider("uid"));
        impl.setUnmappedUsernameAttribute("netid");

        final Map<String, Object> columnsToAttributes = new LinkedHashMap<>();
        columnsToAttributes.put("shirt_color", "color");
        impl.setResultAttributeMapping(columnsToAttributes);

        impl.setNameValueColumnMappings(Collections.singletonMap("attr_name", "attr_val"));

        final Map<String, List<Object>> queryMap = new LinkedHashMap<>();
        queryMap.put("uid", Util.list("awp9"));
        queryMap.put("shirtColor", Util.list("blue"));
        queryMap.put("Name", Util.list("John"));

        final Map<String, List<Object>> attribs = impl.getMultivaluedUserAttributes(queryMap);
        TestCase.assertEquals(Util.list("blue"), attribs.get("color"));
    }

    /**
     * A query that needs mulitple attributes to complete but the needed
     * attributes aren't passed to it.
     */
    public void testInsufficientAttrQuery() {
        final Map<String, String> queryAttributeMapping = new LinkedHashMap<>();
        queryAttributeMapping.put("uid", "netid");
        queryAttributeMapping.put("shirtColor", "attr_val");

        final MultiRowJdbcPersonAttributeDao impl = new MultiRowJdbcPersonAttributeDao(testDataSource,
                "SELECT netid, attr_name, attr_val FROM user_table WHERE {0}");
        impl.setQueryAttributeMapping(queryAttributeMapping);

        impl.setUsernameAttributeProvider(new SimpleUsernameAttributeProvider("uid"));
        impl.setUnmappedUsernameAttribute("netid");
        impl.setRequireAllQueryAttributes(true);

        final Map<String, Object> columnsToAttributes = new LinkedHashMap<>();
        columnsToAttributes.put("name", "firstName");

        final Set<String> emailAttributeNames = new LinkedHashSet<>();
        emailAttributeNames.add("email");
        emailAttributeNames.add("emailAddress");
        columnsToAttributes.put("email", emailAttributeNames);
        impl.setResultAttributeMapping(columnsToAttributes);

        impl.setNameValueColumnMappings(Collections.singletonMap("attr_name", "attr_val"));

        final Map<String, List<Object>> queryMap = new LinkedHashMap<>();
        queryMap.put("uid", Util.list("awp9"));
        queryMap.put("Name", Util.list("John"));

        final Map<String, List<Object>> attribs = impl.getMultivaluedUserAttributes(queryMap);
        TestCase.assertNull(attribs);
    }

    public void testProperties() {
        final MultiRowJdbcPersonAttributeDao impl = new MultiRowJdbcPersonAttributeDao(testDataSource,
                "SELECT netid, name, email FROM user_table WHERE shirt_color = ?");
        impl.setQueryAttributeMapping(Collections.singletonMap("shirt", "netid"));

        impl.setUsernameAttributeProvider(new SimpleUsernameAttributeProvider("shirt"));
        impl.setUnmappedUsernameAttribute("netid");

        final Map<String, Object> columnsToAttributes = new LinkedHashMap<>();
        columnsToAttributes.put("netid", "uid");
        columnsToAttributes.put("name", "firstName");

        final Map<String, Object> expectedColumnsToAttributes = new LinkedHashMap<>();
        expectedColumnsToAttributes.put("netid", Collections.singleton("uid"));
        expectedColumnsToAttributes.put("name", Collections.singleton("firstName"));

        TestCase.assertNull(impl.getResultAttributeMapping());
        impl.setResultAttributeMapping(columnsToAttributes);
        TestCase.assertEquals(expectedColumnsToAttributes, impl.getResultAttributeMapping());

        TestCase.assertEquals(null, impl.getNameValueColumnMappings());
        impl.setNameValueColumnMappings(null);
        TestCase.assertEquals(null, impl.getNameValueColumnMappings());
        try {
            impl.setNameValueColumnMappings(Collections.singletonMap("NullValueKey", null));
            TestCase.fail(
                    "setNameValueColumnMappings(Collections.singletonMap(\"NullValueKey\", null)) should result in an IllegalArgumentException");
        } catch (final IllegalArgumentException iae) {
            //Expected
        }
        impl.setNameValueColumnMappings(Collections.singletonMap("attr_name", "attr_val"));
        TestCase.assertEquals(Collections.singletonMap("attr_name", Collections.singleton("attr_val")),
                impl.getNameValueColumnMappings());

    }

    @Override
    protected AbstractDefaultAttributePersonAttributeDao getAbstractDefaultQueryPersonAttributeDao() {
        final MultiRowJdbcPersonAttributeDao impl = new MultiRowJdbcPersonAttributeDao(this.testDataSource,
                "SELECT netid, name, email FROM user_table WHERE {0}");
        impl.setQueryAttributeMapping(Collections.singletonMap("shirt", "shirt_color"));

        return impl;
    }

}