1   package org.apache.velocity.test.sql;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.    
20   */
21  
22  import java.io.BufferedWriter;
23  import java.io.FileOutputStream;
24  import java.io.OutputStreamWriter;
25  import java.io.StringWriter;
26  import java.io.Writer;
27  
28  import javax.sql.DataSource;
29  
30  import junit.framework.Test;
31  import junit.framework.TestSuite;
32  
33  import org.apache.velocity.Template;
34  import org.apache.velocity.VelocityContext;
35  import org.apache.velocity.app.Velocity;
36  import org.apache.velocity.app.VelocityEngine;
37  import org.apache.velocity.runtime.RuntimeConstants;
38  import org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader;
39  import org.apache.velocity.test.misc.TestLogChute;
40  
41  
42  public class DataSourceResourceLoaderTestCase
43          extends BaseSQLTest
44  {
45      /**
46       * Comparison file extension.
47       */
48      private static final String CMP_FILE_EXT = "cmp";
49  
50      /**
51       * Comparison file extension.
52       */
53      private static final String RESULT_FILE_EXT = "res";
54  
55      /**
56       * Path to template file.  This will get combined with the
57       * application directory to form an absolute path
58       */
59      private final static String DATA_PATH = TEST_COMPARE_DIR + "/ds";
60  
61      /**
62       * Results relative to the build directory.
63       */
64      private static final String RESULTS_DIR = TEST_RESULT_DIR + "/ds";
65  
66      /**
67       * Results relative to the build directory.
68       */
69      private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/ds/templates";
70  
71      /**
72       * String (not containing any VTL) used to test unicode
73       */
74      private String UNICODE_TEMPLATE = "\\u00a9 test \\u0410 \\u0411";
75      
76      /**
77       * Name of template for testing unicode.
78       */
79      private String UNICODE_TEMPLATE_NAME = "testUnicode";
80  
81      VelocityEngine engine;
82      
83      public DataSourceResourceLoaderTestCase(final String name)
84      	throws Exception
85      {
86          super(name, DATA_PATH);
87          setUpUnicode();
88      }
89  
90      public static Test suite()
91      {
92          return new TestSuite(DataSourceResourceLoaderTestCase.class);
93      }
94  
95      public void setUp()
96              throws Exception
97      {
98  
99          assureResultsDirectoryExists(RESULTS_DIR);
100 
101 	    DataSource ds = new HsqlDataSource("jdbc:hsqldb:.");
102 
103         DataSourceResourceLoader rl = new DataSourceResourceLoader();
104         rl.setDataSource(ds);
105 
106         engine = new VelocityEngine();
107         
108         // pass in an instance to Velocity
109         engine.addProperty( "resource.loader", "ds" );
110         engine.setProperty( "ds.resource.loader.instance", rl );
111 
112         engine.setProperty( "ds.resource.loader.resource.table",           "velocity_template");
113         engine.setProperty( "ds.resource.loader.resource.keycolumn",       "id");
114         engine.setProperty( "ds.resource.loader.resource.templatecolumn",  "def");
115         engine.setProperty( "ds.resource.loader.resource.timestampcolumn", "timestamp");
116 
117         Velocity.setProperty(
118                 RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, TestLogChute.class.getName());
119 
120         engine.init();
121     }
122     
123     public void setUpUnicode()
124     throws Exception
125     {
126         String insertString = "insert into velocity_template  (id, timestamp, def) VALUES " +
127         		"( '" + UNICODE_TEMPLATE_NAME + "', NOW(), '" + UNICODE_TEMPLATE + "');";
128         executeSQL(insertString);
129     }
130 
131     /**
132      * Tests loading and rendering of a simple template. If that works, we are able to get data
133      * from the database.
134      */
135     public void testSimpleTemplate()
136             throws Exception
137     {
138         Template t = executeTest("testTemplate1");
139         assertFalse("Timestamp is 0", 0 == t.getLastModified());
140     }
141 
142     public void testUnicode()
143     throws Exception
144     {
145         Template template = engine.getTemplate(UNICODE_TEMPLATE_NAME);
146 
147         Writer writer = new StringWriter();
148         VelocityContext context = new VelocityContext();
149         template.merge(context, writer);
150         writer.flush();
151         writer.close();
152 
153         String outputText = writer.toString();
154         
155         if (!normalizeNewlines(UNICODE_TEMPLATE).equals(
156                 normalizeNewlines( outputText ) ))
157         {
158             fail("Output incorrect for Template: " + UNICODE_TEMPLATE_NAME);
159         }
160     }
161 
162     /**
163      * Now we have a more complex example. Run a very simple tool.
164      * from the database.
165      */
166     public void testRenderTool()
167             throws Exception
168     {
169 	Template t = executeTest("testTemplate2");
170         assertFalse("Timestamp is 0", 0 == t.getLastModified());
171     }
172 
173     /**
174      * Will a NULL timestamp choke the loader?
175      */
176     public void testNullTimestamp()
177             throws Exception
178     {
179         Template t = executeTest("testTemplate3");
180         assertEquals("Timestamp is not 0", 0, t.getLastModified());
181     }
182 
183     /**
184      * Does it load the global Macros from the DB?
185      */
186     public void testMacroInvocation()
187             throws Exception
188     {
189         Template t = executeTest("testTemplate4");
190         assertFalse("Timestamp is 0", 0 == t.getLastModified());
191     }
192 
193     protected Template executeTest(final String templateName)
194     	throws Exception
195     {
196         Template template = engine.getTemplate(templateName);
197 
198         FileOutputStream fos =
199                 new FileOutputStream (
200                         getFileName(RESULTS_DIR, templateName, RESULT_FILE_EXT));
201 
202         Writer writer = new BufferedWriter(new OutputStreamWriter(fos));
203 
204         VelocityContext context = new VelocityContext();
205         context.put("tool", new DSRLTCTool());
206 
207         template.merge(context, writer);
208         writer.flush();
209         writer.close();
210 
211         if (!isMatch(RESULTS_DIR, COMPARE_DIR, templateName,
212                         RESULT_FILE_EXT, CMP_FILE_EXT))
213         {
214             fail("Output incorrect for Template: " + templateName);
215         }
216 
217         return template;
218     }
219 
220     public static final class DSRLTCTool
221     {
222 	public int add(final int a, final int b)
223 	{
224 	    return a + b;
225 	}
226 
227 	public String getMessage()
228 	{
229 	    return "And the result is:";
230 	}
231     }
232 }