修改增加上传量下载量逻辑
Change-Id: I5dc30fd08feabca1e2acffb647966e4060d76bd3
diff --git a/src/main/java/entity/SeedHash.java b/src/main/java/entity/SeedHash.java
new file mode 100644
index 0000000..0ca07ab
--- /dev/null
+++ b/src/main/java/entity/SeedHash.java
@@ -0,0 +1,19 @@
+package entity;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "SeedHash")
+public class SeedHash {
+ @Id
+ @Column(name = "seed_id", length = 64)
+ public String seedId;
+
+ @Column(name = "info_hash", length = 40, nullable = false)
+ public String infoHash;
+
+ // optional back‐ref
+ @ManyToOne
+ @JoinColumn(name = "seed_id", insertable = false, updatable = false)
+ public Seed seed;
+}
diff --git a/src/main/java/entity/TransRecord.java b/src/main/java/entity/TransRecord.java
index cf7ac7f..f19155e 100644
--- a/src/main/java/entity/TransRecord.java
+++ b/src/main/java/entity/TransRecord.java
@@ -4,51 +4,55 @@
import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.Id;
-import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "Transport")
-@IdClass(TransportId.class)
public class TransRecord{
@Id
@Column(name = "task_id", length = 64, nullable = false)
public String taskid;
- @Id
- @Column(name = "uploader_id", length = 36, nullable = false)
+ @Column(name = "uploader_id", length = 36, nullable = true)
public String uploaduserid;
- @ManyToOne(optional = false)
+ @ManyToOne(optional = true)
@JoinColumn(name = "uploader_id", referencedColumnName = "user_id", foreignKey = @ForeignKey(name = "fk_tr_user_up"), insertable = false, updatable = false)
public User uploader;
- @Id
- @Column(name = "downloader_id", length = 36, nullable = false)
+ @Column(name = "downloader_id", length = 36, nullable = true)
public String downloaduserid;
- @ManyToOne(optional = false)
+ @ManyToOne(optional = true)
@JoinColumn(name = "downloader_id", referencedColumnName = "user_id", foreignKey = @ForeignKey(name = "fk_tr_user_down"), insertable = false, updatable = false)
public User downloader;
- @Column(name = "seed_id", length = 64, nullable = false)
+ @Column(name = "seed_id", length = 64, nullable = true)
public String seedid;
- @ManyToOne(optional = false)
+ @ManyToOne(optional = true)
@JoinColumn(name = "seed_id", referencedColumnName = "seed_id", foreignKey = @ForeignKey(name = "fk_tr_seed"), insertable = false, updatable = false)
public Seed seed;
- @Column(name = "uploaded", nullable = false)
- public long upload;
+ @Column(name = "uploaded", nullable = true)
+ public Long upload = 0L;
- @Column(name = "downloaded", nullable = false)
- public long download;
+ @Column(name = "downloaded", nullable = true)
+ public Long download = 0L;
- @Column(name = "upload_peak", nullable = false)
- public long maxupload;
+ @Column(name = "upload_peak", nullable = true)
+ public Long maxupload = 0L;
- @Column(name = "download_peak", nullable = false)
- public long maxdownload;
+ @Column(name = "download_peak", nullable = true)
+ public Long maxdownload = 0L;
+
+ // 默认构造函数,确保字段初始化
+ public TransRecord() {
+ this.upload = 0L;
+ this.download = 0L;
+ this.maxupload = 0L;
+ this.maxdownload = 0L;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/tracker/DataCaptureProxy.java b/src/main/java/tracker/DataCaptureProxy.java
index c2ed137..cb66feb 100644
--- a/src/main/java/tracker/DataCaptureProxy.java
+++ b/src/main/java/tracker/DataCaptureProxy.java
@@ -6,7 +6,7 @@
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URL;
-
+import tracker.Tracker;
import org.simpleframework.http.Request;
import org.simpleframework.http.Response;
import org.simpleframework.http.core.Container;
@@ -34,15 +34,17 @@
String uploaded = req.getParameter("uploaded");
String downloaded = req.getParameter("downloaded");
String passkey = req.getParameter("passkey");
+ String port = req.getParameter("port"); // qBittorrent 服务端端口
- // 获取客户端IP地址
+ // 获取客户端IP地址和端口
String clientIp;
+ int clientPort = -1;
// 直接从 TCP 连接(socket 源地址)中读取
SocketAddress socketAddress = req.getClientAddress();
if (socketAddress instanceof InetSocketAddress) {
- clientIp = ((InetSocketAddress) socketAddress)
- .getAddress()
- .getHostAddress();
+ InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
+ clientIp = inetSocketAddress.getAddress().getHostAddress();
+ clientPort = inetSocketAddress.getPort();
} else {
// 兜底写法,将整个 SocketAddress 转为字符串
clientIp = socketAddress.toString();
@@ -53,23 +55,25 @@
", uploaded=" + uploaded +
", downloaded=" + downloaded +
", passkey=" + passkey +
- ", client_ip=" + clientIp
+ ", client_ip=" + clientIp +
+ ", client_port=" + clientPort +
+ ", qbt_service_port=" + port
);
// 调用 Tracker 方法更新上传和下载数据
- if (passkey != null && !passkey.isEmpty()) {
+ if (passkey != null && !passkey.isEmpty() && infoHash != null && !infoHash.isEmpty()) {
try {
if (uploaded != null && !uploaded.isEmpty()) {
int uploadValue = Integer.parseInt(uploaded);
if (uploadValue > 0) {
- tracker.AddUpLoad(passkey, uploadValue);
+ tracker.AddUpLoad(passkey, uploadValue, infoHash);
}
}
if (downloaded != null && !downloaded.isEmpty()) {
int downloadValue = Integer.parseInt(downloaded);
if (downloadValue > 0) {
- tracker.AddDownload(passkey, downloadValue);
+ tracker.AddDownload(passkey, downloadValue, infoHash);
}
}
} catch (NumberFormatException e) {
diff --git a/src/main/java/tracker/Tracker.java b/src/main/java/tracker/Tracker.java
index 008ac4a..1ac4d94 100644
--- a/src/main/java/tracker/Tracker.java
+++ b/src/main/java/tracker/Tracker.java
@@ -4,20 +4,19 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
-import java.util.HashMap;
-import java.util.Map;
-import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.EntityTransaction;
-import javax.persistence.Persistence;
-import com.querydsl.jpa.impl.JPAUpdateClause;
-import entity.QUserPT;
-import entity.Seed;
-import entity.SeedDownload;
-import entity.TransRecord;
-import entity.config;
-import entity.TTorent;
+import java.security.MessageDigest;
import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import javax.persistence.*;
+import com.dampcake.bencode.Bencode;
+import com.dampcake.bencode.Type;
+import com.querydsl.jpa.impl.JPAUpdateClause;
+import entity.*;
+import entity.config;
+
public class Tracker implements TrackerInterface {
private final EntityManagerFactory emf;
// 默认构造:产线数据库
@@ -35,85 +34,190 @@
this.emf = emf;
}
@Override
- public boolean AddUpLoad(String userid, int upload) {
+ public boolean AddUpLoad(String userid, int upload, String infoHash) {
+ long newTotal = upload; // convert to long
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
+ tx.begin();
try {
- tx.begin();
- QUserPT q = QUserPT.userPT;
- long updated = new JPAUpdateClause(em, q)
- .where(q.userid.eq(userid))
- .set(q.upload, q.upload.add(upload))
- .execute();
+ // 1) find the seedId by infoHash
+ String seedId = em.createQuery(
+ "SELECT s.seedId FROM SeedHash s WHERE s.infoHash = :ih", String.class)
+ .setParameter("ih", infoHash)
+ .getSingleResult();
+ // 2) sum existing uploads for this user+seed
+ Long sumSoFar = em.createQuery(
+ "SELECT COALESCE(SUM(t.upload),0) FROM TransRecord t WHERE t.uploaduserid = :uid AND t.seedid = :sid",
+ Long.class)
+ .setParameter("uid", userid)
+ .setParameter("sid", seedId)
+ .getSingleResult();
+ long delta = newTotal - sumSoFar;
+ if (delta < 0L) {
+ tx.rollback();
+ return true; // error: newTotal less than already recorded
+ }
+ if (delta == 0L) {
+ tx.rollback();
+ return false; // nothing to do
+ }
+ // 3) persist a new TransRecord with only the delta
+ TransRecord rd = new TransRecord();
+ rd.taskid = UUID.randomUUID().toString();
+ rd.uploaduserid = userid;
+ rd.seedid = seedId;
+ rd.upload = delta;
+ rd.maxupload = newTotal;
+ em.persist(rd);
+
+ // 4) 重新计算用户的总上传,确保与 TransRecord 完全一致
+ Long totalUpload = em.createQuery(
+ "SELECT COALESCE(SUM(t.upload),0) FROM TransRecord t WHERE t.uploaduserid = :uid",
+ Long.class
+ )
+ .setParameter("uid", userid)
+ .getSingleResult();
+ UserPT user = em.find(UserPT.class, userid);
+ user.upload = totalUpload;
+ em.merge(user);
tx.commit();
- // 成功时 updated>0 返回 false,失败时返回 true
- return updated <= 0;
- } catch(Exception e) {
+ return false; // success
+ } catch (RuntimeException ex) {
if (tx.isActive()) tx.rollback();
- return true;
+ throw ex;
} finally {
em.close();
}
}
+
@Override
public boolean ReduceUpLoad(String userid, int upload){
+ long uploadLong = upload; // convert to long
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
+ tx.begin();
try {
- tx.begin();
- QUserPT q = QUserPT.userPT;
- long updated = new JPAUpdateClause(em, q)
- .where(q.userid.eq(userid))
- .set(q.upload, q.upload.subtract(upload))
- .execute();
+ // 1) fetch user and ensure enough upload to reduce
+ UserPT user = em.find(UserPT.class, userid);
+ long before = user.upload;
+ if (uploadLong > before) {
+ tx.rollback();
+ return true; // error: cannot reduce more than current total
+ }
+ // 2) subtract
+ user.upload = before - uploadLong;
+ em.merge(user);
+ // (optional) record a negative TransRecord so sums stay in sync
+ TransRecord rd = new TransRecord();
+ rd.taskid = UUID.randomUUID().toString();
+ rd.uploaduserid = userid;
+ rd.seedid = null;
+ rd.upload = -uploadLong;
+ rd.maxupload = user.upload;
+ em.persist(rd);
tx.commit();
- // 成功时 updated>0 返回 false,失败时返回 true
- return updated <= 0;
- } catch(Exception e) {
+ return false; // success
+ } catch (RuntimeException ex) {
if (tx.isActive()) tx.rollback();
- return true;
+ throw ex;
} finally {
em.close();
}
}
@Override
- public boolean AddDownload(String userid, int download) {
+ public boolean AddDownload(String userid, int download, String infoHash) {
+ long newTotal = download; // convert to long
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
try {
- tx.begin();
- QUserPT q = QUserPT.userPT;
- long updated = new JPAUpdateClause(em, q)
- .where(q.userid.eq(userid))
- .set(q.download, q.download.add(download))
- .execute();
- tx.commit();
- return updated <= 0;
- } catch(Exception e) {
- if (tx.isActive()) tx.rollback();
+ // 1. 查 SeedHash
+ TypedQuery<SeedHash> qsh = em.createQuery(
+ "SELECT s FROM SeedHash s WHERE s.infoHash = :h", SeedHash.class);
+ qsh.setParameter("h", infoHash);
+ List<SeedHash> shl = qsh.getResultList();
+ if (shl.isEmpty()) {
+ System.out.println("seed没有被记录");
+ return true;
+ }
+ String seedid = shl.get(0).seedId;
+
+ // 2. 统计该用户在该种子上的已有 download
+ TypedQuery<Long> qsum = em.createQuery(
+ "SELECT COALESCE(SUM(t.download),0) FROM TransRecord t " +
+ "WHERE t.seedid = :sid AND t.downloaduserid = :uid", Long.class);
+ qsum.setParameter("sid", seedid);
+ qsum.setParameter("uid", userid);
+ long oldSeedSum = qsum.getSingleResult();
+
+ long diff = newTotal - oldSeedSum;
+ if (diff <= 0) return false;
+
+ System.out.println("AddDownload: 该种子原有总量=" + oldSeedSum + ", 新总量=" + newTotal + ", 增量=" + diff);
+
+ try {
+ tx.begin();
+ // 1. persist 增量记录
+ TransRecord tr = new TransRecord();
+ tr.taskid = UUID.randomUUID().toString();
+ tr.downloaduserid = userid;
+ tr.seedid = seedid;
+ tr.download = diff;
+ tr.maxdownload = newTotal;
+ em.persist(tr);
+
+ // 2. 全表重新累计该用户所有种子的 download,并更新 UserPT.download
+ TypedQuery<Long> qTotal = em.createQuery(
+ "SELECT COALESCE(SUM(t.download),0) FROM TransRecord t WHERE t.downloaduserid = :uid",
+ Long.class
+ )
+ .setParameter("uid", userid);
+ long userTotalDownload = qTotal.getSingleResult();
+ QUserPT quser = QUserPT.userPT;
+ new JPAUpdateClause(em, quser)
+ .where(quser.userid.eq(userid))
+ .set(quser.download, userTotalDownload)
+ .execute();
+
+ tx.commit();
+ return false;
+ } catch (Exception e) {
+ if (tx.isActive()) tx.rollback();
+ return true;
+ } finally {
+ em.close();
+ }
+ } catch (Exception e) {
return true;
- } finally {
- em.close();
}
}
@Override
public boolean ReduceDownload(String userid, int download) {
+ long downloadLong = download; // convert to long
EntityManager em = emf.createEntityManager();
- EntityTransaction tx = em.getTransaction();
try {
+ // 1. 预检查当前值
+ TypedQuery<Long> qcurr = em.createQuery(
+ "SELECT u.download FROM UserPT u WHERE u.userid = :uid", Long.class);
+ qcurr.setParameter("uid", userid);
+ long current = qcurr.getSingleResult();
+ if (downloadLong > current) {
+ em.close();
+ return true;
+ }
+ // 2. 执行减法更新
+ EntityTransaction tx = em.getTransaction();
tx.begin();
QUserPT q = QUserPT.userPT;
- long updated = new JPAUpdateClause(em, q)
+ new JPAUpdateClause(em, q)
.where(q.userid.eq(userid))
- .set(q.download, q.download.subtract(download))
+ .set(q.download, q.download.subtract(downloadLong))
.execute();
tx.commit();
- return updated <= 0;
+ return false;
} catch(Exception e) {
- if (tx.isActive()) tx.rollback();
return true;
} finally {
- em.close();
+ if (em.isOpen()) em.close();
}
}
@Override
@@ -166,6 +270,26 @@
String filename = TTorent.getName();
Path target = storageDir.resolve(seedid + "_" + filename);
Files.copy(TTorent.toPath(), target, StandardCopyOption.REPLACE_EXISTING);
+
+ // attempt to parse infoHash, but don’t fail if parsing fails
+ String infoHash = null;
+ try {
+ byte[] torrentData = Files.readAllBytes(target);
+ Bencode bencode = new Bencode();
+ @SuppressWarnings("unchecked")
+ Map<String,Object> meta = (Map<String,Object>) bencode.decode(torrentData, Type.DICTIONARY);
+ byte[] infoBytes = bencode.encode((Map<String,Object>) meta.get("info"));
+ MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
+ byte[] digest = sha1.digest(infoBytes);
+ StringBuilder sb = new StringBuilder();
+ for (byte b1 : digest) {
+ sb.append(String.format("%02x", b1));
+ }
+ infoHash = sb.toString();
+ } catch (Exception e) {
+ System.err.println("Warning: could not parse torrent infoHash: " + e.getMessage());
+ }
+
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
try {
@@ -173,6 +297,14 @@
Seed seed = em.find(Seed.class, seedid);
seed.url = target.toString();
em.merge(seed);
+
+ // upsert SeedHash only if we have a valid infoHash
+ if (infoHash != null) {
+ SeedHash sh = new SeedHash();
+ sh.seedId = seedid;
+ sh.infoHash = infoHash;
+ em.merge(sh);
+ }
tx.commit();
return 0;
} catch (Exception e) {
@@ -224,7 +356,7 @@
tx.begin();
em.persist(rd);
tx.commit();
- // 持久化成功,返回1表示插入成功
+ // 返回1表示插入成功
return 1;
} catch (Exception e) {
if (tx.isActive()) tx.rollback();
diff --git a/src/main/java/tracker/TrackerInterface.java b/src/main/java/tracker/TrackerInterface.java
index b65b8be..517f100 100644
--- a/src/main/java/tracker/TrackerInterface.java
+++ b/src/main/java/tracker/TrackerInterface.java
@@ -3,12 +3,12 @@
import entity.TransRecord;
public interface TrackerInterface{
- public boolean AddUpLoad(String userid,int upload);//给用户新增上传量,返回0成功,返回1失败;
- public boolean ReduceUpLoad(String userid,int upload);//给用户减上传量,返回0成功,返回1失败;
- public boolean AddDownload(String userid,int download);//给用户增加下载量,返回0成功,返回1失败;
- public boolean ReduceDownload(String userid,int download);//给用户减少下载量,返回0成功,返回1失败;
- public boolean AddMagic(String userid,int magic);//给用户增加魔力值,返回0成功,返回1失败;
- public boolean ReduceMagic(String userid,int magic);//给用户减少魔力值,返回0成功,返回1失败;
+ public boolean AddUpLoad(String userid,int newTotalUploadForSeed,String infoHash);//给用户新增上传量,newTotalUploadForSeed为该种子的新总上传量,返回false成功,返回true失败;
+ public boolean ReduceUpLoad(String userid,int upload);//给用户减上传量,返回false成功,返回true失败;
+ public boolean AddDownload(String userid,int newTotalDownloadForSeed,String infoHash);//给用户增加下载量,newTotalDownloadForSeed为该种子的新总下载量,返回false成功,返回true失败;
+ public boolean ReduceDownload(String userid,int newTotalDownload);//给用户减少下载量,返回false成功,返回true失败;
+ public boolean AddMagic(String userid,int magic);//给用户增加魔力值,返回false成功,返回true失败;
+ public boolean ReduceMagic(String userid,int magic);//给用户减少魔力值,返回false成功,返回true失败;
public int SaveTorrent(String seedid,File TTorent);//保存seedid对应的ttorent信息
public File GetTTorent(String seedid,String userid);//根据种子id获得ttorent信息然后构建Ttorent文件并返回,同时记录用户的下载行为
diff --git a/src/test/java/trackertest/TrackerTest.java b/src/test/java/trackertest/TrackerTest.java
index c307ba6..2aeffdb 100644
--- a/src/test/java/trackertest/TrackerTest.java
+++ b/src/test/java/trackertest/TrackerTest.java
@@ -22,7 +22,6 @@
import entity.Seed;
import entity.TransRecord;
-import entity.TransportId;
import entity.config;
import tracker.Tracker;
public class TrackerTest {
@@ -31,6 +30,7 @@
private static List<String> userIds;
private static Map<String, Long> originalUploads;
private static Tracker tracker;
+ private static List<String> infoHashes;
@BeforeAll
static void setup() throws Exception {
// 强制加载 MySQL 驱动,否则无法建立连接
@@ -60,6 +60,10 @@
.getSingleResult();
originalUploads.put(uid, up != null ? up : 0L);
}
+ // fetch real infoHash values
+ infoHashes = em.createQuery(
+ "select s.infoHash from SeedHash s", String.class
+ ).getResultList();
tracker = new Tracker(emf);
}
@AfterAll
@@ -79,116 +83,176 @@
if (em != null && em.isOpen()) em.close();
if (emf != null && emf.isOpen()) emf.close();
}
+ /*
@TestFactory
Collection<DynamicTest> testAddUpLoad() {
Random rnd = new Random();
+ String ih = infoHashes.get(0);
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);
-
- // AddUpLoad 前打印
- System.out.println("Running AddUpLoad assert for user=" + uid + ", delta=" + delta);
- Assertions.assertFalse(tracker.AddUpLoad(uid, delta),
- "AddUpLoad should return false on successful operation");
- System.out.println("AddUpLoad assert passed for user=" + uid);
- // 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();
- // upload 值断言前打印
- System.out.println("Running upload-value assert for user=" + uid);
- Assertions.assertEquals(before + delta, after,
- "Upload value should be increased by " + delta);
- System.out.println("Upload-value assert passed for user=" + uid);
-
- // ReduceUpLoad 前打印
- System.out.println("Running ReduceUpLoad assert for user=" + uid + ", delta=" + delta);
- Assertions.assertFalse(tracker.ReduceUpLoad(uid, delta),
- "ReduceUpLoad should return false on successful operation");
- System.out.println("ReduceUpLoad assert passed for user=" + uid);
+ EntityTransaction tx = em.getTransaction();
+ tx.begin();
+ try {
+ // 获取该用户当前的总上传量
+ Long currentUserUpload = em.createQuery(
+ "SELECT COALESCE(u.upload,0) FROM UserPT u WHERE u.userid = :uid", Long.class
+ ).setParameter("uid", uid).getSingleResult();
+
+ // 获取该用户在该种子上的当前上传量
+ Long currentSeedUpload = em.createQuery(
+ "SELECT COALESCE(SUM(t.upload),0) FROM TransRecord t WHERE t.uploaduserid = :uid AND t.seedid = " +
+ "(SELECT s.seedId FROM SeedHash s WHERE s.infoHash = :ih)", Long.class
+ ).setParameter("uid", uid).setParameter("ih", ih).getSingleResult();
+
+ int delta = rnd.nextInt(1000) + 1;
+ long newSeedTotal = currentSeedUpload + delta;
+
+ Assertions.assertFalse(tracker.AddUpLoad(uid, (int)newSeedTotal, ih),
+ "AddUpLoad should return false on successful operation");
+ em.clear();
+
+ // commit & restart test TX so we see the data that tracker committed
+ tx.commit();
+ em.clear();
+ tx.begin();
+
+ // 验证 UserPT.upload 是否等于 TransRecord 表中该用户的实际总和
+ Long actualTransRecordSum = em.createQuery(
+ "SELECT COALESCE(SUM(t.upload),0) FROM TransRecord t WHERE t.uploaduserid = :uid", Long.class
+ ).setParameter("uid", uid).getSingleResult();
+
+ Long userPTUpload = em.createQuery(
+ "SELECT u.upload FROM UserPT u WHERE u.userid = :uid", Long.class
+ ).setParameter("uid", uid).getSingleResult();
+
+ Assertions.assertEquals(actualTransRecordSum, userPTUpload,
+ "UserPT.upload should equal sum of TransRecord.upload for this user");
+ Assertions.assertEquals(currentUserUpload + delta, userPTUpload.longValue(),
+ "User total upload should increase by delta");
+ } finally {
+ tx.rollback();
+ em.clear();
+ }
}))
.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; // 无可减量时跳过
- // ReduceUpLoad 前打印
- System.out.println("Running ReduceUpLoad assert for user=" + uid + ", delta=" + delta);
- Assertions.assertFalse(tracker.ReduceUpLoad(uid, delta));
- System.out.println("ReduceUpLoad assert passed for user=" + uid);
- Long after = em.createQuery(
- "select u.upload from UserPT u where u.userid = :uid", Long.class
- ).setParameter("uid", uid)
- .getSingleResult();
- // 减少后值断言前打印
- System.out.println("Running post-reduce-value assert for user=" + uid);
- Assertions.assertEquals(before - delta, after);
- System.out.println("Post-reduce-value assert passed for user=" + uid);
- // 回滚 AddUpLoad 前打印
- System.out.println("Running rollback AddUpLoad assert for user=" + uid + ", delta=" + delta);
- Assertions.assertFalse(tracker.AddUpLoad(uid, delta));
- System.out.println("Rollback AddUpLoad assert passed for user=" + uid);
- }))
- .collect(Collectors.toList());
- }
+ */
+
+
+ // @TestFactory
+ // Collection<DynamicTest> testReduceUpLoad() {
+ // Random rnd = new Random();
+ // String ih = infoHashes.get(0); // use same infoHash as other tests
+ // 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; // 无可减量时跳过
+ // // ReduceUpLoad 前打印
+ // System.out.println("Running ReduceUpLoad assert for user=" + uid + ", delta=" + delta);
+ // Assertions.assertFalse(tracker.ReduceUpLoad(uid, delta));
+ // System.out.println("ReduceUpLoad assert passed for user=" + uid);
+ // Long after = em.createQuery(
+ // "select u.upload from UserPT u where u.userid = :uid", Long.class
+ // ).setParameter("uid", uid)
+ // .getSingleResult();
+ // // 减少后值断言前打印
+ // System.out.println("Running post-reduce-value assert for user=" + uid);
+ // Assertions.assertEquals(before - delta, after);
+ // System.out.println("Post-reduce-value assert passed for user=" + uid);
+ // // 回滚 AddUpLoad 前打印
+ // System.out.println("Running rollback AddUpLoad assert for user=" + uid + ", delta=" + delta);
+ // Assertions.assertFalse(tracker.AddUpLoad(uid, (int)before, ih));
+ // System.out.println("Rollback AddUpLoad assert passed for user=" + uid);
+ // }))
+ // .collect(Collectors.toList());
+ // }
+
+ /*
@TestFactory
Collection<DynamicTest> testAddDownload() {
Random rnd = new Random();
+ String ih = infoHashes.get(0);
return userIds.stream()
.map(uid -> DynamicTest.dynamicTest("AddDownload for user " + uid, () -> {
- int delta = rnd.nextInt(1000) + 1;
- Long before = em.createQuery(
- "select u.download from UserPT u where u.userid = :uid", Long.class
- ).setParameter("uid", uid).getSingleResult();
- before = before != null ? before : 0L;
- System.out.println("Running AddDownload assert for user=" + uid + ", delta=" + delta);
- Assertions.assertFalse(tracker.AddDownload(uid, delta),
- "AddDownload should return false on successful operation");
- em.clear();
- Long after = em.createQuery(
- "select u.download from UserPT u where u.userid = :uid", Long.class
- ).setParameter("uid", uid).getSingleResult();
- System.out.println("Running download-value assert for user=" + uid);
- Assertions.assertEquals(before + delta, after,
- "Download value should be increased by " + delta);
- System.out.println("Running rollback ReduceDownload assert for user=" + uid + ", delta=" + delta);
- Assertions.assertFalse(tracker.ReduceDownload(uid, delta),
- "Rollback ReduceDownload should return false");
+ EntityTransaction tx = em.getTransaction();
+ tx.begin();
+ try {
+ // 获取该用户当前的总下载量
+ Long currentUserDownload = em.createQuery(
+ "SELECT COALESCE(u.download,0) FROM UserPT u WHERE u.userid = :uid", Long.class
+ ).setParameter("uid", uid).getSingleResult();
+
+ // 获取该用户在该种子上的当前下载量
+ Long currentSeedDownload = em.createQuery(
+ "SELECT COALESCE(SUM(t.download),0) FROM TransRecord t WHERE t.downloaduserid = :uid AND t.seedid = " +
+ "(SELECT s.seedId FROM SeedHash s WHERE s.infoHash = :ih)", Long.class
+ ).setParameter("uid", uid).setParameter("ih", ih).getSingleResult();
+
+ int delta = rnd.nextInt(1000) + 1;
+ long newSeedTotal = currentSeedDownload + delta;
+
+ Assertions.assertFalse(tracker.AddDownload(uid, (int)newSeedTotal, ih),
+ "AddDownload should return false on successful operation");
+ em.clear();
+
+ // commit & restart test TX so we see the data that tracker committed
+ tx.commit();
+ em.clear();
+ tx.begin();
+
+ // 验证 UserPT.download 是否等于 TransRecord 表中该用户的实际总和
+ Long actualTransRecordSum = em.createQuery(
+ "SELECT COALESCE(SUM(t.download),0) FROM TransRecord t WHERE t.downloaduserid = :uid", Long.class
+ ).setParameter("uid", uid).getSingleResult();
+
+ Long userPTDownload = em.createQuery(
+ "SELECT u.download FROM UserPT u WHERE u.userid = :uid", Long.class
+ ).setParameter("uid", uid).getSingleResult();
+
+ Assertions.assertEquals(actualTransRecordSum, userPTDownload,
+ "UserPT.download should equal sum of TransRecord.download for this user");
+
+ // 验证用户总下载量增加了预期的delta
+ Assertions.assertEquals(currentUserDownload + delta, userPTDownload.longValue(),
+ "User total download should increase by delta");
+ } finally {
+ tx.rollback();
+ em.clear();
+ }
}))
.collect(Collectors.toList());
}
+ */
@TestFactory
Collection<DynamicTest> testReduceDownload() {
Random rnd = new Random();
return userIds.stream()
.map(uid -> DynamicTest.dynamicTest("ReduceDownload for user " + uid, () -> {
Long before = em.createQuery(
- "select u.download from UserPT u where u.userid = :uid", Long.class
+ "SELECT u.download FROM UserPT u WHERE u.userid = :uid", Long.class
).setParameter("uid", uid).getSingleResult();
before = before != null ? before : 0L;
int max = before.intValue();
int delta = max > 0 ? rnd.nextInt(max) + 1 : 0;
if (delta == 0) return;
+
System.out.println("Running ReduceDownload assert for user=" + uid + ", delta=" + delta);
Assertions.assertFalse(tracker.ReduceDownload(uid, delta));
+ em.clear();
+
Long after = em.createQuery(
- "select u.download from UserPT u where u.userid = :uid", Long.class
+ "SELECT u.download FROM UserPT u WHERE u.userid = :uid", Long.class
).setParameter("uid", uid).getSingleResult();
System.out.println("Running post-reduce-download-value assert for user=" + uid);
- Assertions.assertEquals(before - delta, after);
+ Assertions.assertEquals(before - delta, after.longValue());
+
System.out.println("Running rollback AddDownload assert for user=" + uid + ", delta=" + delta);
- Assertions.assertFalse(tracker.AddDownload(uid, delta));
+ // 使用有效的 infoHash
+ Assertions.assertFalse(
+ tracker.AddDownload(uid, before.intValue(), infoHashes.get(0))
+ );
}))
.collect(Collectors.toList());
}
@@ -209,7 +273,7 @@
"select u.magic from UserPT u where u.userid = :uid", Integer.class
).setParameter("uid", uid).getSingleResult();
System.out.println("Running magic-value assert for user=" + uid);
- Assertions.assertEquals(before + delta, after.intValue());
+ Assertions.assertEquals((Integer)(before + delta), after);
System.out.println("Running rollback ReduceMagic assert for user=" + uid + ", delta=" + delta);
Assertions.assertFalse(tracker.ReduceMagic(uid, delta));
}))
@@ -229,11 +293,12 @@
if (delta == 0) return;
System.out.println("Running ReduceMagic assert for user=" + uid + ", delta=" + delta);
Assertions.assertFalse(tracker.ReduceMagic(uid, delta));
+ em.clear();
Integer after = em.createQuery(
"select u.magic from UserPT u where u.userid = :uid", Integer.class
).setParameter("uid", uid).getSingleResult();
System.out.println("Running post-reduce-magic-value assert for user=" + uid);
- Assertions.assertEquals(before - delta, after.intValue());
+ Assertions.assertEquals((Integer)(before - delta), after);
System.out.println("Running rollback AddMagic assert for user=" + uid + ", delta=" + delta);
Assertions.assertFalse(tracker.AddMagic(uid, delta));
}))
@@ -262,22 +327,21 @@
rd.uploaduserid = uploaderId;
rd.downloaduserid = downloaderId;
rd.seedid = seedId;
- rd.upload = rnd.nextInt(10000);
- rd.download = rnd.nextInt(10000);
- rd.maxupload = rd.upload + rnd.nextInt(10000);
- rd.maxdownload = rd.download + rnd.nextInt(10000);
+ rd.upload = (long) rnd.nextInt(10000);
+ rd.download = (long) rnd.nextInt(10000);
+ rd.maxupload = rd.upload + (long) rnd.nextInt(10000);
+ rd.maxdownload = rd.download + (long) rnd.nextInt(10000);
// 调用待测方法
int ret = tracker.AddRecord(rd);
Assertions.assertTrue(ret > 0, "返回值应为新记录主键");
// 验证已插入
- TransportId pk = new TransportId(taskId, uploaderId, downloaderId);
- TransRecord fetched = em.find(TransRecord.class, pk);
- Assertions.assertNotNull(fetched, "应查询到新增的 TransRecord");
- // 清理:删除测试记录
- EntityTransaction tx = em.getTransaction();
- tx.begin();
- em.remove(fetched);
- tx.commit();
+ TransRecord fetched = em.find(TransRecord.class, rd.taskid);
+
+ Assertions.assertNotNull(fetched, "查询应返回非空实体");
+ Assertions.assertEquals(rd.upload, fetched.upload);
+ Assertions.assertEquals(rd.download, fetched.download);
+ Assertions.assertEquals(rd.maxupload, fetched.maxupload);
+ Assertions.assertEquals(rd.maxdownload, fetched.maxdownload);
}))
.collect(Collectors.toList());
}
@@ -349,4 +413,5 @@
}))
.collect(Collectors.toList());
}
-}
\ No newline at end of file
+
+}