1 Star 2 Fork 0

Feature Probe / server-sdk-go

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
evaluate_test.go 27.58 KB
一键复制 编辑 原始数据 按行查看 历史
jianggang 提交于 2023-06-01 20:30 . :bug:fix: repo map concurrency issue (#21)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284
package featureprobe
import (
"encoding/json"
"fmt"
"io/ioutil"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func loadRepoFromFile() (repo Repository, err error) {
bytes, _ := ioutil.ReadFile("./resources/fixtures/repo.json")
repoData := RepositoryData{}
err = json.Unmarshal(bytes, &repoData)
repo.flush(repoData)
return
}
func TestTogglesUnmarshal(t *testing.T) {
var toggles Toggles
bytes, _ := ioutil.ReadFile("./resources/fixtures/toggles.json")
err := json.Unmarshal(bytes, &toggles)
assert.Equal(t, nil, err)
}
func TestSaltHash(t *testing.T) {
var h = saltHash("key", "salt", 10000)
assert.Equal(t, h, 2647)
}
func TestMatchInSegmentCondition(t *testing.T) {
repo, err := loadRepoFromFile()
assert.Equal(t, nil, err)
user := NewUser().With("city", "4")
toggle, _ := repo.getToggle("json_toggle")
detail, _ := toggle.evalDetail(user, repo.getToggles(), repo.getSegments(), nil, 10)
v, ok := detail.Value.(map[string]interface{})
assert.True(t, ok)
assert.Equal(t, v["variation_1"], "v2")
}
func TestMatchNotInSegmentCondition(t *testing.T) {
repo, _ := loadRepoFromFile()
user := NewUser().With("city", "100")
toggle, _ := repo.getToggle("not_in_segment")
detail, _ := toggle.evalDetail(user, repo.getToggles(), repo.getSegments(), nil, 10)
v, ok := detail.Value.(map[string]interface{})
assert.True(t, ok)
assert.Equal(t, v["not_in"], true)
}
func TestNotMatchInSegmentCondition(t *testing.T) {
repo, _ := loadRepoFromFile()
user := NewUser().With("city", "100")
toggle, _ := repo.getToggle("json_toggle")
_, _ = toggle.eval(user, repo.getToggles(), repo.getSegments(), nil, 10)
detail, _ := toggle.evalDetail(user, repo.getToggles(), repo.getSegments(), nil, 10)
assert.Equal(t, detail.Reason, "default")
}
func TestNoSegments(t *testing.T) {
c := Condition{
Type: "segment",
Subject: "subject",
Predicate: "name",
Objects: nil,
}
user := NewUser().With("city", "100")
r := c.matchSegmentCondition(user, "is in", nil)
assert.False(t, r)
r = c.matchSegmentCondition(user, "is not in", nil)
assert.False(t, r)
}
func TestSegmentsUnknownPredicate(t *testing.T) {
c := Condition{
Type: "segment",
Subject: "subject",
Predicate: "name",
Objects: nil,
}
segments := map[string]Segment{}
user := NewUser().StableRollout("key11").With("city", "100")
r := c.matchSegmentCondition(user, "unknown", segments)
assert.False(t, r)
}
func TestMultiConditions(t *testing.T) {
repo, _ := loadRepoFromFile()
user := NewUser().StableRollout("key11").With("city", "1").With("os", "linux")
toggle, _ := repo.getToggle("multi_condition_toggle")
r, _ := toggle.eval(user, repo.getToggles(), repo.getSegments(), nil, 10)
v, ok := r.(map[string]interface{})
assert.True(t, ok)
assert.Equal(t, v["variation_0"], "")
user = NewUser().StableRollout("key").With("city", "1").With("os", "linux")
toggle, _ = repo.getToggle("multi_condition_toggle")
detail, _ := toggle.evalDetail(user, repo.getToggles(), repo.getSegments(), nil, 10)
v, ok = detail.Value.(map[string]interface{})
assert.True(t, ok)
assert.Equal(t, v["variation_0"], "")
user = NewUser().StableRollout("key").With("os", "linux")
detail, _ = toggle.evalDetail(user, repo.getToggles(), repo.getSegments(), nil, 10)
_, ok = detail.Value.(map[string]interface{})
assert.True(t, ok)
assert.Equal(t, detail.Reason, "default")
user = NewUser().StableRollout("key").With("city", "1")
detail, _ = toggle.evalDetail(user, repo.getToggles(), repo.getSegments(), nil, 10)
_, ok = detail.Value.(map[string]interface{})
assert.True(t, ok)
assert.Equal(t, detail.Reason, "default")
}
func TestDisabledToggle(t *testing.T) {
repo, _ := loadRepoFromFile()
user := NewUser().With("city", "100")
toggle, _ := repo.getToggle("disabled_toggle")
detail, _ := toggle.evalDetail(user, repo.getToggles(), repo.getSegments(), nil, 10)
assert.Equal(t, detail.Reason, "disabled")
_, err := toggle.eval(user, repo.getToggles(), repo.getSegments(), nil, 10)
assert.Empty(t, err)
}
func TestPrerequisiteToggleMatched(t *testing.T) {
repo, _ := loadRepoFromFile()
user := NewUser().With("city", "1")
toggle, _ := repo.getToggle("prerequisite_toggle")
detail, err := toggle.evalDetail(user, repo.getToggles(), repo.getSegments(), nil, 10)
assert.Empty(t, err)
assert.Equal(t, detail.Value, "2")
}
func TestPrerequisiteToggleNotMatchedShouldBeReturnDefaultValue(t *testing.T) {
repo, _ := loadRepoFromFile()
user := NewUser().With("city", "6")
toggle, _ := repo.getToggle("not_match_prerequisite_toggle")
detail, err := toggle.evalDetail(user, repo.getToggles(), repo.getSegments(), nil, 10)
assert.Empty(t, err)
assert.Equal(t, detail.Reason, "default")
assert.Equal(t, detail.Value, "1")
}
func TestPrerequisiteToggleNotExistShouldBeReturnDefaultValue(t *testing.T) {
repo, _ := loadRepoFromFile()
user := NewUser().With("city", "6")
toggle, _ := repo.getToggle("prerequisite_not_exist_toggle")
detail, err := toggle.evalDetail(user, repo.getToggles(), repo.getSegments(), nil, 10)
assert.Empty(t, err)
assert.Equal(t, detail.Reason, "prerequisite toggle not exist")
assert.Equal(t, detail.Value, "1")
}
func TestPrerequisiteToggleDeepOverlowShouldBeReturnDefaultValue(t *testing.T) {
repo, _ := loadRepoFromFile()
user := NewUser().With("city", "6")
toggle, _ := repo.getToggle("prerequisite_deep_overflow")
detail, err := toggle.evalDetail(user, repo.getToggles(), repo.getSegments(), nil, 5)
assert.Empty(t, err)
assert.Equal(t, detail.Reason, "prerequisite deep overflow")
assert.Equal(t, detail.Value, "1")
}
func TestDistributionNoSalt(t *testing.T) {
distribution := [][]Range{
{Range{Lower: 0, Upper: 2647}},
{Range{Lower: 2647, Upper: 2648}},
{Range{Lower: 2648, Upper: 10000}},
}
split := Split{
Distribution: distribution,
BucketBy: "name",
Salt: "",
}
user := NewUser().StableRollout("key").With("name", "key")
params := EvalParam{
User: user,
Variations: nil,
Segments: nil,
}
index, _ := split.findIndex(params)
assert.Equal(t, index, 2)
}
func TestDistributionInExactBucket(t *testing.T) {
distribution := [][]Range{
{Range{Lower: 0, Upper: 2647}},
{Range{Lower: 2647, Upper: 2648}},
{Range{Lower: 2648, Upper: 10000}},
}
split := Split{
Distribution: distribution,
BucketBy: "name",
Salt: "",
}
user := NewUser().StableRollout("key").With("name", "key")
params := EvalParam{
User: user,
Variations: nil,
Segments: nil,
Key: "salt",
}
index, _ := split.findIndex(params)
assert.Equal(t, index, 1)
}
func TestDistributionInNoneBucket(t *testing.T) {
distribution := [][]Range{
{Range{Lower: 0, Upper: 2647}},
{Range{Lower: 2648, Upper: 10000}},
}
split := Split{
Distribution: distribution,
BucketBy: "name",
Salt: "salt",
}
user := NewUser().StableRollout("key").With("name", "key")
params := EvalParam{
User: user,
Variations: nil,
Segments: nil,
}
_, err := split.findIndex(params)
assert.Error(t, err)
}
func TestSelectVariationFail(t *testing.T) {
distribution := [][]Range{
{Range{Lower: 0, Upper: 5000}},
{Range{Lower: 5000, Upper: 10000}},
}
split := Split{
Distribution: distribution,
BucketBy: "name",
Salt: "salt",
}
serve := Serve{
Split: &split,
Select: nil,
}
user := NewUser().StableRollout("key")
params := EvalParam{
User: user,
Variations: []interface{}{
"a", "b",
},
Segments: nil,
}
v, _, err := serve.selectVariation(params)
assert.Equal(t, v, nil)
assert.Error(t, err)
}
func TestMatchIsOneOf(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "is one of",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "world")
r := condition.matchStringCondition(user, condition.Predicate)
assert.True(t, r)
}
func TestNotMatchIsOneOf(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "is one of",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "not_in")
r := condition.matchStringCondition(user, condition.Predicate)
assert.False(t, r)
}
func TestUserMissKeyIsNotOneOf(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "is not any of",
Objects: []string{
"hello", "world",
},
}
user := NewUser()
r := condition.matchStringCondition(user, condition.Predicate)
assert.False(t, r)
}
func TestMatchIsNotAnyOf(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "is not any of",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "not in")
r := condition.matchStringCondition(user, condition.Predicate)
assert.True(t, r)
}
func TestMatchEndsWith(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "ends with",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "bob world")
r := condition.matchStringCondition(user, condition.Predicate)
assert.True(t, r)
}
func TestNotMatchEndsWith(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "ends with",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "bob")
r := condition.matchStringCondition(user, condition.Predicate)
assert.False(t, r)
}
func TestMatchNotEndsWith(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "does not end with",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "bob")
r := condition.matchStringCondition(user, condition.Predicate)
assert.True(t, r)
}
func TestNotMatchNotEndsWith(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "does not end with",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "bob world")
r := condition.matchStringCondition(user, condition.Predicate)
assert.False(t, r)
}
func TestMatchStartsWith(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "starts with",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "world bob")
r := condition.matchStringCondition(user, condition.Predicate)
assert.True(t, r)
}
func TestNotMatchStartsWith(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "starts with",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "bob")
r := condition.matchStringCondition(user, condition.Predicate)
assert.False(t, r)
}
func TestMatchNotStartsWith(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "does not start with",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "bob")
r := condition.matchStringCondition(user, condition.Predicate)
assert.True(t, r)
}
func TestNotMatchNotStartsWith(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "does not start with",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "world bob")
r := condition.matchStringCondition(user, condition.Predicate)
assert.False(t, r)
}
func TestMatchCondition(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "contains",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "alice world bob")
r := condition.matchStringCondition(user, condition.Predicate)
assert.True(t, r)
}
func TestNotMatchContainsCondition(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "contains",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "alice bob")
r := condition.matchStringCondition(user, condition.Predicate)
assert.False(t, r)
}
func TestMatchNotContainsCondition(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "does not contain",
Objects: []string{
"hello", "world",
},
}
user := NewUser().With("name", "alice world bob")
r := condition.matchStringCondition(user, condition.Predicate)
assert.False(t, r)
}
func TestMatchRegex(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "matches regex",
Objects: []string{
"hello", "world.*",
},
}
user := NewUser().With("name", "alice world bob")
r := condition.matchStringCondition(user, condition.Predicate)
assert.True(t, r)
}
func TestMatchRegexFirstObject(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "matches regex",
Objects: []string{
"hello\\d", "world.*",
},
}
user := NewUser().With("name", "alice orld bob hello3")
r := condition.matchStringCondition(user, condition.Predicate)
assert.True(t, r)
}
func TestNotMatchRegex(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "does not match regex",
Objects: []string{
"hello\\d", "world.*",
},
}
user := NewUser().With("name", "alice orld bob hello")
r := condition.matchStringCondition(user, condition.Predicate)
assert.True(t, r)
}
func TestInvalidRegex(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "matches regex",
Objects: []string{
"\\\\\\",
},
}
user := NewUser().With("name", "\\\\\\")
r := condition.matchStringCondition(user, condition.Predicate)
assert.False(t, r)
}
func TestUnknownPredicate(t *testing.T) {
condition := Condition{
Type: "string",
Subject: "name",
Predicate: "unknown",
Objects: []string{
"123",
},
}
user := NewUser().With("name", "123")
r := condition.matchStringCondition(user, condition.Predicate)
assert.False(t, r)
}
func TestDatetimeBefore(t *testing.T) {
now := time.Now().Unix()
condition := Condition{
Type: "datetime",
Subject: "datetime",
Predicate: "before",
Objects: []string{
fmt.Sprintf("%d", now+1),
},
}
user := NewUser()
r := condition.meet(user, nil)
assert.True(t, r)
user.With("datetime", fmt.Sprintf("%d", now))
r = condition.meet(user, nil)
assert.True(t, r)
user.With("datetime", fmt.Sprintf("%d", now+1))
r = condition.meet(user, nil)
assert.False(t, r)
}
func TestDatetimeAfter(t *testing.T) {
now := time.Now().Unix()
condition := Condition{
Type: "datetime",
Subject: "datetime",
Predicate: "after",
Objects: []string{
fmt.Sprintf("%d", now),
},
}
user := NewUser()
r := condition.meet(user, nil)
assert.True(t, r)
user.With("datetime", fmt.Sprintf("%d", now))
r = condition.meet(user, nil)
assert.True(t, r)
user.With("datetime", fmt.Sprintf("%d", now+1))
r = condition.meet(user, nil)
assert.True(t, r)
user.With("datetime", fmt.Sprintf("%d", now-1))
r = condition.meet(user, nil)
assert.False(t, r)
}
func TestDatetimeInvalidCustomValue(t *testing.T) {
condition := Condition{
Type: "datetime",
Subject: "datetime",
Predicate: "after",
Objects: []string{},
}
user := NewUser().With("datetime", "a")
r := condition.meet(user, nil)
assert.False(t, r)
}
func TestDatetimeInvalid(t *testing.T) {
condition := Condition{
Type: "datetime",
Subject: "datetime",
Predicate: "after",
Objects: []string{
"a",
},
}
user := NewUser()
r := condition.meet(user, nil)
assert.False(t, r)
}
func TestDatetimeUnknownPredicate(t *testing.T) {
condition := Condition{
Type: "datetime",
Subject: "datetime",
Predicate: "a",
Objects: []string{
"a",
},
}
user := NewUser()
r := condition.meet(user, nil)
assert.False(t, r)
}
func TestNumberEqual(t *testing.T) {
condition := Condition{
Type: "number",
Subject: "price",
Predicate: "=",
Objects: []string{
"1", "2", "3",
},
}
user := NewUser().With("price", "1")
r := condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "2")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "3")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "4")
r = condition.meet(user, nil)
assert.False(t, r)
}
func TestNumberNotEqual(t *testing.T) {
condition := Condition{
Type: "number",
Subject: "price",
Predicate: "!=",
Objects: []string{
"1", "2", "3",
},
}
user := NewUser().With("price", "1")
r := condition.meet(user, nil)
assert.False(t, r)
user = NewUser().With("price", "2")
r = condition.meet(user, nil)
assert.False(t, r)
user = NewUser().With("price", "3")
r = condition.meet(user, nil)
assert.False(t, r)
user = NewUser().With("price", "4")
r = condition.meet(user, nil)
assert.True(t, r)
}
func TestNumberGreaterThan(t *testing.T) {
condition := Condition{
Type: "number",
Subject: "price",
Predicate: ">",
Objects: []string{
"1", "2", "3",
},
}
user := NewUser().With("price", "1")
r := condition.meet(user, nil)
assert.False(t, r)
user = NewUser().With("price", "2")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "3")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "4")
r = condition.meet(user, nil)
assert.True(t, r)
}
func TestNumberGreaterThanOrEqualTo(t *testing.T) {
condition := Condition{
Type: "number",
Subject: "price",
Predicate: ">=",
Objects: []string{
"1", "2", "3",
},
}
user := NewUser().With("price", "0")
r := condition.meet(user, nil)
assert.False(t, r)
user = NewUser().With("price", "1")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "2")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "3")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "4")
r = condition.meet(user, nil)
assert.True(t, r)
}
func TestNumberLessThan(t *testing.T) {
condition := Condition{
Type: "number",
Subject: "price",
Predicate: "<",
Objects: []string{
"1", "2", "3",
},
}
user := NewUser().With("price", "0")
r := condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "1")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "2")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "3")
r = condition.meet(user, nil)
assert.False(t, r)
user = NewUser().With("price", "4")
r = condition.meet(user, nil)
assert.False(t, r)
}
func TestNumberLessThanOrEqualTo(t *testing.T) {
condition := Condition{
Type: "number",
Subject: "price",
Predicate: "<=",
Objects: []string{
"1", "2", "3",
},
}
user := NewUser().With("price", "0")
r := condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "1")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "2")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "3")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("price", "4")
r = condition.meet(user, nil)
assert.False(t, r)
}
func TestNumberInvalid(t *testing.T) {
condition := Condition{
Type: "number",
Subject: "price",
Predicate: "?",
Objects: []string{
"1", "2", "3",
},
}
user := NewUser().With("price", "a")
r := condition.meet(user, nil)
assert.False(t, r)
user = NewUser()
r = condition.meet(user, nil)
assert.False(t, r)
condition = Condition{
Type: "number",
Subject: "price",
Predicate: ">",
Objects: []string{
"a",
},
}
user = NewUser().With("price", "1")
r = condition.meet(user, nil)
assert.False(t, r)
}
func TestNumberUnknownPredicate(t *testing.T) {
condition := Condition{
Type: "number",
Subject: "price",
Predicate: "?",
Objects: []string{
"1", "2", "3",
},
}
user := NewUser().With("price", "0")
r := condition.meet(user, nil)
assert.False(t, r)
}
func TestSemVerEqual(t *testing.T) {
condition := Condition{
Type: "semver",
Subject: "version",
Predicate: "=",
Objects: []string{
"1.0.0", "2.0.0", "3.0.0",
},
}
user := NewUser().With("version", "1.0.0")
r := condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "1.1.0")
r = condition.meet(user, nil)
assert.False(t, r)
user = NewUser().With("version", "2.0.0")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "4.1.0")
r = condition.meet(user, nil)
assert.False(t, r)
}
func TestSemVerNotEqual(t *testing.T) {
condition := Condition{
Type: "semver",
Subject: "version",
Predicate: "!=",
Objects: []string{
"1.0.0", "2.0.0", "3.0.0",
},
}
user := NewUser().With("version", "1.0.0")
r := condition.meet(user, nil)
assert.False(t, r)
user = NewUser().With("version", "1.1.0")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "2.0.0")
r = condition.meet(user, nil)
assert.False(t, r)
user = NewUser().With("version", "4.1.0")
r = condition.meet(user, nil)
assert.True(t, r)
}
func TestSemVerGreaterThan(t *testing.T) {
condition := Condition{
Type: "semver",
Subject: "version",
Predicate: ">",
Objects: []string{
"1.0.0", "2.0.0", "3.0.0",
},
}
user := NewUser().With("version", "1.0.0")
r := condition.meet(user, nil)
assert.False(t, r)
user = NewUser().With("version", "1.1.0")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "2.0.0")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "4.1.0")
r = condition.meet(user, nil)
assert.True(t, r)
}
func TestSemVerGreaterThanOrEqualTo(t *testing.T) {
condition := Condition{
Type: "semver",
Subject: "version",
Predicate: ">=",
Objects: []string{
"1.0.0", "2.0.0", "3.0.0",
},
}
user := NewUser().With("version", "1.0.0")
r := condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "1.1.0")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "2.0.0")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "4.1.0")
r = condition.meet(user, nil)
assert.True(t, r)
}
func TestSemVerLessThan(t *testing.T) {
condition := Condition{
Type: "semver",
Subject: "version",
Predicate: "<",
Objects: []string{
"1.0.0", "2.0.0", "3.0.0",
},
}
user := NewUser().With("version", "0.1.0")
r := condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "1.0.0")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "1.1.0")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "3.0.0")
r = condition.meet(user, nil)
assert.False(t, r)
user = NewUser().With("version", "4.1.0")
r = condition.meet(user, nil)
assert.False(t, r)
}
func TestSemVerLessThanOrEqualTo(t *testing.T) {
condition := Condition{
Type: "semver",
Subject: "version",
Predicate: "<=",
Objects: []string{
"1.0.0", "2.0.0", "3.0.0",
},
}
user := NewUser().With("version", "0.1.0")
r := condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "1.0.0")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "1.1.0")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "2.0.0")
r = condition.meet(user, nil)
assert.True(t, r)
user = NewUser().With("version", "4.1.0")
r = condition.meet(user, nil)
assert.False(t, r)
}
func TestSemVerInvalid(t *testing.T) {
condition := Condition{
Type: "semver",
Subject: "version",
Predicate: ">",
Objects: []string{
"invalid",
},
}
user := NewUser().With("version", "0.1.0")
r := condition.meet(user, nil)
assert.False(t, r)
condition.Predicate = "?"
user = NewUser().With("version", "0.1.0")
r = condition.meet(user, nil)
assert.False(t, r)
user = NewUser()
r = condition.meet(user, nil)
assert.False(t, r)
user = NewUser().With("version", "invalid_version")
r = condition.meet(user, nil)
assert.False(t, r)
}
func TestUnknownConditionType(t *testing.T) {
c := Condition{
Type: "unknown",
Subject: "subject",
Predicate: "name",
Objects: nil,
}
u := NewUser()
b := c.meet(u, nil)
assert.False(t, b)
}
func TestMatchEqualString(t *testing.T) {
var repo Repository
bytes, _ := ioutil.ReadFile("./resources/fixtures/repo.json")
repoData := RepositoryData{}
err := json.Unmarshal(bytes, &repoData)
repo.flush(repoData)
assert.Equal(t, nil, err)
user := NewUser().With("city", "1")
toggle, _ := repo.getToggle("json_toggle")
r, _ := toggle.eval(user, repo.getToggles(), repo.getSegments(), nil, 10)
v, ok := r.(map[string]interface{})
assert.True(t, ok)
assert.Equal(t, v["variation_0"], "c2")
}
func TestInvalidJsonRange(t *testing.T) {
var r Range
jsonStr := `{"a": 123}`
err := json.Unmarshal([]byte(jsonStr), &r)
assert.Error(t, err)
jsonStr = `[100]`
err = json.Unmarshal([]byte(jsonStr), &r)
assert.Error(t, err)
}
func TestDisabledOutOfRangeToggle(t *testing.T) {
var toggle Toggle
jsonStr := `
{
"key": "disabled_toggle",
"enabled": false,
"version": 1,
"disabledServe": {
"select": 2
},
"defaultServe": {
"select": 2
},
"rules": [],
"variations": [
{},
{
"disabled_key": "disabled_value"
}
]
}`
err := json.Unmarshal([]byte(jsonStr), &toggle)
assert.Empty(t, err)
user := NewUser()
_, err = toggle.eval(user, nil, nil, nil, 10)
assert.Error(t, err)
_, err = toggle.evalDetail(user, nil, nil, nil, 10)
assert.Error(t, err)
}
func TestEnabledOutOfRangeToggle(t *testing.T) {
var toggle Toggle
jsonStr := `
{
"key": "disabled_toggle",
"enabled": true,
"version": 1,
"disabledServe": {
"select": 2
},
"defaultServe": {
"select": 2
},
"rules": [{
"serve": {
"select": 2
},
"conditions": [
{
"type": "string",
"subject": "city",
"predicate": "is one of",
"objects": [
"1",
"2",
"3"
]
}
]
}],
"variations": [
{},
{
"disabled_key": "disabled_value"
}
]
}`
err := json.Unmarshal([]byte(jsonStr), &toggle)
assert.Empty(t, err)
user := NewUser().With("city", "1")
_, err = toggle.eval(user, nil, nil, nil, 10)
assert.Error(t, err)
_, err = toggle.evalDetail(user, nil, nil, nil, 10)
assert.Error(t, err)
}
func TestDefaultServeOutOfRangeToggle(t *testing.T) {
var toggle Toggle
jsonStr := `
{
"key": "disabled_toggle",
"enabled": true,
"version": 1,
"disabledServe": {
"select": 2
},
"defaultServe": {
"select": 2
},
"rules": [],
"variations": [
{},
{
"disabled_key": "disabled_value"
}
]
}`
err := json.Unmarshal([]byte(jsonStr), &toggle)
assert.Empty(t, err)
user := NewUser().With("city", "1")
_, err = toggle.eval(user, nil, nil, nil, 10)
assert.Error(t, err)
_, err = toggle.evalDetail(user, nil, nil, nil, 10)
assert.Error(t, err)
}
func TestClearRepo(t *testing.T) {
repo, _ := loadRepoFromFile()
assert.True(t, len(repo.getSegments()) > 0)
assert.True(t, len(repo.getToggles()) > 0)
repo.Clear()
assert.Equal(t, 0, len(repo.getSegments()))
assert.Equal(t, 0, len(repo.getToggles()))
}
Go
1
https://gitee.com/featureprobe/server-sdk-go.git
git@gitee.com:featureprobe/server-sdk-go.git
featureprobe
server-sdk-go
server-sdk-go
main

搜索帮助