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.HashSet;
038import java.util.List;
039
040import static java.lang.annotation.ElementType.METHOD;
041import static java.lang.annotation.ElementType.TYPE;
042import static java.lang.annotation.RetentionPolicy.RUNTIME;
043
044/**
045 * Default test base for a full KRAD enabled integration test
046 *
047 * @author Kuali Rice Team (rice.collab@kuali.org)
048 */
049@BaselineTestCase.BaselineMode(BaselineTestCase.Mode.ROLLBACK_CLEAR_DB)
050@RunWith(LoadTimeWeavableTestRunner.class)
051@BootstrapTest(KRADTestCase.BootstrapTest.class)
052public abstract class KRADTestCase extends BaselineTestCase {
053    private static final String SQL_FILE = "classpath:org/kuali/rice/krad/test/DefaultSuiteTestData.sql";
054    private static final String XML_FILE = "classpath:org/kuali/rice/krad/test/DefaultSuiteTestData.xml";
055    private static final String KRAD_MODULE_NAME = "krad";
056
057    protected DataDictionary dd;
058
059    protected static SpringResourceLoader kradTestHarnessSpringResourceLoader;
060
061    private boolean legacyContext = false;
062
063    public KRADTestCase() {
064        super(KRAD_MODULE_NAME);
065    }
066
067    /**
068     * propagate constructor
069     * @param moduleName - the name of the module
070     */
071    public KRADTestCase(String moduleName) {
072        super(moduleName);
073    }
074
075    protected ConfigurableApplicationContext getKRADTestHarnessContext() {
076        return kradTestHarnessSpringResourceLoader.getContext();
077    }
078
079    @Override
080    public void setUp() throws Exception {
081        super.setUp();
082        setUpLegacyContext();
083
084    }
085
086    @Override
087    public void tearDown() throws Exception {
088        try {
089            tearDownLegacyContext();
090        } finally {
091            super.tearDown();    //To change body of overridden methods use File | Settings | File Templates.
092        }
093    }
094
095    protected void setUpLegacyContext() {
096        if (getTestMethod().getAnnotation(Legacy.class) != null || getClass().getAnnotation(Legacy.class) != null) {
097            LegacyUtils.beginLegacyContext();
098            legacyContext = true;
099        }
100    }
101
102    protected void tearDownLegacyContext() {
103        if (getTestMethod().getAnnotation(Legacy.class) != null || getClass().getAnnotation(Legacy.class) != null) {
104            if (legacyContext) {
105                LegacyUtils.endLegacyContext();
106                legacyContext = false;
107            }
108        }
109    }
110
111    @Override
112    protected void setUpInternal() throws Exception {
113        super.setUpInternal();
114
115        List<Class> classes = TestUtilities.getHierarchyClassesToHandle(getClass(),
116                new Class[]{TestDictionaryConfig.class}, new HashSet<String>());
117
118        // if annotation is present then initialize test data dictionary (setup once per suite)
119        if (!classes.isEmpty()) {
120            ConfigurableApplicationContext context  = new ClassPathXmlApplicationContext("TestDataDictionary.xml");
121            dd = (DataDictionary) context.getBean("testDataDictionary");
122
123            // add any additional dictionary files required by the test
124            for (Class c : classes) {
125                if (c.isAnnotationPresent(TestDictionaryConfig.class)) {
126                    TestDictionaryConfig testDictionaryConfig = (TestDictionaryConfig) c.getAnnotation(
127                            TestDictionaryConfig.class);
128
129                    String namespaceCode = testDictionaryConfig.namespaceCode();
130                    String dictionaryFileString = testDictionaryConfig.dataDictionaryFiles();
131
132                    String[] dictionaryFiles = StringUtils.split(dictionaryFileString, ",");
133                    for (String dictionaryFile : dictionaryFiles) {
134                        LOG.info("Adding test data dictionary file: " + dictionaryFile);
135
136                        dd.addConfigFileLocation(namespaceCode, dictionaryFile);
137                    }
138                }
139            }
140
141            dd.parseDataDictionaryConfigurationFiles(false);
142            dd.validateDD(false); // Validation performs some necessary post-processing of the beans - we need to run this each time we add new files
143            dd.performBeanOverrides();
144        }
145    }
146
147    /**
148     * Returns an instance of the bean with the given id that has been configured in the test dictionary
149     *
150     * @param id - id of the bean definition
151     * @return Object instance of the given bean class, or null if not found or dictionary is not loaded
152     */
153    protected Object getTestDictionaryObject(String id) {
154        if (dd != null) {
155            return dd.getDictionaryBean(id);
156        }
157
158        return null;
159    }
160
161    @Override
162    protected List<Lifecycle> getSuiteLifecycles() {
163        List<Lifecycle> suiteLifecycles = super.getSuiteLifecycles();
164        suiteLifecycles.add(new KEWXmlDataLoaderLifecycle(XML_FILE));
165
166        return suiteLifecycles;
167    }
168
169    @Override
170    protected void loadSuiteTestData() throws Exception {
171        super.loadSuiteTestData();
172        new SQLDataLoader(SQL_FILE, ";").runSql();
173    }
174
175    @Override
176    protected Lifecycle getLoadApplicationLifecycle() {
177        // cache the KRAD test harness spring resource loader
178        // this is not great because it doesn't conform to the lifecycle
179        // ...but why are we creating sub-resourceloaders instead of just adding locations to the test harness context?
180        if (kradTestHarnessSpringResourceLoader == null) {
181            kradTestHarnessSpringResourceLoader = new SpringResourceLoader(new QName("KRADTestResourceLoader"),
182                    "classpath:KRADTestHarnessSpringBeans.xml", null);
183            kradTestHarnessSpringResourceLoader.setParentSpringResourceLoader(getTestHarnessSpringResourceLoader());
184        }
185        return kradTestHarnessSpringResourceLoader;
186    }
187
188    /**
189     * Annotation which indicates that a Legacy Context should be used for this individual test method or for all tests
190     * in an annotated class.
191     *
192     * @see org.kuali.rice.krad.util.LegacyUtils#doInLegacyContext(java.util.concurrent.Callable)
193     */
194    @Target({TYPE, METHOD})
195    @Retention(RUNTIME)
196    public @interface Legacy {}
197
198    public static final class BootstrapTest extends KRADTestCase {
199        @Test
200        public void bootstrapTest() {};
201    }
202
203}