0
# Test Configuration
1
2
The MultiNodeConfig class provides the foundation for configuring multi-node tests, including participant roles, Akka settings, and deployment configurations.
3
4
## MultiNodeConfig Class
5
6
```scala { .api }
7
abstract class MultiNodeConfig {
8
def commonConfig(config: Config): Unit
9
def nodeConfig(roles: RoleName*)(configs: Config*): Unit
10
def role(name: String): RoleName
11
def debugConfig(on: Boolean): Config
12
def deployOn(role: RoleName, deployment: String): Unit
13
def deployOnAll(deployment: String): Unit
14
def testTransport(on: Boolean): Unit
15
}
16
```
17
18
### Configuration Methods
19
20
#### Common Configuration
21
22
```scala { .api }
23
def commonConfig(config: Config): Unit
24
```
25
26
Registers a common base configuration that applies to all test participants. This is typically used for shared Akka settings.
27
28
**Usage Example:**
29
30
```scala
31
object MyMultiNodeConfig extends MultiNodeConfig {
32
commonConfig(ConfigFactory.parseString("""
33
akka {
34
actor.provider = remote
35
loglevel = "INFO"
36
remote.artery.canonical.port = 0
37
}
38
"""))
39
}
40
```
41
42
#### Node-Specific Configuration
43
44
```scala { .api }
45
def nodeConfig(roles: RoleName*)(configs: Config*): Unit
46
```
47
48
Registers configuration overrides for specific participants. Multiple roles can share the same configuration, and multiple configs are merged with fallback behavior.
49
50
**Usage Example:**
51
52
```scala
53
val first = role("first")
54
val second = role("second")
55
val third = role("third")
56
57
// Configure first node with specific settings
58
nodeConfig(first)(ConfigFactory.parseString("""
59
akka.cluster.roles = ["seed"]
60
"""))
61
62
// Configure second and third nodes with shared settings
63
nodeConfig(second, third)(ConfigFactory.parseString("""
64
akka.cluster.roles = ["worker"]
65
"""))
66
```
67
68
#### Role Creation
69
70
```scala { .api }
71
def role(name: String): RoleName
72
```
73
74
Creates and registers a new role name for test participants. Each role name must be unique within the test configuration.
75
76
**Usage Example:**
77
78
```scala
79
object ClusterTestConfig extends MultiNodeConfig {
80
val controller = role("controller")
81
val worker1 = role("worker1")
82
val worker2 = role("worker2")
83
val observer = role("observer")
84
}
85
```
86
87
**Parameters:**
88
- `name: String` - Unique name for the role
89
90
**Returns:** `RoleName` - Role identifier for use in test execution
91
92
**Throws:** `IllegalArgumentException` if role name is not unique
93
94
#### Debug Configuration
95
96
```scala { .api }
97
def debugConfig(on: Boolean): Config
98
```
99
100
Generates debug configuration for verbose logging of actor and remoting operations.
101
102
**Usage Example:**
103
104
```scala
105
commonConfig(debugConfig(on = true).withFallback(baseConfig))
106
```
107
108
**Parameters:**
109
- `on: Boolean` - When true, enables debug logging for actors and remoting
110
111
**Returns:** `Config` - Configuration with debug settings or empty config
112
113
### Deployment Configuration
114
115
#### Role-Specific Deployment
116
117
```scala { .api }
118
def deployOn(role: RoleName, deployment: String): Unit
119
```
120
121
Configures actor deployment for a specific role. Deployment strings use HOCON format and support address replacement tokens.
122
123
**Usage Example:**
124
125
```scala
126
deployOn(worker1, """
127
/myActor {
128
remote = "@worker2@/user/service"
129
router = round-robin-pool
130
nr-of-instances = 3
131
}
132
""")
133
```
134
135
#### Global Deployment
136
137
```scala { .api }
138
def deployOnAll(deployment: String): Unit
139
```
140
141
Configures actor deployment that applies to all roles.
142
143
**Usage Example:**
144
145
```scala
146
deployOnAll("""
147
/globalService {
148
router = consistent-hashing-pool
149
nr-of-instances = 5
150
}
151
""")
152
```
153
154
### Network Testing Configuration
155
156
#### Test Transport
157
158
```scala { .api }
159
def testTransport(on: Boolean): Unit
160
```
161
162
Enables or disables the test transport mode required for network failure injection features like blackhole, passThrough, and throttle.
163
164
**Usage Example:**
165
166
```scala
167
object NetworkTestConfig extends MultiNodeConfig {
168
testTransport(on = true) // Required for failure injection
169
170
val node1 = role("node1")
171
val node2 = role("node2")
172
}
173
174
class NetworkFailureTest extends MultiNodeSpec(NetworkTestConfig) {
175
"network test" must {
176
"simulate network partition" in {
177
testConductor.blackhole(node1, node2, Direction.Both).await
178
// Test behavior during network partition
179
}
180
}
181
}
182
```
183
184
**Parameters:**
185
- `on: Boolean` - Enable test transport adapters when true
186
187
**Note:** Must be enabled before using blackhole, passThrough, or throttle methods in TestConductor.
188
189
## Configuration Properties
190
191
The MultiNodeConfig provides several read-only properties for accessing configuration state:
192
193
```scala { .api }
194
// Internal properties (read-only)
195
private[testkit] def myself: RoleName // Current node's role
196
private[akka] def config: Config // Computed final configuration
197
private[testkit] def deployments(node: RoleName): immutable.Seq[String] // Node deployments
198
private[testkit] def roles: immutable.Seq[RoleName] // All registered roles
199
```
200
201
## Address Replacement Tokens
202
203
Deployment configurations support address replacement tokens that are resolved at runtime:
204
205
```scala
206
deployOn(serviceNode, """
207
/client {
208
remote = "@dataNode@/user/database"
209
}
210
""")
211
```
212
213
**Available Tokens:**
214
- `@roleName@` - Replaced with the actual network address of the specified role
215
216
## Configuration Inheritance
217
218
Configuration follows a layered approach with fallback behavior:
219
220
1. **Node-specific config** (highest priority)
221
2. **Common config**
222
3. **Test transport config** (if enabled)
223
4. **Base MultiNodeSpec config**
224
5. **Default Akka config** (lowest priority)
225
226
## Complete Configuration Example
227
228
```scala
229
object ComplexMultiNodeConfig extends MultiNodeConfig {
230
// Define roles
231
val seed = role("seed")
232
val worker1 = role("worker1")
233
val worker2 = role("worker2")
234
val client = role("client")
235
236
// Common configuration for all nodes
237
commonConfig(ConfigFactory.parseString("""
238
akka {
239
actor.provider = remote
240
cluster {
241
seed-nodes = []
242
auto-down-unreachable-after = 10s
243
}
244
remote.artery.canonical.port = 0
245
}
246
"""))
247
248
// Seed node specific configuration
249
nodeConfig(seed)(ConfigFactory.parseString("""
250
akka.cluster.roles = ["seed"]
251
"""))
252
253
// Worker nodes configuration
254
nodeConfig(worker1, worker2)(ConfigFactory.parseString("""
255
akka.cluster.roles = ["worker"]
256
"""))
257
258
// Client node configuration
259
nodeConfig(client)(ConfigFactory.parseString("""
260
akka.cluster.roles = ["client"]
261
"""))
262
263
// Enable network failure injection
264
testTransport(on = true)
265
266
// Deploy services on specific nodes
267
deployOn(worker1, """
268
/workerService {
269
router = round-robin-pool
270
nr-of-instances = 2
271
}
272
""")
273
274
deployOn(client, """
275
/clientService {
276
remote = "@worker1@/user/workerService"
277
}
278
""")
279
280
// Global deployment
281
deployOnAll("""
282
/monitor {
283
dispatcher = "akka.actor.default-dispatcher"
284
}
285
""")
286
}
287
```