blob: ea5b7ccde4952bed31360f4c25128a218590440a [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001/*
2Ginkgo is a BDD-style testing framework for Golang
3
4The godoc documentation describes Ginkgo's API. More comprehensive documentation (with examples!) is available at http://onsi.github.io/ginkgo/
5
6Ginkgo's preferred matcher library is [Gomega](http://github.com/onsi/gomega)
7
8Ginkgo on Github: http://github.com/onsi/ginkgo
9
10Ginkgo is MIT-Licensed
11*/
12package ginkgo
13
14import (
15 "flag"
16 "fmt"
17 "io"
18 "net/http"
19 "os"
20 "strings"
21 "time"
22
23 "github.com/onsi/ginkgo/config"
24 "github.com/onsi/ginkgo/internal/codelocation"
25 "github.com/onsi/ginkgo/internal/failer"
26 "github.com/onsi/ginkgo/internal/remote"
27 "github.com/onsi/ginkgo/internal/suite"
28 "github.com/onsi/ginkgo/internal/testingtproxy"
29 "github.com/onsi/ginkgo/internal/writer"
30 "github.com/onsi/ginkgo/reporters"
31 "github.com/onsi/ginkgo/reporters/stenographer"
32 "github.com/onsi/ginkgo/types"
33)
34
35const GINKGO_VERSION = config.VERSION
36const GINKGO_PANIC = `
37Your test failed.
38Ginkgo panics to prevent subsequent assertions from running.
39Normally Ginkgo rescues this panic so you shouldn't see it.
40
41But, if you make an assertion in a goroutine, Ginkgo can't capture the panic.
42To circumvent this, you should call
43
44 defer GinkgoRecover()
45
46at the top of the goroutine that caused this panic.
47`
48const defaultTimeout = 1
49
50var globalSuite *suite.Suite
51var globalFailer *failer.Failer
52
53func init() {
54 config.Flags(flag.CommandLine, "ginkgo", true)
55 GinkgoWriter = writer.New(os.Stdout)
56 globalFailer = failer.New()
57 globalSuite = suite.New(globalFailer)
58}
59
60//GinkgoWriter implements an io.Writer
61//When running in verbose mode any writes to GinkgoWriter will be immediately printed
62//to stdout. Otherwise, GinkgoWriter will buffer any writes produced during the current test and flush them to screen
63//only if the current test fails.
64var GinkgoWriter io.Writer
65
66//The interface by which Ginkgo receives *testing.T
67type GinkgoTestingT interface {
68 Fail()
69}
70
71//GinkgoRandomSeed returns the seed used to randomize spec execution order. It is
72//useful for seeding your own pseudorandom number generators (PRNGs) to ensure
73//consistent executions from run to run, where your tests contain variability (for
74//example, when selecting random test data).
75func GinkgoRandomSeed() int64 {
76 return config.GinkgoConfig.RandomSeed
77}
78
79//GinkgoParallelNode returns the parallel node number for the current ginkgo process
80//The node number is 1-indexed
81func GinkgoParallelNode() int {
82 return config.GinkgoConfig.ParallelNode
83}
84
85//Some matcher libraries or legacy codebases require a *testing.T
86//GinkgoT implements an interface analogous to *testing.T and can be used if
87//the library in question accepts *testing.T through an interface
88//
89// For example, with testify:
90// assert.Equal(GinkgoT(), 123, 123, "they should be equal")
91//
92// Or with gomock:
93// gomock.NewController(GinkgoT())
94//
95// GinkgoT() takes an optional offset argument that can be used to get the
96// correct line number associated with the failure.
97func GinkgoT(optionalOffset ...int) GinkgoTInterface {
98 offset := 3
99 if len(optionalOffset) > 0 {
100 offset = optionalOffset[0]
101 }
102 return testingtproxy.New(GinkgoWriter, Fail, offset)
103}
104
105//The interface returned by GinkgoT(). This covers most of the methods
106//in the testing package's T.
107type GinkgoTInterface interface {
108 Fail()
109 Error(args ...interface{})
110 Errorf(format string, args ...interface{})
111 FailNow()
112 Fatal(args ...interface{})
113 Fatalf(format string, args ...interface{})
114 Log(args ...interface{})
115 Logf(format string, args ...interface{})
116 Failed() bool
117 Parallel()
118 Skip(args ...interface{})
119 Skipf(format string, args ...interface{})
120 SkipNow()
121 Skipped() bool
122}
123
124//Custom Ginkgo test reporters must implement the Reporter interface.
125//
126//The custom reporter is passed in a SuiteSummary when the suite begins and ends,
127//and a SpecSummary just before a spec begins and just after a spec ends
128type Reporter reporters.Reporter
129
130//Asynchronous specs are given a channel of the Done type. You must close or write to the channel
131//to tell Ginkgo that your async test is done.
132type Done chan<- interface{}
133
134//GinkgoTestDescription represents the information about the current running test returned by CurrentGinkgoTestDescription
135// FullTestText: a concatenation of ComponentTexts and the TestText
136// ComponentTexts: a list of all texts for the Describes & Contexts leading up to the current test
137// TestText: the text in the actual It or Measure node
138// IsMeasurement: true if the current test is a measurement
139// FileName: the name of the file containing the current test
140// LineNumber: the line number for the current test
141// Failed: if the current test has failed, this will be true (useful in an AfterEach)
142type GinkgoTestDescription struct {
143 FullTestText string
144 ComponentTexts []string
145 TestText string
146
147 IsMeasurement bool
148
149 FileName string
150 LineNumber int
151
152 Failed bool
153 Duration time.Duration
154}
155
156//CurrentGinkgoTestDescripton returns information about the current running test.
157func CurrentGinkgoTestDescription() GinkgoTestDescription {
158 summary, ok := globalSuite.CurrentRunningSpecSummary()
159 if !ok {
160 return GinkgoTestDescription{}
161 }
162
163 subjectCodeLocation := summary.ComponentCodeLocations[len(summary.ComponentCodeLocations)-1]
164
165 return GinkgoTestDescription{
166 ComponentTexts: summary.ComponentTexts[1:],
167 FullTestText: strings.Join(summary.ComponentTexts[1:], " "),
168 TestText: summary.ComponentTexts[len(summary.ComponentTexts)-1],
169 IsMeasurement: summary.IsMeasurement,
170 FileName: subjectCodeLocation.FileName,
171 LineNumber: subjectCodeLocation.LineNumber,
172 Failed: summary.HasFailureState(),
173 Duration: summary.RunTime,
174 }
175}
176
177//Measurement tests receive a Benchmarker.
178//
179//You use the Time() function to time how long the passed in body function takes to run
180//You use the RecordValue() function to track arbitrary numerical measurements.
181//The RecordValueWithPrecision() function can be used alternatively to provide the unit
182//and resolution of the numeric measurement.
183//The optional info argument is passed to the test reporter and can be used to
184// provide the measurement data to a custom reporter with context.
185//
186//See http://onsi.github.io/ginkgo/#benchmark_tests for more details
187type Benchmarker interface {
188 Time(name string, body func(), info ...interface{}) (elapsedTime time.Duration)
189 RecordValue(name string, value float64, info ...interface{})
190 RecordValueWithPrecision(name string, value float64, units string, precision int, info ...interface{})
191}
192
193//RunSpecs is the entry point for the Ginkgo test runner.
194//You must call this within a Golang testing TestX(t *testing.T) function.
195//
196//To bootstrap a test suite you can use the Ginkgo CLI:
197//
198// ginkgo bootstrap
199func RunSpecs(t GinkgoTestingT, description string) bool {
200 specReporters := []Reporter{buildDefaultReporter()}
201 return RunSpecsWithCustomReporters(t, description, specReporters)
202}
203
204//To run your tests with Ginkgo's default reporter and your custom reporter(s), replace
205//RunSpecs() with this method.
206func RunSpecsWithDefaultAndCustomReporters(t GinkgoTestingT, description string, specReporters []Reporter) bool {
207 specReporters = append(specReporters, buildDefaultReporter())
208 return RunSpecsWithCustomReporters(t, description, specReporters)
209}
210
211//To run your tests with your custom reporter(s) (and *not* Ginkgo's default reporter), replace
212//RunSpecs() with this method. Note that parallel tests will not work correctly without the default reporter
213func RunSpecsWithCustomReporters(t GinkgoTestingT, description string, specReporters []Reporter) bool {
214 writer := GinkgoWriter.(*writer.Writer)
215 writer.SetStream(config.DefaultReporterConfig.Verbose)
216 reporters := make([]reporters.Reporter, len(specReporters))
217 for i, reporter := range specReporters {
218 reporters[i] = reporter
219 }
220 passed, hasFocusedTests := globalSuite.Run(t, description, reporters, writer, config.GinkgoConfig)
221 if passed && hasFocusedTests && strings.TrimSpace(os.Getenv("GINKGO_EDITOR_INTEGRATION")) == "" {
222 fmt.Println("PASS | FOCUSED")
223 os.Exit(types.GINKGO_FOCUS_EXIT_CODE)
224 }
225 return passed
226}
227
228func buildDefaultReporter() Reporter {
229 remoteReportingServer := config.GinkgoConfig.StreamHost
230 if remoteReportingServer == "" {
231 stenographer := stenographer.New(!config.DefaultReporterConfig.NoColor, config.GinkgoConfig.FlakeAttempts > 1)
232 return reporters.NewDefaultReporter(config.DefaultReporterConfig, stenographer)
233 } else {
234 return remote.NewForwardingReporter(remoteReportingServer, &http.Client{}, remote.NewOutputInterceptor())
235 }
236}
237
238//Skip notifies Ginkgo that the current spec was skipped.
239func Skip(message string, callerSkip ...int) {
240 skip := 0
241 if len(callerSkip) > 0 {
242 skip = callerSkip[0]
243 }
244
245 globalFailer.Skip(message, codelocation.New(skip+1))
246 panic(GINKGO_PANIC)
247}
248
249//Fail notifies Ginkgo that the current spec has failed. (Gomega will call Fail for you automatically when an assertion fails.)
250func Fail(message string, callerSkip ...int) {
251 skip := 0
252 if len(callerSkip) > 0 {
253 skip = callerSkip[0]
254 }
255
256 globalFailer.Fail(message, codelocation.New(skip+1))
257 panic(GINKGO_PANIC)
258}
259
260//GinkgoRecover should be deferred at the top of any spawned goroutine that (may) call `Fail`
261//Since Gomega assertions call fail, you should throw a `defer GinkgoRecover()` at the top of any goroutine that
262//calls out to Gomega
263//
264//Here's why: Ginkgo's `Fail` method records the failure and then panics to prevent
265//further assertions from running. This panic must be recovered. Ginkgo does this for you
266//if the panic originates in a Ginkgo node (an It, BeforeEach, etc...)
267//
268//Unfortunately, if a panic originates on a goroutine *launched* from one of these nodes there's no
269//way for Ginkgo to rescue the panic. To do this, you must remember to `defer GinkgoRecover()` at the top of such a goroutine.
270func GinkgoRecover() {
271 e := recover()
272 if e != nil {
273 globalFailer.Panic(codelocation.New(1), e)
274 }
275}
276
277//Describe blocks allow you to organize your specs. A Describe block can contain any number of
278//BeforeEach, AfterEach, JustBeforeEach, It, and Measurement blocks.
279//
280//In addition you can nest Describe, Context and When blocks. Describe, Context and When blocks are functionally
281//equivalent. The difference is purely semantic -- you typical Describe the behavior of an object
282//or method and, within that Describe, outline a number of Contexts and Whens.
283func Describe(text string, body func()) bool {
284 globalSuite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1))
285 return true
286}
287
288//You can focus the tests within a describe block using FDescribe
289func FDescribe(text string, body func()) bool {
290 globalSuite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1))
291 return true
292}
293
294//You can mark the tests within a describe block as pending using PDescribe
295func PDescribe(text string, body func()) bool {
296 globalSuite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
297 return true
298}
299
300//You can mark the tests within a describe block as pending using XDescribe
301func XDescribe(text string, body func()) bool {
302 globalSuite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
303 return true
304}
305
306//Context blocks allow you to organize your specs. A Context block can contain any number of
307//BeforeEach, AfterEach, JustBeforeEach, It, and Measurement blocks.
308//
309//In addition you can nest Describe, Context and When blocks. Describe, Context and When blocks are functionally
310//equivalent. The difference is purely semantic -- you typical Describe the behavior of an object
311//or method and, within that Describe, outline a number of Contexts and Whens.
312func Context(text string, body func()) bool {
313 globalSuite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1))
314 return true
315}
316
317//You can focus the tests within a describe block using FContext
318func FContext(text string, body func()) bool {
319 globalSuite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1))
320 return true
321}
322
323//You can mark the tests within a describe block as pending using PContext
324func PContext(text string, body func()) bool {
325 globalSuite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
326 return true
327}
328
329//You can mark the tests within a describe block as pending using XContext
330func XContext(text string, body func()) bool {
331 globalSuite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
332 return true
333}
334
335//When blocks allow you to organize your specs. A When block can contain any number of
336//BeforeEach, AfterEach, JustBeforeEach, It, and Measurement blocks.
337//
338//In addition you can nest Describe, Context and When blocks. Describe, Context and When blocks are functionally
339//equivalent. The difference is purely semantic -- you typical Describe the behavior of an object
340//or method and, within that Describe, outline a number of Contexts and Whens.
341func When(text string, body func()) bool {
342 globalSuite.PushContainerNode("when "+text, body, types.FlagTypeNone, codelocation.New(1))
343 return true
344}
345
346//You can focus the tests within a describe block using FWhen
347func FWhen(text string, body func()) bool {
348 globalSuite.PushContainerNode("when "+text, body, types.FlagTypeFocused, codelocation.New(1))
349 return true
350}
351
352//You can mark the tests within a describe block as pending using PWhen
353func PWhen(text string, body func()) bool {
354 globalSuite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1))
355 return true
356}
357
358//You can mark the tests within a describe block as pending using XWhen
359func XWhen(text string, body func()) bool {
360 globalSuite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1))
361 return true
362}
363
364//It blocks contain your test code and assertions. You cannot nest any other Ginkgo blocks
365//within an It block.
366//
367//Ginkgo will normally run It blocks synchronously. To perform asynchronous tests, pass a
368//function that accepts a Done channel. When you do this, you can also provide an optional timeout.
369func It(text string, body interface{}, timeout ...float64) bool {
370 globalSuite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
371 return true
372}
373
374//You can focus individual Its using FIt
375func FIt(text string, body interface{}, timeout ...float64) bool {
376 globalSuite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
377 return true
378}
379
380//You can mark Its as pending using PIt
381func PIt(text string, _ ...interface{}) bool {
382 globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
383 return true
384}
385
386//You can mark Its as pending using XIt
387func XIt(text string, _ ...interface{}) bool {
388 globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
389 return true
390}
391
392//Specify blocks are aliases for It blocks and allow for more natural wording in situations
393//which "It" does not fit into a natural sentence flow. All the same protocols apply for Specify blocks
394//which apply to It blocks.
395func Specify(text string, body interface{}, timeout ...float64) bool {
396 globalSuite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
397 return true
398}
399
400//You can focus individual Specifys using FSpecify
401func FSpecify(text string, body interface{}, timeout ...float64) bool {
402 globalSuite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
403 return true
404}
405
406//You can mark Specifys as pending using PSpecify
407func PSpecify(text string, is ...interface{}) bool {
408 globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
409 return true
410}
411
412//You can mark Specifys as pending using XSpecify
413func XSpecify(text string, is ...interface{}) bool {
414 globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
415 return true
416}
417
418//By allows you to better document large Its.
419//
420//Generally you should try to keep your Its short and to the point. This is not always possible, however,
421//especially in the context of integration tests that capture a particular workflow.
422//
423//By allows you to document such flows. By must be called within a runnable node (It, BeforeEach, Measure, etc...)
424//By will simply log the passed in text to the GinkgoWriter. If By is handed a function it will immediately run the function.
425func By(text string, callbacks ...func()) {
426 preamble := "\x1b[1mSTEP\x1b[0m"
427 if config.DefaultReporterConfig.NoColor {
428 preamble = "STEP"
429 }
430 fmt.Fprintln(GinkgoWriter, preamble+": "+text)
431 if len(callbacks) == 1 {
432 callbacks[0]()
433 }
434 if len(callbacks) > 1 {
435 panic("just one callback per By, please")
436 }
437}
438
439//Measure blocks run the passed in body function repeatedly (determined by the samples argument)
440//and accumulate metrics provided to the Benchmarker by the body function.
441//
442//The body function must have the signature:
443// func(b Benchmarker)
444func Measure(text string, body interface{}, samples int) bool {
445 globalSuite.PushMeasureNode(text, body, types.FlagTypeNone, codelocation.New(1), samples)
446 return true
447}
448
449//You can focus individual Measures using FMeasure
450func FMeasure(text string, body interface{}, samples int) bool {
451 globalSuite.PushMeasureNode(text, body, types.FlagTypeFocused, codelocation.New(1), samples)
452 return true
453}
454
455//You can mark Maeasurements as pending using PMeasure
456func PMeasure(text string, _ ...interface{}) bool {
457 globalSuite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
458 return true
459}
460
461//You can mark Maeasurements as pending using XMeasure
462func XMeasure(text string, _ ...interface{}) bool {
463 globalSuite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
464 return true
465}
466
467//BeforeSuite blocks are run just once before any specs are run. When running in parallel, each
468//parallel node process will call BeforeSuite.
469//
470//BeforeSuite blocks can be made asynchronous by providing a body function that accepts a Done channel
471//
472//You may only register *one* BeforeSuite handler per test suite. You typically do so in your bootstrap file at the top level.
473func BeforeSuite(body interface{}, timeout ...float64) bool {
474 globalSuite.SetBeforeSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
475 return true
476}
477
478//AfterSuite blocks are *always* run after all the specs regardless of whether specs have passed or failed.
479//Moreover, if Ginkgo receives an interrupt signal (^C) it will attempt to run the AfterSuite before exiting.
480//
481//When running in parallel, each parallel node process will call AfterSuite.
482//
483//AfterSuite blocks can be made asynchronous by providing a body function that accepts a Done channel
484//
485//You may only register *one* AfterSuite handler per test suite. You typically do so in your bootstrap file at the top level.
486func AfterSuite(body interface{}, timeout ...float64) bool {
487 globalSuite.SetAfterSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
488 return true
489}
490
491//SynchronizedBeforeSuite blocks are primarily meant to solve the problem of setting up singleton external resources shared across
492//nodes when running tests in parallel. For example, say you have a shared database that you can only start one instance of that
493//must be used in your tests. When running in parallel, only one node should set up the database and all other nodes should wait
494//until that node is done before running.
495//
496//SynchronizedBeforeSuite accomplishes this by taking *two* function arguments. The first is only run on parallel node #1. The second is
497//run on all nodes, but *only* after the first function completes succesfully. Ginkgo also makes it possible to send data from the first function (on Node 1)
498//to the second function (on all the other nodes).
499//
500//The functions have the following signatures. The first function (which only runs on node 1) has the signature:
501//
502// func() []byte
503//
504//or, to run asynchronously:
505//
506// func(done Done) []byte
507//
508//The byte array returned by the first function is then passed to the second function, which has the signature:
509//
510// func(data []byte)
511//
512//or, to run asynchronously:
513//
514// func(data []byte, done Done)
515//
516//Here's a simple pseudo-code example that starts a shared database on Node 1 and shares the database's address with the other nodes:
517//
518// var dbClient db.Client
519// var dbRunner db.Runner
520//
521// var _ = SynchronizedBeforeSuite(func() []byte {
522// dbRunner = db.NewRunner()
523// err := dbRunner.Start()
524// Ω(err).ShouldNot(HaveOccurred())
525// return []byte(dbRunner.URL)
526// }, func(data []byte) {
527// dbClient = db.NewClient()
528// err := dbClient.Connect(string(data))
529// Ω(err).ShouldNot(HaveOccurred())
530// })
531func SynchronizedBeforeSuite(node1Body interface{}, allNodesBody interface{}, timeout ...float64) bool {
532 globalSuite.SetSynchronizedBeforeSuiteNode(
533 node1Body,
534 allNodesBody,
535 codelocation.New(1),
536 parseTimeout(timeout...),
537 )
538 return true
539}
540
541//SynchronizedAfterSuite blocks complement the SynchronizedBeforeSuite blocks in solving the problem of setting up
542//external singleton resources shared across nodes when running tests in parallel.
543//
544//SynchronizedAfterSuite accomplishes this by taking *two* function arguments. The first runs on all nodes. The second runs only on parallel node #1
545//and *only* after all other nodes have finished and exited. This ensures that node 1, and any resources it is running, remain alive until
546//all other nodes are finished.
547//
548//Both functions have the same signature: either func() or func(done Done) to run asynchronously.
549//
550//Here's a pseudo-code example that complements that given in SynchronizedBeforeSuite. Here, SynchronizedAfterSuite is used to tear down the shared database
551//only after all nodes have finished:
552//
553// var _ = SynchronizedAfterSuite(func() {
554// dbClient.Cleanup()
555// }, func() {
556// dbRunner.Stop()
557// })
558func SynchronizedAfterSuite(allNodesBody interface{}, node1Body interface{}, timeout ...float64) bool {
559 globalSuite.SetSynchronizedAfterSuiteNode(
560 allNodesBody,
561 node1Body,
562 codelocation.New(1),
563 parseTimeout(timeout...),
564 )
565 return true
566}
567
568//BeforeEach blocks are run before It blocks. When multiple BeforeEach blocks are defined in nested
569//Describe and Context blocks the outermost BeforeEach blocks are run first.
570//
571//Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts
572//a Done channel
573func BeforeEach(body interface{}, timeout ...float64) bool {
574 globalSuite.PushBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
575 return true
576}
577
578//JustBeforeEach blocks are run before It blocks but *after* all BeforeEach blocks. For more details,
579//read the [documentation](http://onsi.github.io/ginkgo/#separating_creation_and_configuration_)
580//
581//Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts
582//a Done channel
583func JustBeforeEach(body interface{}, timeout ...float64) bool {
584 globalSuite.PushJustBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
585 return true
586}
587
588//AfterEach blocks are run after It blocks. When multiple AfterEach blocks are defined in nested
589//Describe and Context blocks the innermost AfterEach blocks are run first.
590//
591//Like It blocks, AfterEach blocks can be made asynchronous by providing a body function that accepts
592//a Done channel
593func AfterEach(body interface{}, timeout ...float64) bool {
594 globalSuite.PushAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
595 return true
596}
597
598func parseTimeout(timeout ...float64) time.Duration {
599 if len(timeout) == 0 {
600 return time.Duration(defaultTimeout * int64(time.Second))
601 } else {
602 return time.Duration(timeout[0] * float64(time.Second))
603 }
604}