/* * The MIT License * * Copyright 2014 sorrge. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.nyan.dch.posts; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import org.junit.After; import org.junit.AfterClass; import static org.junit.Assert.*; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.nyan.dch.crypto.SHA256Hash; /** * * @author sorrge */ public class StorageTest { public static ArrayList<Post> GenerateStream(int numPosts, Random rand, long dd, String... boards) { ArrayList<Post> allPosts = new ArrayList<>(numPosts); for(int i = 0; i < numPosts; ++i) { Post newPost; if(allPosts.isEmpty() || rand.nextBoolean()) { SHA256Hash thread = rand.nextBoolean() ? null : allPosts.isEmpty() || rand.nextBoolean() ? SHA256Hash.Digest(String.valueOf(rand.nextInt()).getBytes()) : allPosts.get(allPosts.size() - 1 - rand.nextInt(Math.min(100, allPosts.size()))).GetId(); String board = rand.nextBoolean() ? String.valueOf((char)rand.nextInt(256)) : boards[rand.nextInt(boards.length)]; newPost = new Post(new PostData(board, thread, String.valueOf(rand.nextInt()), String.valueOf(rand.nextInt()), new Date(dd++))); } else { Post parent = allPosts.get(allPosts.size() - 1 - rand.nextInt(Math.min(100, allPosts.size()))); newPost = new Post(new PostData(parent.GetBoard(), parent.GetThreadId() == null ? parent.GetId() : parent.GetThreadId(), String.valueOf(rand.nextInt()), String.valueOf(rand.nextInt()), new Date(dd++))); } allPosts.add(newPost); } return allPosts; } public static ArrayList<Post> GenerateOPs(int numPosts, Random rand, String board, long dd) { ArrayList<Post> allPosts = new ArrayList<>(numPosts); for(int i = 0; i < numPosts; ++i) allPosts.add(new Post(new PostData(board, null, String.valueOf(rand.nextInt()), String.valueOf(rand.nextInt()), new Date(dd++)))); return allPosts; } public static Set<SHA256Hash> GatherPosts(Storage storage) { HashSet<SHA256Hash> res = new HashSet<>(); for(String board : storage.GetChan().GetBoards()) for(SHA256Hash threadId : storage.GetChan().GetBoard(board).GetThreads()) res.addAll(storage.GetChan().GetBoard(board).GetThread(threadId).GetPostIds()); return res; } public static void AssertSynced(Storage s1, Storage s2) { assert(s1.GetChan().GetBoards().equals(s2.GetChan().GetBoards())); for(String board : s1.GetChan().GetBoards()) { assert(s1.GetChan().GetBoard(board).GetThreads().equals(s2.GetChan().GetBoard(board).GetThreads())); for(SHA256Hash threadId : s1.GetChan().GetBoard(board).GetThreads()) assert(s1.GetChan().GetBoard(board).GetThread(threadId).GetPostIds().equals(s2.GetChan().GetBoard(board).GetThread(threadId).GetPostIds())); } Set<SHA256Hash> postsOnBoard1 = StorageTest.GatherPosts(s1), postsOnBoard2 = StorageTest.GatherPosts(s2); assert(postsOnBoard1.equals(postsOnBoard2)); if(s1.NumPosts() != s2.NumPosts()) fail(); List<Post> posts1 = s1.GetPostsAfter(new Date(0)); for(Post p : posts1) if(!s2.Contains(p)) fail(); } public static void AssertApproxSynced(Storage s1, Storage s2, double percentThreads) { Set<String> boards = Sets.intersection(s1.GetChan().GetBoards(), s2.GetChan().GetBoards()); int unmatched = 0, total = 0; for(String board : boards) { Set<SHA256Hash> ts1 = s1.GetChan().GetBoard(board).GetThreads(), ts2 = s2.GetChan().GetBoard(board).GetThreads(); Set<SHA256Hash> all = Sets.union(ts1, ts2); Set<SHA256Hash> common = Sets.intersection(ts1, ts2); total += all.size(); unmatched += all.size() - common.size(); for(SHA256Hash tid : common) if(!s1.GetChan().GetBoard(board).GetThread(tid).GetPostIds().equals(s2.GetChan().GetBoard(board).GetThread(tid).GetPostIds())) ++unmatched; } assert(unmatched <= total * percentThreads); } public static ArrayList<Post> GenerateThread(int numPosts, Random rand, String board, long dd) { Post OP = new Post(new PostData(board, null, String.valueOf(rand.nextInt()), String.valueOf(rand.nextInt()), new Date(dd++))); ArrayList<Post> allPosts = new ArrayList<>(numPosts); allPosts.add(OP); for(int i = 1; i < numPosts; ++i) allPosts.add(new Post(new PostData(board, OP.GetId(), String.valueOf(rand.nextInt()), String.valueOf(rand.nextInt()), new Date(dd++)))); return allPosts; } /** * Test of Add method, of class Storage. */ @org.junit.Test public void testAdd() { String[] boards = new String[] {"b", "d", "e"}; Storage storage = new Storage(boards); Random rand = new Random(12); ArrayList<Post> allPosts = GenerateStream(10000, rand, 111, boards); int maxPosts = 0; for(Post p : allPosts) { storage.Add(p); maxPosts = Math.max(maxPosts, storage.NumPosts()); } List<Post> history = storage.GetPostsAfter(new Date(0)); Set<SHA256Hash> postsOnBoard = GatherPosts(storage); assert(history.size() == postsOnBoard.size()); for(Post p : history) assert(postsOnBoard.contains(p.GetId())); System.out.printf("Posts at the end: %1$d, max seen posts: %2$d\n", storage.NumPosts(), maxPosts); } /** * Test of Contains method, of class Storage. */ @org.junit.Test public void testContains() { Storage storage = new Storage("b"); Random rand = new Random(12); Post OP = new Post(new PostData("b", null, String.valueOf(rand.nextInt()), String.valueOf(rand.nextInt()), new Date())); storage.Add(OP); Post newPost = new Post(new PostData("b", OP.GetId(), String.valueOf(rand.nextInt()), String.valueOf(rand.nextInt()), new Date())); assert(storage.NumPosts() == 1); assert(storage.Contains(OP)); assert(!storage.Contains(newPost)); } /** * Test of GetPostsAfter method, of class Storage. */ @org.junit.Test public void testGetPostsAfter() { Storage storage = new Storage("b"); Random rand = new Random(12); ArrayList<Post> allPosts = new ArrayList<>(); int maxPosts = 0; long dd = 111; for(int i = 0; i < 100000; ++i) { Post newPost = new Post(new PostData("b", null, String.valueOf(rand.nextInt()), String.valueOf(rand.nextInt()), new Date(dd++))); allPosts.add(newPost); storage.Add(newPost); maxPosts = Math.max(maxPosts, storage.NumPosts()); } int numPosts = storage.NumPosts(); assert(numPosts > 0); for(int i = 0; i < numPosts; ++i) assert(storage.Contains(allPosts.get(allPosts.size() - i - 1))); assert(storage.GetPostsAfter(allPosts.get(allPosts.size() - 1).GetSentAt()).size() == 1); List<Post> end = storage.GetPostsAfter(allPosts.get(allPosts.size() - numPosts).GetSentAt()); assert(end.size() == numPosts); for(int i = 0; i < numPosts; ++i) assert(end.get(i).equals(allPosts.get(allPosts.size() - numPosts + i))); end = storage.GetPostsAfter(new Date(0)); for(Post p : end) assert(storage.Contains(p)); } }