Explorar o código

Ensure client ("psiphon" package) tests run on Windows

- Set DataRootDirectory in the Config struct rather than the
  JSON string, to avoid Windows path value JSON encoding issues.

- Skip datastore resiliency test cases that depend on file
  system behavior not available on Windows.

- Conditionally compile references to signals not defined for
  Windows.

- Workaround lack of server shutdown on Windows.
Rod Hynes %!s(int64=5) %!d(string=hai) anos
pai
achega
9ceb0367e2

+ 14 - 6
psiphon/dataStoreRecovery_test.go

@@ -36,6 +36,11 @@ import (
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
 )
 
+// Set canTruncateOpenDataStore to false on platforms, such as Windows, where
+// the OS doesn't allow an open memory-mapped file to be truncated. This will
+// skip the associated test cases.
+var canTruncateOpenDataStore = true
+
 func TestBoltResiliency(t *testing.T) {
 
 	testDataDirName, err := ioutil.TempDir("", "psiphon-bolt-recovery-test")
@@ -46,9 +51,8 @@ func TestBoltResiliency(t *testing.T) {
 
 	SetEmitDiagnosticNotices(true, true)
 
-	clientConfigJSONTemplate := `
+	clientConfigJSON := `
     {
-        "DataRootDirectory" : "%s",
         "ClientPlatform" : "",
         "ClientVersion" : "0",
         "SponsorId" : "0",
@@ -58,14 +62,13 @@ func TestBoltResiliency(t *testing.T) {
         "EstablishTunnelPausePeriodSeconds" : 1
     }`
 
-	clientConfigJSON := fmt.Sprintf(
-		clientConfigJSONTemplate,
-		testDataDirName)
-
 	clientConfig, err := LoadConfig([]byte(clientConfigJSON))
 	if err != nil {
 		t.Fatalf("LoadConfig failed: %s", err)
 	}
+
+	clientConfig.DataRootDirectory = testDataDirName
+
 	err = clientConfig.Commit(false)
 	if err != nil {
 		t.Fatalf("Commit failed: %s", err)
@@ -243,6 +246,11 @@ func TestBoltResiliency(t *testing.T) {
 
 	<-noticeResetDatastore
 
+	if !canTruncateOpenDataStore {
+		CloseDataStore()
+		return
+	}
+
 	paveServerEntries()
 
 	// Truncate datastore while running the controller. First, complete one

+ 26 - 0
psiphon/dataStoreRecovery_windows_test.go

@@ -0,0 +1,26 @@
+// +build !PSIPHON_USE_BADGER_DB,!PSIPHON_USE_FILES_DB
+
+/*
+ * Copyright (c) 2021, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package psiphon
+
+func init() {
+	canTruncateOpenDataStore = false
+}

+ 3 - 2
psiphon/exchange_test.go

@@ -65,7 +65,6 @@ func TestServerEntryExchange(t *testing.T) {
 		    {
                 "SponsorId" : "0",
                 "PropagationChannelId" : "0",
-		        "DataRootDirectory" : "%s",
 		        "ServerEntrySignaturePublicKey" : "%s",
 		        "ExchangeObfuscationKey" : "%s",
 		        "NetworkID" : "%s"
@@ -73,7 +72,6 @@ func TestServerEntryExchange(t *testing.T) {
 
 	configJSON := fmt.Sprintf(
 		configJSONTemplate,
-		testDataDirName,
 		publicKey,
 		obfuscationKey,
 		networkID)
@@ -82,6 +80,9 @@ func TestServerEntryExchange(t *testing.T) {
 	if err != nil {
 		t.Fatalf("LoadConfig failed: %s", err)
 	}
+
+	config.DataRootDirectory = testDataDirName
+
 	err = config.Commit(false)
 	if err != nil {
 		t.Fatalf("Commit failed: %s", err)

+ 13 - 4
psiphon/remoteServerList_test.go

@@ -35,6 +35,7 @@ import (
 	"path"
 	"path/filepath"
 	"sync"
+	"sync/atomic"
 	"syscall"
 	"testing"
 	"time"
@@ -56,6 +57,13 @@ func TestObfuscatedRemoteServerListsOmitMD5Sums(t *testing.T) {
 	testObfuscatedRemoteServerLists(t, true)
 }
 
+// Each instance testObfuscatedRemoteServerLists runs a server which binds to
+// specific network ports. Server shutdown, via SIGTERM, is not supported on
+// Windows. Shutdown is not necessary for these tests, but, without shutdown,
+// multiple testObfuscatedRemoteServerLists calls fail when trying to reuse
+// network ports. This workaround selects unique ports for each server.
+var nextServerPort int32 = 8000
+
 func testObfuscatedRemoteServerLists(t *testing.T, omitMD5Sums bool) {
 
 	testDataDirName, err := ioutil.TempDir("", "psiphon-remote-server-list-test")
@@ -83,8 +91,8 @@ func testObfuscatedRemoteServerLists(t *testing.T, omitMD5Sums bool) {
 		&server.GenerateConfigParams{
 			ServerIPAddress:      serverIPAddress,
 			EnableSSHAPIRequests: true,
-			WebServerPort:        8001,
-			TunnelProtocolPorts:  map[string]int{"OSSH": 4001},
+			WebServerPort:        int(atomic.AddInt32(&nextServerPort, 1)),
+			TunnelProtocolPorts:  map[string]int{"OSSH": int(atomic.AddInt32(&nextServerPort, 1))},
 			LogFilename:          filepath.Join(testDataDirName, "psiphond.log"),
 			LogLevel:             "debug",
 
@@ -379,7 +387,6 @@ func testObfuscatedRemoteServerLists(t *testing.T, omitMD5Sums bool) {
 	// Note: calling LoadConfig ensures all *int config fields are initialized
 	clientConfigJSONTemplate := `
     {
-        "DataRootDirectory" : "%s",
         "ClientPlatform" : "",
         "ClientVersion" : "0",
         "SponsorId" : "0",
@@ -395,7 +402,6 @@ func testObfuscatedRemoteServerLists(t *testing.T, omitMD5Sums bool) {
 
 	clientConfigJSON := fmt.Sprintf(
 		clientConfigJSONTemplate,
-		testDataDirName,
 		signingPublicKey,
 		remoteServerListURL,
 		obfuscatedServerListRootURLsJSONConfig,
@@ -405,6 +411,9 @@ func testObfuscatedRemoteServerLists(t *testing.T, omitMD5Sums bool) {
 	if err != nil {
 		t.Fatalf("error processing configuration file: %s", err)
 	}
+
+	clientConfig.DataRootDirectory = testDataDirName
+
 	err = clientConfig.Commit(false)
 	if err != nil {
 		t.Fatalf("error committing configuration file: %s", err)

+ 4 - 8
psiphon/server/services.go

@@ -240,20 +240,16 @@ func RunServices(configJSON []byte) (retErr error) {
 	signal.Notify(systemStopSignal, os.Interrupt, syscall.SIGTERM)
 
 	// SIGUSR1 triggers a reload of support services
-	reloadSupportServicesSignal := make(chan os.Signal, 1)
-	signal.Notify(reloadSupportServicesSignal, syscall.SIGUSR1)
+	reloadSupportServicesSignal := makeSIGUSR1Channel()
 
 	// SIGUSR2 triggers an immediate load log and optional process profile output
-	logServerLoadSignal := make(chan os.Signal, 1)
-	signal.Notify(logServerLoadSignal, syscall.SIGUSR2)
+	logServerLoadSignal := makeSIGUSR2Channel()
 
 	// SIGTSTP triggers tunnelServer to stop establishing new tunnels
-	stopEstablishingTunnelsSignal := make(chan os.Signal, 1)
-	signal.Notify(stopEstablishingTunnelsSignal, syscall.SIGTSTP)
+	stopEstablishingTunnelsSignal := makeSIGTSTPChannel()
 
 	// SIGCONT triggers tunnelServer to resume establishing new tunnels
-	resumeEstablishingTunnelsSignal := make(chan os.Signal, 1)
-	signal.Notify(resumeEstablishingTunnelsSignal, syscall.SIGCONT)
+	resumeEstablishingTunnelsSignal := makeSIGCONTChannel()
 
 	err = nil
 

+ 52 - 0
psiphon/server/signal.go

@@ -0,0 +1,52 @@
+// +build !windows
+
+/*
+ * Copyright (c) 2021, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package server
+
+import (
+	"os"
+	"os/signal"
+	"syscall"
+)
+
+func makeSIGUSR1Channel() chan os.Signal {
+	channel := make(chan os.Signal, 1)
+	signal.Notify(channel, syscall.SIGUSR1)
+	return channel
+}
+
+func makeSIGUSR2Channel() chan os.Signal {
+	channel := make(chan os.Signal, 1)
+	signal.Notify(channel, syscall.SIGUSR2)
+	return channel
+}
+
+func makeSIGTSTPChannel() chan os.Signal {
+	channel := make(chan os.Signal, 1)
+	signal.Notify(channel, syscall.SIGTSTP)
+	return channel
+}
+
+func makeSIGCONTChannel() chan os.Signal {
+	channel := make(chan os.Signal, 1)
+	signal.Notify(channel, syscall.SIGCONT)
+	return channel
+}

+ 40 - 0
psiphon/server/signal_windows.go

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package server
+
+import (
+	"os"
+)
+
+func makeSIGUSR1Channel() chan os.Signal {
+	return nil
+}
+
+func makeSIGUSR2Channel() chan os.Signal {
+	return nil
+}
+
+func makeSIGTSTPChannel() chan os.Signal {
+	return nil
+}
+
+func makeSIGCONTChannel() chan os.Signal {
+	return nil
+}