blob: 8f45a4ac4a01ebaf9460517158f34f2f51c28270 [file] [log] [blame]
rootff0769a2025-05-18 17:24:41 +00001package trackertest;
rootd4959a82025-05-27 07:07:37 +00002import java.io.File;
rootff0769a2025-05-18 17:24:41 +00003import java.util.Collection;
4import java.util.HashMap;
5import java.util.List;
6import java.util.Map;
7import java.util.Random;
rootf35409f2025-05-19 04:41:57 +00008import java.util.UUID;
rootff0769a2025-05-18 17:24:41 +00009import java.util.stream.Collectors;
rootf35409f2025-05-19 04:41:57 +000010import java.util.stream.IntStream;
rootff0769a2025-05-18 17:24:41 +000011import javax.persistence.EntityManager;
12import javax.persistence.EntityManagerFactory;
rootf35409f2025-05-19 04:41:57 +000013import javax.persistence.EntityTransaction;
rootff0769a2025-05-18 17:24:41 +000014import javax.persistence.Persistence;
rootff0769a2025-05-18 17:24:41 +000015import org.junit.jupiter.api.AfterAll;
16import org.junit.jupiter.api.Assertions;
17import org.junit.jupiter.api.BeforeAll;
18import org.junit.jupiter.api.DynamicTest;
19import org.junit.jupiter.api.TestFactory;
rootd4959a82025-05-27 07:07:37 +000020import entity.Seed;
rootf35409f2025-05-19 04:41:57 +000021import entity.TransRecord;
22import entity.TransportId;
rootff0769a2025-05-18 17:24:41 +000023import entity.config;
24import tracker.Tracker;
rootff0769a2025-05-18 17:24:41 +000025public class TrackerTest {
26 private static EntityManagerFactory emf;
27 private static EntityManager em;
28 private static List<String> userIds;
29 private static Map<String, Long> originalUploads;
30 private static Tracker tracker;
rootff0769a2025-05-18 17:24:41 +000031 @BeforeAll
32 static void setup() throws Exception {
33 // 强制加载 MySQL 驱动,否则无法建立连接
34 Class.forName("com.mysql.cj.jdbc.Driver");
35 config cfg = new config();
36 Map<String,Object> props = new HashMap<>();
37 // 添加时区和 SSL 参数
38 String jdbcUrl = String.format(
39 "jdbc:mysql://%s/%s?useSSL=false&serverTimezone=UTC",
40 cfg.SqlURL, cfg.TestDatabase);
41 props.put("javax.persistence.jdbc.url", jdbcUrl);
42 props.put("javax.persistence.jdbc.user", cfg.SqlUsername);
43 props.put("javax.persistence.jdbc.password", cfg.SqlPassword);
44 props.put("javax.persistence.jdbc.driver", "com.mysql.cj.jdbc.Driver");
45 emf = Persistence.createEntityManagerFactory("myPersistenceUnit", props);
46 em = emf.createEntityManager();
47 // 使用简单实体名而非带包名前缀
48 userIds = em.createQuery(
49 "select u.userid from UserPT u", String.class
50 ).getResultList();
rootff0769a2025-05-18 17:24:41 +000051 // 保存初始 upload 值
52 originalUploads = new HashMap<>();
53 for (String uid : userIds) {
54 Long up = em.createQuery(
55 "select u.upload from UserPT u where u.userid = :uid", Long.class
56 ).setParameter("uid", uid)
57 .getSingleResult();
58 originalUploads.put(uid, up != null ? up : 0L);
59 }
60 tracker = new Tracker(emf);
61 }
rootff0769a2025-05-18 17:24:41 +000062 @AfterAll
63 static void teardown() {
rootd4959a82025-05-27 07:07:37 +000064 // 清理:删除测试过程中保存的所有 torrent 文件
65 File storageDir = new File(config.TORRENT_STORAGE_DIR);
66 if (storageDir.exists() && storageDir.isDirectory()) {
67 File[] files = storageDir.listFiles();
68 if (files != null) {
69 for (File f : files) {
70 if (f.isFile()) {
71 f.delete();
72 }
73 }
74 }
75 }
rootff0769a2025-05-18 17:24:41 +000076 if (em != null && em.isOpen()) em.close();
77 if (emf != null && emf.isOpen()) emf.close();
78 }
rootff0769a2025-05-18 17:24:41 +000079 @TestFactory
80 Collection<DynamicTest> testAddUpLoad() {
81 Random rnd = new Random();
82 return userIds.stream()
83 .map(uid -> DynamicTest.dynamicTest("AddUpLoad for user " + uid, () -> {
84 int delta = rnd.nextInt(1000) + 1; // Ensure non-zero value
85 long before = originalUploads.get(uid);
86
rootf35409f2025-05-19 04:41:57 +000087 // AddUpLoad 前打印
88 System.out.println("Running AddUpLoad assert for user=" + uid + ", delta=" + delta);
rootff0769a2025-05-18 17:24:41 +000089 Assertions.assertFalse(tracker.AddUpLoad(uid, delta),
90 "AddUpLoad should return false on successful operation");
rootf35409f2025-05-19 04:41:57 +000091 System.out.println("AddUpLoad assert passed for user=" + uid);
rootff0769a2025-05-18 17:24:41 +000092 // Clear the persistence context to ensure fresh data is fetched
93 em.clear();
94
95 // Fetch updated value
96 Long after = em.createQuery(
97 "select u.upload from UserPT u where u.userid = :uid", Long.class
98 ).setParameter("uid", uid)
99 .getSingleResult();
rootf35409f2025-05-19 04:41:57 +0000100 // upload 值断言前打印
101 System.out.println("Running upload-value assert for user=" + uid);
rootff0769a2025-05-18 17:24:41 +0000102 Assertions.assertEquals(before + delta, after,
103 "Upload value should be increased by " + delta);
rootf35409f2025-05-19 04:41:57 +0000104 System.out.println("Upload-value assert passed for user=" + uid);
rootff0769a2025-05-18 17:24:41 +0000105
rootf35409f2025-05-19 04:41:57 +0000106 // ReduceUpLoad 前打印
107 System.out.println("Running ReduceUpLoad assert for user=" + uid + ", delta=" + delta);
rootff0769a2025-05-18 17:24:41 +0000108 Assertions.assertFalse(tracker.ReduceUpLoad(uid, delta),
109 "ReduceUpLoad should return false on successful operation");
rootf35409f2025-05-19 04:41:57 +0000110 System.out.println("ReduceUpLoad assert passed for user=" + uid);
rootff0769a2025-05-18 17:24:41 +0000111 }))
112 .collect(Collectors.toList());
113 }
rootff0769a2025-05-18 17:24:41 +0000114 @TestFactory
115 Collection<DynamicTest> testReduceUpLoad() {
116 Random rnd = new Random();
117 return userIds.stream()
118 .map(uid -> DynamicTest.dynamicTest("ReduceUpLoad for user " + uid, () -> {
119 long before = originalUploads.get(uid);
120 int max = (int)Math.min(before, 1000);
121 int delta = max > 0 ? rnd.nextInt(max) + 1 : 0;
122 if (delta == 0) return; // 无可减量时跳过
rootf35409f2025-05-19 04:41:57 +0000123 // ReduceUpLoad 前打印
124 System.out.println("Running ReduceUpLoad assert for user=" + uid + ", delta=" + delta);
rootff0769a2025-05-18 17:24:41 +0000125 Assertions.assertFalse(tracker.ReduceUpLoad(uid, delta));
rootf35409f2025-05-19 04:41:57 +0000126 System.out.println("ReduceUpLoad assert passed for user=" + uid);
rootff0769a2025-05-18 17:24:41 +0000127 Long after = em.createQuery(
128 "select u.upload from UserPT u where u.userid = :uid", Long.class
129 ).setParameter("uid", uid)
130 .getSingleResult();
rootf35409f2025-05-19 04:41:57 +0000131 // 减少后值断言前打印
132 System.out.println("Running post-reduce-value assert for user=" + uid);
rootff0769a2025-05-18 17:24:41 +0000133 Assertions.assertEquals(before - delta, after);
rootf35409f2025-05-19 04:41:57 +0000134 System.out.println("Post-reduce-value assert passed for user=" + uid);
rootf35409f2025-05-19 04:41:57 +0000135 // 回滚 AddUpLoad 前打印
136 System.out.println("Running rollback AddUpLoad assert for user=" + uid + ", delta=" + delta);
rootff0769a2025-05-18 17:24:41 +0000137 Assertions.assertFalse(tracker.AddUpLoad(uid, delta));
rootf35409f2025-05-19 04:41:57 +0000138 System.out.println("Rollback AddUpLoad assert passed for user=" + uid);
139 }))
140 .collect(Collectors.toList());
141 }
rootf35409f2025-05-19 04:41:57 +0000142 @TestFactory
143 Collection<DynamicTest> testAddDownload() {
144 Random rnd = new Random();
145 return userIds.stream()
146 .map(uid -> DynamicTest.dynamicTest("AddDownload for user " + uid, () -> {
147 int delta = rnd.nextInt(1000) + 1;
148 Long before = em.createQuery(
149 "select u.download from UserPT u where u.userid = :uid", Long.class
150 ).setParameter("uid", uid).getSingleResult();
151 before = before != null ? before : 0L;
rootf35409f2025-05-19 04:41:57 +0000152 System.out.println("Running AddDownload assert for user=" + uid + ", delta=" + delta);
153 Assertions.assertFalse(tracker.AddDownload(uid, delta),
154 "AddDownload should return false on successful operation");
155 em.clear();
rootf35409f2025-05-19 04:41:57 +0000156 Long after = em.createQuery(
157 "select u.download from UserPT u where u.userid = :uid", Long.class
158 ).setParameter("uid", uid).getSingleResult();
159 System.out.println("Running download-value assert for user=" + uid);
160 Assertions.assertEquals(before + delta, after,
161 "Download value should be increased by " + delta);
rootf35409f2025-05-19 04:41:57 +0000162 System.out.println("Running rollback ReduceDownload assert for user=" + uid + ", delta=" + delta);
163 Assertions.assertFalse(tracker.ReduceDownload(uid, delta),
164 "Rollback ReduceDownload should return false");
165 }))
166 .collect(Collectors.toList());
167 }
rootf35409f2025-05-19 04:41:57 +0000168 @TestFactory
169 Collection<DynamicTest> testReduceDownload() {
170 Random rnd = new Random();
171 return userIds.stream()
172 .map(uid -> DynamicTest.dynamicTest("ReduceDownload for user " + uid, () -> {
173 Long before = em.createQuery(
174 "select u.download from UserPT u where u.userid = :uid", Long.class
175 ).setParameter("uid", uid).getSingleResult();
176 before = before != null ? before : 0L;
177 int max = before.intValue();
178 int delta = max > 0 ? rnd.nextInt(max) + 1 : 0;
179 if (delta == 0) return;
rootf35409f2025-05-19 04:41:57 +0000180 System.out.println("Running ReduceDownload assert for user=" + uid + ", delta=" + delta);
181 Assertions.assertFalse(tracker.ReduceDownload(uid, delta));
182 Long after = em.createQuery(
183 "select u.download from UserPT u where u.userid = :uid", Long.class
184 ).setParameter("uid", uid).getSingleResult();
185 System.out.println("Running post-reduce-download-value assert for user=" + uid);
186 Assertions.assertEquals(before - delta, after);
rootf35409f2025-05-19 04:41:57 +0000187 System.out.println("Running rollback AddDownload assert for user=" + uid + ", delta=" + delta);
188 Assertions.assertFalse(tracker.AddDownload(uid, delta));
189 }))
190 .collect(Collectors.toList());
191 }
rootf35409f2025-05-19 04:41:57 +0000192 @TestFactory
193 Collection<DynamicTest> testAddMagic() {
194 Random rnd = new Random();
195 return userIds.stream()
196 .map(uid -> DynamicTest.dynamicTest("AddMagic for user " + uid, () -> {
197 int delta = rnd.nextInt(1000) + 1;
198 Integer before = em.createQuery(
199 "select u.magic from UserPT u where u.userid = :uid", Integer.class
200 ).setParameter("uid", uid).getSingleResult();
201 before = before != null ? before : 0;
rootf35409f2025-05-19 04:41:57 +0000202 System.out.println("Running AddMagic assert for user=" + uid + ", delta=" + delta);
203 Assertions.assertFalse(tracker.AddMagic(uid, delta));
204 em.clear();
rootf35409f2025-05-19 04:41:57 +0000205 Integer after = em.createQuery(
206 "select u.magic from UserPT u where u.userid = :uid", Integer.class
207 ).setParameter("uid", uid).getSingleResult();
208 System.out.println("Running magic-value assert for user=" + uid);
209 Assertions.assertEquals(before + delta, after.intValue());
rootf35409f2025-05-19 04:41:57 +0000210 System.out.println("Running rollback ReduceMagic assert for user=" + uid + ", delta=" + delta);
211 Assertions.assertFalse(tracker.ReduceMagic(uid, delta));
212 }))
213 .collect(Collectors.toList());
214 }
rootf35409f2025-05-19 04:41:57 +0000215 @TestFactory
216 Collection<DynamicTest> testReduceMagic() {
217 Random rnd = new Random();
218 return userIds.stream()
219 .map(uid -> DynamicTest.dynamicTest("ReduceMagic for user " + uid, () -> {
220 Integer before = em.createQuery(
221 "select u.magic from UserPT u where u.userid = :uid", Integer.class
222 ).setParameter("uid", uid).getSingleResult();
223 before = before != null ? before : 0;
224 int max = before.intValue();
225 int delta = max > 0 ? rnd.nextInt(max) + 1 : 0;
226 if (delta == 0) return;
rootf35409f2025-05-19 04:41:57 +0000227 System.out.println("Running ReduceMagic assert for user=" + uid + ", delta=" + delta);
228 Assertions.assertFalse(tracker.ReduceMagic(uid, delta));
229 Integer after = em.createQuery(
230 "select u.magic from UserPT u where u.userid = :uid", Integer.class
231 ).setParameter("uid", uid).getSingleResult();
232 System.out.println("Running post-reduce-magic-value assert for user=" + uid);
233 Assertions.assertEquals(before - delta, after.intValue());
rootf35409f2025-05-19 04:41:57 +0000234 System.out.println("Running rollback AddMagic assert for user=" + uid + ", delta=" + delta);
235 Assertions.assertFalse(tracker.AddMagic(uid, delta));
236 }))
237 .collect(Collectors.toList());
238 }
rootf35409f2025-05-19 04:41:57 +0000239 @TestFactory
240 Collection<DynamicTest> testAddRecord() {
241 Random rnd = new Random();
242 // 取所有 seed_id 用于外键测试
243 List<String> seedIds = em.createQuery(
244 "select s.seedid from Seed s", String.class
245 ).getResultList();
246 // 若无可用 seedId 则跳过此组测试,避免 rnd.nextInt(0) 抛错
247 // if (seedIds.isEmpty()) {
248 // return Collections.emptyList();
249 // }
250 return IntStream.range(0, 10)
251 .mapToObj(i -> DynamicTest.dynamicTest("AddRecord test #" + i, () -> {
252 // 随机构造 TransRecord
253 String uploaderId = userIds.get(rnd.nextInt(userIds.size()));
254 String downloaderId = userIds.get(rnd.nextInt(userIds.size()));
255 String seedId = seedIds.get(rnd.nextInt(seedIds.size()));
256 String taskId = UUID.randomUUID().toString();
rootf35409f2025-05-19 04:41:57 +0000257 TransRecord rd = new TransRecord();
258 rd.taskid = taskId;
259 rd.uploaduserid = uploaderId;
260 rd.downloaduserid = downloaderId;
261 rd.seedid = seedId;
262 rd.upload = rnd.nextInt(10000);
263 rd.download = rnd.nextInt(10000);
264 rd.maxupload = rd.upload + rnd.nextInt(10000);
265 rd.maxdownload = rd.download + rnd.nextInt(10000);
rootf35409f2025-05-19 04:41:57 +0000266 // 调用待测方法
267 int ret = tracker.AddRecord(rd);
268 Assertions.assertTrue(ret > 0, "返回值应为新记录主键");
rootf35409f2025-05-19 04:41:57 +0000269 // 验证已插入
270 TransportId pk = new TransportId(taskId, uploaderId, downloaderId);
271 TransRecord fetched = em.find(TransRecord.class, pk);
272 Assertions.assertNotNull(fetched, "应查询到新增的 TransRecord");
rootf35409f2025-05-19 04:41:57 +0000273 // 清理:删除测试记录
274 EntityTransaction tx = em.getTransaction();
275 tx.begin();
276 em.remove(fetched);
277 tx.commit();
rootff0769a2025-05-18 17:24:41 +0000278 }))
279 .collect(Collectors.toList());
280 }
rootd4959a82025-05-27 07:07:37 +0000281 @TestFactory
282 Collection<DynamicTest> testSaveTorrent() {
283 List<String> seedIds = em.createQuery(
284 "select s.seedid from Seed s", String.class
285 ).getResultList();
286 return seedIds.stream()
287 .map(sid -> DynamicTest.dynamicTest("SaveTorrent for seed " + sid, () -> {
288 // 准备一个临时空文件
289 File temp = File.createTempFile(sid + "_test", ".torrent");
290 // 调用 SaveTorrent
291 int ret = tracker.SaveTorrent(sid, temp);
292 Assertions.assertEquals(0, ret, "SaveTorrent 应返回 0");
rootd4959a82025-05-27 07:07:37 +0000293 // 验证文件已按约定存储
294 File stored = new File(config.TORRENT_STORAGE_DIR,
295 sid + "_" + temp.getName());
296 Assertions.assertTrue(stored.exists(), "存储文件应存在");
rootd4959a82025-05-27 07:07:37 +0000297 // 验证数据库中 url 字段已更新
298 em.clear();
299 Seed seed = em.find(Seed.class, sid);
300 // 将 seed.url 转为 File 再取绝对路径进行比较
301 Assertions.assertEquals(
302 stored.getAbsolutePath(),
303 new File(seed.url).getAbsolutePath(),
304 "Seed.url 应更新为存储路径"
305 );
rootd4959a82025-05-27 07:07:37 +0000306 // 清理测试文件
307 stored.delete();
308 temp.delete();
309 }))
310 .collect(Collectors.toList());
311 }
rootd4959a82025-05-27 07:07:37 +0000312 @TestFactory
313 Collection<DynamicTest> testGetTTorent() {
314 // 拿到所有 seedid
315 List<String> seedIds = em.createQuery(
316 "select s.seedid from Seed s", String.class
317 ).getResultList();
318 return seedIds.stream()
319 .map(sid -> DynamicTest.dynamicTest("GetTTorent for seed " + sid, () -> {
320 // 准备一个临时空文件并 SaveTorrent
321 File temp = File.createTempFile(sid + "_test", ".torrent");
322 int saveRet = tracker.SaveTorrent(sid, temp);
323 Assertions.assertEquals(0, saveRet, "SaveTorrent 应返回 0");
rootd4959a82025-05-27 07:07:37 +0000324 // 刷新上下文并取回更新后的 seed 实体
325 em.clear();
326 Seed seed = em.find(Seed.class, sid);
327 Assertions.assertNotNull(seed.url, "Seed.url 应已被更新");
rootd4959a82025-05-27 07:07:37 +0000328 // 调用 GetTTorent 并断言路径一致
329 String uid = userIds.get(0), ip = "127.0.0.1";
330 File ret = tracker.GetTTorent(sid, uid, ip);
331 File expected = new File(seed.url);
332 Assertions.assertNotNull(ret, "应返回文件对象");
333 Assertions.assertEquals(
334 expected.getAbsolutePath(),
335 ret.getAbsolutePath(),
336 "返回文件路径应与Seed.url一致"
337 );
rootd4959a82025-05-27 07:07:37 +0000338 // 清理:删掉本地文件,回滚 DB url 字段,删掉 temp
339 expected.delete();
340 EntityTransaction tx = em.getTransaction();
341 tx.begin();
342 seed.url = null;
343 em.merge(seed);
344 tx.commit();
345 temp.delete();
346 }))
347 .collect(Collectors.toList());
348 }
root33a7d952025-05-18 17:24:41 +0000349}