Skip to content

Commit

Permalink
feat: add junit test for java code
Browse files Browse the repository at this point in the history
添加 Java 代码及单元测试
  • Loading branch information
yanglbme committed Sep 22, 2019
1 parent 8735131 commit 2e2c789
Show file tree
Hide file tree
Showing 11 changed files with 389 additions and 3 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
| 2 | Redis 使用手册[2019] | 黄健宏 | 帮助读者学习如何将 Redis 应用到实际开发中,内容涵盖最新的 Redis 5。 |


学习下面知识之前,先来[感受一波 Redis 面试连环炮](/docs/redis-interview.md)

## Redis 数据结构与应用

### [String 字符串](/docs/redis-string-introduction.md)
Expand Down
2 changes: 2 additions & 0 deletions java/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ repositories {
dependencies {
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.2'
compile group: 'redis.clients', name: 'jedis', version: '3.1.0'
compile group: 'commons-codec', name: 'commons-codec', version: '1.13'

}
102 changes: 102 additions & 0 deletions java/src/main/java/LoginSession.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import org.apache.commons.codec.binary.Hex;
import redis.clients.jedis.Jedis;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Random;


public class LoginSession {

private final String SESSION_TOKEN_KEY = "SESSION:TOKEN";
private final String SESSION_EXPIRE_TS_KEY = "SESSION:EXPIRE";

private final String SESSION_NOT_LOGIN = "SESSION_NOT_LOGIN";
private final String SESSION_EXPIRE = "SESSION_EXPIRE";
private final String SESSION_TOKEN_CORRECT = "SESSION_TOKEN_CORRECT";
private final String SESSION_TOKEN_INCORRECT = "SESSION_TOKEN_INCORRECT";

private Jedis client;
private String userId;

public LoginSession(Jedis client, String userId) {
this.client = client;
this.userId = userId;
}

/**
* 生成随机token
*
* @return token
*/
private String generateToken() {
byte[] b = new byte[256];
new Random().nextBytes(b);

MessageDigest messageDigest;

String sessionToken = "";
try {
messageDigest = MessageDigest.getInstance("SHA-256");
byte[] hash = messageDigest.digest(b);
sessionToken = Hex.encodeHexString(hash);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return sessionToken;
}

/**
* 创建会话,并返回token
*
* @param timeout 过期时长
* @return token
*/
public String create(int timeout) {
String token = generateToken();
long expireTime = Instant.now().getEpochSecond() + timeout;
client.hset(SESSION_TOKEN_KEY, userId, token);
client.hset(SESSION_EXPIRE_TS_KEY, userId, String.valueOf(expireTime));
return token;
}

public String create() {
// 设置默认过期时长
int defaultTimeout = 30 * 24 * 3600;
return create(defaultTimeout);
}

/**
* 校验token
*
* @param token 输入的token
* @return 校验结果
*/
public String validate(String token) {
String sessionToken = client.hget(SESSION_TOKEN_KEY, userId);
String expireTimeStr = client.hget(SESSION_EXPIRE_TS_KEY, userId);

if (sessionToken == null || expireTimeStr == null) {
return SESSION_NOT_LOGIN;
}

Long expireTime = Long.parseLong(expireTimeStr);
if (Instant.now().getEpochSecond() > expireTime) {
return SESSION_EXPIRE;
}

if (sessionToken.equals(token)) {
return SESSION_TOKEN_CORRECT;
}
return SESSION_TOKEN_INCORRECT;
}

/**
* 销毁会话
*/
public void destroy() {
client.hdel(SESSION_TOKEN_KEY, userId);
client.hdel(SESSION_EXPIRE_TS_KEY, userId);
}
}
45 changes: 45 additions & 0 deletions java/src/main/java/Paginate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import redis.clients.jedis.Jedis;

import java.util.List;

public class Paginate {

private Jedis client;
private String key;

public Paginate(Jedis client, String key) {
this.client = client;
this.key = key;
}

/**
* 添加元素到分页列表中
*
* @param item 元素
*/
public void add(String item) {
client.lpush(key, item);
}

/**
* 根据页码取出指定数量的元素
*
* @param page 页码
* @param pageSize 数量
* @return 元素列表
*/
public List<String> getPage(int page, int pageSize) {
long start = (page - 1) * pageSize;
long end = page * pageSize - 1;
return client.lrange(key, start, end);
}

/**
* 获取列表的元素数量
*
* @return 总数
*/
public Long getTotalCount() {
return client.llen(key);
}
}
67 changes: 67 additions & 0 deletions java/src/main/java/Ranking.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Tuple;

import java.util.Calendar;
import java.util.Set;

/**
* @author bingoyang
* @date 2019/9/7
*/
public class Ranking {
private Jedis client = new Jedis();
private Calendar calendar = Calendar.getInstance();

public Ranking() {
client.flushAll();
calendar.setFirstDayOfWeek(Calendar.MONDAY);
}

private String getDayRankKey() {
return String.format("rank:day:%s%s%s", calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
}

private String getWeekRankKey() {
return String.format("rank:week:%s%s", calendar.get(Calendar.YEAR), calendar.get(Calendar.WEEK_OF_YEAR));
}

private String getMonthRankKey() {
return String.format("rank:month:%s%s", calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH));
}

public void incr(String user, double score) {
client.zincrby(getDayRankKey(), score, user);
client.zincrby(getWeekRankKey(), score, user);
client.zincrby(getMonthRankKey(), score, user);
}

/**
* 获取日榜单topN
*
* @param n 前n位
* @return 结果集合
*/
public Set<Tuple> getTodayTopNWithScores(long n) {
return client.zrevrangeWithScores(getDayRankKey(), 0, n - 1);
}

/**
* 获取周榜单topN
*
* @param n 前n位
* @return 结果集合
*/
public Set<Tuple> getWeekTopNWithScores(long n) {
return client.zrevrangeWithScores(getWeekRankKey(), 0, n - 1);
}

/**
* 获取月榜单topN
*
* @param n 前n位
* @return 结果集合
*/
public Set<Tuple> getMonthTopNWithScores(long n) {
return client.zrevrangeWithScores(getMonthRankKey(), 0, n - 1);
}
}
55 changes: 55 additions & 0 deletions java/src/main/java/URLShorten.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import redis.clients.jedis.Jedis;

public class URLShorten {
private Jedis client;

private final String URL_HASH_SHORT_SOURCE_KEY = "url_hash:short_source";
private final String ID_COUNTER = "short_url:id_counter";

/**
* 将10进制数转换为36进制字符串
*
* @param number 10进制数
* @return 36进制字符串
*/
private String base10ToBase36(long number) {
String alphabets = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] chars = alphabets.toCharArray();
StringBuilder result = new StringBuilder();
while (number != 0) {
int i = (int) number % 36;
number /= 36;
result.insert(0, chars[i]);
}
return result.toString();
}

public URLShorten(Jedis client) {
this.client = client;
// 设置初始ID值,保留1-5位的短码,从6位的短码开始生成
this.client.set(ID_COUNTER, String.valueOf((long) Math.pow(36, 5) - 1));
}

/**
* 对源网址进行缩短,返回短网址ID
*
* @param sourceUrl 源网址
* @return 短网址ID
*/
public String shorten(String sourceUrl) {
long newId = client.incr(ID_COUNTER);
String shortId = base10ToBase36(newId);
client.hset(URL_HASH_SHORT_SOURCE_KEY, shortId, sourceUrl);
return shortId;
}

/**
* 根据短网址ID,返回对应的源网址
*
* @param shortId 短网址ID
* @return 源网址
*/
public String restore(String shortId) {
return client.hget(URL_HASH_SHORT_SOURCE_KEY, shortId);
}
}
2 changes: 1 addition & 1 deletion java/src/test/java/DistributedLockTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
public class DistributedLockTest {

@Test
public void test() throws InterruptedException {
public void testDistributedLock() throws InterruptedException {
Jedis jedis = new Jedis();
jedis.flushAll();

Expand Down
26 changes: 26 additions & 0 deletions java/src/test/java/LoginSessionTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class LoginSessionTest {

@Test
public void testLoginSession() {
Jedis client = new Jedis();
client.flushAll();
LoginSession session = new LoginSession(client, "bingo");

String token = session.create();

String res = session.validate("this is a wrong token");
assertEquals( "SESSION_TOKEN_INCORRECT", res);

res = session.validate(token);
assertEquals("SESSION_TOKEN_CORRECT", res);

session.destroy();
res = session.validate(token);
assertEquals("SESSION_NOT_LOGIN", res);
}
}
36 changes: 36 additions & 0 deletions java/src/test/java/PaginateTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;

import java.util.Arrays;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class PaginateTest {

@Test
public void testPaginate() {
Jedis client = new Jedis();
client.flushAll();

Paginate topics = new Paginate(client, "user-topics");
for (int i = 0; i < 24; ++i) {
topics.add(i + "");
}

// 取总数
assertEquals(24, topics.getTotalCount());

// 以每页5条数据的方式取出第1页数据
assertEquals(Arrays.asList("23", "22", "21", "20", "19"),
topics.getPage(1, 5));

// 以每页10条数据的方式取出第1页数据
assertEquals(Arrays.asList("23", "22", "21", "20", "19", "18", "17", "16", "15", "14"),
topics.getPage(1, 10));

// 以每页5条数据的方式取出第5页数据
assertEquals(Arrays.asList("3", "2", "1", "0"),
topics.getPage(5, 5));

}
}
31 changes: 31 additions & 0 deletions java/src/test/java/RankingTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Tuple;

import java.util.HashSet;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;


public class RankingTest {

@Test
public void testRanking() {
Ranking ranking = new Ranking();

ranking.incr("bingo", 5);
ranking.incr("iris", 3);
ranking.incr("lily", 4);
ranking.incr("helen", 6);

Set<Tuple> expectResult = new HashSet<Tuple>() {{
add(new Tuple("helen", 6.0));
add(new Tuple("bingo", 5.0));
}};
assertEquals(expectResult, ranking.getTodayTopNWithScores(2));
assertEquals(expectResult, ranking.getWeekTopNWithScores(2));

expectResult.add(new Tuple("lily", 4.0));
assertEquals(expectResult, ranking.getMonthTopNWithScores(3));
}
}
Loading

0 comments on commit 2e2c789

Please sign in to comment.