github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/parameters/transferURLs_test.go (about) 1 /* 2 * Copyright (c) 2018, Psiphon Inc. 3 * All rights reserved. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package parameters 21 22 import ( 23 "encoding/base64" 24 "testing" 25 ) 26 27 func TestTransferURLs(t *testing.T) { 28 29 decodedA := "a.example.com" 30 encodedA := base64.StdEncoding.EncodeToString([]byte(decodedA)) 31 encodedB := base64.StdEncoding.EncodeToString([]byte("b.example.com")) 32 encodedC := base64.StdEncoding.EncodeToString([]byte("c.example.com")) 33 34 testCases := []struct { 35 description string 36 transferURLs TransferURLs 37 attempts int 38 expectedValid bool 39 expectedCanonicalURL string 40 expectedDistinctSelections int 41 }{ 42 { 43 "missing OnlyAfterAttempts = 0", 44 TransferURLs{ 45 { 46 URL: encodedA, 47 OnlyAfterAttempts: 1, 48 }, 49 }, 50 1, 51 false, 52 decodedA, 53 0, 54 }, 55 { 56 "single URL, multiple attempts", 57 TransferURLs{ 58 { 59 URL: encodedA, 60 OnlyAfterAttempts: 0, 61 }, 62 }, 63 2, 64 true, 65 decodedA, 66 1, 67 }, 68 { 69 "multiple URLs, single attempt", 70 TransferURLs{ 71 { 72 URL: encodedA, 73 OnlyAfterAttempts: 0, 74 }, 75 { 76 URL: encodedB, 77 OnlyAfterAttempts: 1, 78 }, 79 { 80 URL: encodedC, 81 OnlyAfterAttempts: 1, 82 }, 83 }, 84 1, 85 true, 86 decodedA, 87 1, 88 }, 89 { 90 "multiple URLs, multiple attempts", 91 TransferURLs{ 92 { 93 URL: encodedA, 94 OnlyAfterAttempts: 0, 95 }, 96 { 97 URL: encodedB, 98 OnlyAfterAttempts: 1, 99 }, 100 { 101 URL: encodedC, 102 OnlyAfterAttempts: 1, 103 }, 104 }, 105 2, 106 true, 107 decodedA, 108 3, 109 }, 110 { 111 "multiple URLs, multiple attempts", 112 TransferURLs{ 113 { 114 URL: encodedA, 115 OnlyAfterAttempts: 0, 116 }, 117 { 118 URL: encodedB, 119 OnlyAfterAttempts: 1, 120 }, 121 { 122 URL: encodedC, 123 OnlyAfterAttempts: 3, 124 }, 125 }, 126 4, 127 true, 128 decodedA, 129 3, 130 }, 131 } 132 133 for _, testCase := range testCases { 134 t.Run(testCase.description, func(t *testing.T) { 135 136 err := testCase.transferURLs.DecodeAndValidate() 137 138 if testCase.expectedValid { 139 if err != nil { 140 t.Fatalf("unexpected validation error: %s", err) 141 } 142 } else { 143 if err == nil { 144 t.Fatalf("expected validation error") 145 } 146 return 147 } 148 149 // Track distinct selections for each attempt; the 150 // expected number of distinct should be for at least 151 // one particular attempt. 152 attemptDistinctSelections := make(map[int]map[string]int) 153 for i := 0; i < testCase.attempts; i++ { 154 attemptDistinctSelections[i] = make(map[string]int) 155 } 156 157 // Perform enough runs to account for random selection. 158 runs := 1000 159 160 attempt := 0 161 for i := 0; i < runs; i++ { 162 canonicalURL := testCase.transferURLs.CanonicalURL() 163 if canonicalURL != testCase.expectedCanonicalURL { 164 t.Fatalf("unexpected canonical URL: %s", canonicalURL) 165 } 166 transferUrl := testCase.transferURLs.Select(attempt) 167 if transferUrl.SkipVerify { 168 t.Fatalf("unexpected skipVerify") 169 } 170 attemptDistinctSelections[attempt][transferUrl.URL] += 1 171 attempt = (attempt + 1) % testCase.attempts 172 } 173 174 maxDistinctSelections := 0 175 for _, m := range attemptDistinctSelections { 176 if len(m) > maxDistinctSelections { 177 maxDistinctSelections = len(m) 178 } 179 } 180 181 if maxDistinctSelections != testCase.expectedDistinctSelections { 182 t.Fatalf("got %d distinct selections, expected %d", 183 maxDistinctSelections, 184 testCase.expectedDistinctSelections) 185 } 186 }) 187 } 188 189 }