import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import org.apache.avro.generic.GenericArray; import org.rakam.EventBuilder; import org.rakam.TestingConfigManager; import org.rakam.analysis.ApiKeyService; import org.rakam.analysis.InMemoryApiKeyService; import org.rakam.analysis.InMemoryMetastore; import org.rakam.analysis.metadata.SchemaChecker; import org.rakam.collection.Event; import org.rakam.collection.EventList; import org.rakam.collection.EventListDeserializer; import org.rakam.collection.FieldDependencyBuilder; import org.rakam.collection.FieldType; import org.rakam.collection.JsonEventDeserializer; import org.rakam.collection.SchemaField; import org.rakam.config.ProjectConfig; import org.rakam.util.JsonHelper; import org.rakam.util.RakamException; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; import java.time.Instant; import java.time.LocalDate; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; public class TestEventJsonParser { private ObjectMapper mapper; private ApiKeyService.ProjectApiKeys apiKeys; private EventBuilder eventBuilder; private InMemoryMetastore metastore; private JsonEventDeserializer eventDeserializer; private InMemoryApiKeyService apiKeyService; @BeforeSuite public void setUp() throws Exception { FieldDependencyBuilder.FieldDependency fieldDependency = new FieldDependencyBuilder().build(); apiKeyService = new InMemoryApiKeyService(); metastore = new InMemoryMetastore(apiKeyService); SchemaChecker schemaChecker = new SchemaChecker(metastore, fieldDependency); eventDeserializer = new JsonEventDeserializer(metastore, apiKeyService, new TestingConfigManager(), schemaChecker, new ProjectConfig(), fieldDependency); EventListDeserializer eventListDeserializer = new EventListDeserializer(apiKeyService, eventDeserializer); mapper = JsonHelper.getMapper(); mapper.registerModule(new SimpleModule() .addDeserializer(Event.class, eventDeserializer) .addDeserializer(EventList.class, eventListDeserializer)); eventBuilder = new EventBuilder("test", metastore); } @AfterMethod public void tearDownMethod() throws Exception { metastore.deleteProject("test"); eventDeserializer.cleanCache(); eventBuilder.cleanCache(); } @BeforeMethod public void setupMethod() throws Exception { metastore.createProject("test"); apiKeys = apiKeyService.createApiKeys("test"); } @Test public void testSimple() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "collection", "test", "api", api, "properties", ImmutableMap.of())); Event event = mapper.readValue(bytes, Event.class); assertEquals("test", event.project()); assertEquals("test", event.collection()); assertEquals(api, event.api()); assertEquals(eventBuilder .createEvent("test", ImmutableMap.of()).properties(), event.properties()); } @Test public void testSimpleWithoutProject() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "collection", "test", "api", api, "properties", ImmutableMap.of())); Event event = mapper.readValue(bytes, Event.class); assertEquals("test", event.project()); assertEquals("test", event.collection()); assertEquals(api, event.api()); assertEquals(eventBuilder .createEvent("test", ImmutableMap.of()).properties(), event.properties()); } @Test public void testPrimitiveTypes() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); ImmutableMap<String, Object> properties = ImmutableMap.of( "test", 1L, "test1", false, "test2", Instant.now(), "test3", "test", "test4", LocalDate.now()); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "collection", "test", "api", api, "properties", properties)); Event event = mapper.readValue(bytes, Event.class); assertEquals("test", event.project()); assertEquals("test", event.collection()); assertEquals(api, event.api()); assertEquals(eventBuilder .createEvent("test", properties).properties(), event.properties()); assertEquals(ImmutableSet.copyOf(metastore.getCollection("test", "test")), ImmutableSet.of( new SchemaField("test", FieldType.DOUBLE), new SchemaField("_user", FieldType.STRING), new SchemaField("test1", FieldType.BOOLEAN), new SchemaField("test2", FieldType.TIMESTAMP), new SchemaField("test3", FieldType.STRING), new SchemaField("test4", FieldType.DATE))); } @Test public void testMapType() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); ImmutableMap<String, Object> properties = ImmutableMap.of("test0", "test", "test1", ImmutableMap.of("a", 4.0, "b", 5.0, "c", 6.0, "d", 7.0), "test2", false); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "collection", "test", "api", api, "properties", properties)); Event event = mapper.readValue(bytes, Event.class); assertEquals("test", event.project()); assertEquals("test", event.collection()); assertEquals(api, event.api()); assertEquals(eventBuilder .createEvent("test", properties).properties(), event.properties()); } @Test public void testArrayType() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); ImmutableMap<String, Object> properties = ImmutableMap.of("test0", "test", "test1", ImmutableList.of("test", "test"), "test2", false); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "collection", "test", "api", api, "properties", properties)); Event event = mapper.readValue(bytes, Event.class); assertEquals("test", event.project()); assertEquals("test", event.collection()); assertEquals(api, event.api()); assertEquals(eventBuilder .createEvent("test", properties).properties(), event.properties()); } public void testInvalidOrder() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "properties", ImmutableMap.of("test0", "test", "test1", ImmutableList.of("test", "test"), "test2", false), "api", api, "collection", "test")); mapper.readValue(bytes, Event.class); } @Test(expectedExceptions = RakamException.class) public void testInvalidField() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "collection", "test", "api", api, "properties", ImmutableMap.of("test0", "test", "test1", ImmutableList.of("test", "test"), "test2", false), "test", "test" )); Event event = mapper.readValue(bytes, Event.class); ; assertEquals("test", event.project()); assertEquals("test", event.collection()); assertEquals(api, event.api()); assertEquals(eventBuilder .createEvent("test", ImmutableMap.of()).properties(), event.properties()); } @Test() public void testInvalidArrayRecursiveType() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "collection", "test", "api", api, "properties", ImmutableMap.of("test0", "test", "test1", ImmutableList.of("test", ImmutableMap.of("test", 2)), "test2", false))); Event event = mapper.readValue(bytes, Event.class); GenericArray test1 = event.getAttribute("test1"); assertEquals(test1.get(0), "test"); assertEquals(test1.get(1), "{\"test\":2}"); } @Test public void testInvalidMapRecursiveType() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "collection", "test", "api", api, "properties", ImmutableMap.of("test0", "test0", "test1", ImmutableMap.of("test", ImmutableList.of("test4")), "test2", false))); Event event = mapper.readValue(bytes, Event.class); Map test1 = event.getAttribute("test1"); assertEquals(test1.get("test"), "[\"test4\"]"); } @Test public void testInvalidArray() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "collection", "test", "api", api, "properties", ImmutableMap.of("test1", ImmutableList.of(true, 10)))); Event event = mapper.readValue(bytes, Event.class); assertEquals("test", event.project()); assertEquals("test", event.collection()); assertEquals(api, event.api()); assertEquals(eventBuilder.createEvent("test", ImmutableMap.of("test1", ImmutableList.of(true, true))).properties(), event.properties()); } @Test public void testInvalidMap() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "collection", "test", "api", api, "properties", ImmutableMap.of("test1", ImmutableMap.of("test", 1, "test2", "test")))); Event event = mapper.readValue(bytes, Event.class); assertEquals("test", event.project()); assertEquals("test", event.collection()); assertEquals(api, event.api()); assertEquals(eventBuilder .createEvent("test", ImmutableMap.of("test1", ImmutableMap.of("test", 1.0, "test2", 0.0))).properties(), event.properties()); } @Test public void testEmptyArray() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "collection", "test", "api", api, "properties", ImmutableMap.of("test", 1, "test2", Arrays.asList(null, null), "test20", Arrays.asList(), "test3", true))); Event event = mapper.readValue(bytes, Event.class); assertEquals("test", event.project()); assertEquals("test", event.collection()); assertEquals(api, event.api()); assertEquals(eventBuilder .createEvent("test", ImmutableMap.of("test", 1.0, "test3", true)).properties(), event.properties()); } @Test public void testEmptyMap() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "collection", "test", "api", api, "properties", ImmutableMap.of("test", 1, "test2", new HashMap<String, String>() { { put("a", null); } }), "test20", ImmutableMap.of(), "test3", true)); Event event = mapper.readValue(bytes, Event.class); assertEquals("test", event.project()); assertEquals("test", event.collection()); assertEquals(api, event.api()); assertEquals(eventBuilder .createEvent("test", ImmutableMap.of("test", 1.0, "test3", true)).properties(), event.properties()); } @Test public void testBatch() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); ImmutableMap<String, Object> props = ImmutableMap.of( "test0", "test", "test1", ImmutableList.of("test"), "test2", false); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "api", api, "events", ImmutableList.of( ImmutableMap.of("collection", "test", "properties", props), ImmutableMap.of("collection", "test", "properties", props)))); EventList events = mapper.readValue(bytes, EventList.class); assertEquals("test", events.project); assertEquals(api, events.api); for (Event event : events.events) { assertEquals("test", event.collection()); assertEquals(eventBuilder.createEvent("test", props).properties(), event.properties()); } } @Test public void testBatchWithoutProject() throws Exception { Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); ImmutableMap<String, Object> props = ImmutableMap.of( "test0", "test", "test1", ImmutableList.of("test"), "test2", false); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "api", api, "events", ImmutableList.of( ImmutableMap.of("collection", "test", "properties", props), ImmutableMap.of("collection", "test", "properties", props)))); EventList events = mapper.readValue(bytes, EventList.class); assertEquals("test", events.project); assertEquals(api, events.api); for (Event event : events.events) { assertEquals("test", event.collection()); assertEquals(eventBuilder.createEvent("test", props).properties(), event.properties()); } } @Test public void testObjectSentToScalarValue() throws Exception { metastore.getOrCreateCollectionFields("test", "test", ImmutableSet.of(new SchemaField("test", FieldType.STRING))); Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); ImmutableMap<String, Object> props = ImmutableMap.of( "test", ImmutableList.of("test")); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "api", api, "collection", "test", "properties", props)); Event events = mapper.readValue(bytes, Event.class); assertEquals(events.properties().get("test"), "[\"test\"]"); } // @Test(expectedExceptions = JsonMappingException.class, expectedExceptionsMessageRegExp = "Cannot cast object to INTEGER for 'test' field.*") @Test() public void testObjectSentToInvalidScalarValue() throws Exception { metastore.getOrCreateCollectionFields("test", "test", ImmutableSet.of(new SchemaField("test", FieldType.INTEGER))); Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); ImmutableMap<String, Object> props = ImmutableMap.of( "test", ImmutableList.of("test")); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "api", api, "collection", "test", "properties", props)); Event event = mapper.readValue(bytes, Event.class); assertNull(event.getAttribute("test")); } @Test(expectedExceptions = JsonMappingException.class, expectedExceptionsMessageRegExp = "Scalar value 'test' cannot be cast to ARRAY_BOOLEAN type for 'test' field.*") public void testScalarSentToObjectValue() throws Exception { metastore.getOrCreateCollectionFields("test", "test", ImmutableSet.of(new SchemaField("test", FieldType.ARRAY_BOOLEAN))); Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); ImmutableMap<String, Object> props = ImmutableMap.of( "test", "test"); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "api", api, "collection", "test", "properties", props)); mapper.readValue(bytes, Event.class); } @Test public void testNullSentToObjectValue() throws Exception { metastore.getOrCreateCollectionFields("test", "test", ImmutableSet.of(new SchemaField("test", FieldType.ARRAY_BOOLEAN))); Event.EventContext api = Event.EventContext.apiKey(apiKeys.writeKey()); HashMap<String, Object> props = new HashMap<>(); props.put("test", null); byte[] bytes = mapper.writeValueAsBytes(ImmutableMap.of( "api", api, "collection", "test", "properties", props)); Event event = mapper.readValue(bytes, Event.class); assertNull(event.properties().get("test")); } }