• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

temporalio / sdk-java / #351

04 Aug 2026 11:58PM UTC coverage: 67.781% (-0.5%) from 68.245%
#351

push

github

web-flow
Add dev server downloader & runner to testing package (#2982)

7311 of 12876 branches covered (56.78%)

Branch coverage included in aggregate %.

331 of 703 new or added lines in 12 files covered. (47.08%)

28 existing lines in 13 files now uncovered.

30207 of 42476 relevant lines covered (71.12%)

0.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.92
/temporal-testing/src/main/java/io/temporal/testing/TemporalDevServerOptions.java
1
package io.temporal.testing;
2

3
import io.temporal.common.Experimental;
4
import java.time.Duration;
5
import java.util.ArrayList;
6
import java.util.Collections;
7
import java.util.List;
8
import javax.annotation.Nonnull;
9
import javax.annotation.Nullable;
10

11
/** Options for a {@link TemporalDevServer}. */
12
@Experimental
13
public final class TemporalDevServerOptions {
14
  private static final TemporalDevServerOptions DEFAULT_INSTANCE = newBuilder().build();
1✔
15

16
  public static Builder newBuilder() {
17
    return new Builder();
1✔
18
  }
19

20
  public static Builder newBuilder(@Nonnull TemporalDevServerOptions options) {
21
    return new Builder(options);
1✔
22
  }
23

24
  public static TemporalDevServerOptions getDefaultInstance() {
25
    return DEFAULT_INSTANCE;
1✔
26
  }
27

28
  public static final class Builder {
29
    private String existingPath;
30
    private String downloadVersion = "default";
1✔
31
    private String downloadDestination;
32
    private Duration downloadCacheTtl;
33
    private boolean downloadEnabled = true;
1✔
34
    private String ip = "127.0.0.1";
1✔
35
    private Integer port;
36
    private String databaseFilename;
37
    private boolean uiEnabled;
38
    private Integer uiPort;
39
    private String logFormat = "pretty";
1✔
40
    private String logLevel = "warn";
1✔
41
    private String workingDirectory;
42
    private String logFile;
43
    private Duration startupTimeout = Duration.ofSeconds(60);
1✔
44
    private List<String> extraArgs = new ArrayList<>();
1✔
45

46
    private Builder() {}
1✔
47

48
    private Builder(@Nonnull TemporalDevServerOptions options) {
1✔
49
      if (options == null) {
1!
NEW
50
        throw new NullPointerException("options");
×
51
      }
52
      this.existingPath = options.existingPath;
1✔
53
      this.downloadVersion = options.downloadVersion;
1✔
54
      this.downloadDestination = options.downloadDestination;
1✔
55
      this.downloadCacheTtl = options.downloadCacheTtl;
1✔
56
      this.downloadEnabled = options.downloadEnabled;
1✔
57
      this.ip = options.ip;
1✔
58
      this.port = options.port;
1✔
59
      this.databaseFilename = options.databaseFilename;
1✔
60
      this.uiEnabled = options.uiEnabled;
1✔
61
      this.uiPort = options.uiPort;
1✔
62
      this.logFormat = options.logFormat;
1✔
63
      this.logLevel = options.logLevel;
1✔
64
      this.workingDirectory = options.workingDirectory;
1✔
65
      this.logFile = options.logFile;
1✔
66
      this.startupTimeout = options.startupTimeout;
1✔
67
      this.extraArgs = new ArrayList<>(options.extraArgs);
1✔
68
    }
1✔
69

70
    /** Sets an existing Temporal CLI executable instead of using the download cache. */
71
    public Builder setExistingPath(@Nullable String existingPath) {
72
      this.existingPath = existingPath;
1✔
73
      return this;
1✔
74
    }
75

76
    /**
77
     * Sets the CLI version to download. {@code "default"} selects the version associated with the
78
     * running sdk-java version; any other non-empty value is sent to temporal.download unchanged.
79
     */
80
    public Builder setDownloadVersion(@Nonnull String downloadVersion) {
81
      this.downloadVersion = downloadVersion;
1✔
82
      return this;
1✔
83
    }
84

85
    /** Sets the root directory for cached downloads. Defaults to the JVM temporary directory. */
86
    public Builder setDownloadDestination(@Nullable String downloadDestination) {
87
      this.downloadDestination = downloadDestination;
1✔
88
      return this;
1✔
89
    }
90

91
    /** Sets the maximum age of a cached executable. A null value caches indefinitely. */
92
    public Builder setDownloadCacheTtl(@Nullable Duration downloadCacheTtl) {
93
      this.downloadCacheTtl = downloadCacheTtl;
1✔
94
      return this;
1✔
95
    }
96

97
    /** Alias for {@link #setDownloadCacheTtl(Duration)}. */
98
    public Builder setDownloadTtl(@Nullable Duration downloadCacheTtl) {
NEW
99
      return setDownloadCacheTtl(downloadCacheTtl);
×
100
    }
101

102
    /** Sets whether a missing or expired executable may be downloaded. */
103
    public Builder setDownloadEnabled(boolean downloadEnabled) {
104
      this.downloadEnabled = downloadEnabled;
1✔
105
      return this;
1✔
106
    }
107

108
    /** Sets the IP address on which the dev server listens. */
109
    public Builder setIp(@Nonnull String ip) {
NEW
110
      this.ip = ip;
×
NEW
111
      return this;
×
112
    }
113

114
    /** Alias for {@link #setIp(String)}. */
115
    public Builder setBindIp(@Nonnull String ip) {
NEW
116
      return setIp(ip);
×
117
    }
118

119
    /** Sets the gRPC port. A null value asks the OS for an available port. */
120
    public Builder setPort(@Nullable Integer port) {
121
      this.port = port;
1✔
122
      return this;
1✔
123
    }
124

125
    /** Sets an SQLite database filename. A null value uses in-memory SQLite. */
126
    public Builder setDatabaseFilename(@Nullable String databaseFilename) {
NEW
127
      this.databaseFilename = databaseFilename;
×
NEW
128
      return this;
×
129
    }
130

131
    /** Sets whether the Temporal UI is enabled. */
132
    public Builder setUiEnabled(boolean uiEnabled) {
133
      this.uiEnabled = uiEnabled;
1✔
134
      return this;
1✔
135
    }
136

137
    /** Alias for {@link #setUiEnabled(boolean)}. */
138
    public Builder setUi(boolean uiEnabled) {
NEW
139
      return setUiEnabled(uiEnabled);
×
140
    }
141

142
    /** Sets the UI port and implicitly enables the UI. */
143
    public Builder setUiPort(@Nullable Integer uiPort) {
144
      this.uiPort = uiPort;
1✔
145
      if (uiPort != null) {
1!
146
        this.uiEnabled = true;
1✔
147
      }
148
      return this;
1✔
149
    }
150

151
    /** Sets the Temporal CLI log format. Defaults to {@code pretty}. */
152
    public Builder setLogFormat(@Nonnull String logFormat) {
NEW
153
      this.logFormat = logFormat;
×
NEW
154
      return this;
×
155
    }
156

157
    /** Sets the Temporal CLI log level. Defaults to {@code warn}. */
158
    public Builder setLogLevel(@Nonnull String logLevel) {
NEW
159
      this.logLevel = logLevel;
×
NEW
160
      return this;
×
161
    }
162

163
    /** Sets the child process working directory. Defaults to the current working directory. */
164
    public Builder setWorkingDirectory(@Nullable String workingDirectory) {
NEW
165
      this.workingDirectory = workingDirectory;
×
NEW
166
      return this;
×
167
    }
168

169
    /** Sets a file that receives server output. A null value inherits the parent output. */
170
    public Builder setLogFile(@Nullable String logFile) {
NEW
171
      this.logFile = logFile;
×
NEW
172
      return this;
×
173
    }
174

175
    /** Sets the single timeout used for health and namespace readiness checks. */
176
    public Builder setStartupTimeout(@Nonnull Duration startupTimeout) {
177
      this.startupTimeout = startupTimeout;
1✔
178
      return this;
1✔
179
    }
180

181
    /** Sets additional arguments appended to the generated {@code server start-dev} command. */
182
    public Builder setExtraArgs(@Nonnull List<String> extraArgs) {
183
      if (extraArgs == null) {
1!
NEW
184
        throw new NullPointerException("extraArgs");
×
185
      }
186
      this.extraArgs = new ArrayList<>(extraArgs);
1✔
187
      return this;
1✔
188
    }
189

190
    /** Sets additional arguments appended to the generated {@code server start-dev} command. */
191
    public Builder setExtraArgs(@Nonnull String... extraArgs) {
192
      if (extraArgs == null) {
1!
NEW
193
        throw new NullPointerException("extraArgs");
×
194
      }
195
      this.extraArgs = new ArrayList<>();
1✔
196
      Collections.addAll(this.extraArgs, extraArgs);
1✔
197
      return this;
1✔
198
    }
199

200
    public TemporalDevServerOptions build() {
201
      requireNonBlank(downloadVersion, "downloadVersion");
1✔
202
      requireNonBlank(ip, "ip");
1✔
203
      validatePort(port, "port");
1✔
204
      validatePort(uiPort, "uiPort");
1✔
205
      requireNonBlank(logFormat, "logFormat");
1✔
206
      requireNonBlank(logLevel, "logLevel");
1✔
207
      if (existingPath != null) {
1✔
208
        requireNonBlank(existingPath, "existingPath");
1✔
209
      }
210
      if (downloadDestination != null) {
1✔
211
        requireNonBlank(downloadDestination, "downloadDestination");
1✔
212
      }
213
      if (databaseFilename != null) {
1!
NEW
214
        requireNonBlank(databaseFilename, "databaseFilename");
×
215
      }
216
      if (workingDirectory != null) {
1!
NEW
217
        requireNonBlank(workingDirectory, "workingDirectory");
×
218
      }
219
      if (logFile != null) {
1!
NEW
220
        requireNonBlank(logFile, "logFile");
×
221
      }
222
      if (downloadCacheTtl != null && downloadCacheTtl.isNegative()) {
1✔
223
        throw new IllegalArgumentException("downloadCacheTtl cannot be negative");
1✔
224
      }
225
      if (startupTimeout == null || startupTimeout.isZero() || startupTimeout.isNegative()) {
1!
226
        throw new IllegalArgumentException("startupTimeout must be positive");
1✔
227
      }
228
      for (String arg : extraArgs) {
1✔
229
        if (arg == null) {
1!
NEW
230
          throw new IllegalArgumentException("extraArgs cannot contain null");
×
231
        }
232
        if (arg.indexOf('\n') >= 0 || arg.indexOf('\r') >= 0) {
1!
233
          throw new IllegalArgumentException("extraArgs cannot contain newlines");
1✔
234
        }
235
      }
1✔
236
      return new TemporalDevServerOptions(this);
1✔
237
    }
238

239
    private static void requireNonBlank(@Nullable String value, @Nonnull String name) {
240
      if (value == null || value.trim().isEmpty()) {
1!
241
        throw new IllegalArgumentException(name + " cannot be blank");
1✔
242
      }
243
    }
1✔
244

245
    private static void validatePort(@Nullable Integer port, @Nonnull String name) {
246
      if (port != null && (port < 1 || port > 65535)) {
1!
247
        throw new IllegalArgumentException(name + " must be between 1 and 65535");
1✔
248
      }
249
    }
1✔
250
  }
251

252
  private final String existingPath;
253
  private final String downloadVersion;
254
  private final String downloadDestination;
255
  private final Duration downloadCacheTtl;
256
  private final boolean downloadEnabled;
257
  private final String ip;
258
  private final Integer port;
259
  private final String databaseFilename;
260
  private final boolean uiEnabled;
261
  private final Integer uiPort;
262
  private final String logFormat;
263
  private final String logLevel;
264
  private final String workingDirectory;
265
  private final String logFile;
266
  private final Duration startupTimeout;
267
  private final List<String> extraArgs;
268

269
  private TemporalDevServerOptions(@Nonnull Builder builder) {
1✔
270
    this.existingPath = builder.existingPath;
1✔
271
    this.downloadVersion = builder.downloadVersion;
1✔
272
    this.downloadDestination = builder.downloadDestination;
1✔
273
    this.downloadCacheTtl = builder.downloadCacheTtl;
1✔
274
    this.downloadEnabled = builder.downloadEnabled;
1✔
275
    this.ip = builder.ip;
1✔
276
    this.port = builder.port;
1✔
277
    this.databaseFilename = builder.databaseFilename;
1✔
278
    this.uiEnabled = builder.uiEnabled;
1✔
279
    this.uiPort = builder.uiPort;
1✔
280
    this.logFormat = builder.logFormat;
1✔
281
    this.logLevel = builder.logLevel;
1✔
282
    this.workingDirectory = builder.workingDirectory;
1✔
283
    this.logFile = builder.logFile;
1✔
284
    this.startupTimeout = builder.startupTimeout;
1✔
285
    this.extraArgs = Collections.unmodifiableList(new ArrayList<>(builder.extraArgs));
1✔
286
  }
1✔
287

288
  @Nullable
289
  public String getExistingPath() {
290
    return existingPath;
1✔
291
  }
292

293
  public String getDownloadVersion() {
294
    return downloadVersion;
1✔
295
  }
296

297
  @Nullable
298
  public String getDownloadDestination() {
299
    return downloadDestination;
1✔
300
  }
301

302
  @Nullable
303
  public Duration getDownloadCacheTtl() {
304
    return downloadCacheTtl;
1✔
305
  }
306

307
  /** Alias for {@link #getDownloadCacheTtl()}. */
308
  @Nullable
309
  public Duration getDownloadTtl() {
NEW
310
    return downloadCacheTtl;
×
311
  }
312

313
  public boolean isDownloadEnabled() {
314
    return downloadEnabled;
1✔
315
  }
316

317
  public String getIp() {
NEW
318
    return ip;
×
319
  }
320

321
  /** Alias for {@link #getIp()}. */
322
  public String getBindIp() {
NEW
323
    return ip;
×
324
  }
325

326
  @Nullable
327
  public Integer getPort() {
NEW
328
    return port;
×
329
  }
330

331
  @Nullable
332
  public String getDatabaseFilename() {
NEW
333
    return databaseFilename;
×
334
  }
335

336
  public boolean isUiEnabled() {
337
    return uiEnabled;
1✔
338
  }
339

340
  @Nullable
341
  public Integer getUiPort() {
NEW
342
    return uiPort;
×
343
  }
344

345
  public String getLogFormat() {
NEW
346
    return logFormat;
×
347
  }
348

349
  public String getLogLevel() {
NEW
350
    return logLevel;
×
351
  }
352

353
  @Nullable
354
  public String getWorkingDirectory() {
NEW
355
    return workingDirectory;
×
356
  }
357

358
  @Nullable
359
  public String getLogFile() {
NEW
360
    return logFile;
×
361
  }
362

363
  public Duration getStartupTimeout() {
NEW
364
    return startupTimeout;
×
365
  }
366

367
  public List<String> getExtraArgs() {
368
    return extraArgs;
1✔
369
  }
370
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc