Skip to content

Commit a157fd1

Browse files
committed
test:add simple test case
1 parent 401dab5 commit a157fd1

File tree

3 files changed

+163
-0
lines changed

3 files changed

+163
-0
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* SimpleReadWrite.actor.cpp
3+
*
4+
* This source file is part of the FoundationDB open source project
5+
*
6+
* Copyright 2013-2024 Apple Inc. and the FoundationDB project authors
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
#include "fdbclient/NativeAPI.actor.h"
22+
#include "fdbserver/workloads/workloads.actor.h"
23+
#include "flow/actorcompiler.h" // This must be the last #include.
24+
25+
// A simple workload that writes a key-value pair and then reads it back
26+
struct SimpleReadWriteWorkload : TestWorkload {
27+
static constexpr auto NAME = "SimpleReadWrite";
28+
29+
Key testKey;
30+
Value testValue;
31+
bool writeSuccess;
32+
bool readSuccess;
33+
34+
SimpleReadWriteWorkload(WorkloadContext const& wcx) : TestWorkload(wcx), writeSuccess(false), readSuccess(false) {
35+
// Use a unique key per client to avoid conflicts
36+
testKey = StringRef(format("SimpleReadWrite/Client%d", clientId));
37+
testValue = "HelloFoundationDB"_sr;
38+
}
39+
40+
Future<Void> setup(Database const& cx) override {
41+
if (clientId == 0) {
42+
// Only client 0 writes the test data
43+
return _setup(this, cx);
44+
}
45+
return Void();
46+
}
47+
48+
ACTOR static Future<Void> _setup(SimpleReadWriteWorkload* self, Database cx) {
49+
state Transaction tr(cx);
50+
loop {
51+
try {
52+
tr.set(self->testKey, self->testValue);
53+
wait(tr.commit());
54+
self->writeSuccess = true;
55+
TraceEvent("SimpleReadWriteSetup").detail("Key", self->testKey).detail("Value", self->testValue);
56+
break;
57+
} catch (Error& e) {
58+
wait(tr.onError(e));
59+
}
60+
}
61+
return Void();
62+
}
63+
64+
Future<Void> start(Database const& cx) override {
65+
// All clients read the value
66+
return _start(this, cx);
67+
}
68+
69+
ACTOR static Future<Void> _start(SimpleReadWriteWorkload* self, Database cx) {
70+
state Transaction tr(cx);
71+
loop {
72+
try {
73+
Optional<Value> value = wait(tr.get(self->testKey));
74+
if (value.present() && value.get() == self->testValue) {
75+
self->readSuccess = true;
76+
TraceEvent("SimpleReadWriteRead")
77+
.detail("Key", self->testKey)
78+
.detail("Value", value.get())
79+
.detail("Expected", self->testValue);
80+
} else {
81+
TraceEvent(SevError, "SimpleReadWriteReadFailed")
82+
.detail("Key", self->testKey)
83+
.detail("ValuePresent", value.present())
84+
.detail("Value", value.present() ? value.get() : "NOT_PRESENT"_sr)
85+
.detail("Expected", self->testValue);
86+
}
87+
break;
88+
} catch (Error& e) {
89+
wait(tr.onError(e));
90+
}
91+
}
92+
return Void();
93+
}
94+
95+
Future<bool> check(Database const& cx) override {
96+
// Verify the data is still correct
97+
return _check(this, cx);
98+
}
99+
100+
ACTOR static Future<bool> _check(SimpleReadWriteWorkload* self, Database cx) {
101+
state Transaction tr(cx);
102+
loop {
103+
try {
104+
Optional<Value> value = wait(tr.get(self->testKey));
105+
if (self->clientId == 0) {
106+
// Client 0 should have written successfully
107+
if (!self->writeSuccess) {
108+
TraceEvent(SevError, "SimpleReadWriteCheckFailed").detail("Reason", "Write did not succeed");
109+
return false;
110+
}
111+
}
112+
// All clients should have read successfully
113+
if (!self->readSuccess) {
114+
TraceEvent(SevError, "SimpleReadWriteCheckFailed").detail("Reason", "Read did not succeed");
115+
return false;
116+
}
117+
// Verify the value is still correct
118+
if (!value.present() || value.get() != self->testValue) {
119+
TraceEvent(SevError, "SimpleReadWriteCheckFailed")
120+
.detail("Reason", "Value mismatch")
121+
.detail("ValuePresent", value.present())
122+
.detail("Value", value.present() ? value.get() : "NOT_PRESENT"_sr)
123+
.detail("Expected", self->testValue);
124+
return false;
125+
}
126+
TraceEvent("SimpleReadWriteCheck").detail("Key", self->testKey).detail("Value", value.get());
127+
return true;
128+
} catch (Error& e) {
129+
wait(tr.onError(e));
130+
}
131+
}
132+
}
133+
134+
void getMetrics(std::vector<PerfMetric>& m) override {
135+
m.emplace_back("WriteSuccess", writeSuccess ? 1.0 : 0.0, Averaged::False);
136+
m.emplace_back("ReadSuccess", readSuccess ? 1.0 : 0.0, Averaged::False);
137+
}
138+
};
139+
140+
WorkloadFactory<SimpleReadWriteWorkload> SimpleReadWriteWorkloadFactory;
141+

tests/fast/SimpleReadWrite.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[configuration]
2+
3+
[[test]]
4+
testTitle = 'SimpleReadWriteTest'
5+
6+
[[test.workload]]
7+
testName = 'SimpleReadWrite'
8+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[configuration]
2+
3+
[[test]]
4+
testTitle = 'SimpleReadWriteWithNetworkFailures'
5+
6+
[[test.workload]]
7+
testName = 'SimpleReadWrite'
8+
9+
[[test.workload]]
10+
testName = 'RandomClogging'
11+
testDuration = 60.0
12+
scale = 0.5
13+
clogginess = 1.5
14+

0 commit comments

Comments
 (0)