package cc.blynk.server.db; import cc.blynk.server.core.BlockingIOProcessor; import cc.blynk.server.core.dao.UserKey; import cc.blynk.server.core.model.AppName; import cc.blynk.server.core.model.DashBoard; import cc.blynk.server.core.model.Profile; import cc.blynk.server.core.model.auth.User; import cc.blynk.server.core.model.enums.GraphType; import cc.blynk.server.core.model.enums.PinType; import cc.blynk.server.core.reporting.average.AggregationKey; import cc.blynk.server.core.reporting.average.AggregationValue; import cc.blynk.server.core.reporting.average.AverageAggregatorProcessor; import cc.blynk.server.db.dao.ReportingDBDao; import cc.blynk.server.db.model.Purchase; import cc.blynk.server.db.model.Redeem; import cc.blynk.utils.DateTimeUtils; import org.junit.*; import org.postgresql.copy.CopyManager; import org.postgresql.core.BaseConnection; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; import java.time.Instant; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.zip.GZIPOutputStream; import static org.junit.Assert.*; /** * The Blynk Project. * Created by Dmitriy Dumanskiy. * Created on 19.02.16. */ public class DBManagerTest { private static DBManager dbManager; private static BlockingIOProcessor blockingIOProcessor; private static final Calendar UTC = Calendar.getInstance(TimeZone.getTimeZone("UTC")); @BeforeClass public static void init() throws Exception { blockingIOProcessor = new BlockingIOProcessor(2, 10000); dbManager = new DBManager("db-test.properties", blockingIOProcessor, true); assertNotNull(dbManager.getConnection()); } @AfterClass public static void close() { dbManager.close(); } @Before public void cleanAll() throws Exception { //clean everything just in case dbManager.executeSQL("DELETE FROM users"); dbManager.executeSQL("DELETE FROM reporting_average_minute"); dbManager.executeSQL("DELETE FROM reporting_average_hourly"); dbManager.executeSQL("DELETE FROM reporting_average_daily"); dbManager.executeSQL("DELETE FROM purchase"); dbManager.executeSQL("DELETE FROM redeem"); } @Test public void test() throws Exception { assertNotNull(dbManager.getConnection()); } @Test @Ignore("Ignoring because of travis CI") public void testDbVersion() throws Exception { int dbVersion = dbManager.userDBDao.getDBVersion(); assertTrue(dbVersion >= 90500); } @Test public void testInsert1000RecordsAndSelect() throws Exception { int a = 0; String userName = "test@gmail.com"; long start = System.currentTimeMillis(); long minute = (start / AverageAggregatorProcessor.MINUTE) * AverageAggregatorProcessor.MINUTE; long startMinute = minute; try (Connection connection = dbManager.getConnection(); PreparedStatement ps = connection.prepareStatement(ReportingDBDao.insertMinute)) { for (int i = 0; i < 1000; i++) { ReportingDBDao.prepareReportingInsert(ps, userName, 1, 2, (byte) 0, 'v', minute, (double) i); ps.addBatch(); minute += AverageAggregatorProcessor.MINUTE; a++; } ps.executeBatch(); connection.commit(); } System.out.println("Finished : " + (System.currentTimeMillis() - start) + " millis. Executed : " + a); try (Connection connection = dbManager.getConnection(); Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery("select * from reporting_average_minute order by ts ASC")) { int i = 0; while (rs.next()) { assertEquals(userName, rs.getString("email")); assertEquals(1, rs.getInt("project_id")); assertEquals(2, rs.getInt("device_id")); assertEquals(0, rs.getByte("pin")); assertEquals("v", rs.getString("pinType")); assertEquals(startMinute, rs.getTimestamp("ts", UTC).getTime()); assertEquals((double) i, rs.getDouble("value"), 0.0001); startMinute += AverageAggregatorProcessor.MINUTE; i++; } connection.commit(); } } @Test @Ignore public void testCopy100RecordsIntoFile() throws Exception { System.out.println("Starting"); int a = 0; long start = System.currentTimeMillis(); try (Connection connection = dbManager.getConnection(); PreparedStatement ps = connection.prepareStatement(ReportingDBDao.insertMinute)) { String userName = "test@gmail.com"; long minute = (System.currentTimeMillis() / AverageAggregatorProcessor.MINUTE) * AverageAggregatorProcessor.MINUTE; for (int i = 0; i < 100; i++) { ReportingDBDao.prepareReportingInsert(ps, userName, 1, 0, (byte) 0, 'v', minute, (double) i); ps.addBatch(); minute += AverageAggregatorProcessor.MINUTE; a++; } ps.executeBatch(); connection.commit(); } System.out.println("Finished : " + (System.currentTimeMillis() - start) + " millis. Executed : " + a); try (Connection connection = dbManager.getConnection(); Writer gzipWriter = new OutputStreamWriter(new GZIPOutputStream(new FileOutputStream(new File("/home/doom369/output.csv.gz"))), "UTF-8")) { CopyManager copyManager = new CopyManager(connection.unwrap(BaseConnection.class)); String selectQuery = "select pintype || pin, ts, value from reporting_average_minute where project_id = 1 and email = 'test@gmail.com'"; long res = copyManager.copyOut("COPY (" + selectQuery + " ) TO STDOUT WITH (FORMAT CSV)", gzipWriter); System.out.println(res); } } @Test public void testDeleteWorksAsExpected() throws Exception { long minute; try (Connection connection = dbManager.getConnection(); PreparedStatement ps = connection.prepareStatement(ReportingDBDao.insertMinute)) { minute = (System.currentTimeMillis() / AverageAggregatorProcessor.MINUTE) * AverageAggregatorProcessor.MINUTE; for (int i = 0; i < 370; i++) { ReportingDBDao.prepareReportingInsert(ps, "test1111@gmail.com", 1, 0, (byte) 0, 'v', minute, (double) i); ps.addBatch(); minute += AverageAggregatorProcessor.MINUTE; } ps.executeBatch(); connection.commit(); } //todo finish. //todo this breaks testInsert1000RecordsAndSelect() test //Instant now = Instant.ofEpochMilli(minute); //dbManager.cleanOldReportingRecords(now); } @Test public void testManyConnections() throws Exception { User user = new User(); user.email = "test@test.com"; user.appName = AppName.BLYNK; Map<AggregationKey, AggregationValue> map = new ConcurrentHashMap<>(); AggregationValue value = new AggregationValue(); value.update(1); long ts = System.currentTimeMillis(); for (int i = 0; i < 60; i++) { map.put(new AggregationKey(user.email, user.appName, i, 0, PinType.ANALOG.pintTypeChar, (byte) i, ts), value); dbManager.insertReporting(map, GraphType.MINUTE); dbManager.insertReporting(map, GraphType.HOURLY); dbManager.insertReporting(map, GraphType.DAILY); map.clear(); } while (blockingIOProcessor.getActiveCount() > 0) { Thread.sleep(100); } } @Test @Ignore("Ignored cause travis postgres is old and doesn't support upserts") public void testUpsertForDifferentApps() throws Exception { ArrayList<User> users = new ArrayList<>(); users.add(new User("test1@gmail.com", "pass", "testapp2", "local", false, false)); users.add(new User("test1@gmail.com", "pass", "testapp1", "local", false, false)); dbManager.userDBDao.save(users); ConcurrentMap<UserKey, User> dbUsers = dbManager.userDBDao.getAllUsers("local"); assertEquals(2, dbUsers.size()); } @Test @Ignore("Ignored cause travis postgres is old and doesn't support upserts") public void testUpsertAndSelect() throws Exception { ArrayList<User> users = new ArrayList<>(); for (int i = 0; i < 10000; i++) { users.add(new User("test" + i + "@gmail.com", "pass", AppName.BLYNK, "local", false, false)); } //dbManager.saveUsers(users); dbManager.userDBDao.save(users); ConcurrentMap<UserKey, User> dbUsers = dbManager.userDBDao.getAllUsers("local"); System.out.println("Records : " + dbUsers.size()); } @Test @Ignore("Ignored cause travis postgres is old and doesn't support upserts") public void testUpsertUser() throws Exception { ArrayList<User> users = new ArrayList<>(); User user = new User("test@gmail.com", "pass", AppName.BLYNK, "local", false, false); user.name = "123"; user.lastModifiedTs = 0; user.lastLoggedAt = 1; user.lastLoggedIP = "127.0.0.1"; users.add(user); user = new User("test@gmail.com", "pass", AppName.BLYNK, "local", false, false); user.lastModifiedTs = 0; user.lastLoggedAt = 1; user.lastLoggedIP = "127.0.0.1"; user.name = "123"; users.add(user); user = new User("test2@gmail.com", "pass", AppName.BLYNK, "local", false, false); user.lastModifiedTs = 0; user.lastLoggedAt = 1; user.lastLoggedIP = "127.0.0.1"; user.name = "123"; users.add(user); dbManager.userDBDao.save(users); try (Connection connection = dbManager.getConnection(); Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery("select * from users where email = 'test@gmail.com'")) { while (rs.next()) { assertEquals("test@gmail.com", rs.getString("email")); assertEquals(AppName.BLYNK, rs.getString("appName")); assertEquals("local", rs.getString("region")); assertEquals("123", rs.getString("name")); assertEquals("pass", rs.getString("pass")); assertEquals(0, rs.getTimestamp("last_modified", DateTimeUtils.UTC_CALENDAR).getTime()); assertEquals(1, rs.getTimestamp("last_logged", DateTimeUtils.UTC_CALENDAR).getTime()); assertEquals("127.0.0.1", rs.getString("last_logged_ip")); assertFalse(rs.getBoolean("is_facebook_user")); assertFalse(rs.getBoolean("is_super_admin")); assertEquals(2000, rs.getInt("energy")); assertEquals("{}", rs.getString("json")); } connection.commit(); } } @Test @Ignore("Ignored cause travis postgres is old and doesn't support upserts") public void testUpsertUserFieldUpdated() throws Exception { ArrayList<User> users = new ArrayList<>(); User user = new User("test@gmail.com", "pass", AppName.BLYNK, "local", false, false); user.lastModifiedTs = 0; user.lastLoggedAt = 1; user.lastLoggedIP = "127.0.0.1"; users.add(user); dbManager.userDBDao.save(users); users = new ArrayList<>(); user = new User("test@gmail.com", "pass2", AppName.BLYNK, "local2", true, true); user.name = "1234"; user.lastModifiedTs = 1; user.lastLoggedAt = 2; user.lastLoggedIP = "127.0.0.2"; user.energy = 1000; user.profile = new Profile(); DashBoard dash = new DashBoard(); dash.id = 1; dash.name = "123"; user.profile.dashBoards = new DashBoard[]{dash}; users.add(user); dbManager.userDBDao.save(users); try (Connection connection = dbManager.getConnection(); Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery("select * from users where email = 'test@gmail.com'")) { while (rs.next()) { assertEquals("test@gmail.com", rs.getString("email")); assertEquals(AppName.BLYNK, rs.getString("appName")); assertEquals("local2", rs.getString("region")); assertEquals("pass2", rs.getString("pass")); assertEquals("1234", rs.getString("name")); assertEquals(1, rs.getTimestamp("last_modified", DateTimeUtils.UTC_CALENDAR).getTime()); assertEquals(2, rs.getTimestamp("last_logged", DateTimeUtils.UTC_CALENDAR).getTime()); assertEquals("127.0.0.2", rs.getString("last_logged_ip")); assertTrue(rs.getBoolean("is_facebook_user")); assertTrue(rs.getBoolean("is_super_admin")); assertEquals(1000, rs.getInt("energy")); assertEquals("{\"dashBoards\":[{\"id\":1,\"name\":\"123\",\"createdAt\":0,\"updatedAt\":0,\"theme\":\"Blynk\",\"keepScreenOn\":false,\"isAppConnectedOn\":false,\"isShared\":false,\"isActive\":false}]}", rs.getString("json")); } connection.commit(); } } @Test @Ignore("Ignored cause travis postgres is old and doesn't support upserts") public void testInsertAndGetUser() throws Exception { ArrayList<User> users = new ArrayList<>(); User user = new User("test@gmail.com", "pass", AppName.BLYNK, "local", true, true); user.lastModifiedTs = 0; user.lastLoggedAt = 1; user.lastLoggedIP = "127.0.0.1"; user.profile = new Profile(); DashBoard dash = new DashBoard(); dash.id = 1; dash.name = "123"; user.profile.dashBoards = new DashBoard[]{dash}; users.add(user); dbManager.userDBDao.save(users); ConcurrentMap<UserKey, User> dbUsers = dbManager.userDBDao.getAllUsers("local"); assertNotNull(dbUsers); assertEquals(1, dbUsers.size()); User dbUser = dbUsers.get(new UserKey(user.email, user.appName)); assertEquals("test@gmail.com", dbUser.email); assertEquals(AppName.BLYNK, dbUser.appName); assertEquals("local", dbUser.region); assertEquals("pass", dbUser.pass); assertEquals(0, dbUser.lastModifiedTs); assertEquals(1, dbUser.lastLoggedAt); assertEquals("127.0.0.1", dbUser.lastLoggedIP); assertEquals("{\"dashBoards\":[{\"id\":1,\"parentId\":-1,\"isPreview\":false,\"name\":\"123\",\"createdAt\":0,\"updatedAt\":0,\"theme\":\"Blynk\",\"keepScreenOn\":false,\"isAppConnectedOn\":false,\"isShared\":false,\"isActive\":false}]}", dbUser.profile.toString()); assertTrue(dbUser.isFacebookUser); assertTrue(dbUser.isSuperAdmin); assertEquals(2000, dbUser.energy); assertEquals("{\"dashBoards\":[{\"id\":1,\"parentId\":-1,\"isPreview\":false,\"name\":\"123\",\"createdAt\":0,\"updatedAt\":0,\"theme\":\"Blynk\",\"keepScreenOn\":false,\"isAppConnectedOn\":false,\"isShared\":false,\"isActive\":false}]}", dbUser.profile.toString()); } @Test @Ignore("Ignored cause travis postgres is old and doesn't support upserts") public void testInsertGetDeleteUser() throws Exception { ArrayList<User> users = new ArrayList<>(); User user = new User("test@gmail.com", "pass", AppName.BLYNK, "local", true, true); user.lastModifiedTs = 0; user.lastLoggedAt = 1; user.lastLoggedIP = "127.0.0.1"; user.profile = new Profile(); DashBoard dash = new DashBoard(); dash.id = 1; dash.name = "123"; user.profile.dashBoards = new DashBoard[]{dash}; users.add(user); dbManager.userDBDao.save(users); Map<UserKey, User> dbUsers = dbManager.userDBDao.getAllUsers("local"); assertNotNull(dbUsers); assertEquals(1, dbUsers.size()); User dbUser = dbUsers.get(new UserKey(user.email, user.appName)); assertEquals("test@gmail.com", dbUser.email); assertEquals(AppName.BLYNK, dbUser.appName); assertEquals("local", dbUser.region); assertEquals("pass", dbUser.pass); assertEquals(0, dbUser.lastModifiedTs); assertEquals(1, dbUser.lastLoggedAt); assertEquals("127.0.0.1", dbUser.lastLoggedIP); assertEquals("{\"dashBoards\":[{\"id\":1,\"parentId\":-1,\"isPreview\":false,\"name\":\"123\",\"createdAt\":0,\"updatedAt\":0,\"theme\":\"Blynk\",\"keepScreenOn\":false,\"isAppConnectedOn\":false,\"isShared\":false,\"isActive\":false}]}", dbUser.profile.toString()); assertTrue(dbUser.isFacebookUser); assertTrue(dbUser.isSuperAdmin); assertEquals(2000, dbUser.energy); assertEquals("{\"dashBoards\":[{\"id\":1,\"parentId\":-1,\"isPreview\":false,\"name\":\"123\",\"createdAt\":0,\"updatedAt\":0,\"theme\":\"Blynk\",\"keepScreenOn\":false,\"isAppConnectedOn\":false,\"isShared\":false,\"isActive\":false}]}", dbUser.profile.toString()); assertTrue(dbManager.userDBDao.deleteUser(new UserKey(user.email, user.appName))); dbUsers = dbManager.userDBDao.getAllUsers("local"); assertNotNull(dbUsers); assertEquals(0, dbUsers.size()); } @Test public void testRedeem() throws Exception { assertNull(dbManager.selectRedeemByToken("123")); String token = UUID.randomUUID().toString().replace("-", ""); dbManager.executeSQL("insert into redeem (token) values('" + token + "')"); assertNotNull(dbManager.selectRedeemByToken(token)); assertNull(dbManager.selectRedeemByToken("123")); } @Test public void testPurchase() throws Exception { dbManager.insertPurchase(new Purchase("test@gmail.com", 1000, "123456")); try (Connection connection = dbManager.getConnection(); Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery("select * from purchase")) { while (rs.next()) { assertEquals("test@gmail.com", rs.getString("email")); assertEquals(1000, rs.getInt("reward")); assertEquals("123456", rs.getString("transactionId")); assertEquals(0.99D, rs.getDouble("price"), 0.1D); assertNotNull(rs.getDate("ts")); } connection.commit(); } } @Test public void testOptimisticLockingRedeem() throws Exception { String token = UUID.randomUUID().toString().replace("-", ""); dbManager.executeSQL("insert into redeem (token) values('" + token + "')"); Redeem redeem = dbManager.selectRedeemByToken(token); assertNotNull(redeem); assertEquals(redeem.token, token); assertFalse(redeem.isRedeemed); assertEquals(1, redeem.version); assertNull(redeem.ts); assertTrue(dbManager.updateRedeem("user@user.com", token)); assertFalse(dbManager.updateRedeem("user@user.com", token)); redeem = dbManager.selectRedeemByToken(token); assertNotNull(redeem); assertEquals(redeem.token, token); assertTrue(redeem.isRedeemed); assertEquals(2, redeem.version); assertEquals("user@user.com", redeem.email); assertNotNull(redeem.ts); } @Test public void testSelect() throws Exception { long ts = 1455924480000L; try (Connection connection = dbManager.getConnection(); PreparedStatement ps = connection.prepareStatement(ReportingDBDao.selectMinute)) { ReportingDBDao.prepareReportingSelect(ps, ts, 2); ResultSet rs = ps.executeQuery(); while(rs.next()) { System.out.println(rs.getLong("ts") + " " + rs.getDouble("value")); } rs.close(); } } @Test public void cleanOutdatedRecords() throws Exception{ dbManager.reportingDBDao.cleanOldReportingRecords(Instant.now()); } }