clientParameters_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  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. package parameters
  20. import (
  21. "encoding/json"
  22. "net/http"
  23. "reflect"
  24. "testing"
  25. "time"
  26. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  27. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
  28. )
  29. func TestGetDefaultParameters(t *testing.T) {
  30. p, err := NewClientParameters(nil)
  31. if err != nil {
  32. t.Fatalf("NewClientParameters failed: %s", err)
  33. }
  34. for name, defaults := range defaultClientParameters {
  35. switch v := defaults.value.(type) {
  36. case string:
  37. g := p.Get().String(name)
  38. if v != g {
  39. t.Fatalf("String returned %+v expected %+v", g, v)
  40. }
  41. case int:
  42. g := p.Get().Int(name)
  43. if v != g {
  44. t.Fatalf("Int returned %+v expected %+v", g, v)
  45. }
  46. case float64:
  47. g := p.Get().Float(name)
  48. if v != g {
  49. t.Fatalf("Float returned %+v expected %+v", g, v)
  50. }
  51. case bool:
  52. g := p.Get().Bool(name)
  53. if v != g {
  54. t.Fatalf("Bool returned %+v expected %+v", g, v)
  55. }
  56. case time.Duration:
  57. g := p.Get().Duration(name)
  58. if v != g {
  59. t.Fatalf("Duration returned %+v expected %+v", g, v)
  60. }
  61. case protocol.TunnelProtocols:
  62. g := p.Get().TunnelProtocols(name)
  63. if !reflect.DeepEqual(v, g) {
  64. t.Fatalf("TunnelProtocols returned %+v expected %+v", g, v)
  65. }
  66. case protocol.TLSProfiles:
  67. g := p.Get().TLSProfiles(name)
  68. if !reflect.DeepEqual(v, g) {
  69. t.Fatalf("TLSProfiles returned %+v expected %+v", g, v)
  70. }
  71. case protocol.LabeledTLSProfiles:
  72. for label, profiles := range v {
  73. g := p.Get().LabeledTLSProfiles(name, label)
  74. if !reflect.DeepEqual(profiles, g) {
  75. t.Fatalf("LabeledTLSProfiles returned %+v expected %+v", g, profiles)
  76. }
  77. }
  78. case protocol.QUICVersions:
  79. g := p.Get().QUICVersions(name)
  80. if !reflect.DeepEqual(v, g) {
  81. t.Fatalf("QUICVersions returned %+v expected %+v", g, v)
  82. }
  83. case protocol.LabeledQUICVersions:
  84. for label, versions := range v {
  85. g := p.Get().LabeledTLSProfiles(name, label)
  86. if !reflect.DeepEqual(versions, g) {
  87. t.Fatalf("LabeledQUICVersions returned %+v expected %+v", g, versions)
  88. }
  89. }
  90. case TransferURLs:
  91. g := p.Get().TransferURLs(name)
  92. if !reflect.DeepEqual(v, g) {
  93. t.Fatalf("TransferURLs returned %+v expected %+v", g, v)
  94. }
  95. case common.RateLimits:
  96. g := p.Get().RateLimits(name)
  97. if !reflect.DeepEqual(v, g) {
  98. t.Fatalf("RateLimits returned %+v expected %+v", g, v)
  99. }
  100. case http.Header:
  101. g := p.Get().HTTPHeaders(name)
  102. if !reflect.DeepEqual(v, g) {
  103. t.Fatalf("HTTPHeaders returned %+v expected %+v", g, v)
  104. }
  105. case protocol.CustomTLSProfiles:
  106. g := p.Get().CustomTLSProfileNames()
  107. names := make([]string, len(v))
  108. for i, profile := range v {
  109. names[i] = profile.Name
  110. }
  111. if !reflect.DeepEqual(names, g) {
  112. t.Fatalf("CustomTLSProfileNames returned %+v expected %+v", g, names)
  113. }
  114. case KeyValues:
  115. g := p.Get().KeyValues(name)
  116. if !reflect.DeepEqual(v, g) {
  117. t.Fatalf("KeyValues returned %+v expected %+v", g, v)
  118. }
  119. case *BPFProgramSpec:
  120. ok, name, rawInstructions := p.Get().BPFProgram(name)
  121. if v != nil || ok || name != "" || rawInstructions != nil {
  122. t.Fatalf(
  123. "BPFProgramSpec returned %+v %+v %+v expected %+v",
  124. ok, name, rawInstructions, v)
  125. }
  126. default:
  127. t.Fatalf("Unhandled default type: %s", name)
  128. }
  129. }
  130. }
  131. func TestGetValueLogger(t *testing.T) {
  132. loggerCalled := false
  133. p, err := NewClientParameters(
  134. func(error) {
  135. loggerCalled = true
  136. })
  137. if err != nil {
  138. t.Fatalf("NewClientParameters failed: %s", err)
  139. }
  140. p.Get().Int("unknown-parameter-name")
  141. if !loggerCalled {
  142. t.Fatalf("logged not called")
  143. }
  144. }
  145. func TestOverrides(t *testing.T) {
  146. tag := "tag"
  147. applyParameters := make(map[string]interface{})
  148. // Below minimum, should not apply
  149. defaultConnectionWorkerPoolSize := defaultClientParameters[ConnectionWorkerPoolSize].value.(int)
  150. minimumConnectionWorkerPoolSize := defaultClientParameters[ConnectionWorkerPoolSize].minimum.(int)
  151. newConnectionWorkerPoolSize := minimumConnectionWorkerPoolSize - 1
  152. applyParameters[ConnectionWorkerPoolSize] = newConnectionWorkerPoolSize
  153. // Above minimum, should apply
  154. defaultInitialLimitTunnelProtocolsCandidateCount := defaultClientParameters[InitialLimitTunnelProtocolsCandidateCount].value.(int)
  155. minimumInitialLimitTunnelProtocolsCandidateCount := defaultClientParameters[InitialLimitTunnelProtocolsCandidateCount].minimum.(int)
  156. newInitialLimitTunnelProtocolsCandidateCount := minimumInitialLimitTunnelProtocolsCandidateCount + 1
  157. applyParameters[InitialLimitTunnelProtocolsCandidateCount] = newInitialLimitTunnelProtocolsCandidateCount
  158. p, err := NewClientParameters(nil)
  159. if err != nil {
  160. t.Fatalf("NewClientParameters failed: %s", err)
  161. }
  162. // No skip on error; should fail and not apply any changes
  163. _, err = p.Set(tag, false, applyParameters)
  164. if err == nil {
  165. t.Fatalf("Set succeeded unexpectedly")
  166. }
  167. if p.Get().Tag() != "" {
  168. t.Fatalf("GetTag returned unexpected value")
  169. }
  170. v := p.Get().Int(ConnectionWorkerPoolSize)
  171. if v != defaultConnectionWorkerPoolSize {
  172. t.Fatalf("GetInt returned unexpected ConnectionWorkerPoolSize: %d", v)
  173. }
  174. v = p.Get().Int(InitialLimitTunnelProtocolsCandidateCount)
  175. if v != defaultInitialLimitTunnelProtocolsCandidateCount {
  176. t.Fatalf("GetInt returned unexpected InitialLimitTunnelProtocolsCandidateCount: %d", v)
  177. }
  178. // Skip on error; should skip ConnectionWorkerPoolSize and apply InitialLimitTunnelProtocolsCandidateCount
  179. counts, err := p.Set(tag, true, applyParameters)
  180. if err != nil {
  181. t.Fatalf("Set failed: %s", err)
  182. }
  183. if counts[0] != 1 {
  184. t.Fatalf("Apply returned unexpected count: %d", counts[0])
  185. }
  186. v = p.Get().Int(ConnectionWorkerPoolSize)
  187. if v != defaultConnectionWorkerPoolSize {
  188. t.Fatalf("GetInt returned unexpected ConnectionWorkerPoolSize: %d", v)
  189. }
  190. v = p.Get().Int(InitialLimitTunnelProtocolsCandidateCount)
  191. if v != newInitialLimitTunnelProtocolsCandidateCount {
  192. t.Fatalf("GetInt returned unexpected InitialLimitTunnelProtocolsCandidateCount: %d", v)
  193. }
  194. }
  195. func TestNetworkLatencyMultiplier(t *testing.T) {
  196. p, err := NewClientParameters(nil)
  197. if err != nil {
  198. t.Fatalf("NewClientParameters failed: %s", err)
  199. }
  200. timeout1 := p.Get().Duration(TunnelConnectTimeout)
  201. applyParameters := map[string]interface{}{"NetworkLatencyMultiplier": 2.0}
  202. _, err = p.Set("", false, applyParameters)
  203. if err != nil {
  204. t.Fatalf("Set failed: %s", err)
  205. }
  206. timeout2 := p.Get().Duration(TunnelConnectTimeout)
  207. if 2*timeout1 != timeout2 {
  208. t.Fatalf("Unexpected timeouts: 2 * %s != %s", timeout1, timeout2)
  209. }
  210. }
  211. func TestCustomNetworkLatencyMultiplier(t *testing.T) {
  212. p, err := NewClientParameters(nil)
  213. if err != nil {
  214. t.Fatalf("NewClientParameters failed: %s", err)
  215. }
  216. timeout1 := p.Get().Duration(TunnelConnectTimeout)
  217. applyParameters := map[string]interface{}{"NetworkLatencyMultiplier": 2.0}
  218. _, err = p.Set("", false, applyParameters)
  219. if err != nil {
  220. t.Fatalf("Set failed: %s", err)
  221. }
  222. timeout2 := p.GetCustom(4.0).Duration(TunnelConnectTimeout)
  223. if 4*timeout1 != timeout2 {
  224. t.Fatalf("Unexpected timeouts: 4 * %s != %s", timeout1, timeout2)
  225. }
  226. }
  227. func TestLimitTunnelProtocolProbability(t *testing.T) {
  228. p, err := NewClientParameters(nil)
  229. if err != nil {
  230. t.Fatalf("NewClientParameters failed: %s", err)
  231. }
  232. // Default probability should be 1.0 and always return tunnelProtocols
  233. tunnelProtocols := protocol.TunnelProtocols{"OSSH", "SSH"}
  234. applyParameters := map[string]interface{}{
  235. "LimitTunnelProtocols": tunnelProtocols,
  236. }
  237. _, err = p.Set("", false, applyParameters)
  238. if err != nil {
  239. t.Fatalf("Set failed: %s", err)
  240. }
  241. for i := 0; i < 1000; i++ {
  242. l := p.Get().TunnelProtocols(LimitTunnelProtocols)
  243. if !reflect.DeepEqual(l, tunnelProtocols) {
  244. t.Fatalf("unexpected %+v != %+v", l, tunnelProtocols)
  245. }
  246. }
  247. // With probability set to 0.5, should return tunnelProtocols ~50%
  248. defaultLimitTunnelProtocols := protocol.TunnelProtocols{}
  249. applyParameters = map[string]interface{}{
  250. "LimitTunnelProtocolsProbability": 0.5,
  251. "LimitTunnelProtocols": tunnelProtocols,
  252. }
  253. _, err = p.Set("", false, applyParameters)
  254. if err != nil {
  255. t.Fatalf("Set failed: %s", err)
  256. }
  257. matchCount := 0
  258. for i := 0; i < 1000; i++ {
  259. l := p.Get().TunnelProtocols(LimitTunnelProtocols)
  260. if reflect.DeepEqual(l, tunnelProtocols) {
  261. matchCount += 1
  262. } else if !reflect.DeepEqual(l, defaultLimitTunnelProtocols) {
  263. t.Fatalf("unexpected %+v != %+v", l, defaultLimitTunnelProtocols)
  264. }
  265. }
  266. if matchCount < 250 || matchCount > 750 {
  267. t.Fatalf("Unexpected probability result: %d", matchCount)
  268. }
  269. }
  270. func TestLabeledLists(t *testing.T) {
  271. p, err := NewClientParameters(nil)
  272. if err != nil {
  273. t.Fatalf("NewClientParameters failed: %s", err)
  274. }
  275. tlsProfiles := make(protocol.TLSProfiles, 0)
  276. for i, tlsProfile := range protocol.SupportedTLSProfiles {
  277. if i%2 == 0 {
  278. tlsProfiles = append(tlsProfiles, tlsProfile)
  279. }
  280. }
  281. quicVersions := make(protocol.QUICVersions, 0)
  282. for i, quicVersion := range protocol.SupportedQUICVersions {
  283. if i%2 == 0 {
  284. quicVersions = append(quicVersions, quicVersion)
  285. }
  286. }
  287. applyParameters := map[string]interface{}{
  288. "DisableFrontingProviderTLSProfiles": protocol.LabeledTLSProfiles{"validLabel": tlsProfiles},
  289. "DisableFrontingProviderQUICVersions": protocol.LabeledQUICVersions{"validLabel": quicVersions},
  290. }
  291. _, err = p.Set("", false, applyParameters)
  292. if err != nil {
  293. t.Fatalf("Set failed: %s", err)
  294. }
  295. disableTLSProfiles := p.Get().LabeledTLSProfiles(DisableFrontingProviderTLSProfiles, "validLabel")
  296. if !reflect.DeepEqual(disableTLSProfiles, tlsProfiles) {
  297. t.Fatalf("LabeledTLSProfiles returned %+v expected %+v", disableTLSProfiles, tlsProfiles)
  298. }
  299. disableTLSProfiles = p.Get().LabeledTLSProfiles(DisableFrontingProviderTLSProfiles, "invalidLabel")
  300. if disableTLSProfiles != nil {
  301. t.Fatalf("LabeledTLSProfiles returned unexpected non-empty list %+v", disableTLSProfiles)
  302. }
  303. disableQUICVersions := p.Get().LabeledQUICVersions(DisableFrontingProviderQUICVersions, "validLabel")
  304. if !reflect.DeepEqual(disableQUICVersions, quicVersions) {
  305. t.Fatalf("LabeledQUICVersions returned %+v expected %+v", disableQUICVersions, quicVersions)
  306. }
  307. disableQUICVersions = p.Get().LabeledQUICVersions(DisableFrontingProviderQUICVersions, "invalidLabel")
  308. if disableQUICVersions != nil {
  309. t.Fatalf("LabeledQUICVersions returned unexpected non-empty list %+v", disableQUICVersions)
  310. }
  311. }
  312. func TestCustomTLSProfiles(t *testing.T) {
  313. p, err := NewClientParameters(nil)
  314. if err != nil {
  315. t.Fatalf("NewClientParameters failed: %s", err)
  316. }
  317. customTLSProfiles := protocol.CustomTLSProfiles{
  318. &protocol.CustomTLSProfile{Name: "Profile1", UTLSSpec: &protocol.UTLSSpec{}},
  319. &protocol.CustomTLSProfile{Name: "Profile2", UTLSSpec: &protocol.UTLSSpec{}},
  320. }
  321. applyParameters := map[string]interface{}{
  322. "CustomTLSProfiles": customTLSProfiles}
  323. _, err = p.Set("", false, applyParameters)
  324. if err != nil {
  325. t.Fatalf("Set failed: %s", err)
  326. }
  327. names := p.Get().CustomTLSProfileNames()
  328. if len(names) != 2 || names[0] != "Profile1" || names[1] != "Profile2" {
  329. t.Fatalf("Unexpected CustomTLSProfileNames: %+v", names)
  330. }
  331. profile := p.Get().CustomTLSProfile("Profile1")
  332. if profile == nil || profile.Name != "Profile1" {
  333. t.Fatalf("Unexpected profile")
  334. }
  335. profile = p.Get().CustomTLSProfile("Profile2")
  336. if profile == nil || profile.Name != "Profile2" {
  337. t.Fatalf("Unexpected profile")
  338. }
  339. profile = p.Get().CustomTLSProfile("Profile3")
  340. if profile != nil {
  341. t.Fatalf("Unexpected profile")
  342. }
  343. }
  344. func TestApplicationParameters(t *testing.T) {
  345. parametersJSON := []byte(`
  346. {
  347. "ApplicationParameters" : {
  348. "AppFlag1" : true,
  349. "AppConfig1" : {"Option1" : "A", "Option2" : "B"},
  350. "AppSwitches1" : [1, 2, 3, 4]
  351. }
  352. }
  353. `)
  354. validators := map[string]func(v interface{}) bool{
  355. "AppFlag1": func(v interface{}) bool { return reflect.DeepEqual(v, true) },
  356. "AppConfig1": func(v interface{}) bool {
  357. return reflect.DeepEqual(v, map[string]interface{}{"Option1": "A", "Option2": "B"})
  358. },
  359. "AppSwitches1": func(v interface{}) bool {
  360. return reflect.DeepEqual(v, []interface{}{float64(1), float64(2), float64(3), float64(4)})
  361. },
  362. }
  363. var applyParameters map[string]interface{}
  364. err := json.Unmarshal(parametersJSON, &applyParameters)
  365. if err != nil {
  366. t.Fatalf("Unmarshal failed: %s", err)
  367. }
  368. p, err := NewClientParameters(nil)
  369. if err != nil {
  370. t.Fatalf("NewClientParameters failed: %s", err)
  371. }
  372. _, err = p.Set("", false, applyParameters)
  373. if err != nil {
  374. t.Fatalf("Set failed: %s", err)
  375. }
  376. keyValues := p.Get().KeyValues(ApplicationParameters)
  377. if len(keyValues) != len(validators) {
  378. t.Fatalf("Unexpected key value count")
  379. }
  380. for key, value := range keyValues {
  381. validator, ok := validators[key]
  382. if !ok {
  383. t.Fatalf("Unexpected key: %s", key)
  384. }
  385. var unmarshaledValue interface{}
  386. err := json.Unmarshal(value, &unmarshaledValue)
  387. if err != nil {
  388. t.Fatalf("Unmarshal failed: %s", err)
  389. }
  390. if !validator(unmarshaledValue) {
  391. t.Fatalf("Invalid value: %s, %T: %+v",
  392. key, unmarshaledValue, unmarshaledValue)
  393. }
  394. }
  395. }