Skip to content

Commit f35bfa0

Browse files
Nontserathius
Nont
authored andcommitted
Use robustness traffic generation
Signed-off-by: Nont <[email protected]>
1 parent eae9a91 commit f35bfa0

File tree

2 files changed

+67
-70
lines changed
  • tests

2 files changed

+67
-70
lines changed

tests/antithesis/test-template/robustness/main.go

+59-70
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,38 @@ import (
2020
"context"
2121
"log"
2222
"os"
23+
"sync"
2324
"time"
2425

2526
"github.com/antithesishq/antithesis-sdk-go/assert"
2627
"github.com/antithesishq/antithesis-sdk-go/random"
28+
"golang.org/x/time/rate"
2729

28-
clientv3 "go.etcd.io/etcd/client/v3"
2930
"go.etcd.io/etcd/tests/v3/robustness/client"
3031
"go.etcd.io/etcd/tests/v3/robustness/identity"
32+
robustnessrand "go.etcd.io/etcd/tests/v3/robustness/random"
33+
"go.etcd.io/etcd/tests/v3/robustness/report"
34+
"go.etcd.io/etcd/tests/v3/robustness/traffic"
3135
)
3236

33-
func Connect() *client.RecordingClient {
34-
// This function returns a client connection to an etcd node
37+
var (
38+
// Please keep the sum of weights equal 100.
39+
profile = traffic.Profile{
40+
MinimalQPS: 100,
41+
MaximalQPS: 1000,
42+
BurstableQPS: 1000,
43+
ClientCount: 3,
44+
MaxNonUniqueRequestConcurrency: 3,
45+
}
46+
IDProvider = identity.NewIDProvider()
47+
LeaseIDStorage = identity.NewLeaseIDStorage()
48+
ConcurrencyLimiter = traffic.NewConcurrencyLimiter(profile.MaxNonUniqueRequestConcurrency)
49+
)
3550

51+
// Connect returns a client connection to an etcd node
52+
func Connect() *client.RecordingClient {
3653
hosts := []string{"etcd0:2379", "etcd1:2379", "etcd2:2379"}
37-
cli, err := client.NewRecordingClient(hosts, identity.NewIDProvider(), time.Now())
54+
cli, err := client.NewRecordingClient(hosts, IDProvider, time.Now())
3855
if err != nil {
3956
log.Fatalf("Failed to connect to etcd: %v", err)
4057
// Antithesis Assertion: client should always be able to connect to an etcd host
@@ -45,77 +62,49 @@ func Connect() *client.RecordingClient {
4562
return cli
4663
}
4764

48-
func DeleteKeys() {
49-
// This function will:
50-
// 1. Get all keys
51-
// 2. Select half of the keys received
52-
// 3. Attempt to delete the keys selected
53-
// 4. Check that the keys were deleted
54-
65+
func testRobustness() {
5566
ctx := context.Background()
56-
57-
// Connect to an etcd node
58-
cli := Connect()
59-
60-
// Get all keys
61-
resp, err := cli.Get(ctx, "", clientv3.WithPrefix())
62-
63-
// Antithesis Assertion: sometimes get with prefix requests are successful. A failed request is OK since we expect them to happen.
64-
assert.Sometimes(err == nil, "Client can make successful get all requests", map[string]any{"error": err})
65-
cli.Close()
66-
67-
if err != nil {
68-
log.Printf("Client failed to get all keys: %v", err)
69-
os.Exit(0)
67+
var wg sync.WaitGroup
68+
var mux sync.Mutex
69+
runfor := time.Duration(robustnessrand.RandRange(5, 60) * int64(time.Second))
70+
limiter := rate.NewLimiter(rate.Limit(profile.MaximalQPS), profile.BurstableQPS)
71+
finish := wrap(time.After(runfor))
72+
reports := []report.ClientReport{}
73+
74+
for range profile.ClientCount {
75+
wg.Add(1)
76+
c := Connect()
77+
go func(c *client.RecordingClient) {
78+
defer wg.Done()
79+
defer c.Close()
80+
81+
traffic.EtcdAntithesis.RunTrafficLoop(ctx, c, limiter,
82+
IDProvider,
83+
LeaseIDStorage,
84+
ConcurrencyLimiter,
85+
finish,
86+
)
87+
mux.Lock()
88+
reports = append(reports, c.Report())
89+
mux.Unlock()
90+
}(c)
7091
}
92+
wg.Wait()
93+
assert.Reachable("Completion robustness traffic generation", nil)
94+
}
7195

72-
// Choose half of the keys
73-
var keys []string
74-
for _, k := range resp.Kvs {
75-
keys = append(keys, string(k.Key))
76-
}
77-
half := len(keys) / 2
78-
halfKeys := keys[:half]
79-
80-
// Connect to a new etcd node
81-
cli = Connect()
82-
83-
// Delete half of the keys chosen
84-
var deletedKeys []string
85-
for _, k := range halfKeys {
86-
_, err := cli.Delete(ctx, k)
87-
// Antithesis Assertion: sometimes delete requests are successful. A failed request is OK since we expect them to happen.
88-
assert.Sometimes(err == nil, "Client can make successful delete requests", map[string]any{"error": err})
89-
if err != nil {
90-
log.Printf("Failed to delete key %s: %v", k, err)
91-
} else {
92-
log.Printf("Successfully deleted key %v", k)
93-
deletedKeys = append(deletedKeys, k)
94-
}
95-
}
96-
cli.Close()
97-
98-
// Connect to a new etcd node
99-
cli = Connect()
100-
101-
// Check to see if those keys were deleted / exist
102-
for _, k := range deletedKeys {
103-
resp, err := cli.Get(ctx, k)
104-
// Antithesis Assertion: sometimes get requests are successful. A failed request is OK since we expect them to happen.
105-
assert.Sometimes(err == nil, "Client can make successful get requests", map[string]any{"error": err})
106-
if err != nil {
107-
log.Printf("Client failed to get key %s: %v", k, err)
108-
continue
96+
// wrap converts a receive-only channel to receive-only struct{} channel
97+
func wrap[T any](from <-chan T) <-chan struct{} {
98+
out := make(chan struct{})
99+
go func() {
100+
for {
101+
<-from
102+
out <- struct{}{}
109103
}
110-
// Antithesis Assertion: if we deleted a key, we should not get a value
111-
assert.Always(resp.Count == 0, "Key was deleted correctly", map[string]any{"key": k})
112-
}
113-
cli.Close()
114-
115-
assert.Reachable("Completion of a key deleting check", nil)
116-
log.Printf("Completion of a key deleting check")
104+
}()
105+
return out
117106
}
118107

119108
func main() {
120-
DeleteKeys()
109+
testRobustness()
121110
}

tests/robustness/traffic/etcd.go

+8
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,14 @@ var (
7575
{Choice: Delete, Weight: 50},
7676
},
7777
}
78+
EtcdAntithesis Traffic = etcdTraffic{
79+
keyCount: 10,
80+
// Please keep the sum of weights equal 100.
81+
requests: []random.ChoiceWeight[etcdRequestType]{
82+
{Choice: Get, Weight: 50},
83+
{Choice: Put, Weight: 50},
84+
},
85+
}
7886
)
7987

8088
type etcdTraffic struct {

0 commit comments

Comments
 (0)