package org.rakam.collection; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.ImmutableList; import org.rakam.analysis.ConfigManager; import org.rakam.analysis.metadata.Metastore; import org.rakam.plugin.user.AbstractUserService; import org.rakam.plugin.user.User; import org.rakam.util.JsonHelper; import org.rakam.util.RakamException; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; import java.time.Instant; import java.util.Set; import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.UnaryOperator; import static org.testng.Assert.assertEquals; import static org.testng.AssertJUnit.assertNotNull; public abstract class TestUserStorage { private final String PROJECT_NAME = this.getClass().getSimpleName().toLowerCase(); private ObjectNode sampleProperties = JsonHelper.jsonObject() .put("test", 1.0) .put("test1 Naber Abi", "value") .put("test4 Şamil", true) .put("created_at", 100) .put("test5", 1.5); private ObjectNode samplePropertiesExpected = JsonHelper.jsonObject() .put("test", 1.0) .put("test1 naber abi", "value") .put("test4 şamil", true) .put("created_at", Instant.ofEpochMilli(100).toString()) .put("test5", 1.5); @BeforeSuite public void setUp() throws Exception { getMetastore().createProject(PROJECT_NAME); } @AfterSuite public void setDown() throws Exception { getMetastore().deleteProject(PROJECT_NAME); } @AfterMethod public void deleteProject() throws Exception { getUserService().dropProject(PROJECT_NAME); getConfigManager().clear(); } @Test public void testCreate() throws Exception { AbstractUserService userService = getUserService(); userService.setUserProperties(PROJECT_NAME, 1L, sampleProperties); User test = userService.getUser(PROJECT_NAME, 1L).join(); assertEquals(test.id, 1L); assertEquals((Object) test.properties, samplePropertiesExpected); } @Test public void testCastingSetProperties() throws Exception { AbstractUserService userService = getUserService(); userService.setUserProperties(PROJECT_NAME, 2, sampleProperties); userService.setUserProperties(PROJECT_NAME, 2, JsonHelper.jsonObject() .put("test", "2") .put("test1 Naber abi", 324) .put("test4 şamil", "true") .put("created_at", "test") .put("test5", "2.5")); User test = userService.getUser(PROJECT_NAME, 2).join(); assertEquals(test.id, 2); assertEquals((Object) test.properties, JsonHelper.jsonObject() .put("test", 2.0) .put("test1 naber abi", "324") .put("test4 şamil", true) .put("created_at", Instant.ofEpochMilli(100).toString()) .put("test5", 2.5)); } @Test public void testSetProperties() throws Exception { AbstractUserService userService = getUserService(); userService.setUserProperties(PROJECT_NAME, 3, sampleProperties); User test = userService.getUser(PROJECT_NAME, 3).join(); assertEquals(test.id, 3); assertEquals((Object) test.properties, samplePropertiesExpected); } @Test public void testSetNullProperties() throws Exception { AbstractUserService userService = getUserService(); userService.setUserProperties(PROJECT_NAME, 3, JsonHelper.jsonObject() .put("test", (String) null) .put("test1", (String) null)); User test = userService.getUser(PROJECT_NAME, 3).join(); assertEquals(test.id, 3); assertNotNull(test.properties.get("created_at").asText()); } @Test public void testSetSomeOfNullProperties() throws Exception { AbstractUserService userService = getUserService(); userService.setUserProperties(PROJECT_NAME, 3, JsonHelper.jsonObject() .put("test10", "val") .put("created_at", 100.0) .put("test", (String) null) .put("test1", (String) null) ); User test = userService.getUser(PROJECT_NAME, 3).join(); assertEquals(test.id, 3); assertEquals((Object) test.properties, JsonHelper.jsonObject() .put("test10", "val") .put("created_at", Instant.ofEpochMilli(100).toString())); } @Test public void testUserIdStringToNumber() throws Exception { AbstractUserService userService = getUserService(); userService.setUserProperties(PROJECT_NAME, "3", sampleProperties); User test = userService.getUser(PROJECT_NAME, 3).join(); assertEquals(test.id, 3); assertEquals((Object) test.properties, samplePropertiesExpected); } @Test public void testUserIdInitialConcurrent() throws Exception { AbstractUserService userService = getUserService(); ExecutorService executorService = Executors.newFixedThreadPool(8); AtomicReference<Boolean> isNumeric = new AtomicReference(); CountDownLatch latch = new CountDownLatch(8); for (int i = 0; i < 8; i++) { executorService.submit(() -> { boolean numeric = Math.random() > 0.5; isNumeric.updateAndGet(aBoolean -> aBoolean == null ? numeric : aBoolean); userService.setUserProperties(PROJECT_NAME, numeric ? 3 : "3", sampleProperties); latch.countDown(); }); } latch.await(1, TimeUnit.MINUTES); assertEquals((Object) samplePropertiesExpected, userService.getUser(PROJECT_NAME, isNumeric.get() ? 3 : "3").join().properties); } @Test public void testUserIdNumberToString() throws Exception { AbstractUserService userService = getUserService(); userService.setUserProperties(PROJECT_NAME, 3, sampleProperties); User test = userService.getUser(PROJECT_NAME, "3").join(); assertEquals(test.id, "3"); assertEquals((Object) test.properties, samplePropertiesExpected); } @Test(expectedExceptions = CompletionException.class) public void testUserIdInvalid() throws Exception { AbstractUserService userService = getUserService(); userService.setUserProperties(PROJECT_NAME, 3, sampleProperties); User test = userService.getUser(PROJECT_NAME, "selami").join(); assertEquals(test.id, 3); assertEquals((Object) test.properties, samplePropertiesExpected); } @Test public void testConcurrentSetProperties() throws Exception { ExecutorService executorService = Executors.newFixedThreadPool(8); Set<String> objects = new ConcurrentSkipListSet<>(); getUserService().setUserProperties(PROJECT_NAME, 3, JsonHelper.jsonObject().put("created_at", 10)); CountDownLatch countDownLatch = new CountDownLatch(1000); for (int x = 0; x < 1000; x++) { executorService.submit(() -> { AbstractUserService userService = getUserService(); ObjectNode builder = JsonHelper.jsonObject(); for (int i = 0; i < 4; i++) { String key = "test" + ((int) (Math.random() * 100)); objects.add(key); builder.put(key, 10L); } userService.setUserProperties(PROJECT_NAME, 3, builder); countDownLatch.countDown(); }); } countDownLatch.await(1, TimeUnit.MINUTES); User test = getUserService().getUser(PROJECT_NAME, 3).join(); assertEquals(test.id, 3); ObjectNode builder = JsonHelper.jsonObject(); builder.put("created_at", Instant.ofEpochMilli(10).toString()); for (String object : objects) { builder.put(object, 10.0); } assertEquals((Object) test.properties, builder); } @Test public void testChangeSchemaSetProperties() throws Exception { AbstractUserService userService = getUserService(); userService.setUserProperties(PROJECT_NAME, 4, sampleProperties); ObjectNode newProperties = JsonHelper.jsonObject() .put("test100", 1.0) .put("test200", "value") .put("test400", true); userService.setUserProperties(PROJECT_NAME, 4, newProperties); User test = userService.getUser(PROJECT_NAME, 4).join(); assertEquals(test.id, 4); ObjectNode builder = JsonHelper.jsonObject(); builder.setAll(samplePropertiesExpected); builder.setAll(newProperties); assertEquals((Object) test.properties, builder); } @Test public void testSetOncePropertiesFirstSet() throws Exception { AbstractUserService userService = getUserService(); userService.setUserPropertiesOnce(PROJECT_NAME, 5, sampleProperties); User test = userService.getUser(PROJECT_NAME, 5).join(); assertEquals(test.id, 5); assertEquals((Object) test.properties, samplePropertiesExpected); } @Test public void testSetOncePropertiesLatterSet() throws Exception { AbstractUserService userService = getUserService(); userService.setUserProperties(PROJECT_NAME, 6, sampleProperties); userService.setUserPropertiesOnce(PROJECT_NAME, 6, JsonHelper.jsonObject() .put("test", 2) .put("test1 Naber Abi", "value1") .put("test4 Şamil", false) .put("created_at", Instant.now().toEpochMilli()) .put("test5", 2.5)); User test = userService.getUser(PROJECT_NAME, 6).join(); assertEquals((Object) test.properties, samplePropertiesExpected); } @Test public void testUnsetSetProperties() throws Exception { AbstractUserService userService = getUserService(); userService.setUserProperties(PROJECT_NAME, 7, sampleProperties); userService.unsetProperties(PROJECT_NAME, 7, ImmutableList.of( "test", "test1 Naber Abi", "test4 Şamil")); User test = userService.getUser(PROJECT_NAME, 7).join(); assertEquals(test.id, 7); assertEquals((Object) test.properties, JsonHelper.jsonObject() .put("created_at", Instant.ofEpochMilli(100).toString()) .put("test5", 1.5)); } @Test public void testIncrementProperties() throws Exception { AbstractUserService userService = getUserService(); userService.incrementProperty(PROJECT_NAME, 8, "test", 10); assertEquals(userService.getUser(PROJECT_NAME, 8).join().properties.get("test").asDouble(), 10.0); userService.incrementProperty(PROJECT_NAME, 8, "test", 10); assertEquals(userService.getUser(PROJECT_NAME, 8).join().properties.get("test").asDouble(), 20.0); } public abstract AbstractUserService getUserService(); public abstract ConfigManager getConfigManager(); public abstract Metastore getMetastore(); }