Skip to content

Commit 4d4468c

Browse files
authored
Add data-source helper for SystemRule and FlowRule (alibaba#90)
1 parent adb9db4 commit 4d4468c

File tree

6 files changed

+386
-2
lines changed

6 files changed

+386
-2
lines changed

core/flow/rule_manager.go

+5
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ func GetRules() []*FlowRule {
8080
return rulesFrom(tcMap)
8181
}
8282

83+
func ClearRules() error {
84+
_, err := LoadRules(nil)
85+
return err
86+
}
87+
8388
func rulesFrom(m TrafficControllerMap) []*FlowRule {
8489
rules := make([]*FlowRule, 0)
8590
if len(m) == 0 {

core/system/rule_manager.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ func initRuleRecvTask() {
4040
}
4141
}, logger)
4242
}
43+
func ClearRules() error {
44+
_, err := LoadRules(nil)
45+
return err
46+
}
4347

4448
func GetRules() []*SystemRule {
4549
ruleMapMux.RLock()
@@ -54,8 +58,8 @@ func GetRules() []*SystemRule {
5458

5559
// LoadRules loads given system rules to the rule manager, while all previous rules will be replaced.
5660
func LoadRules(rules []*SystemRule) (bool, error) {
57-
ruleChan <- rules
58-
return true, nil
61+
err := onRuleUpdate(rules)
62+
return true, err
5963
}
6064

6165
func onRuleUpdate(rules []*SystemRule) error {

ext/datasource/helper.go

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package datasource
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"github.com/alibaba/sentinel-golang/core/flow"
7+
"github.com/alibaba/sentinel-golang/core/system"
8+
"github.com/pkg/errors"
9+
)
10+
11+
// FlowRulesJsonConverter provide JSON as the default serialization for list of flow.FlowRule
12+
func FlowRulesJsonConverter(src []byte) (interface{}, error) {
13+
if len(src) == 0 {
14+
return nil, nil
15+
}
16+
ret := make([]*flow.FlowRule, 0)
17+
err := json.Unmarshal(src, &ret)
18+
if err != nil {
19+
return nil, errors.Errorf("Fail to unmarshal source: %+v to []flow.FlowRule, err: %+v", src, err)
20+
}
21+
return ret, nil
22+
}
23+
24+
// FlowRulesUpdater load the newest []flow.FlowRule to downstream flow component.
25+
func FlowRulesUpdater(data interface{}) error {
26+
if data == nil {
27+
return nil
28+
}
29+
30+
rules := make([]*flow.FlowRule, 0)
31+
if val, ok := data.([]flow.FlowRule); ok {
32+
for _, v := range val {
33+
rules = append(rules, &v)
34+
}
35+
} else if val, ok := data.([]*flow.FlowRule); ok {
36+
rules = val
37+
} else {
38+
return errors.New(fmt.Sprintf("Fail to type assert data to []flow.FlowRule or []*flow.FlowRule, in fact, data: %+v", data))
39+
}
40+
succ, err := flow.LoadRules(rules)
41+
if succ {
42+
return err
43+
}
44+
return err
45+
}
46+
47+
func NewFlowRulesHandler(converter PropertyConverter) PropertyHandler {
48+
return NewDefaultPropertyHandler(converter, FlowRulesUpdater)
49+
}
50+
51+
// SystemRulesJsonConverter provide JSON as the default serialization for list of system.SystemRule
52+
func SystemRulesJsonConverter(src []byte) (interface{}, error) {
53+
if len(src) == 0 {
54+
return nil, nil
55+
}
56+
ret := make([]*system.SystemRule, 0)
57+
err := json.Unmarshal(src, &ret)
58+
if err != nil {
59+
return nil, errors.Errorf("Fail to unmarshal source: %+v to []system.SystemRule, err: %+v", src, err)
60+
}
61+
return ret, nil
62+
}
63+
64+
// SystemRulesUpdater load the newest []system.SystemRule to downstream system component.
65+
func SystemRulesUpdater(data interface{}) error {
66+
if data == nil {
67+
return nil
68+
}
69+
70+
rules := make([]*system.SystemRule, 0)
71+
if val, ok := data.([]system.SystemRule); ok {
72+
for _, v := range val {
73+
rules = append(rules, &v)
74+
}
75+
} else if val, ok := data.([]*system.SystemRule); ok {
76+
rules = val
77+
} else {
78+
return errors.New(fmt.Sprintf("Fail to type assert data to []system.SystemRule or []*system.SystemRule, in fact, data: %+v", data))
79+
}
80+
succ, err := system.LoadRules(rules)
81+
if succ {
82+
return err
83+
}
84+
return err
85+
}
86+
87+
func NewSystemRulesHandler(converter PropertyConverter) *DefaultPropertyHandler {
88+
return NewDefaultPropertyHandler(converter, SystemRulesUpdater)
89+
}

ext/datasource/helper_test.go

+222
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
package datasource
2+
3+
import (
4+
"encoding/json"
5+
"github.com/alibaba/sentinel-golang/core/flow"
6+
"github.com/alibaba/sentinel-golang/core/system"
7+
"github.com/pkg/errors"
8+
"github.com/stretchr/testify/assert"
9+
"io/ioutil"
10+
"os"
11+
"reflect"
12+
"strings"
13+
"testing"
14+
)
15+
16+
func TestFlowRulesJsonConverter(t *testing.T) {
17+
// Prepare test data
18+
f, err := os.Open("../../tests/testdata/extension/plugin/FlowRule.json")
19+
defer f.Close()
20+
if err != nil {
21+
t.Errorf("The rules file is not existed, err:%+v.", errors.WithStack(err))
22+
}
23+
normalSrc, err := ioutil.ReadAll(f)
24+
if err != nil {
25+
t.Errorf("Fail to read file, err: %+v.", errors.WithStack(err))
26+
}
27+
normalWant := make([]*flow.FlowRule, 0)
28+
err = json.Unmarshal(normalSrc, &normalWant)
29+
if err != nil {
30+
t.Errorf("Fail to unmarshal source:%+v to []flow.FlowRule, err:%+v", normalSrc, err)
31+
}
32+
33+
type args struct {
34+
src []byte
35+
}
36+
tests := []struct {
37+
name string
38+
args args
39+
want interface{}
40+
wantErr bool
41+
}{
42+
{
43+
name: "TestFlowRulesJsonConverter_Nil",
44+
args: args{
45+
src: nil,
46+
},
47+
want: nil,
48+
wantErr: false,
49+
},
50+
{
51+
name: "TestFlowRulesJsonConverter_Unmarshal_Error",
52+
args: args{
53+
src: []byte("{1111111}"),
54+
},
55+
want: nil,
56+
wantErr: true,
57+
},
58+
{
59+
name: "TestFlowRulesJsonConverter_Normal",
60+
args: args{
61+
src: normalSrc,
62+
},
63+
want: normalWant,
64+
wantErr: false,
65+
},
66+
}
67+
for _, tt := range tests {
68+
t.Run(tt.name, func(t *testing.T) {
69+
got, err := FlowRulesJsonConverter(tt.args.src)
70+
if (err != nil) != tt.wantErr {
71+
t.Errorf("FlowRulesJsonConverter() error = %v, wantErr %v", err, tt.wantErr)
72+
return
73+
}
74+
if !reflect.DeepEqual(got, tt.want) {
75+
t.Errorf("FlowRulesJsonConverter() got = %v, want %v", got, tt.want)
76+
}
77+
})
78+
}
79+
}
80+
81+
func TestFlowRulesUpdater(t *testing.T) {
82+
t.Run("TestFlowRulesUpdater_Nil", func(t *testing.T) {
83+
flow.ClearRules()
84+
err := FlowRulesUpdater(nil)
85+
assert.True(t, err == nil && len(flow.GetRules()) == 0, "Fail to test TestFlowRulesUpdater_Nil")
86+
})
87+
88+
t.Run("TestFlowRulesUpdater_Assert_Failed", func(t *testing.T) {
89+
flow.ClearRules()
90+
err := FlowRulesUpdater("xxxxxxxx")
91+
assert.True(t, err != nil && strings.Contains(err.Error(), "Fail to type assert data to []flow.FlowRule"))
92+
})
93+
94+
t.Run("TestFlowRulesUpdater_Empty_Rules", func(t *testing.T) {
95+
flow.ClearRules()
96+
p := make([]flow.FlowRule, 0)
97+
err := FlowRulesUpdater(p)
98+
assert.True(t, err == nil && len(flow.GetRules()) == 0)
99+
})
100+
101+
t.Run("TestFlowRulesUpdater_Normal", func(t *testing.T) {
102+
flow.ClearRules()
103+
p := make([]flow.FlowRule, 0)
104+
fw := flow.FlowRule{
105+
ID: 0,
106+
Resource: "aaaa",
107+
LimitOrigin: "aaa",
108+
MetricType: 0,
109+
Count: 0,
110+
RelationStrategy: 0,
111+
ControlBehavior: 0,
112+
RefResource: "",
113+
WarmUpPeriodSec: 0,
114+
MaxQueueingTimeMs: 0,
115+
ClusterMode: false,
116+
ClusterConfig: flow.ClusterRuleConfig{},
117+
}
118+
p = append(p, fw)
119+
err := FlowRulesUpdater(p)
120+
assert.True(t, err == nil && len(flow.GetRules()) == 1)
121+
})
122+
}
123+
124+
func TestSystemRulesJsonConvert(t *testing.T) {
125+
// Prepare test data
126+
f, err := os.Open("../../tests/testdata/extension/plugin/SystemRule.json")
127+
defer f.Close()
128+
if err != nil {
129+
t.Errorf("The rules file is not existed, err:%+v.", errors.WithStack(err))
130+
}
131+
normalSrc, err := ioutil.ReadAll(f)
132+
if err != nil {
133+
t.Errorf("Fail to read file, err: %+v.", errors.WithStack(err))
134+
}
135+
normalWant := make([]*system.SystemRule, 0)
136+
err = json.Unmarshal(normalSrc, &normalWant)
137+
if err != nil {
138+
t.Errorf("Fail to unmarshal source:%+v to []system.SystemRule, err:%+v", normalSrc, err)
139+
}
140+
141+
type args struct {
142+
src []byte
143+
}
144+
tests := []struct {
145+
name string
146+
args args
147+
want interface{}
148+
wantErr bool
149+
}{
150+
{
151+
name: "TestSystemRulesJsonConvert_Nil",
152+
args: args{
153+
src: nil,
154+
},
155+
want: nil,
156+
wantErr: false,
157+
},
158+
{
159+
name: "TestSystemRulesJsonConvert_Unmarshal_Error",
160+
args: args{
161+
src: []byte("{1111111}"),
162+
},
163+
want: nil,
164+
wantErr: true,
165+
},
166+
{
167+
name: "TestSystemRulesJsonConvert_Normal",
168+
args: args{
169+
src: normalSrc,
170+
},
171+
want: normalWant,
172+
wantErr: false,
173+
},
174+
}
175+
for _, tt := range tests {
176+
t.Run(tt.name, func(t *testing.T) {
177+
got, err := SystemRulesJsonConverter(tt.args.src)
178+
if (err != nil) != tt.wantErr {
179+
t.Errorf("SystemRulesJsonConverter() error = %v, wantErr %v", err, tt.wantErr)
180+
return
181+
}
182+
if !reflect.DeepEqual(got, tt.want) {
183+
t.Errorf("SystemRulesJsonConverter() got = %v, want %v", got, tt.want)
184+
}
185+
})
186+
}
187+
}
188+
189+
func TestSystemRulesUpdater(t *testing.T) {
190+
t.Run("TestSystemRulesUpdater_Nil", func(t *testing.T) {
191+
system.ClearRules()
192+
err := SystemRulesUpdater(nil)
193+
assert.True(t, err == nil && len(system.GetRules()) == 0, "Fail to test TestSystemRulesUpdater_Nil")
194+
})
195+
196+
t.Run("TestSystemRulesUpdater_Assert_Failed", func(t *testing.T) {
197+
system.ClearRules()
198+
err := SystemRulesUpdater("xxxxxxxx")
199+
assert.True(t, err != nil && strings.Contains(err.Error(), "Fail to type assert data to []system.SystemRule"))
200+
})
201+
202+
t.Run("TestSystemRulesUpdater_Empty_Rules", func(t *testing.T) {
203+
system.ClearRules()
204+
p := make([]system.SystemRule, 0)
205+
err := SystemRulesUpdater(p)
206+
assert.True(t, err == nil && len(system.GetRules()) == 0)
207+
})
208+
209+
t.Run("TestSystemRulesUpdater_Normal", func(t *testing.T) {
210+
system.ClearRules()
211+
p := make([]system.SystemRule, 0)
212+
sr := system.SystemRule{
213+
ID: 0,
214+
MetricType: 0,
215+
TriggerCount: 0,
216+
Strategy: 0,
217+
}
218+
p = append(p, sr)
219+
err := SystemRulesUpdater(p)
220+
assert.True(t, err == nil && len(system.GetRules()) == 1)
221+
})
222+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[
2+
{
3+
"id": 0,
4+
"resource": "abc0",
5+
"limitApp": "default",
6+
"grade": 1,
7+
"strategy": 0,
8+
"controlBehavior": 0,
9+
"refResource": "refDefault",
10+
"warmUpPeriodSec": 10,
11+
"maxQueueingTimeMs": 1000,
12+
"clusterMode": false,
13+
"clusterConfig": {
14+
"thresholdType": 0
15+
}
16+
},
17+
{
18+
"id": 1,
19+
"resource": "abc1",
20+
"limitApp": "default",
21+
"grade": 1,
22+
"strategy": 0,
23+
"controlBehavior": 0,
24+
"refResource": "refDefault",
25+
"warmUpPeriodSec": 10,
26+
"maxQueueingTimeMs": 1000,
27+
"clusterMode": false,
28+
"clusterConfig": {
29+
"thresholdType": 0
30+
}
31+
},
32+
{
33+
"id": 2,
34+
"resource": "abc2",
35+
"limitApp": "default",
36+
"grade": 1,
37+
"strategy": 0,
38+
"controlBehavior": 0,
39+
"refResource": "refDefault",
40+
"warmUpPeriodSec": 10,
41+
"maxQueueingTimeMs": 1000,
42+
"clusterMode": false,
43+
"clusterConfig": {
44+
"thresholdType": 0
45+
}
46+
}
47+
]

0 commit comments

Comments
 (0)