001/**
002 * Copyright 2005-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krad.test;
017
018import org.apache.commons.lang.StringUtils;
019import org.junit.Test;
020import org.junit.runner.RunWith;
021import org.kuali.rice.core.api.lifecycle.Lifecycle;
022import org.kuali.rice.core.framework.resourceloader.SpringResourceLoader;
023import org.kuali.rice.krad.datadictionary.DataDictionary;
024import org.kuali.rice.krad.util.LegacyUtils;
025import org.kuali.rice.test.BaselineTestCase;
026import org.kuali.rice.test.SQLDataLoader;
027import org.kuali.rice.test.TestUtilities;
028import org.kuali.rice.test.lifecycles.KEWXmlDataLoaderLifecycle;
029import org.kuali.rice.test.runners.BootstrapTest;
030import org.kuali.rice.test.runners.LoadTimeWeavableTestRunner;
031import org.springframework.context.ConfigurableApplicationContext;
032import org.springframework.context.support.ClassPathXmlApplicationContext;
033
034import javax.xml.namespace.QName;
035import java.lang.annotation.Retention;
036import java.lang.annotation.Target;
037import java.util.ArrayList;
038import java.util.HashSet;
039import java.util.List;
040
041import static java.lang.annotation.ElementType.METHOD;
042import static java.lang.annotation.ElementType.TYPE;
043import static java.lang.annotation.RetentionPolicy.RUNTIME;
044
045/**
046 * Default test base for a full KRAD enabled integration test
047 *
048 * @author Kuali Rice Team (rice.collab@kuali.org)
049 */
050@BaselineTestCase.BaselineMode(BaselineTestCase.Mode.ROLLBACK_CLEAR_DB)
051@RunWith(LoadTimeWeavableTestRunner.class)
052@BootstrapTest(KRADTestCase.BootstrapTest.class)
053public abstract class KRADTestCase extends BaselineTestCase {
054    private static final String SQL_FILE = "classpath:org/kuali/rice/krad/test/DefaultSuiteTestData.sql";
055    private static final String XML_FILE = "classpath:org/kuali/rice/krad/test/DefaultSuiteTestData.xml";
056    private static final String KRAD_MODULE_NAME = "krad";
057
058    protected DataDictionary dd;
059
060    protected static SpringResourceLoader kradTestHarnessSpringResourceLoader;
061
062    private boolean legacyContext = false;
063
064    public KRADTestCase() {
065        super(KRAD_MODULE_NAME);
066    }
067
068    /**
069     * propagate constructor
070     * @param moduleName - the name of the module
071     */
072    public KRADTestCase(String moduleName) {
073        super(moduleName);
074    }
075
076    protected ConfigurableApplicationContext getKRADTestHarnessContext() {
077        return kradTestHarnessSpringResourceLoader.getContext();
078    }
079
080    @Override
081    public void setUp() throws Exception {
082        super.setUp();
083        setUpLegacyContext();
084
085    }
086
087    @Override
088    public void tearDown() throws Exception {
089        try {
090            tearDownLegacyContext();
091        } finally {
092            super.tearDown();    //To change body of overridden methods use File | Settings | File Templates.
093        }
094    }
095
096    protected void setUpLegacyContext() {
097        if (getTestMethod().getAnnotation(Legacy.class) != null || getClass().getAnnotation(Legacy.class) != null) {
098            LegacyUtils.beginLegacyContext();
099            legacyContext = true;
100        }
101    }
102
103    protected void tearDownLegacyContext() {
104        if (getTestMethod().getAnnotation(Legacy.class) != null || getClass().getAnnotation(Legacy.class) != null) {
105            if (legacyContext) {
106                LegacyUtils.endLegacyContext();
107                legacyContext = false;
108            }
109        }
110    }
111
112    @Override
113    protected void setUpInternal() throws Exception {
114        super.setUpInternal();
115
116        List<Class> classes = TestUtilities.getHierarchyClassesToHandle(getClass(),
117                new Class[]{TestDictionaryConfig.class}, new HashSet<String>());
118
119        // if annotation is present then initialize test data dictionary (setup once per suite)
120        if (!classes.isEmpty()) {
121            ConfigurableApplicationContext context  = new ClassPathXmlApplicationContext("TestDataDictionary.xml");
122            dd = (DataDictionary) context.getBean("testDataDictionary");
123
124            // add any additional dictionary files required by the test
125            for (Class c : classes) {
126                if (c.isAnnotationPresent(TestDictionaryConfig.class)) {
127                    TestDictionaryConfig testDictionaryConfig = (TestDictionaryConfig) c.getAnnotation(
128                            TestDictionaryConfig.class);
129
130                    String namespaceCode = testDictionaryConfig.namespaceCode();
131                    String dictionaryFileString = testDictionaryConfig.dataDictionaryFiles();
132
133                    String[] dictionaryFiles = StringUtils.split(dictionaryFileString, ",");
134                    for (String dictionaryFile : dictionaryFiles) {
135                        LOG.info("Adding test data dictionary file: " + dictionaryFile);
136
137                        dd.addConfigFileLocation(namespaceCode, dictionaryFile);
138                    }
139                }
140            }
141
142            dd.parseDataDictionaryConfigurationFiles(false);
143            dd.validateDD(false); // Validation performs some necessary post-processing of the beans - we need to run this each time we add new files
144            dd.performBeanOverrides();
145        }
146    }
147
148    /**
149     * Returns an instance of the bean with the given id that has been configured in the test dictionary
150     *
151     * @param id - id of the bean definition
152     * @return Object instance of the given bean class, or null if not found or dictionary is not loaded
153     */
154    protected Object getTestDictionaryObject(String id) {
155        if (dd != null) {
156            return dd.getDictionaryBean(id);
157        }
158
159        return null;
160    }
161
162    @Override
163    protected List<Lifecycle> getSuiteLifecycles() {
164        List<Lifecycle> suiteLifecycles = super.getSuiteLifecycles();
165        suiteLifecycles.add(new KEWXmlDataLoaderLifecycle(XML_FILE));
166
167        return suiteLifecycles;
168    }
169
170    @Override
171    protected List<String> getPerTestTablesNotToClear() {
172        List<String> tablesNotToClear = new ArrayList<String>();
173        tablesNotToClear.add("KRIM_.*");
174        tablesNotToClear.add("KRCR_.*");
175        tablesNotToClear.add("KREW_.*");
176        return tablesNotToClear;
177    }
178
179    @Override
180    protected void loadSuiteTestData() throws Exception {
181        super.loadSuiteTestData();
182        new SQLDataLoader(SQL_FILE, ";").runSql();
183    }
184
185    @Override
186    protected Lifecycle getLoadApplicationLifecycle() {
187        // cache the KRAD test harness spring resource loader
188        // this is not great because it doesn't conform to the lifecycle
189        // ...but why are we creating sub-resourceloaders instead of just adding locations to the test harness context?
190        if (kradTestHarnessSpringResourceLoader == null) {
191            kradTestHarnessSpringResourceLoader = new SpringResourceLoader(new QName("KRADTestResourceLoader"),
192                    "classpath:KRADTestHarnessSpringBeans.xml", null);
193            kradTestHarnessSpringResourceLoader.setParentSpringResourceLoader(getTestHarnessSpringResourceLoader());
194        }
195        return kradTestHarnessSpringResourceLoader;
196    }
197
198    /**
199     * Annotation which indicates that a Legacy Context should be used for this individual test method or for all tests
200     * in an annotated class.
201     *
202     * @see org.kuali.rice.krad.util.LegacyUtils#doInLegacyContext(java.util.concurrent.Callable)
203     */
204    @Target({TYPE, METHOD})
205    @Retention(RUNTIME)
206    public @interface Legacy {}
207
208    public static final class BootstrapTest extends KRADTestCase {
209        @Test
210        public void bootstrapTest() {};
211    }
212
213}