diff --git a/test/CryptographyTest.cs b/test/CryptographyTest.cs new file mode 100644 index 00000000..68c2e3a8 --- /dev/null +++ b/test/CryptographyTest.cs @@ -0,0 +1,233 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Shadowsocks.Encryption; +using System.Threading; +using System.Collections.Generic; +using Shadowsocks.Encryption.Stream; +using System.Diagnostics; + +namespace Shadowsocks.Test +{ + [TestClass] + public class CryptographyTest + { + + [TestMethod] + public void TestMD5() + { + for (int len = 1; len < 64; len++) + { + System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); + byte[] bytes = new byte[len]; + var random = new Random(); + random.NextBytes(bytes); + string md5str = Convert.ToBase64String(md5.ComputeHash(bytes)); + string md5str2 = Convert.ToBase64String(MbedTLS.MD5(bytes)); + Assert.IsTrue(md5str == md5str2); + } + } + + private void RunEncryptionRound(IEncryptor encryptor, IEncryptor decryptor) + { + RNG.Reload(); + byte[] plain = new byte[16384]; + byte[] cipher = new byte[plain.Length + 16]; + byte[] plain2 = new byte[plain.Length + 16]; + int outLen = 0; + int outLen2 = 0; + var random = new Random(); + random.NextBytes(plain); + encryptor.Encrypt(plain, plain.Length, cipher, out outLen); + decryptor.Decrypt(cipher, outLen, plain2, out outLen2); + Assert.AreEqual(plain.Length, outLen2); + for (int j = 0; j < plain.Length; j++) + { + Assert.AreEqual(plain[j], plain2[j]); + } + encryptor.Encrypt(plain, 1000, cipher, out outLen); + decryptor.Decrypt(cipher, outLen, plain2, out outLen2); + Assert.AreEqual(1000, outLen2); + for (int j = 0; j < outLen2; j++) + { + Assert.AreEqual(plain[j], plain2[j]); + } + encryptor.Encrypt(plain, 12333, cipher, out outLen); + decryptor.Decrypt(cipher, outLen, plain2, out outLen2); + Assert.AreEqual(12333, outLen2); + for (int j = 0; j < outLen2; j++) + { + Assert.AreEqual(plain[j], plain2[j]); + } + } + + private static bool encryptionFailed = false; + private static object locker = new object(); + + [TestMethod] + public void TestMbedTLSEncryption() + { + encryptionFailed = false; + // run it once before the multi-threading test to initialize global tables + RunSingleMbedTLSEncryptionThread(); + List threads = new List(); + for (int i = 0; i < 10; i++) + { + Thread t = new Thread(new ThreadStart(RunSingleMbedTLSEncryptionThread)); + threads.Add(t); + t.Start(); + } + foreach (Thread t in threads) + { + t.Join(); + } + RNG.Close(); + Assert.IsFalse(encryptionFailed); + } + + private void RunSingleMbedTLSEncryptionThread() + { + try + { + for (int i = 0; i < 100; i++) + { + IEncryptor encryptor; + IEncryptor decryptor; + encryptor = new StreamMbedTLSEncryptor("aes-256-cfb", "barfoo!"); + decryptor = new StreamMbedTLSEncryptor("aes-256-cfb", "barfoo!"); + RunEncryptionRound(encryptor, decryptor); + } + } + catch + { + encryptionFailed = true; + throw; + } + } + + [TestMethod] + public void TestRC4Encryption() + { + encryptionFailed = false; + // run it once before the multi-threading test to initialize global tables + RunSingleRC4EncryptionThread(); + List threads = new List(); + for (int i = 0; i < 10; i++) + { + Thread t = new Thread(new ThreadStart(RunSingleRC4EncryptionThread)); + threads.Add(t); + t.Start(); + } + foreach (Thread t in threads) + { + t.Join(); + } + RNG.Close(); + Assert.IsFalse(encryptionFailed); + } + + private void RunSingleRC4EncryptionThread() + { + try + { + for (int i = 0; i < 100; i++) + { + var random = new Random(); + IEncryptor encryptor; + IEncryptor decryptor; + encryptor = new StreamMbedTLSEncryptor("rc4-md5", "barfoo!"); + decryptor = new StreamMbedTLSEncryptor("rc4-md5", "barfoo!"); + RunEncryptionRound(encryptor, decryptor); + } + } + catch + { + encryptionFailed = true; + throw; + } + } + + [TestMethod] + public void TestSodiumEncryption() + { + encryptionFailed = false; + // run it once before the multi-threading test to initialize global tables + RunSingleSodiumEncryptionThread(); + List threads = new List(); + for (int i = 0; i < 10; i++) + { + Thread t = new Thread(new ThreadStart(RunSingleSodiumEncryptionThread)); + threads.Add(t); + t.Start(); + } + foreach (Thread t in threads) + { + t.Join(); + } + RNG.Close(); + Assert.IsFalse(encryptionFailed); + } + + private void RunSingleSodiumEncryptionThread() + { + try + { + for (int i = 0; i < 100; i++) + { + var random = new Random(); + IEncryptor encryptor; + IEncryptor decryptor; + encryptor = new StreamSodiumEncryptor("salsa20", "barfoo!"); + decryptor = new StreamSodiumEncryptor("salsa20", "barfoo!"); + RunEncryptionRound(encryptor, decryptor); + } + } + catch + { + encryptionFailed = true; + throw; + } + } + + [TestMethod] + public void TestOpenSSLEncryption() + { + encryptionFailed = false; + // run it once before the multi-threading test to initialize global tables + RunSingleOpenSSLEncryptionThread(); + List threads = new List(); + for (int i = 0; i < 10; i++) + { + Thread t = new Thread(new ThreadStart(RunSingleOpenSSLEncryptionThread)); + threads.Add(t); + t.Start(); + } + foreach (Thread t in threads) + { + t.Join(); + } + RNG.Close(); + Assert.IsFalse(encryptionFailed); + } + + private void RunSingleOpenSSLEncryptionThread() + { + try + { + for (int i = 0; i < 100; i++) + { + var random = new Random(); + IEncryptor encryptor; + IEncryptor decryptor; + encryptor = new StreamOpenSSLEncryptor("aes-256-cfb", "barfoo!"); + decryptor = new StreamOpenSSLEncryptor("aes-256-cfb", "barfoo!"); + RunEncryptionRound(encryptor, decryptor); + } + } + catch + { + encryptionFailed = true; + throw; + } + } + } +} diff --git a/test/ProcessEnvironment.cs b/test/ProcessEnvironment.cs index 166cad97..106afee2 100644 --- a/test/ProcessEnvironment.cs +++ b/test/ProcessEnvironment.cs @@ -48,7 +48,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -namespace test +namespace Shadowsocks.Test { static class ProcessEnvironment { diff --git a/test/Sip003PluginTest.cs b/test/Sip003PluginTest.cs new file mode 100644 index 00000000..49b1c0a3 --- /dev/null +++ b/test/Sip003PluginTest.cs @@ -0,0 +1,175 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading; +using System.Collections.Generic; +using Shadowsocks.Model; +using Shadowsocks.Controller.Service; +using System.Diagnostics; +using System.Net; + +namespace Shadowsocks.Test +{ + [TestClass] + public class Sip003PluginTest + { + [TestMethod] + public void Sip003PluginSupport() + { + string fake_plugin = "ftp"; + + var NoPlugin = Sip003Plugin.CreateIfConfigured(new Server + { + server = "192.168.100.1", + server_port = 8888, + password = "test", + method = "bf-cfb" + }); + + RunPluginSupportTest( + NoPlugin, + "", + "", + "", + "192.168.100.1", + 8888); + + var Plugin = Sip003Plugin.CreateIfConfigured(new Server + { + server = "192.168.100.1", + server_port = 8888, + password = "test", + method = "bf-cfb", + plugin = fake_plugin + }); + RunPluginSupportTest( + Plugin, + fake_plugin, + "", + "", + "192.168.100.1", + 8888); + + var PluginWithOpts = Sip003Plugin.CreateIfConfigured(new Server + { + server = "192.168.100.1", + server_port = 8888, + password = "test", + method = "bf-cfb", + plugin = fake_plugin, + plugin_opts = "_option" + }); + RunPluginSupportTest( + PluginWithOpts, + fake_plugin, + "_option", + "", + "192.168.100.1", + 8888); + + var PluginWithArgs = Sip003Plugin.CreateIfConfigured(new Server + { + server = "192.168.100.1", + server_port = 8888, + password = "test", + method = "bf-cfb", + plugin = fake_plugin, + plugin_args = "_test" + }); + RunPluginSupportTest( + PluginWithArgs, + fake_plugin, + "", + "_test", + "192.168.100.1", + 8888); + + var PluginWithOptsAndArgs = Sip003Plugin.CreateIfConfigured(new Server + { + server = "192.168.100.1", + server_port = 8888, + password = "test", + method = "bf-cfb", + plugin = fake_plugin, + plugin_opts = "_option", + plugin_args = "_test" + }); + RunPluginSupportTest( + PluginWithOptsAndArgs, + fake_plugin, + "_option", + "_test", + "192.168.100.1", + 8888); + + var PluginWithArgsReplaced = Sip003Plugin.CreateIfConfigured(new Server + { + server = "192.168.100.1", + server_port = 8888, + password = "test", + method = "bf-cfb", + plugin = fake_plugin, + plugin_args = "_test,%SS_REMOTE_HOST%" + }); + RunPluginSupportTest( + PluginWithArgsReplaced, + fake_plugin, + "", + "_test,192.168.100.1", + "192.168.100.1", + 8888); + + var PluginWithOptsAndArgsReplaced = Sip003Plugin.CreateIfConfigured(new Server + { + server = "192.168.100.1", + server_port = 8888, + password = "test", + method = "bf-cfb", + plugin = fake_plugin, + plugin_opts = "_option", + plugin_args = "_test,%SS_REMOTE_HOST%,%SS_PLUGIN_OPTIONS%" + }); + RunPluginSupportTest( + PluginWithOptsAndArgsReplaced, + fake_plugin, + "_option", + "_test,192.168.100.1,_option", + "192.168.100.1", + 8888); + } + + private static void RunPluginSupportTest(Sip003Plugin plugin, string pluginName, string pluginOpts, string pluginArgs, string serverAddress, int serverPort) + { + + if (string.IsNullOrWhiteSpace(pluginName)) return; + + plugin.StartIfNeeded(); + + Process[] processes = Process.GetProcessesByName(pluginName); + Assert.AreEqual(processes.Length, 1); + Process p = processes[0]; + + + var penv = ProcessEnvironment.ReadEnvironmentVariables(p); + var pcmd = ProcessEnvironment.GetCommandLine(p).Trim(); + pcmd = pcmd.IndexOf(' ') >= 0 ? pcmd.Substring(pcmd.IndexOf(' ') + 1) : ""; + + Assert.AreEqual(penv["SS_REMOTE_HOST"], serverAddress); + Assert.AreEqual(penv["SS_REMOTE_PORT"], serverPort.ToString()); + Assert.AreEqual(penv["SS_LOCAL_HOST"], IPAddress.Loopback.ToString()); + + int _ignored; + Assert.IsTrue(int.TryParse(penv["SS_LOCAL_PORT"], out _ignored)); + + Assert.AreEqual(penv["SS_PLUGIN_OPTIONS"], pluginOpts); + Assert.AreEqual(pcmd, pluginArgs); + + + plugin.Dispose(); + for (int i = 0; i < 50; i++) + { + if (Process.GetProcessesByName(pluginName).Length == 0) return; + Thread.Sleep(50); + } + } + } +} diff --git a/test/UnitTest.cs b/test/UnitTest.cs index 7592aff8..8487119f 100755 --- a/test/UnitTest.cs +++ b/test/UnitTest.cs @@ -1,19 +1,15 @@ using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using Shadowsocks.Controller; -using Shadowsocks.Encryption; using GlobalHotKey; using System.Windows.Input; using System.Threading; using System.Collections.Generic; using Shadowsocks.Controller.Hotkeys; -using Shadowsocks.Encryption.Stream; -using Shadowsocks.Model; -using Shadowsocks.Controller.Service; using System.Diagnostics; -using System.Net; -namespace test + +namespace Shadowsocks.Test { [TestClass] public class UnitTest @@ -57,592 +53,5 @@ namespace test Assert.IsTrue(testKey3 != null && testKey3.Equals(new HotKey(Key.NumPad7, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift)))); } - [TestMethod] - public void TestMD5() - { - for (int len = 1; len < 64; len++) - { - System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); - byte[] bytes = new byte[len]; - var random = new Random(); - random.NextBytes(bytes); - string md5str = Convert.ToBase64String(md5.ComputeHash(bytes)); - string md5str2 = Convert.ToBase64String(MbedTLS.MD5(bytes)); - Assert.IsTrue(md5str == md5str2); - } - } - - private void RunEncryptionRound(IEncryptor encryptor, IEncryptor decryptor) - { - RNG.Reload(); - byte[] plain = new byte[16384]; - byte[] cipher = new byte[plain.Length + 16]; - byte[] plain2 = new byte[plain.Length + 16]; - int outLen = 0; - int outLen2 = 0; - var random = new Random(); - random.NextBytes(plain); - encryptor.Encrypt(plain, plain.Length, cipher, out outLen); - decryptor.Decrypt(cipher, outLen, plain2, out outLen2); - Assert.AreEqual(plain.Length, outLen2); - for (int j = 0; j < plain.Length; j++) - { - Assert.AreEqual(plain[j], plain2[j]); - } - encryptor.Encrypt(plain, 1000, cipher, out outLen); - decryptor.Decrypt(cipher, outLen, plain2, out outLen2); - Assert.AreEqual(1000, outLen2); - for (int j = 0; j < outLen2; j++) - { - Assert.AreEqual(plain[j], plain2[j]); - } - encryptor.Encrypt(plain, 12333, cipher, out outLen); - decryptor.Decrypt(cipher, outLen, plain2, out outLen2); - Assert.AreEqual(12333, outLen2); - for (int j = 0; j < outLen2; j++) - { - Assert.AreEqual(plain[j], plain2[j]); - } - } - - private static bool encryptionFailed = false; - private static object locker = new object(); - - [TestMethod] - public void TestMbedTLSEncryption() - { - // run it once before the multi-threading test to initialize global tables - RunSingleMbedTLSEncryptionThread(); - List threads = new List(); - for (int i = 0; i < 10; i++) - { - Thread t = new Thread(new ThreadStart(RunSingleMbedTLSEncryptionThread)); - threads.Add(t); - t.Start(); - } - foreach (Thread t in threads) - { - t.Join(); - } - RNG.Close(); - Assert.IsFalse(encryptionFailed); - } - - private void RunSingleMbedTLSEncryptionThread() - { - try - { - for (int i = 0; i < 100; i++) - { - IEncryptor encryptor; - IEncryptor decryptor; - encryptor = new StreamMbedTLSEncryptor("aes-256-cfb", "barfoo!"); - decryptor = new StreamMbedTLSEncryptor("aes-256-cfb", "barfoo!"); - RunEncryptionRound(encryptor, decryptor); - } - } - catch - { - encryptionFailed = true; - throw; - } - } - - [TestMethod] - public void TestRC4Encryption() - { - // run it once before the multi-threading test to initialize global tables - RunSingleRC4EncryptionThread(); - List threads = new List(); - for (int i = 0; i < 10; i++) - { - Thread t = new Thread(new ThreadStart(RunSingleRC4EncryptionThread)); - threads.Add(t); - t.Start(); - } - foreach (Thread t in threads) - { - t.Join(); - } - RNG.Close(); - Assert.IsFalse(encryptionFailed); - } - - private void RunSingleRC4EncryptionThread() - { - try - { - for (int i = 0; i < 100; i++) - { - var random = new Random(); - IEncryptor encryptor; - IEncryptor decryptor; - encryptor = new StreamMbedTLSEncryptor("rc4-md5", "barfoo!"); - decryptor = new StreamMbedTLSEncryptor("rc4-md5", "barfoo!"); - RunEncryptionRound(encryptor, decryptor); - } - } - catch - { - encryptionFailed = true; - throw; - } - } - - [TestMethod] - public void TestSodiumEncryption() - { - // run it once before the multi-threading test to initialize global tables - RunSingleSodiumEncryptionThread(); - List threads = new List(); - for (int i = 0; i < 10; i++) - { - Thread t = new Thread(new ThreadStart(RunSingleSodiumEncryptionThread)); - threads.Add(t); - t.Start(); - } - foreach (Thread t in threads) - { - t.Join(); - } - RNG.Close(); - Assert.IsFalse(encryptionFailed); - } - - private void RunSingleSodiumEncryptionThread() - { - try - { - for (int i = 0; i < 100; i++) - { - var random = new Random(); - IEncryptor encryptor; - IEncryptor decryptor; - encryptor = new StreamSodiumEncryptor("salsa20", "barfoo!"); - decryptor = new StreamSodiumEncryptor("salsa20", "barfoo!"); - RunEncryptionRound(encryptor, decryptor); - } - } - catch - { - encryptionFailed = true; - throw; - } - } - - [TestMethod] - public void TestOpenSSLEncryption() - { - // run it once before the multi-threading test to initialize global tables - RunSingleOpenSSLEncryptionThread(); - List threads = new List(); - for (int i = 0; i < 10; i++) - { - Thread t = new Thread(new ThreadStart(RunSingleOpenSSLEncryptionThread)); - threads.Add(t); - t.Start(); - } - foreach (Thread t in threads) - { - t.Join(); - } - RNG.Close(); - Assert.IsFalse(encryptionFailed); - } - - private void RunSingleOpenSSLEncryptionThread() - { - try - { - for (int i = 0; i < 100; i++) - { - var random = new Random(); - IEncryptor encryptor; - IEncryptor decryptor; - encryptor = new StreamOpenSSLEncryptor("aes-256-cfb", "barfoo!"); - decryptor = new StreamOpenSSLEncryptor("aes-256-cfb", "barfoo!"); - RunEncryptionRound(encryptor, decryptor); - } - } - catch - { - encryptionFailed = true; - throw; - } - } - - [TestMethod] - public void ParseAndGenerateShadowsocksUrl() - { - var server = new Server - { - server = "192.168.100.1", - server_port = 8888, - password = "test", - method = "bf-cfb" - }; - var serverCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4"; - - var server2 = new Server - { - server = "192.168.1.1", - server_port = 8388, - password = "test", - method = "bf-cfb" - }; - var server2CanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA=="; - - var serverWithRemark = new Server - { - server = server.server, - server_port = server.server_port, - password = server.password, - method = server.method, - remarks = "example-server" - }; - var serverWithRemarkCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4#example-server"; - - var server2WithRemark = new Server - { - server = server2.server, - server_port = server2.server_port, - password = server2.password, - method = server2.method, - remarks = "example-server" - }; - var server2WithRemarkCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==#example-server"; - - var serverWithPlugin = new Server - { - server = server.server, - server_port = server.server_port, - password = server.password, - method = server.method, - plugin = "obfs-local", - plugin_opts = "obfs=http;obfs-host=google.com" - }; - var serverWithPluginCanonUrl = - "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com"; - - var server2WithPlugin = new Server - { - server = server2.server, - server_port = server2.server_port, - password = server2.password, - method = server2.method, - plugin = "obfs-local", - plugin_opts = "obfs=http;obfs-host=google.com" - }; - var server2WithPluginCanonUrl = - "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com"; - - var serverWithPluginAndRemark = new Server - { - server = server.server, - server_port = server.server_port, - password = server.password, - method = server.method, - plugin = serverWithPlugin.plugin, - plugin_opts = serverWithPlugin.plugin_opts, - remarks = serverWithRemark.remarks - }; - var serverWithPluginAndRemarkCanonUrl = - "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com#example-server"; - - var server2WithPluginAndRemark = new Server - { - server = server2.server, - server_port = server2.server_port, - password = server2.password, - method = server2.method, - plugin = server2WithPlugin.plugin, - plugin_opts = server2WithPlugin.plugin_opts, - remarks = server2WithRemark.remarks - }; - var server2WithPluginAndRemarkCanonUrl = - "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com#example-server"; - - - RunParseShadowsocksUrlTest( - string.Join( - "\r\n", - serverCanonUrl, - "\r\n", - "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4/", - serverWithRemarkCanonUrl, - "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4/#example-server"), - new[] - { - server, - server, - serverWithRemark, - serverWithRemark - }); - - RunParseShadowsocksUrlTest( - string.Join( - "\r\n", - server2CanonUrl, - "\r\n", - "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==/", - server2WithRemarkCanonUrl, - "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==/#example-server"), - new[] - { - server2, - server2, - server2WithRemark, - server2WithRemark - }); - - RunParseShadowsocksUrlTest( - string.Join( - "\r\n", - "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888", - "\r\n", - "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/", - "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888#example-server", - "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/#example-server", - serverWithPluginCanonUrl, - serverWithPluginAndRemarkCanonUrl, - "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com&unsupported=1#example-server"), - new[] - { - server, - server, - serverWithRemark, - serverWithRemark, - serverWithPlugin, - serverWithPluginAndRemark, - serverWithPluginAndRemark - }); - - RunParseShadowsocksUrlTest( - string.Join( - "\r\n", - "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388", - "\r\n", - "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/", - "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388#example-server", - "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/#example-server", - server2WithPluginCanonUrl, - server2WithPluginAndRemarkCanonUrl, - "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com&unsupported=1#example-server"), - new[] - { - server2, - server2, - server2WithRemark, - server2WithRemark, - server2WithPlugin, - server2WithPluginAndRemark, - server2WithPluginAndRemark - }); - - var generateUrlCases = new Dictionary - { - [serverCanonUrl] = server, - [serverWithRemarkCanonUrl] = serverWithRemark, - [serverWithPluginCanonUrl] = serverWithPlugin, - [serverWithPluginAndRemarkCanonUrl] = serverWithPluginAndRemark - }; - RunGenerateShadowsocksUrlTest(generateUrlCases); - } - - private static void RunParseShadowsocksUrlTest(string testCase, IReadOnlyList expected) - { - var actual = Server.GetServers(testCase); - if (actual.Count != expected.Count) - { - Assert.Fail("Wrong number of configs. Expected: {0}. Actual: {1}", expected.Count, actual.Count); - } - - for (int i = 0; i < expected.Count; i++) - { - var expectedServer = expected[i]; - var actualServer = actual[i]; - - Assert.AreEqual(expectedServer.server, actualServer.server); - Assert.AreEqual(expectedServer.server_port, actualServer.server_port); - Assert.AreEqual(expectedServer.password, actualServer.password); - Assert.AreEqual(expectedServer.method, actualServer.method); - Assert.AreEqual(expectedServer.plugin, actualServer.plugin); - Assert.AreEqual(expectedServer.plugin_opts, actualServer.plugin_opts); - Assert.AreEqual(expectedServer.remarks, actualServer.remarks); - Assert.AreEqual(expectedServer.timeout, actualServer.timeout); - } - } - - private static void RunGenerateShadowsocksUrlTest(IReadOnlyDictionary testCases) - { - foreach (var testCase in testCases) - { - string expected = testCase.Key; - Server config = testCase.Value; - - var actual = ShadowsocksController.GetServerURL(config); - Assert.AreEqual(expected, actual); - } - } - - [TestMethod] - public void PluginSupport() - { - string fake_plugin = "ftp"; - - var NoPlugin = Sip003Plugin.CreateIfConfigured(new Server - { - server = "192.168.100.1", - server_port = 8888, - password = "test", - method = "bf-cfb" - }); - - RunPluginSupportTest( - NoPlugin, - "", - "", - "", - "192.168.100.1", - 8888); - - var Plugin = Sip003Plugin.CreateIfConfigured(new Server - { - server = "192.168.100.1", - server_port = 8888, - password = "test", - method = "bf-cfb", - plugin = fake_plugin - }); - RunPluginSupportTest( - Plugin, - fake_plugin, - "", - "", - "192.168.100.1", - 8888); - - var PluginWithOpts = Sip003Plugin.CreateIfConfigured(new Server - { - server = "192.168.100.1", - server_port = 8888, - password = "test", - method = "bf-cfb", - plugin = fake_plugin, - plugin_opts = "_option" - }); - RunPluginSupportTest( - PluginWithOpts, - fake_plugin, - "_option", - "", - "192.168.100.1", - 8888); - - var PluginWithArgs = Sip003Plugin.CreateIfConfigured(new Server - { - server = "192.168.100.1", - server_port = 8888, - password = "test", - method = "bf-cfb", - plugin = fake_plugin, - plugin_args = "_test" - }); - RunPluginSupportTest( - PluginWithArgs, - fake_plugin, - "", - "_test", - "192.168.100.1", - 8888); - - var PluginWithOptsAndArgs = Sip003Plugin.CreateIfConfigured(new Server - { - server = "192.168.100.1", - server_port = 8888, - password = "test", - method = "bf-cfb", - plugin = fake_plugin, - plugin_opts = "_option", - plugin_args = "_test" - }); - RunPluginSupportTest( - PluginWithOptsAndArgs, - fake_plugin, - "_option", - "_test", - "192.168.100.1", - 8888); - - var PluginWithArgsReplaced = Sip003Plugin.CreateIfConfigured(new Server - { - server = "192.168.100.1", - server_port = 8888, - password = "test", - method = "bf-cfb", - plugin = fake_plugin, - plugin_args = "_test,%SS_REMOTE_HOST%" - }); - RunPluginSupportTest( - PluginWithArgsReplaced, - fake_plugin, - "", - "_test,192.168.100.1", - "192.168.100.1", - 8888); - - var PluginWithOptsAndArgsReplaced = Sip003Plugin.CreateIfConfigured(new Server - { - server = "192.168.100.1", - server_port = 8888, - password = "test", - method = "bf-cfb", - plugin = fake_plugin, - plugin_opts = "_option", - plugin_args = "_test,%SS_REMOTE_HOST%,%SS_PLUGIN_OPTIONS%" - }); - RunPluginSupportTest( - PluginWithOptsAndArgsReplaced, - fake_plugin, - "_option", - "_test,192.168.100.1,_option", - "192.168.100.1", - 8888); - } - - private static void RunPluginSupportTest(Sip003Plugin plugin, string pluginName, string pluginOpts, string pluginArgs, string serverAddress, int serverPort) - { - - if (string.IsNullOrWhiteSpace(pluginName)) return; - - plugin.StartIfNeeded(); - - Process[] processes = Process.GetProcessesByName(pluginName); - Assert.AreEqual(processes.Length, 1); - Process p = processes[0]; - - - var penv = ProcessEnvironment.ReadEnvironmentVariables(p); - var pcmd = ProcessEnvironment.GetCommandLine(p).Trim(); - pcmd = pcmd.IndexOf(' ') >= 0 ? pcmd.Substring(pcmd.IndexOf(' ') + 1) : ""; - - Assert.AreEqual(penv["SS_REMOTE_HOST"], serverAddress); - Assert.AreEqual(penv["SS_REMOTE_PORT"], serverPort.ToString()); - Assert.AreEqual(penv["SS_LOCAL_HOST"], IPAddress.Loopback.ToString()); - - int _ignored; - Assert.IsTrue(int.TryParse(penv["SS_LOCAL_PORT"], out _ignored)); - - Assert.AreEqual(penv["SS_PLUGIN_OPTIONS"], pluginOpts); - Assert.AreEqual(pcmd, pluginArgs); - - - plugin.Dispose(); - for (int i = 0; i < 50; i++) - { - if (Process.GetProcessesByName(pluginName).Length == 0) return; - Thread.Sleep(50); - } - } } } diff --git a/test/UrlTest.cs b/test/UrlTest.cs new file mode 100644 index 00000000..01696760 --- /dev/null +++ b/test/UrlTest.cs @@ -0,0 +1,229 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Shadowsocks.Controller; +using System.Threading; +using System.Collections.Generic; +using Shadowsocks.Model; +using System.Diagnostics; + +namespace Shadowsocks.Test +{ + [TestClass] + public class UrlTest + { + [TestMethod] + public void ParseAndGenerateShadowsocksUrl() + { + var server = new Server + { + server = "192.168.100.1", + server_port = 8888, + password = "test", + method = "bf-cfb" + }; + var serverCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4"; + + var server2 = new Server + { + server = "192.168.1.1", + server_port = 8388, + password = "test", + method = "bf-cfb" + }; + var server2CanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA=="; + + var serverWithRemark = new Server + { + server = server.server, + server_port = server.server_port, + password = server.password, + method = server.method, + remarks = "example-server" + }; + var serverWithRemarkCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4#example-server"; + + var server2WithRemark = new Server + { + server = server2.server, + server_port = server2.server_port, + password = server2.password, + method = server2.method, + remarks = "example-server" + }; + var server2WithRemarkCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==#example-server"; + + var serverWithPlugin = new Server + { + server = server.server, + server_port = server.server_port, + password = server.password, + method = server.method, + plugin = "obfs-local", + plugin_opts = "obfs=http;obfs-host=google.com" + }; + var serverWithPluginCanonUrl = + "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com"; + + var server2WithPlugin = new Server + { + server = server2.server, + server_port = server2.server_port, + password = server2.password, + method = server2.method, + plugin = "obfs-local", + plugin_opts = "obfs=http;obfs-host=google.com" + }; + var server2WithPluginCanonUrl = + "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com"; + + var serverWithPluginAndRemark = new Server + { + server = server.server, + server_port = server.server_port, + password = server.password, + method = server.method, + plugin = serverWithPlugin.plugin, + plugin_opts = serverWithPlugin.plugin_opts, + remarks = serverWithRemark.remarks + }; + var serverWithPluginAndRemarkCanonUrl = + "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com#example-server"; + + var server2WithPluginAndRemark = new Server + { + server = server2.server, + server_port = server2.server_port, + password = server2.password, + method = server2.method, + plugin = server2WithPlugin.plugin, + plugin_opts = server2WithPlugin.plugin_opts, + remarks = server2WithRemark.remarks + }; + var server2WithPluginAndRemarkCanonUrl = + "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com#example-server"; + + + RunParseShadowsocksUrlTest( + string.Join( + "\r\n", + serverCanonUrl, + "\r\n", + "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4/", + serverWithRemarkCanonUrl, + "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4/#example-server"), + new[] + { + server, + server, + serverWithRemark, + serverWithRemark + }); + + RunParseShadowsocksUrlTest( + string.Join( + "\r\n", + server2CanonUrl, + "\r\n", + "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==/", + server2WithRemarkCanonUrl, + "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==/#example-server"), + new[] + { + server2, + server2, + server2WithRemark, + server2WithRemark + }); + + RunParseShadowsocksUrlTest( + string.Join( + "\r\n", + "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888", + "\r\n", + "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/", + "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888#example-server", + "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/#example-server", + serverWithPluginCanonUrl, + serverWithPluginAndRemarkCanonUrl, + "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com&unsupported=1#example-server"), + new[] + { + server, + server, + serverWithRemark, + serverWithRemark, + serverWithPlugin, + serverWithPluginAndRemark, + serverWithPluginAndRemark + }); + + RunParseShadowsocksUrlTest( + string.Join( + "\r\n", + "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388", + "\r\n", + "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/", + "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388#example-server", + "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/#example-server", + server2WithPluginCanonUrl, + server2WithPluginAndRemarkCanonUrl, + "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com&unsupported=1#example-server"), + new[] + { + server2, + server2, + server2WithRemark, + server2WithRemark, + server2WithPlugin, + server2WithPluginAndRemark, + server2WithPluginAndRemark + }); + + var generateUrlCases = new Dictionary + { + [serverCanonUrl] = server, + [serverWithRemarkCanonUrl] = serverWithRemark, + [serverWithPluginCanonUrl] = serverWithPlugin, + [serverWithPluginAndRemarkCanonUrl] = serverWithPluginAndRemark + }; + RunGenerateShadowsocksUrlTest(generateUrlCases); + } + + private static void RunParseShadowsocksUrlTest(string testCase, IReadOnlyList expected) + { + var actual = Server.GetServers(testCase); + if (actual.Count != expected.Count) + { + Assert.Fail("Wrong number of configs. Expected: {0}. Actual: {1}", expected.Count, actual.Count); + } + + for (int i = 0; i < expected.Count; i++) + { + var expectedServer = expected[i]; + var actualServer = actual[i]; + + Assert.AreEqual(expectedServer.server, actualServer.server); + Assert.AreEqual(expectedServer.server_port, actualServer.server_port); + Assert.AreEqual(expectedServer.password, actualServer.password); + Assert.AreEqual(expectedServer.method, actualServer.method); + Assert.AreEqual(expectedServer.plugin, actualServer.plugin); + Assert.AreEqual(expectedServer.plugin_opts, actualServer.plugin_opts); + Assert.AreEqual(expectedServer.remarks, actualServer.remarks); + Assert.AreEqual(expectedServer.timeout, actualServer.timeout); + } + } + + private static void RunGenerateShadowsocksUrlTest(IReadOnlyDictionary testCases) + { + foreach (var testCase in testCases) + { + string expected = testCase.Key; + Server config = testCase.Value; + + var actual = ShadowsocksController.GetServerURL(config); + Assert.AreEqual(expected, actual); + } + } + + } +} diff --git a/test/test.csproj b/test/test.csproj index 5ef22e36..d85a006e 100755 --- a/test/test.csproj +++ b/test/test.csproj @@ -56,6 +56,9 @@ + + +