View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.chukwa.database;
19  
20  import junit.framework.*;
21  import java.util.*;
22  import java.text.*;
23  import java.io.*;
24  import java.net.URL;
25  import java.sql.*;
26  import org.apache.commons.httpclient.*;
27  import org.apache.commons.httpclient.methods.*;
28  import org.apache.commons.httpclient.params.HttpMethodParams;
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.json.*;
32  import org.json.simple.JSONArray;
33  import org.json.simple.JSONObject;
34  import org.json.simple.JSONValue;
35  import org.mortbay.jetty.Server;
36  import org.mortbay.xml.XmlConfiguration;
37  import org.apache.hadoop.chukwa.util.*;
38  
39  /*
40   * Testing the JSON output from the website with the database result.
41   *
42   */
43  public class TestDatabaseWebJson extends TestCase {
44      protected HashMap testTables;
45      protected String data_url="http://localhost:8080/hicc/jsp/get_db_data.jsp";
46      private Server server = null;
47      private Log log = LogFactory.getLog(TestDatabaseWebJson.class);
48  
49      /* 
50       * setup list of tables to do testing. 
51       * Add the table name and the table's primary keys.
52       */
53      protected void setUp() {
54        testTables = new HashMap();
55  
56        ArrayList<String> keys = new ArrayList<String>();
57        keys.add("timestamp");
58        keys.add("mount");
59        testTables.put("cluster_disk", keys);
60  
61        keys = new ArrayList<String>();
62        keys.add("timestamp");
63        testTables.put("cluster_system_metrics", keys);
64  
65        keys = new ArrayList<String>();
66        keys.add("timestamp");
67        keys.add("host");
68        keys.add("mount");
69        testTables.put("disk", keys);
70  
71        keys = new ArrayList<String>();
72        keys.add("job_id");
73        testTables.put("mr_job", keys);
74  
75        keys = new ArrayList<String>();
76        keys.add("task_id");
77        testTables.put("mr_task", keys);
78  
79        keys = new ArrayList<String>();
80        keys.add("timestamp");
81        testTables.put("system_metrics", keys);
82        URL serverConf = TestDatabaseWebJson.class
83          .getResource("/WEB-INF/jetty.xml");
84        server = new Server();
85        XmlConfiguration configuration;
86        try {
87          configuration = new XmlConfiguration(serverConf);
88          configuration.configure(server);
89          server.start();
90          server.setStopAtShutdown(true);
91        } catch (Exception e) {
92          log.error(ExceptionUtil.getStackTrace(e));
93        }
94      }
95  
96      protected void tearDown() {
97        try {
98          server.stop();
99          Thread.sleep(2000);
100       } catch (Exception e) {
101         log.error(ExceptionUtil.getStackTrace(e));
102       }
103     }
104 
105     /*
106      * similar to PHP join function to join a string array to one single string.
107      * for example, if the token is "," and the strings array is ('a','b','c')
108      * the final result will be "a,b,c"
109      *
110      * @param token The separator which join the strings together
111      * @param strings list of strings which we want to merge together
112      * @return final string which merge together.
113      */
114     protected static String join( String token, ArrayList<String> strings )
115     {
116         StringBuffer sb = new StringBuffer();
117 	
118         for( int x = 0; x < ( strings.size() - 1 ); x++ )  {
119 	    sb.append( strings.get(x) );
120 	    sb.append( token );
121 	}
122         sb.append( strings.get( strings.size() - 1 ) );
123 	
124         return( sb.toString() );
125     }
126 
127     /*
128      * format the query string for the database testing. Select the
129      * primary key value from the json object.
130      *
131      * @param tableName The name of the database table to build the query on.
132      * @param jo JSON object which contain the primary key of the row which we 
133      *           want to test.
134      * @return the actual database query string for the row selection.
135      */
136     protected String getDatabaseQuery(String tableName, JSONObject jo) {
137 	ArrayList<String> keys = (ArrayList<String>)testTables.get(tableName);
138 	ArrayList<String> criterias = new ArrayList<String>();
139 	Iterator i = keys.iterator();
140 	while (i.hasNext()) {
141 	    String key=(String)i.next();
142 	    try {
143 		String value=(String)jo.get(key);
144 		if (key.compareToIgnoreCase("timestamp")==0) {
145 		    value=DatabaseWriter.formatTimeStamp(Long.parseLong(value));
146 		}
147 		String c=key+"=\""+value+"\"";
148 		criterias.add(c);
149 	    } catch (Exception e) {
150 		System.out.println("Cannot get value for key: "+key);
151 	    }
152 	}
153 	String criteria=join(" and ", criterias);
154 
155 	String query="select * from ["+tableName+"] where "+criteria;
156 	return query;
157     }
158 
159     /*
160      * the function will do the actual table verification. If will first
161      * get the result from the website JSON object. Then it will compare the
162      * JSON object with the values in the database.
163      *
164      * @param table name of the table to be verified.
165      */
166     protected void verifyTableData(String table) {
167 	Calendar startCalendar = new GregorianCalendar();
168 	// startCalendar.add(Calendar.HOUR_OF_DAY,-1);
169 	startCalendar.add(Calendar.MINUTE, -30);
170 	long startTime=startCalendar.getTime().getTime();
171 
172 	Calendar endCalendar = new GregorianCalendar();
173 	// endCalendar.add(Calendar.HOUR_OF_DAY,1);
174 	long endTime=endCalendar.getTime().getTime();
175 
176 	String url=data_url+"?table="+table+"&start="+startTime+"&end="+endTime;
177 	System.out.println(url);
178 
179 	HttpClient client = new HttpClient();       
180 	GetMethod method = new GetMethod(url);
181 
182 
183 	try {
184 
185 	    /*
186 	     * 1. get the json result for the specified table
187 	     */
188 	    int statusCode = client.executeMethod(method);
189 	    if (statusCode != HttpStatus.SC_OK) {
190 		System.out.println("Http Error: "+method.getStatusLine());
191 	    }
192 	    BufferedReader reader = new BufferedReader(new InputStreamReader( method.getResponseBodyAsStream(),
193 									      method.getResponseCharSet()));
194 	    String json_str="";
195 	    String str;
196 	    while ((str = reader.readLine()) != null) {
197 		json_str+=str;
198 	    }
199 	    
200 	    /*
201 	     * 2. convert the json string to individual field and compare it 
202 	     * with the database
203 	     */
204 
205 	    String cluster = "demo";
206 	    DatabaseWriter db = new DatabaseWriter(cluster);
207 
208 	    JSONArray json_array=(JSONArray)JSONValue.parse(json_str);
209 	    for (int i=0; i < json_array.size(); i++) {
210 		JSONObject row_obj=(JSONObject) json_array.get(i);
211 
212 		// get the database row
213 
214 		String queryString=getDatabaseQuery(table, row_obj);
215 		Macro m=new Macro(startTime, endTime, queryString);
216 		ResultSet rs = db.query(m.toString());
217 		// move to the first record
218 		rs.next();
219 		ResultSetMetaData md=rs.getMetaData();
220 		Iterator names=row_obj.keySet().iterator();
221 		while (names.hasNext()) {
222 		    String name=(String)names.next();
223 		    String jsonValue=(String)row_obj.get(name);
224 		    String dbValue=rs.getString(name);
225 		    int dbCol=rs.findColumn(name);
226 		    int dbType=md.getColumnType(dbCol);
227 		    if (dbType==93) {
228 			// timestamp
229 			dbValue=Long.toString(rs.getTimestamp(name).getTime());
230 		    }
231 		    // System.out.println("compare "+name+":"+dbType+":"+dbValue+":"+jsonValue);
232 		    assertEquals(dbValue, jsonValue);
233 		}
234 	    }
235 
236 	    db.close();
237 	} catch (SQLException e) {
238 	    System.out.println("Exception: "+e.toString()+":"+e.getMessage());
239 	    System.out.println("Exception: "+e.toString()+":"+e.getSQLState());
240 	    System.out.println("Exception: "+e.toString()+":"+e.getErrorCode());
241             fail("SQL Error:"+ExceptionUtil.getStackTrace(e));
242 	} catch (Exception eOther) {
243 	    System.out.println("Other Exception: "+eOther.toString());
244 	    eOther.printStackTrace();
245             fail("Error:"+ExceptionUtil.getStackTrace(eOther));
246 	} finally {
247 	}
248     }
249 
250     /*
251      * Perform the actual testing. It will get the result from the web URL first.
252      * Then it will get the result from the database and compare it.
253      */
254     public void testJsonResult() {
255 	Iterator i=testTables.keySet().iterator();
256 	while (i.hasNext()) {
257 	    String tableName=(String)i.next();
258 	    verifyTableData(tableName);
259 
260 	}
261     }
262 }