Skip to content

Commit 05fecda

Browse files
committed
test: add txn test
Signed-off-by: iGxnon <[email protected]>
1 parent 0f718d1 commit 05fecda

File tree

3 files changed

+187
-10
lines changed

3 files changed

+187
-10
lines changed

jxline-core/src/main/java/cloud/xline/jxline/op/TxnImpl.java

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
import java.util.List;
66
import java.util.concurrent.CompletableFuture;
77
import java.util.function.Function;
8+
import java.util.stream.Stream;
89

910
import cloud.xline.jxline.Txn;
1011
import cloud.xline.jxline.kv.TxnResponse;
11-
import com.xline.protobuf.Command;
12-
import com.xline.protobuf.RequestWithToken;
13-
import com.xline.protobuf.TxnRequest;
12+
import com.xline.protobuf.*;
1413
import io.etcd.jetcd.ByteSequence;
1514

1615
import com.google.common.annotations.VisibleForTesting;
@@ -108,8 +107,55 @@ private Command toTxnRequest() {
108107
requestBuilder.addFailure(o.toRequestOp(namespace));
109108
}
110109

110+
TxnRequest txnReq = requestBuilder.build();
111+
111112
return Command.newBuilder()
112-
.setRequest(RequestWithToken.newBuilder().setTxnRequest(requestBuilder).build())
113+
.addAllKeys(getTxnReqKeyRanges(txnReq))
114+
.setRequest(RequestWithToken.newBuilder().setTxnRequest(txnReq).build())
113115
.build();
114116
}
117+
118+
private static List<KeyRange> getTxnReqKeyRanges(TxnRequest req) {
119+
List<KeyRange> keyRanges = new ArrayList<>();
120+
req.getCompareList()
121+
.forEach(
122+
cmp ->
123+
keyRanges.add(
124+
KeyRange.newBuilder()
125+
.setKey(cmp.getKey())
126+
.setRangeEnd(cmp.getRangeEnd())
127+
.build()));
128+
Stream.concat(req.getSuccessList().stream(), req.getFailureList().stream())
129+
.forEach(
130+
op -> {
131+
if (op.hasRequestRange()) {
132+
keyRanges.add(
133+
KeyRange.newBuilder()
134+
.setKey(op.getRequestRange().getKey())
135+
.setRangeEnd(op.getRequestRange().getRangeEnd())
136+
.build());
137+
return;
138+
}
139+
if (op.hasRequestPut()) {
140+
keyRanges.add(
141+
KeyRange.newBuilder()
142+
.setKey(op.getRequestPut().getKey())
143+
.build());
144+
return;
145+
}
146+
if (op.hasRequestDeleteRange()) {
147+
keyRanges.add(
148+
KeyRange.newBuilder()
149+
.setKey(op.getRequestDeleteRange().getKey())
150+
.setRangeEnd(
151+
op.getRequestDeleteRange().getRangeEnd())
152+
.build());
153+
return;
154+
}
155+
if (op.hasRequestTxn()) {
156+
keyRanges.addAll(getTxnReqKeyRanges(op.getRequestTxn()));
157+
}
158+
});
159+
return keyRanges;
160+
}
115161
}

