clientlib_test.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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 clientlib
  20. import (
  21. "context"
  22. "encoding/json"
  23. "io/ioutil"
  24. "os"
  25. "testing"
  26. "time"
  27. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
  28. )
  29. func TestStartTunnel(t *testing.T) {
  30. // TODO: More comprehensive tests. This is only a smoke test.
  31. clientPlatform := "clientlib_test.go"
  32. networkID := "UNKNOWN"
  33. timeout := 60
  34. quickTimeout := 1
  35. configJSON, err := ioutil.ReadFile("../../psiphon/controller_test.config")
  36. if err != nil {
  37. // Skip, don't fail, if config file is not present
  38. t.Skipf("error loading configuration file: %s", err)
  39. }
  40. // Initialize a fresh datastore and create a modified config which cannot
  41. // connect without known servers, to be used in timeout cases.
  42. testDataDirName, err := ioutil.TempDir("", "psiphon-clientlib-test")
  43. if err != nil {
  44. t.Fatalf("ioutil.TempDir failed: %v", err)
  45. }
  46. defer os.RemoveAll(testDataDirName)
  47. var config map[string]interface{}
  48. err = json.Unmarshal(configJSON, &config)
  49. if err != nil {
  50. t.Fatalf("json.Unmarshal failed: %v", err)
  51. }
  52. // Use the legacy encoding to both exercise that case, and facilitate a
  53. // gradual network upgrade to new encoding support.
  54. config["TargetAPIEncoding"] = protocol.PSIPHON_API_ENCODING_JSON
  55. configJSON, err = json.Marshal(config)
  56. if err != nil {
  57. t.Fatalf("json.Marshal failed: %v", err)
  58. }
  59. config["DisableRemoteServerListFetcher"] = true
  60. configJSONNoFetcher, err := json.Marshal(config)
  61. if err != nil {
  62. t.Fatalf("json.Marshal failed: %v", err)
  63. }
  64. type args struct {
  65. ctxTimeout time.Duration
  66. configJSON []byte
  67. embeddedServerEntryList string
  68. params Parameters
  69. paramsDelta ParametersDelta
  70. noticeReceiver func(NoticeEvent)
  71. }
  72. tests := []struct {
  73. name string
  74. args args
  75. wantTunnel bool
  76. expectedErr error
  77. }{
  78. {
  79. name: "Failure: context timeout",
  80. args: args{
  81. ctxTimeout: 10 * time.Millisecond,
  82. configJSON: configJSONNoFetcher,
  83. embeddedServerEntryList: "",
  84. params: Parameters{
  85. DataRootDirectory: &testDataDirName,
  86. ClientPlatform: &clientPlatform,
  87. NetworkID: &networkID,
  88. EstablishTunnelTimeoutSeconds: &timeout,
  89. },
  90. paramsDelta: nil,
  91. noticeReceiver: nil,
  92. },
  93. wantTunnel: false,
  94. expectedErr: ErrTimeout,
  95. },
  96. {
  97. name: "Failure: config timeout",
  98. args: args{
  99. ctxTimeout: 0,
  100. configJSON: configJSONNoFetcher,
  101. embeddedServerEntryList: "",
  102. params: Parameters{
  103. DataRootDirectory: &testDataDirName,
  104. ClientPlatform: &clientPlatform,
  105. NetworkID: &networkID,
  106. EstablishTunnelTimeoutSeconds: &quickTimeout,
  107. },
  108. paramsDelta: nil,
  109. noticeReceiver: nil,
  110. },
  111. wantTunnel: false,
  112. expectedErr: ErrTimeout,
  113. },
  114. {
  115. name: "Success: simple",
  116. args: args{
  117. ctxTimeout: 0,
  118. configJSON: configJSON,
  119. embeddedServerEntryList: "",
  120. params: Parameters{
  121. DataRootDirectory: &testDataDirName,
  122. ClientPlatform: &clientPlatform,
  123. NetworkID: &networkID,
  124. EstablishTunnelTimeoutSeconds: &timeout,
  125. },
  126. paramsDelta: nil,
  127. noticeReceiver: nil,
  128. },
  129. wantTunnel: true,
  130. expectedErr: nil,
  131. },
  132. }
  133. for _, tt := range tests {
  134. t.Run(tt.name, func(t *testing.T) {
  135. ctx := context.Background()
  136. var cancelFunc context.CancelFunc
  137. if tt.args.ctxTimeout > 0 {
  138. ctx, cancelFunc = context.WithTimeout(ctx, tt.args.ctxTimeout)
  139. }
  140. tunnel, err := StartTunnel(
  141. ctx,
  142. tt.args.configJSON,
  143. tt.args.embeddedServerEntryList,
  144. tt.args.params,
  145. tt.args.paramsDelta,
  146. tt.args.noticeReceiver)
  147. gotTunnel := (tunnel != nil)
  148. if cancelFunc != nil {
  149. cancelFunc()
  150. }
  151. if tunnel != nil {
  152. tunnel.Stop()
  153. }
  154. if gotTunnel != tt.wantTunnel {
  155. t.Errorf("StartTunnel() gotTunnel = %v, wantTunnel %v", err, tt.wantTunnel)
  156. }
  157. if err != tt.expectedErr {
  158. t.Fatalf("StartTunnel() error = %v, expectedErr %v", err, tt.expectedErr)
  159. return
  160. }
  161. })
  162. }
  163. }