Skip to content

Commit 8918c6d

Browse files
authored
Merge pull request #515 from marle3003/develop
v0.14.3
2 parents 6ab3538 + d924104 commit 8918c6d

File tree

6 files changed

+112
-10
lines changed

6 files changed

+112
-10
lines changed

api/handler_system_test.go

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,43 @@ func TestHandler_System(t *testing.T) {
3939
h,
4040
try.HasStatusCode(200),
4141
try.HasHeader("Content-Type", "application/json"),
42-
try.HasBody(`[{"traits":{"namespace":"http"},"size":1}]`))
42+
try.HasBody(`[{"traits":{"namespace":"http"},"size":1,"numEvents":0}]`))
43+
},
44+
},
45+
{
46+
name: "with namespace and name",
47+
fn: func(t *testing.T, h http.Handler) {
48+
events.SetStore(1, events.NewTraits().WithNamespace("kafka"))
49+
events.SetStore(1, events.NewTraits().WithNamespace("kafka").WithName("Kafka Testserver"))
50+
events.SetStore(1, events.NewTraits().WithNamespace("kafka").WithName("Kafka Testserver").With("topic", "foo"))
51+
52+
try.Handler(t,
53+
http.MethodGet,
54+
"http://foo.api/api/system/events?namespace=kafka&name=Kafka Testserver",
55+
nil,
56+
"",
57+
h,
58+
try.HasStatusCode(200),
59+
try.HasHeader("Content-Type", "application/json"),
60+
try.HasBody(`[{"traits":{"namespace":"kafka"},"size":1,"numEvents":0},{"traits":{"name":"Kafka Testserver","namespace":"kafka"},"size":1,"numEvents":0}]`))
61+
},
62+
},
63+
{
64+
name: "with namespace, name and topic",
65+
fn: func(t *testing.T, h http.Handler) {
66+
events.SetStore(1, events.NewTraits().WithNamespace("kafka"))
67+
events.SetStore(1, events.NewTraits().WithNamespace("kafka").WithName("Kafka Testserver"))
68+
events.SetStore(1, events.NewTraits().WithNamespace("kafka").WithName("Kafka Testserver").With("topic", "foo"))
69+
70+
try.Handler(t,
71+
http.MethodGet,
72+
"http://foo.api/api/system/events?namespace=kafka&name=Kafka Testserver&topic=foo",
73+
nil,
74+
"",
75+
h,
76+
try.HasStatusCode(200),
77+
try.HasHeader("Content-Type", "application/json"),
78+
try.HasBody(`[{"traits":{"namespace":"kafka"},"size":1,"numEvents":0},{"traits":{"name":"Kafka Testserver","namespace":"kafka"},"size":1,"numEvents":0},{"traits":{"name":"Kafka Testserver","namespace":"kafka","topic":"foo"},"size":1,"numEvents":0}]`))
4379
},
4480
},
4581
}

providers/openapi/schema/marshal.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ func (s *Schema) Marshal(i interface{}, contentType media.ContentType) ([]byte,
3939
}
4040

4141
func (s *Schema) MarshalJSON() ([]byte, error) {
42-
e := encoder{refs: map[string]bool{}}
42+
e := encoder{visited: map[*Schema]bool{}}
4343
return e.encode(s)
4444
}
4545

4646
type encoder struct {
47-
refs map[string]bool
47+
visited map[*Schema]bool
4848
}
4949

5050
func (e *encoder) encode(s *Schema) ([]byte, error) {
@@ -54,6 +54,21 @@ func (e *encoder) encode(s *Schema) ([]byte, error) {
5454
return b.Bytes(), nil
5555
}
5656

57+
// check circular reference
58+
if e.visited[s] {
59+
var v string
60+
if s.Ref != "" {
61+
v = fmt.Sprintf(`{"$ref":"%s","description":"circular reference"}`, s.Ref)
62+
63+
} else {
64+
v = `{"description":"circular reference"}`
65+
}
66+
b.Write([]byte(v))
67+
return b.Bytes(), nil
68+
}
69+
e.visited[s] = true
70+
defer delete(e.visited, s)
71+
5772
b.WriteRune('{')
5873

5974
v := reflect.ValueOf(s).Elem()

providers/openapi/schema/marshal_schema_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,30 @@ func TestSchema_Marshal(t *testing.T) {
6767
})
6868
}
6969
}
70+
71+
func TestCircularRef(t *testing.T) {
72+
s := &schema.Schema{}
73+
s.Properties = &schema.Schemas{}
74+
s.Properties.Set("foo", s)
75+
76+
b, err := json.Marshal(s)
77+
require.NoError(t, err)
78+
require.Equal(t, "{\"properties\":{\"foo\":{\"description\":\"circular reference\"}}}", string(b))
79+
80+
// with ref
81+
s.Ref = "#/components/schemas/Foo"
82+
b, err = json.Marshal(s)
83+
require.NoError(t, err)
84+
require.Equal(t, "{\"$ref\":\"#/components/schemas/Foo\",\"properties\":{\"foo\":{\"$ref\":\"#/components/schemas/Foo\",\"description\":\"circular reference\"}}}", string(b))
85+
86+
// multi-level circular refs
87+
s = &schema.Schema{Properties: &schema.Schemas{}}
88+
89+
bar := &schema.Schema{Properties: &schema.Schemas{}}
90+
bar.Properties.Set("foo", s)
91+
92+
s.Properties.Set("bar", bar)
93+
b, err = json.Marshal(s)
94+
require.NoError(t, err)
95+
require.Equal(t, "{\"properties\":{\"bar\":{\"properties\":{\"foo\":{\"description\":\"circular reference\"}}}}}", string(b))
96+
}