jxline-core/src/main/java/cloud/xline/jxline/support/Requests.java

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public static Command mapPutCommand(
2525
ByteSequence key, ByteSequence value, PutOption option, ByteSequence namespace) {
2626
PutRequest req = mapPutRequest(key, value, option, namespace);
2727
return Command.newBuilder()
28-
.addKeys(KeyRange.newBuilder().setKey(ByteString.copyFrom(key.getBytes())).build())
28+
.addKeys(KeyRange.newBuilder().setKey(Util.prefixNamespace(key, namespace)))
2929
.setRequest(
3030
RequestWithToken.newBuilder().setPutRequest(req).build()) // TODO: add token
3131
.build();
@@ -51,11 +51,20 @@ public static RangeRequest.Builder mapRangeRequest(
5151
public static Command mapRangeCommand(
5252
ByteSequence key, GetOption option, ByteSequence namespace) {
5353
RangeRequest.Builder builder = mapRangeRequest(key, option, namespace);
54+
KeyRange.Builder keyRange =
55+
KeyRange.newBuilder().setKey(Util.prefixNamespace(key, namespace));
5456

5557
defineRangeRequestEnd(
56-
key, option.getEndKey(), option.isPrefix(), namespace, builder::setRangeEnd);
58+
key,
59+
option.getEndKey(),
60+
option.isPrefix(),
61+
namespace,
62+
endKey -> {
63+
builder.setRangeEnd(endKey);
64+
keyRange.setRangeEnd(endKey);
65+
});
5766
return Command.newBuilder()
58-
.addKeys(KeyRange.newBuilder().setKey(ByteString.copyFrom(key.getBytes())).build())
67+
.addKeys(keyRange)
5968
.setRequest(
6069
RequestWithToken.newBuilder()
6170
.setRangeRequest(builder.build())
@@ -73,11 +82,20 @@ public static DeleteRangeRequest.Builder mapDeleteRequest(
7382
public static Command mapDeleteCommand(
7483
ByteSequence key, DeleteOption option, ByteSequence namespace) {
7584
DeleteRangeRequest.Builder builder = mapDeleteRequest(key, option, namespace);
76-
defineRangeRequestEnd(
77-
key, option.getEndKey(), option.isPrefix(), namespace, builder::setRangeEnd);
85+
KeyRange.Builder keyRange =
86+
KeyRange.newBuilder().setKey(Util.prefixNamespace(key, namespace));
7887

88+
defineRangeRequestEnd(
89+
key,
90+
option.getEndKey(),
91+
option.isPrefix(),
92+
namespace,
93+
endKey -> {
94+
builder.setRangeEnd(endKey);
95+
keyRange.setRangeEnd(endKey);
96+
});
7997
return Command.newBuilder()
80-
.addKeys(KeyRange.newBuilder().setKey(ByteString.copyFrom(key.getBytes())).build())
98+
.addKeys(keyRange)
8199
.setRequest(
82100
RequestWithToken.newBuilder()
83101
.setDeleteRangeRequest(builder.build())

jxline-core/src/test/java/KVTest.java

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
import cloud.xline.jxline.Client;
22
import cloud.xline.jxline.KV;
3+
import cloud.xline.jxline.Txn;
34
import cloud.xline.jxline.kv.DeleteResponse;
45
import cloud.xline.jxline.kv.GetResponse;
56
import cloud.xline.jxline.kv.PutResponse;
7+
import cloud.xline.jxline.kv.TxnResponse;
8+
import cloud.xline.jxline.op.Cmp;
9+
import cloud.xline.jxline.op.CmpTarget;
10+
import cloud.xline.jxline.op.Op;
611
import io.etcd.jetcd.ByteSequence;
712
import io.etcd.jetcd.options.DeleteOption;
813
import io.etcd.jetcd.options.GetOption;
14+
import io.etcd.jetcd.options.PutOption;
915
import org.junit.jupiter.api.BeforeAll;
1016
import org.junit.jupiter.api.Test;
1117
import org.junit.jupiter.api.Timeout;
1218
import static org.assertj.core.api.Assertions.*;
1319

1420
import java.nio.charset.Charset;
1521
import java.nio.charset.StandardCharsets;
22+
import java.util.List;
1623
import java.util.concurrent.CompletableFuture;
1724
import java.util.concurrent.ExecutionException;
1825

@@ -121,4 +128,110 @@ public void testDelete() throws Exception {
121128
DeleteResponse delResp = deleteFuture.get();
122129
assertThat(delResp.getDeleted()).isEqualTo(resp.getKvs().size());
123130
}
131+
132+
@Test
133+
public void testGetSortedPrefix() throws Exception {
134+
String prefix = randomString();
135+
int numPrefix = 3;
136+
putKeysWithPrefix(prefix, numPrefix);
137+
138+
GetOption option =
139+
GetOption.builder()
140+
.withSortField(GetOption.SortTarget.KEY)
141+
.withSortOrder(GetOption.SortOrder.DESCEND)
142+
.isPrefix(true)
143+
.build();
144+
CompletableFuture<GetResponse> getFeature = kvClient.get(bytesOf(prefix), option);
145+
GetResponse response = getFeature.get();
146+
147+
assertThat(response.getKvs()).hasSize(numPrefix);
148+
for (int i = 0; i < numPrefix; i++) {
149+
assertThat(response.getKvs().get(i).getKey().toString(StandardCharsets.UTF_8))
150+
.isEqualTo(prefix + (numPrefix - i - 1));
151+
assertThat(response.getKvs().get(i).getValue().toString(StandardCharsets.UTF_8))
152+
.isEqualTo(String.valueOf(numPrefix - i - 1));
153+
}
154+
}
155+
156+
@Test
157+
public void testGetAndDeleteWithPrefix() throws Exception {
158+
String prefix = randomString();
159+
ByteSequence key = bytesOf(prefix);
160+
int numPrefixes = 10;
161+
162+
putKeysWithPrefix(prefix, numPrefixes);
163+
164+
// verify get withPrefix.
165+
CompletableFuture<GetResponse> getFuture =
166+
kvClient.get(key, GetOption.builder().isPrefix(true).build());
167+
GetResponse getResp = getFuture.get();
168+
assertThat(getResp.getCount()).isEqualTo(numPrefixes);
169+
170+
// verify del withPrefix.
171+
DeleteOption deleteOpt = DeleteOption.builder().isPrefix(true).build();
172+
CompletableFuture<DeleteResponse> delFuture = kvClient.delete(key, deleteOpt);
173+
DeleteResponse delResp = delFuture.get();
174+
assertThat(delResp.getDeleted()).isEqualTo(numPrefixes);
175+
}
176+
177+
private static void putKeysWithPrefix(String prefix, int numPrefixes)
178+
throws ExecutionException, InterruptedException {
179+
for (int i = 0; i < numPrefixes; i++) {
180+
ByteSequence key = bytesOf(prefix + i);
181+
ByteSequence value = bytesOf("" + i);
182+
kvClient.put(key, value).get();
183+
}
184+
}
185+
186+
@Test
187+
public void testTxn() throws Exception {
188+
ByteSequence sampleKey = bytesOf("txn_key");
189+
ByteSequence sampleValue = bytesOf("xyz");
190+
ByteSequence cmpValue = bytesOf("abc");
191+
ByteSequence putValue = bytesOf("XYZ");
192+
ByteSequence putValueNew = bytesOf("ABC");
193+
// put the original txn key value pair
194+
kvClient.put(sampleKey, sampleValue).get();
195+
196+
// construct txn operation
197+
Txn txn = kvClient.txn();
198+
Cmp cmp = new Cmp(sampleKey, Cmp.Op.GREATER, CmpTarget.value(cmpValue));
199+
CompletableFuture<TxnResponse> txnResp =
200+
txn.If(cmp)
201+
.Then(Op.put(sampleKey, putValue, PutOption.DEFAULT))
202+
.Else(Op.put(sampleKey, putValueNew, PutOption.DEFAULT))
203+
.commit();
204+
txnResp.get();
205+
// get the value
206+
GetResponse getResp = kvClient.get(sampleKey).get();
207+
assertThat(getResp.getKvs()).hasSize(1);
208+
assertThat(getResp.getKvs().get(0).getValue().toString(StandardCharsets.UTF_8))
209+
.isEqualTo(putValue.toString(StandardCharsets.UTF_8));
210+
}
211+
212+
@Test
213+
public void testTxnForCmpOpNotEqual() throws Exception {
214+
ByteSequence sampleKey = bytesOf("txn_key");
215+
ByteSequence sampleValue = bytesOf("xyz");
216+
ByteSequence cmpValue = bytesOf("abc");
217+
ByteSequence putValue = bytesOf("XYZ");
218+
ByteSequence putValueNew = bytesOf("ABC");
219+
// put the original txn key value pair
220+
kvClient.put(sampleKey, sampleValue).get();
221+
222+
// construct txn operation
223+
Txn txn = kvClient.txn();
224+
Cmp cmp = new Cmp(sampleKey, Cmp.Op.NOT_EQUAL, CmpTarget.value(cmpValue));
225+
CompletableFuture<TxnResponse> txnResp =
226+
txn.If(cmp)
227+
.Then(Op.put(sampleKey, putValue, PutOption.DEFAULT))
228+
.Else(Op.put(sampleKey, putValueNew, PutOption.DEFAULT))
229+
.commit();
230+
txnResp.get();
231+
// get the value
232+
GetResponse getResp = kvClient.get(sampleKey).get();
233+
assertThat(getResp.getKvs()).hasSize(1);
234+
assertThat(getResp.getKvs().get(0).getValue().toString(StandardCharsets.UTF_8))
235+
.isEqualTo(putValue.toString(StandardCharsets.UTF_8));
236+
}
124237
}

0 commit comments

Comments
 (0)