Skip to content

Commit 74061c0

Browse files
authored
Merge pull request #333 from smocker-dev/fix/go-template-delay
fix(templates): apply delay from go_template_json dynamic responses
2 parents c29583c + a72a54d commit 74061c0

2 files changed

Lines changed: 83 additions & 9 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package templates
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/smocker-dev/smocker/server/types"
8+
)
9+
10+
// TestGoTemplateJsonDelay reproduces #305: a delay written as duration strings ("10ms") in a
11+
// go_template_json dynamic response must be applied — it was previously silently dropped because
12+
// Delay.UnmarshalJSON only accepted numeric nanoseconds.
13+
func TestGoTemplateJsonDelay(t *testing.T) {
14+
script := `{
15+
"body": {"message": "request path {{.Request.Path}}"},
16+
"headers": {"Content-Type": ["application/json"]},
17+
"delay": {"min": "0", "max": "10ms"}
18+
}`
19+
res, err := NewGoTemplateJsonEngine().Execute(types.Request{Path: "/test"}, script)
20+
if err != nil {
21+
t.Fatalf("Execute: %v", err)
22+
}
23+
if res.Delay.Min != 0 {
24+
t.Errorf("delay.min = %v, want 0", res.Delay.Min)
25+
}
26+
if res.Delay.Max != 10*time.Millisecond {
27+
t.Errorf("delay.max = %v, want 10ms", res.Delay.Max)
28+
}
29+
}
30+
31+
// TestGoTemplateJsonDelayScalar covers the single-value shorthand ("delay": "5ms").
32+
func TestGoTemplateJsonDelayScalar(t *testing.T) {
33+
res, err := NewGoTemplateJsonEngine().Execute(types.Request{Path: "/test"},
34+
`{"body": "hi", "delay": "5ms"}`)
35+
if err != nil {
36+
t.Fatalf("Execute: %v", err)
37+
}
38+
if res.Delay.Min != 5*time.Millisecond || res.Delay.Max != 5*time.Millisecond {
39+
t.Errorf("delay = {%v, %v}, want {5ms, 5ms}", res.Delay.Min, res.Delay.Max)
40+
}
41+
}

server/types/mock.go

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,26 +165,59 @@ type Delay struct {
165165
}
166166

167167
func (d *Delay) UnmarshalJSON(data []byte) error {
168-
var s time.Duration
169-
if err := json.Unmarshal(data, &s); err == nil {
170-
d.Min = s
171-
d.Max = s
168+
// Scalar form: a single duration applied to both bounds.
169+
if v, ok, err := parseJSONDuration(data); err != nil {
170+
return err
171+
} else if ok {
172+
d.Min, d.Max = v, v
172173
return d.validate()
173174
}
174175

176+
// Object form: {"min": ..., "max": ...}. Each bound is a duration string ("10ms") or a number
177+
// of nanoseconds — the same shapes the Lua and go_template_yaml engines already accept.
175178
var res struct {
176-
Min time.Duration `json:"min"`
177-
Max time.Duration `json:"max"`
179+
Min json.RawMessage `json:"min"`
180+
Max json.RawMessage `json:"max"`
178181
}
179-
180182
if err := json.Unmarshal(data, &res); err != nil {
181183
return err
182184
}
183-
d.Min = res.Min
184-
d.Max = res.Max
185+
if len(res.Min) > 0 {
186+
v, _, err := parseJSONDuration(res.Min)
187+
if err != nil {
188+
return err
189+
}
190+
d.Min = v
191+
}
192+
if len(res.Max) > 0 {
193+
v, _, err := parseJSONDuration(res.Max)
194+
if err != nil {
195+
return err
196+
}
197+
d.Max = v
198+
}
185199
return d.validate()
186200
}
187201

202+
// parseJSONDuration reads a JSON scalar as a duration: a string like "10ms" (time.ParseDuration)
203+
// or a number of nanoseconds. ok is false when the value is not a scalar (e.g. an object), so the
204+
// caller can fall back to the {min, max} form.
205+
func parseJSONDuration(data []byte) (time.Duration, bool, error) {
206+
var v interface{}
207+
if err := json.Unmarshal(data, &v); err != nil {
208+
return 0, false, err
209+
}
210+
switch x := v.(type) {
211+
case string:
212+
dur, err := time.ParseDuration(x)
213+
return dur, true, err
214+
case float64:
215+
return time.Duration(int64(x)), true, nil
216+
default:
217+
return 0, false, nil
218+
}
219+
}
220+
188221
func (d *Delay) UnmarshalYAML(unmarshal func(interface{}) error) error {
189222
var s time.Duration
190223
if err := unmarshal(&s); err == nil {

0 commit comments

Comments
 (0)