rebase and resubmit
Change-Id: I840888ad5aadceaacb5cd64c6472614cd82ffe17
diff --git a/src/test/java/trackertest/TrackerTest.java b/src/test/java/trackertest/TrackerTest.java
new file mode 100644
index 0000000..1ef5f44
--- /dev/null
+++ b/src/test/java/trackertest/TrackerTest.java
@@ -0,0 +1,119 @@
+package trackertest;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.stream.Collectors;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DynamicTest;
+import org.junit.jupiter.api.TestFactory;
+
+import entity.config;
+import tracker.Tracker;
+
+public class TrackerTest {
+ private static EntityManagerFactory emf;
+ private static EntityManager em;
+ private static List<String> userIds;
+ private static Map<String, Long> originalUploads;
+ private static Tracker tracker;
+
+ @BeforeAll
+ static void setup() throws Exception {
+ // 强制加载 MySQL 驱动,否则无法建立连接
+ Class.forName("com.mysql.cj.jdbc.Driver");
+ config cfg = new config();
+ Map<String,Object> props = new HashMap<>();
+ // 添加时区和 SSL 参数
+ String jdbcUrl = String.format(
+ "jdbc:mysql://%s/%s?useSSL=false&serverTimezone=UTC",
+ cfg.SqlURL, cfg.TestDatabase);
+ props.put("javax.persistence.jdbc.url", jdbcUrl);
+ props.put("javax.persistence.jdbc.user", cfg.SqlUsername);
+ props.put("javax.persistence.jdbc.password", cfg.SqlPassword);
+ props.put("javax.persistence.jdbc.driver", "com.mysql.cj.jdbc.Driver");
+ emf = Persistence.createEntityManagerFactory("myPersistenceUnit", props);
+ em = emf.createEntityManager();
+ // 使用简单实体名而非带包名前缀
+ userIds = em.createQuery(
+ "select u.userid from UserPT u", String.class
+ ).getResultList();
+
+ // 保存初始 upload 值
+ originalUploads = new HashMap<>();
+ for (String uid : userIds) {
+ Long up = em.createQuery(
+ "select u.upload from UserPT u where u.userid = :uid", Long.class
+ ).setParameter("uid", uid)
+ .getSingleResult();
+ originalUploads.put(uid, up != null ? up : 0L);
+ }
+ tracker = new Tracker(emf);
+ }
+
+ @AfterAll
+ static void teardown() {
+ if (em != null && em.isOpen()) em.close();
+ if (emf != null && emf.isOpen()) emf.close();
+ }
+
+ @TestFactory
+ Collection<DynamicTest> testAddUpLoad() {
+ Random rnd = new Random();
+ return userIds.stream()
+ .map(uid -> DynamicTest.dynamicTest("AddUpLoad for user " + uid, () -> {
+ int delta = rnd.nextInt(1000) + 1; // Ensure non-zero value
+ long before = originalUploads.get(uid);
+
+ // 操作成功时返回 false
+ Assertions.assertFalse(tracker.AddUpLoad(uid, delta),
+ "AddUpLoad should return false on successful operation");
+
+ // Clear the persistence context to ensure fresh data is fetched
+ em.clear();
+
+ // Fetch updated value
+ Long after = em.createQuery(
+ "select u.upload from UserPT u where u.userid = :uid", Long.class
+ ).setParameter("uid", uid)
+ .getSingleResult();
+
+ Assertions.assertEquals(before + delta, after,
+ "Upload value should be increased by " + delta);
+
+ // 操作成功时返回 false
+ Assertions.assertFalse(tracker.ReduceUpLoad(uid, delta),
+ "ReduceUpLoad should return false on successful operation");
+ }))
+ .collect(Collectors.toList());
+ }
+
+ @TestFactory
+ Collection<DynamicTest> testReduceUpLoad() {
+ Random rnd = new Random();
+ return userIds.stream()
+ .map(uid -> DynamicTest.dynamicTest("ReduceUpLoad for user " + uid, () -> {
+ long before = originalUploads.get(uid);
+ int max = (int)Math.min(before, 1000);
+ int delta = max > 0 ? rnd.nextInt(max) + 1 : 0;
+ if (delta == 0) return; // 无可减量时跳过
+ Assertions.assertFalse(tracker.ReduceUpLoad(uid, delta));
+ Long after = em.createQuery(
+ "select u.upload from UserPT u where u.userid = :uid", Long.class
+ ).setParameter("uid", uid)
+ .getSingleResult();
+ Assertions.assertEquals(before - delta, after);
+ // 回滚到初始值
+ Assertions.assertFalse(tracker.AddUpLoad(uid, delta));
+ }))
+ .collect(Collectors.toList());
+ }
+}