/** * Copyright (C) 2014 Stratio (http://stratio.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 com.stratio.ingestion.sink.mongodb; import static org.fest.assertions.Assertions.assertThat; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import org.apache.flume.event.EventBuilder; import org.bson.types.ObjectId; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.format.ISODateTimeFormat; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import com.google.common.base.Charsets; import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; import com.mongodb.util.JSONParseException; @RunWith(JUnit4.class) public class EventParserTest { private FieldDefinition definition(MongoDataType type) { FieldDefinition def; switch (type) { case DATE: def = new DateFieldDefinition(); break; case DOCUMENT: def = new DocumentFieldDefinition(); break; default: def = new SimpleFieldDefinition(type); } return def; } @Test public void parseDocumentTypeWithValidRegularExpressionSeparator() { EventParser eventParser = new EventParser(); DBObject dbObject = buildExpectedObject(); DocumentFieldDefinition fieldDefinition = (DocumentFieldDefinition) definition(MongoDataType.DOCUMENT); fieldDefinition.setDelimiter("(#¬**#)"); Map<String, FieldDefinition> documentMapping = new LinkedHashMap<String, FieldDefinition>(); documentMapping.put("field1", new SimpleFieldDefinition(MongoDataType.STRING)); documentMapping.put("field2", new SimpleFieldDefinition(MongoDataType.ARRAY)); DocumentFieldDefinition fieldDefinition2 = (DocumentFieldDefinition) definition(MongoDataType.DOCUMENT); fieldDefinition2.setDelimiter("(#¬**#)"); documentMapping.put("field3", fieldDefinition2); documentMapping.put("field6", new SimpleFieldDefinition(MongoDataType.STRING)); Map<String, FieldDefinition> documentMapping2 = new LinkedHashMap<String, FieldDefinition>(); documentMapping2.put("field4", new SimpleFieldDefinition(MongoDataType.STRING)); documentMapping2.put("field5", new SimpleFieldDefinition(MongoDataType.ARRAY)); fieldDefinition.setDocumentMapping(documentMapping); fieldDefinition2.setDocumentMapping(documentMapping2); assertThat( eventParser.parseValue(fieldDefinition, "Point1(#¬**#)[111.11,222.22](#¬**#)Point2(#¬**#)[111.11,222.22](#¬**#)Point3")) .isEqualTo(dbObject); } @Test public void parseValue() { final EventParser eventParser = new EventParser(); assertThat(eventParser.parseValue(definition(MongoDataType.STRING), "foo")).isEqualTo("foo"); assertThat(eventParser.parseValue(definition(MongoDataType.INT32), "32")).isEqualTo(32); assertThat(eventParser.parseValue(definition(MongoDataType.INT64), "64")).isEqualTo(64L); assertThat(eventParser.parseValue(definition(MongoDataType.DOUBLE), "1.0")).isEqualTo(1.0); assertThat(eventParser.parseValue(definition(MongoDataType.BOOLEAN), "true")).isEqualTo(true); final DateTime now = DateTime.now().toDateTime(DateTimeZone.UTC); assertThat(eventParser.parseValue(definition(MongoDataType.DATE), Long.toString(now.getMillis()))).isEqualTo( now.toDate()); assertThat((eventParser.parseValue(definition(MongoDataType.DATE), ISODateTimeFormat.dateTime().print(now)))) .isEqualTo( now.toDate()); assertThat(eventParser.parseValue(definition(MongoDataType.NULL), "full")).isNull(); assertThat(eventParser.parseValue(definition(MongoDataType.OBJECTID), "507c7f79bcf86cd7994f6c0e")).isEqualTo( new ObjectId("507c7f79bcf86cd7994f6c0e")); BasicDBList dbList = new BasicDBList(); dbList.add(1); dbList.add(2); dbList.add(3); DBObject dbObject = new BasicDBObject(); dbObject.put("abc", 123); dbObject.put("myArray", dbList); assertThat(eventParser.parseValue(definition(MongoDataType.OBJECT), "{ \"abc\": 123, \"myArray\": [1, 2, 3] }")) .isEqualTo( dbObject); assertThat(eventParser.parseValue(definition(MongoDataType.BINARY), "U3RyYXRpbw==")).isEqualTo( "Stratio".getBytes(Charsets.UTF_8)); } @Test public void parseValueForDate() { final EventParser eventParser = new EventParser(); DateFieldDefinition fd = (DateFieldDefinition) definition(MongoDataType.DATE); fd.setDateFormat("yyyy/MM/dd"); assertThat(eventParser.parseValue(fd, "2004/03/13")).isEqualTo(new Date(104, 2, 13)); } @Test public void parseNegativeValueForDate() { final EventParser eventParser = new EventParser(); long before1970Millis = -100; final DateTime pastDate = new DateTime(before1970Millis); assertThat(eventParser.parseValue(definition(MongoDataType.DATE), Long.toString(before1970Millis))).isEqualTo(pastDate.toDate()); } @Test(expected = MongoSinkException.class) public void eventParserWithBadType() { new EventParser(MappingDefinition.load("/mapping_definition_bad_type.json")); } @Test public void parseRawBodyToRow() { final EventParser eventParser = new EventParser(MappingDefinition.load("/simple_body_row_raw.json")); assertThat(eventParser.parse(EventBuilder.withBody("TEST".getBytes(Charsets.UTF_8))).get("data")).isEqualTo( "TEST".getBytes(Charsets.UTF_8)); } @Test public void parseJsonBodyToRow() { final EventParser eventParser = new EventParser(MappingDefinition.load("/simple_body_row_json.json")); assertThat( eventParser.parse(EventBuilder.withBody("{ \"foo\": \"bar\" }".getBytes(Charsets.UTF_8))).get("data")) .isEqualTo( new BasicDBObject("foo", "bar")); } @Test(expected = JSONParseException.class) public void parseBadJsonBodyToRow() { final EventParser eventParser = new EventParser(MappingDefinition.load("/simple_body_row_json.json")); eventParser.parse(EventBuilder.withBody("{???? \"foo\": \"bar\" }".getBytes(Charsets.UTF_8))); } @Test public void parseWithoutMapping() { final EventParser eventParser = new EventParser(MappingDefinition.load("/full_map.json")); Map<String, String> headers = new HashMap<String, String>(); headers.put("myString", "\"bar\""); // Overwrites the value defined in JSON body headers.put("myInt64", "64"); headers.put("myBoolean", "true"); headers.put("myDouble", "1.0"); headers.put("myNull", "\"foobar\""); headers.put("myObj", "{ \"foo\": \"bar\" }"); headers.put("myArr", "[1,1.0,\"str\"]"); DBObject dbObject = eventParser.parse(EventBuilder.withBody(new byte[0], headers)); assertThat(dbObject.get("myString")).isEqualTo("bar"); assertThat(dbObject.get("myInt64")) .isEqualTo(64); // XXX: If auto-mapped, 64 will be recognized as int32, not int64 assertThat(dbObject.get("myBoolean")).isEqualTo(true); assertThat(dbObject.get("myDouble")).isEqualTo(1.0); assertThat(dbObject.get("myNull")).isEqualTo("foobar"); assertThat(dbObject.get("myObj")).isEqualTo(new BasicDBObject("foo", "bar")); BasicDBList dbList = new BasicDBList(); dbList.add(1); dbList.add(1.0); dbList.add("str"); assertThat(dbObject.get("myArr")).isEqualTo(dbList); } @Test(expected = MongoSinkException.class) public void parseDocumentTypeWithNoValidSeparator() { EventParser eventParser = new EventParser(); DBObject dbObject = buildExpectedObject(); DocumentFieldDefinition fieldDefinition = (DocumentFieldDefinition) definition(MongoDataType.DOCUMENT); Map<String, FieldDefinition> documentMapping = new LinkedHashMap<String, FieldDefinition>(); documentMapping.put("field1", new SimpleFieldDefinition(MongoDataType.STRING)); documentMapping.put("field2", new SimpleFieldDefinition(MongoDataType.ARRAY)); DocumentFieldDefinition fieldDefinition2 = (DocumentFieldDefinition) definition(MongoDataType.DOCUMENT); documentMapping.put("field3", fieldDefinition2); documentMapping.put("field6", new SimpleFieldDefinition(MongoDataType.STRING)); Map<String, FieldDefinition> documentMapping2 = new LinkedHashMap<String, FieldDefinition>(); documentMapping2.put("field4", new SimpleFieldDefinition(MongoDataType.STRING)); documentMapping2.put("field5", new SimpleFieldDefinition(MongoDataType.ARRAY)); fieldDefinition.setDocumentMapping(documentMapping); fieldDefinition2.setDocumentMapping(documentMapping2); assertThat(eventParser.parseValue(fieldDefinition, "Point1#[111.11,222.22]#Point2#[111.11,222.22]#Point3")) .isEqualTo( dbObject); } @Test public void parseDocumentTypeWithValidSeparator() { EventParser eventParser = new EventParser(); DBObject dbObject = buildExpectedObject(); DocumentFieldDefinition fieldDefinition = (DocumentFieldDefinition) definition(MongoDataType.DOCUMENT); fieldDefinition.setDelimiter("#"); Map<String, FieldDefinition> documentMapping = new LinkedHashMap<String, FieldDefinition>(); documentMapping.put("field1", new SimpleFieldDefinition(MongoDataType.STRING)); documentMapping.put("field2", new SimpleFieldDefinition(MongoDataType.ARRAY)); DocumentFieldDefinition fieldDefinition2 = (DocumentFieldDefinition) definition(MongoDataType.DOCUMENT); fieldDefinition2.setDelimiter("#"); documentMapping.put("field3", fieldDefinition2); documentMapping.put("field6", new SimpleFieldDefinition(MongoDataType.STRING)); Map<String, FieldDefinition> documentMapping2 = new LinkedHashMap<String, FieldDefinition>(); documentMapping2.put("field4", new SimpleFieldDefinition(MongoDataType.STRING)); documentMapping2.put("field5", new SimpleFieldDefinition(MongoDataType.ARRAY)); fieldDefinition.setDocumentMapping(documentMapping); fieldDefinition2.setDocumentMapping(documentMapping2); assertThat(eventParser.parseValue(fieldDefinition, "Point1#[111.11,222.22]#Point2#[111.11,222.22]#Point3")) .isEqualTo( dbObject); } private DBObject buildExpectedObject() { DBObject dbObject = new BasicDBObject(); BasicDBObject object2 = new BasicDBObject(); BasicDBList locList = new BasicDBList(); locList.add(111.11); locList.add(222.22); dbObject.put("field1", "Point1"); dbObject.put("field2", locList); dbObject.put("field3", object2); dbObject.put("field6", "Point3"); object2.put("field4", "Point2"); object2.put("field5", locList); return dbObject; } }