//
// Copyright 2010 Cinch Logic Pty Ltd.
//
// http://www.chililog.com
//
// Licensed 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
//
// 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.chililog.server.pubsub;
import static org.junit.Assert.*;
import java.net.HttpURLConnection;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.regex.Pattern;
import org.chililog.server.common.JsonTranslator;
import org.chililog.server.common.Log4JLogger;
import org.chililog.server.data.MongoConnection;
import org.chililog.server.data.RepositoryConfigBO;
import org.chililog.server.data.RepositoryConfigController;
import org.chililog.server.data.RepositoryEntryBO;
import org.chililog.server.data.UserBO;
import org.chililog.server.data.UserController;
import org.chililog.server.engine.MqService;
import org.chililog.server.engine.RepositoryService;
import org.chililog.server.pubsub.jsonhttp.JsonHttpService;
import org.chililog.server.pubsub.jsonhttp.LogEntryAO;
import org.chililog.server.pubsub.jsonhttp.PublicationRequestAO;
import org.chililog.server.pubsub.jsonhttp.PublicationResponseAO;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
/**
* Test JSON HTTP Request publication
*
* @author vibul
*
*/
public class JsonHttpPubishTest {
private static DB _db;
private static RepositoryConfigBO _repoInfo;
private static final String REPOSITORY_NAME = "json_http_publish_test";
private static final String MONGODB_COLLECTION_NAME = "repo_json_http_publish_test";
@BeforeClass
public static void classSetup() throws Exception {
// Create repo
_repoInfo = new RepositoryConfigBO();
_repoInfo.setName(REPOSITORY_NAME);
_repoInfo.setDisplayName("Json Http Pubish Test");
_repoInfo.setStoreEntriesIndicator(true);
_repoInfo.setStorageQueueDurableIndicator(false);
_repoInfo.setStorageQueueWorkerCount(2);
// Database
_db = MongoConnection.getInstance().getConnection();
assertNotNull(_db);
// Clean up old users
DBCollection coll = _db.getCollection(UserController.MONGODB_COLLECTION_NAME);
Pattern pattern = Pattern.compile("^JsonHttpPublishTestUser[\\w]*$");
DBObject query = new BasicDBObject();
query.put("username", pattern);
coll.remove(query);
// Clean old repository info
coll = _db.getCollection(RepositoryConfigController.MONGODB_COLLECTION_NAME);
pattern = Pattern.compile("^" + REPOSITORY_NAME + "$");
query = new BasicDBObject();
query.put("name", pattern);
coll.remove(query);
// Clean up old test data if any exists
coll = _db.getCollection(MONGODB_COLLECTION_NAME);
if (coll != null) {
coll.drop();
}
// Create repository record
RepositoryConfigController.getInstance().save(_db, _repoInfo);
// Create user that cannot access this repository
UserBO user = new UserBO();
user.setUsername("JsonHttpPublishTestUser_NoAccess");
user.setPassword("111", true);
UserController.getInstance().save(_db, user);
// Create publisher user
user = new UserBO();
user.setUsername("JsonHttpPublishTestUser_Publisher");
user.setPassword("222", true);
user.addRole(_repoInfo.getPublisherRoleName());
UserController.getInstance().save(_db, user);
// Create subscriber user
user = new UserBO();
user.setUsername("JsonHttpPublishTestUser_Subscriber");
user.setPassword("333", true);
user.addRole(_repoInfo.getSubscriberRoleName());
UserController.getInstance().save(_db, user);
// Start it up
MqService.getInstance().start();
RepositoryService.getInstance().start();
JsonHttpService.getInstance().start();
}
@Before
public void testSetup() throws Exception {
// Drop collection for each test
DBCollection coll = _db.getCollection(MONGODB_COLLECTION_NAME);
if (coll != null) {
coll.drop();
}
}
@AfterClass
public static void classTeardown() throws Exception {
// Stop it all
JsonHttpService.getInstance().stop();
RepositoryService.getInstance().stop();
MqService.getInstance().stop();
// Drop collection
DBCollection coll = _db.getCollection(MONGODB_COLLECTION_NAME);
if (coll != null) {
coll.drop();
}
// Drop users
coll = _db.getCollection(UserController.MONGODB_COLLECTION_NAME);
Pattern pattern = Pattern.compile("^JsonHttpPublishTestUser[\\w]*$");
DBObject query = new BasicDBObject();
query.put("username", pattern);
coll.remove(query);
// Clean old repository info
coll = _db.getCollection(RepositoryConfigController.MONGODB_COLLECTION_NAME);
pattern = Pattern.compile("^" + REPOSITORY_NAME + "$");
query = new BasicDBObject();
query.put("name", pattern);
coll.remove(query);
}
/**
* Send valid log entry request to the server for processing
*
* @param msgID
* message ID
* @param entryCount
* Number of log entries to send
* @param includePreparsedFields
* If true, fields will be sent
* @throws Exception
* if error
*/
public static void sendPublishRequest(String msgID, int entryCount, boolean includePreparsedFields)
throws Exception {
HttpURLConnection httpConn;
StringBuilder responseContent = new StringBuilder();
StringBuilder responseCode = new StringBuilder();
HashMap<String, String> headers = new HashMap<String, String>();
// Create
httpConn = TestUtils.getHttpURLConnection("http://localhost:61615/publish", HttpMethod.POST);
PublicationRequestAO request = new PublicationRequestAO();
request.setMessageID(msgID);
request.setUsername("JsonHttpPublishTestUser_Publisher");
request.setPassword("222");
request.setRepositoryName(REPOSITORY_NAME);
LogEntryAO[] logEntries = new LogEntryAO[entryCount];
StringBuilder preparsedFields = new StringBuilder();
preparsedFields.append("{");
preparsedFields.append("\"fld_field1\": 1,"); // Integer
preparsedFields.append("\"fld_field2\": \"abc\","); // String
preparsedFields.append("\"fld_field3\": true,"); // Boolean
preparsedFields.append("\"fld_field4\": 8888888888,"); // Long. 10 - digit numbers converts to long
preparsedFields.append("\"fld_field5\": \"NumberLong(888)\",");
preparsedFields.append("\"fld_field6\": 5.5,"); // Double
preparsedFields.append("\"fld_field7\": \"2010-11-29T19:41:46.000Z\",");
preparsedFields.append("}");
for (int i = 0; i < entryCount; i++) {
LogEntryAO logEntry = new LogEntryAO();
logEntry.setTimestamp("2011-01-01T00:00:00.000Z");
logEntry.setSource("junit");
logEntry.setHost("localhost");
logEntry.setSeverity("4");
if (includePreparsedFields) {
logEntry.setFields(preparsedFields.toString());
}
logEntry.setMessage("test message " + i);
logEntries[i] = logEntry;
}
request.setLogEntries(logEntries);
TestUtils.postJSON(httpConn, request);
TestUtils.getResponse(httpConn, responseContent, responseCode, headers);
TestUtils.check200OKResponse(responseCode.toString(), headers);
PublicationResponseAO response = JsonTranslator.getInstance().fromJson(responseContent.toString(),
PublicationResponseAO.class);
assertEquals(msgID, response.getMessageID());
assertTrue(response.isSuccess());
assertNull(response.getErrorMessage());
assertNull(response.getErrorStackTrace());
}
@Test
public void testOneLogEntry() throws Exception {
sendPublishRequest("testOneLogEntry", 1, true);
// Wait a moment for log entry to be processed
Thread.sleep(1000);
// Check that the entry is written to the log
DBCollection coll = _db.getCollection(MONGODB_COLLECTION_NAME);
assertEquals(1, coll.find().count());
DBObject dbObject = coll.findOne();
assertTrue(dbObject.containsField(RepositoryEntryBO.TIMESTAMP_FIELD_NAME));
assertTrue(dbObject.containsField(RepositoryEntryBO.SAVED_TIMESTAMP_FIELD_NAME));
assertEquals("junit", dbObject.get(RepositoryEntryBO.SOURCE_FIELD_NAME));
assertEquals("localhost", dbObject.get(RepositoryEntryBO.HOST_FIELD_NAME));
assertEquals(4L, dbObject.get(RepositoryEntryBO.SEVERITY_FIELD_NAME));
assertTrue(dbObject.containsField(RepositoryEntryBO.MESSAGE_FIELD_NAME));
assertEquals(1, dbObject.get("fld_field1"));
assertEquals("abc", dbObject.get("fld_field2"));
assertEquals(true, dbObject.get("fld_field3"));
assertEquals(8888888888L, dbObject.get("fld_field4"));
assertEquals(888L, dbObject.get("fld_field5"));
assertEquals(5.5d, dbObject.get("fld_field6"));
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
assertEquals(sf.parse("2010-11-29T19:41:46GMT"), dbObject.get("fld_field7"));
}
/**
* Test 2 requests on same Keep Alive connection
*
* @throws Exception
*/
@Test
public void testSubsequentRequests() throws Exception {
sendPublishRequest("testSubsequentRequests", 1, false);
sendPublishRequest("testSubsequentRequests", 2, false);
sendPublishRequest("testSubsequentRequests", 3, false);
// Wait a moment for log entry to be processed
Thread.sleep(1000);
// Check that the entry is written to the log
DBCollection coll = _db.getCollection(MONGODB_COLLECTION_NAME);
assertEquals(6, coll.find().count());
}
@Test
public void testManyLogEntries() throws Exception {
sendPublishRequest("testManyLogEntries", 100, false);
// Wait a moment for log entry to be processed
Thread.sleep(2000);
// Check that the entry is written to the log
DBCollection coll = _db.getCollection(MONGODB_COLLECTION_NAME);
assertEquals(100, coll.find().count());
}
@Test
public void testMultipleConnections() throws Exception {
// 20 threads each adding 2 log entries = 40 log entries in total
for (int i = 0; i < 20; i++) {
PublishThread runnable = new PublishThread();
Thread thread = new Thread(runnable);
thread.start();
}
// Wait a moment for log entry to be processed
Thread.sleep(5000);
// Check that the entry is written to the log
DBCollection coll = _db.getCollection(MONGODB_COLLECTION_NAME);
assertEquals(40, coll.find().count());
}
@Test
public void testBadUsername() throws Exception {
HttpURLConnection httpConn;
StringBuilder responseContent = new StringBuilder();
StringBuilder responseCode = new StringBuilder();
HashMap<String, String> headers = new HashMap<String, String>();
// Create
httpConn = TestUtils.getHttpURLConnection("http://localhost:61615/publish", HttpMethod.POST);
PublicationRequestAO request = new PublicationRequestAO();
request.setMessageID("testBadUsername");
request.setUsername("XXX");
request.setPassword("222");
request.setRepositoryName(REPOSITORY_NAME);
LogEntryAO[] logEntries = new LogEntryAO[1];
LogEntryAO logEntry = new LogEntryAO();
logEntry.setTimestamp("2011-01-01T00:00:00.000Z");
logEntry.setSource("junit");
logEntry.setHost("localhost");
logEntry.setSeverity("4");
logEntry.setMessage("test message 1");
logEntries[0] = logEntry;
request.setLogEntries(logEntries);
TestUtils.postJSON(httpConn, request);
TestUtils.getResponse(httpConn, responseContent, responseCode, headers);
TestUtils.check400BadRequestResponse(responseCode.toString(), headers);
PublicationResponseAO response = JsonTranslator.getInstance().fromJson(responseContent.toString(),
PublicationResponseAO.class);
assertEquals("testBadUsername", response.getMessageID());
assertFalse(response.isSuccess());
assertEquals("Cannot find user 'XXX'.", response.getErrorMessage());
}
@Test
public void testBadPassword() throws Exception {
HttpURLConnection httpConn;
StringBuilder responseContent = new StringBuilder();
StringBuilder responseCode = new StringBuilder();
HashMap<String, String> headers = new HashMap<String, String>();
// Create
httpConn = TestUtils.getHttpURLConnection("http://localhost:61615/publish", HttpMethod.POST);
PublicationRequestAO request = new PublicationRequestAO();
request.setMessageID("testBadPassword");
request.setUsername("JsonHttpPublishTestUser_Publisher");
request.setPassword("xxx");
request.setRepositoryName(REPOSITORY_NAME);
LogEntryAO[] logEntries = new LogEntryAO[1];
LogEntryAO logEntry = new LogEntryAO();
logEntry.setTimestamp("2011-01-01T00:00:00.000Z");
logEntry.setSource("junit");
logEntry.setHost("localhost");
logEntry.setSeverity("4");
logEntry.setMessage("test message 1");
logEntries[0] = logEntry;
request.setLogEntries(logEntries);
TestUtils.postJSON(httpConn, request);
TestUtils.getResponse(httpConn, responseContent, responseCode, headers);
TestUtils.check400BadRequestResponse(responseCode.toString(), headers);
PublicationResponseAO response = JsonTranslator.getInstance().fromJson(responseContent.toString(),
PublicationResponseAO.class);
assertEquals("testBadPassword", response.getMessageID());
assertFalse(response.isSuccess());
assertEquals("Access denied.", response.getErrorMessage());
}
@Test
public void testBadRole() throws Exception {
HttpURLConnection httpConn;
StringBuilder responseContent = new StringBuilder();
StringBuilder responseCode = new StringBuilder();
HashMap<String, String> headers = new HashMap<String, String>();
// Create
httpConn = TestUtils.getHttpURLConnection("http://localhost:61615/publish", HttpMethod.POST);
PublicationRequestAO request = new PublicationRequestAO();
request.setMessageID("testBadRole");
request.setUsername("JsonHttpPublishTestUser_NoAccess");
request.setPassword("111");
request.setRepositoryName(REPOSITORY_NAME);
LogEntryAO[] logEntries = new LogEntryAO[1];
LogEntryAO logEntry = new LogEntryAO();
logEntry.setTimestamp("2011-01-01T00:00:00.000Z");
logEntry.setSource("junit");
logEntry.setHost("localhost");
logEntry.setSeverity("4");
logEntry.setMessage("test message 1");
logEntries[0] = logEntry;
request.setLogEntries(logEntries);
TestUtils.postJSON(httpConn, request);
TestUtils.getResponse(httpConn, responseContent, responseCode, headers);
TestUtils.check400BadRequestResponse(responseCode.toString(), headers);
PublicationResponseAO response = JsonTranslator.getInstance().fromJson(responseContent.toString(),
PublicationResponseAO.class);
assertEquals("testBadRole", response.getMessageID());
assertFalse(response.isSuccess());
assertEquals("Access denied.", response.getErrorMessage());
}
/**
* Thread for running in testMultipleConnections
*
* @author vibul
*
*/
public static class PublishThread implements Runnable {
private static Log4JLogger _logger = Log4JLogger.getLogger(PublishThread.class);
public void run() {
try {
_logger.debug("HTTP thread " + Thread.currentThread().getName() + " started");
sendPublishRequest("PublishThread " + Thread.currentThread().getName(), 2, false);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}