1 package growthbook
2
3 import (
4 "net/url"
5 "os"
6 "testing"
7 )
8
9 func TestIsURLTargetedNoTargetingRules(t *testing.T) {
10 url := mustParseUrl("https://example.com/testing")
11 if isURLTargeted(url, []URLTarget{}) != false {
12 t.Error("expected isURLTargeted to return false")
13 }
14 }
15
16 func TestIsURLTargetedMixIncludeExclude(t *testing.T) {
17 urls := "https://www.example.com"
18 url := mustParseUrl(urls)
19
20 includeMatch := URLTarget{SimpleURLTarget, true, urls}
21 excludeMatch := URLTarget{SimpleURLTarget, false, urls}
22 includeNoMatch := URLTarget{SimpleURLTarget, true, "https://wrong.com"}
23 excludeNoMatch := URLTarget{SimpleURLTarget, false, "https://another.com"}
24
25 check := func(icase int, expected bool, targets ...URLTarget) {
26 if isURLTargeted(url, targets) != expected {
27 t.Errorf("%d: expected isURLTargets to return %v", icase, expected)
28 }
29 }
30
31
32 check(1, false, includeMatch, includeNoMatch, excludeMatch, excludeNoMatch)
33
34
35 check(2, true, includeMatch, includeNoMatch, excludeNoMatch)
36
37
38 check(3, false, includeNoMatch, excludeNoMatch)
39
40
41 check(4, false, includeNoMatch, excludeNoMatch, excludeMatch)
42
43
44 check(5, true, excludeNoMatch, excludeNoMatch)
45
46
47 check(6, false, excludeNoMatch, excludeMatch)
48
49
50 check(7, false, includeNoMatch, includeNoMatch)
51
52
53 check(8, true, includeNoMatch, includeMatch)
54 }
55
56 func TestIsURLTargetedExcludeOnTopOfInclude(t *testing.T) {
57 rules := []URLTarget{
58 {Include: true, Type: SimpleURLTarget, Pattern: "/search"},
59 {Include: false, Type: SimpleURLTarget, Pattern: "/search?bad=true"},
60 }
61
62 check := func(icase int, expected bool, urls string) {
63 if isURLTargeted(mustParseUrl(urls), rules) != expected {
64 t.Errorf("%d: expected isURLTargets to return %v", icase, expected)
65 }
66 }
67
68 check(1, true, "https://example.com/search")
69 check(2, false, "https://example.com/search?bad=true")
70 check(3, true, "https://example.com/search?good=true")
71 }
72
73 type urlTest struct {
74 targetType URLTargetType
75 url string
76 pattern string
77 expected bool
78 }
79
80 var cases = []urlTest{
81 {RegexURLTarget, "https://www.example.com/post/123", "^/post/[0-9]+", true},
82 {RegexURLTarget, "https://www.example.com/post/abc", "^/post/[0-9]+", false},
83 {RegexURLTarget, "https://www.example.com/new/post/123", "^/post/[0-9]+", false},
84 {RegexURLTarget, "https://www.example.com/new/post/123", "example\\.com.*/post/[0-9]+", true},
85 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "/foo", true},
86 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "/foo?baz=2", true},
87 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "/foo?foo=3", false},
88 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "/bar?baz=2", false},
89 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "foo", true},
90 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "*?baz=2&bar=1", true},
91 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "*.example.com/foo", true},
92 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "blah.example.com/foo", false},
93 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "https://www.*.com/foo", true},
94 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "*.example.com", false},
95 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "http://www.example.com/foo", true},
96 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "f", false},
97 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "f*", true},
98 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "*f*", true},
99 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "/foo/", true},
100 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "/foo/bar", false},
101 {SimpleURLTarget, "https://www.example.com/foo?bar=1&baz=2", "/bar/foo", false},
102 {SimpleURLTarget, "https://www.example.com/foo/bar/baz", "/foo/*/baz", true},
103 {SimpleURLTarget, "https://www.example.com/foo/bar/(baz", "/foo/*", true},
104 {SimpleURLTarget, "https://www.example.com/foo/bar/#test", "/foo/*", true},
105 {SimpleURLTarget, "https://www.example.com/foo/#test", "/foo/", true},
106 {SimpleURLTarget, "https://www.example.com/foo/#test", "/foo/#test", true},
107 {SimpleURLTarget, "https://www.example.com/foo/#test", "/foo/#blah", false},
108 {SimpleURLTarget, "/foo/bar/?baz=1", "http://example.com/foo/bar", false},
109 {SimpleURLTarget, "/foo/bar/?baz=1", "/foo/bar", true},
110 {SimpleURLTarget, "&??*&&(", "/foo/bar", false},
111 {SimpleURLTarget, "&??*&&(", "((*)(*$&#@!!)))", false},
112 }
113
114 func TestIsURLTargetedTableDriven(t *testing.T) {
115 for itest, test := range cases {
116 targets := []URLTarget{{test.targetType, true, test.pattern}}
117 if isURLTargeted(mustParseUrl(test.url), targets) != test.expected {
118 types := "simple"
119 if test.targetType == RegexURLTarget {
120 types = "regexp"
121 }
122 t.Errorf("%d: type=%s url=%s pattern=%s expected=%v",
123 itest+1, types, test.url, test.pattern, test.expected)
124 }
125 }
126 }
127
128 func mustParseUrl(u string) *url.URL {
129 result, err := url.Parse(u)
130 if err != nil {
131 logError("Failed to parse URL: ", u)
132 os.Exit(1)
133 }
134 return result
135 }
136
View as plain text