runtime/events/events.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ package events
33
import (
44
"fmt"
55
"github.com/google/uuid"
6+
log "github.com/sirupsen/logrus"
67
"sort"
78
"sync"
89
"time"
910
)
1011

1112
var (
1213
stores []*store
13-
m sync.Mutex
14+
m sync.RWMutex
1415
)
1516

1617
type Event struct {
@@ -21,9 +22,10 @@ type Event struct {
2122
}
2223

2324
type StoreInfo struct {
24-
Traits Traits `json:"traits"`
25-
Events []Event `json:"events,omitempty"`
26-
Size int `json:"size"`
25+
Traits Traits `json:"traits"`
26+
Events []Event `json:"events,omitempty"`
27+
Size int `json:"size"`
28+
NumEvents int `json:"numEvents"`
2729
}
2830

2931
func SetStore(size int, traits Traits) {
@@ -34,19 +36,26 @@ func SetStore(size int, traits Traits) {
3436
}
3537

3638
func GetStores(traits Traits) []StoreInfo {
39+
m.RLock()
40+
defer m.RUnlock()
41+
3742
var result []StoreInfo
3843
for _, s := range stores {
3944
if s.traits.Match(traits) {
4045
result = append(result, StoreInfo{
41-
Traits: s.traits,
42-
Size: s.size,
46+
Traits: s.traits,
47+
Size: s.size,
48+
NumEvents: len(s.events),
4349
})
4450
}
4551
}
4652
return result
4753
}
4854

4955
func Push(data interface{}, traits Traits) error {
56+
m.RLock()
57+
defer m.RUnlock()
58+
5059
if len(traits) == 0 {
5160
return fmt.Errorf("empty traits not allowed")
5261
}
@@ -73,6 +82,9 @@ func Push(data interface{}, traits Traits) error {
7382
}
7483

7584
func GetEvents(traits Traits) []Event {
85+
m.RLock()
86+
defer m.RUnlock()
87+
7688
events := make([]Event, 0)
7789

7890
for _, s := range stores {
@@ -89,6 +101,9 @@ func GetEvents(traits Traits) []Event {
89101
}
90102

91103
func GetEvent(id string) Event {
104+
m.RLock()
105+
defer m.RUnlock()
106+
92107
for _, s := range stores {
93108
for _, e := range s.events {
94109
if e.Id == id {
@@ -116,6 +131,8 @@ func ResetStores(traits Traits) {
116131
// copy and increment index
117132
stores[i] = s
118133
i++
134+
} else {
135+
log.Debugf("reset store %s", traits.String())
119136
}
120137
}
121138
// Prevent memory leak by erasing truncated values

runtime/events/store.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ type store struct {
88
size int
99
events []Event
1010
traits Traits
11-
m sync.Mutex
11+
m sync.RWMutex
1212
}
1313

1414
func (s *store) Push(e Event) {
@@ -28,6 +28,9 @@ func (s *store) Push(e Event) {
2828
}
2929

3030
func (s *store) Events(traits Traits) []Event {
31+
s.m.RLock()
32+
defer s.m.RUnlock()
33+
3134
var events []Event
3235
for _, e := range s.events {
3336
if e.Traits.Contains(traits) {

server/httpmanager_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"mokapi/providers/openapi"
1313
"mokapi/providers/openapi/openapitest"
1414
"mokapi/runtime"
15+
"mokapi/runtime/events"
1516
"mokapi/server/cert"
1617
"mokapi/try"
1718
"mokapi/version"
@@ -164,9 +165,12 @@ func TestHttpManager_Update(t *testing.T) {
164165

165166
for _, data := range testdata {
166167
t.Run(data.name, func(t *testing.T) {
168+
defer events.Reset()
169+
167170
logrus.SetOutput(io.Discard)
168171
hook := logtest.NewGlobal()
169172
logrus.SetLevel(logrus.DebugLevel)
173+
170174
store, err := cert.NewStore(&static.Config{})
171175
require.NoError(t, err)
172176

0 commit comments

Comments
 (0)