@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 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(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 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 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());
  }
  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
  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.*")
  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));

    mapper.readValue(bytes, Event.class);
  }
  @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"));
  }
  @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(
      expectedExceptions = RakamException.class,
      expectedExceptionsMessageRegExp =
          "Nested properties are not supported\\. \\(non-scalar value in object property\\)")
  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",
                    "test",
                    "test1",
                    ImmutableMap.of("test", ImmutableList.of("test")),
                    "test2",
                    false)));

    mapper.readValue(bytes, Event.class);
  }
  @Test(
      expectedExceptions = JsonMappingException.class,
      expectedExceptionsMessageRegExp =
          "Nested properties are not supported. \\(\'test1\\' field\\).*")
  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)));

    mapper.readValue(bytes, Event.class);
  }