Communication between instances
For some test plans, it is useful to pass information from one instance to another. In addition to direct network connectivity, test plans can pass information between instances using the Testground sync service.
In this tutorial, we will explore typed message passing through the Testground sync service.
Lets create a plan in which one of the plans produces a struct which is re-constructed on the distant end. First, I'll show short snippets with the relevant information, and the whole test plan will be shown at the end.

Setting up thetopic

Transferrable is the value type we will be transferring.
1
type Transferrable struct {
2
Name string
3
FavoriteSport int
4
CareWhoKnows bool
5
}
Copied!
The value will be transferred over a topic. Think of the topic as a named and typed channel for transferring values between plan instances. This topic is named transfer-key and the value type I expect to get out of it is pointer to Transferrable.
1
st := sync.NewTopic("transfer-key", &Transferrable{})
Copied!

Publishing to a topic

To write to a topic, create a bounded client and use it to publish to the topic we have just defined.
1
ctx := context.Background()
2
3
client := sync.MustBoundClient(ctx, runenv)
4
defer client.Close()
5
6
client.Publish(ctx, st, &Transferrable{"Guy#1", 1, false})
Copied!

Reading from a topic

Subscribe to the topic we created earlier and set up a channel to receive the values.
1
tch := make(chan *Transferrable)
2
3
_, err = client.Subscribe(ctx, st, tch)
4
if err != nil {
5
panic(err)
6
}
Copied!

Who subscribes and who publishes?

This question is left up to the plan writer, and certainly different situations will call for different implementations. In this example, all the plans will publish and all will subscribe, but there are scenarios where this is inappropriate.

Full Example

1
package main
2
3
import (
4
"context"
5
"fmt"
6
"math/rand"
7
"time"
8
9
"github.com/testground/sdk-go/runtime"
10
"github.com/testground/sdk-go/sync"
11
)
12
13
type Sport int
14
15
const (
16
football Sport = iota
17
tennis
18
hockey
19
golf
20
)
21
22
func (s Sport) String() string {
23
return [...]string{"football", "tennis", "hockey", "golf"}[s]
24
}
25
26
type Transferrable struct {
27
Name string
28
FavoriteSport Sport
29
CareWhoKnows bool
30
}
31
32
func (t *Transferrable) String() string {
33
msg := fmt.Sprintf("%s: I like %s", t.Name, t.FavoriteSport)
34
if t.CareWhoKnows {
35
return msg + " and I really care!"
36
}
37
return msg + " and I don't care who knows!"
38
}
39
40
func main() {
41
runtime.Invoke(run)
42
}
43
44
func run(runenv *runtime.RunEnv) error {
45
rand.Seed(time.Now().UnixNano())
46
47
ctx := context.Background()
48
client := sync.MustBoundClient(ctx, runenv)
49
defer client.Close()
50
51
st := sync.NewTopic("transfer-key", &Transferrable{})
52
53
// Configure the test
54
myName := fmt.Sprintf("Guy#%d", rand.Int()%100)
55
mySport := Sport(rand.Int() % 4)
56
howMany := runenv.TestInstanceCount
57
58
// Publish my entry
59
client.Publish(ctx, st, &Transferrable{myName, mySport, false})
60
61
// Wait until all instances have published entries
62
readyState := sync.State("ready")
63
client.MustSignalEntry(ctx, readyState)
64
<-client.MustBarrier(ctx, readyState, howMany).C
65
66
// Subscribe to the `transfer-key` topic
67
tch := make(chan *Transferrable)
68
client.Subscribe(ctx, st, tch)
69
70
for i := 0; i < howMany; i++ {
71
t := <-tch
72
runenv.RecordMessage("%s", t)
73
}
74
75
return nil
76
}
Copied!
Run with multiple instances:
1
$ testground run single -p quickstart -t quickstart -b exec:go -r local:exec -i 4
Copied!
Notice that instances is set to 4. Four instances will run at the same time.
Last modified 1yr ago