Commit 67d23ca1 authored by Nick Craver's avatar Nick Craver

Tests host:port cleanup

There were several mismatches here...this should help avoid future ones.
parent 72b1cbab
...@@ -8,7 +8,7 @@ public class AsyncTests : TestBase ...@@ -8,7 +8,7 @@ public class AsyncTests : TestBase
{ {
public AsyncTests(ITestOutputHelper output) : base (output) { } public AsyncTests(ITestOutputHelper output) : base (output) { }
protected override string GetConfiguration() => TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort; protected override string GetConfiguration() => TestConfig.Current.MasterServerAndPort;
#if DEBUG // IRedisServerDebug and AllowConnect are only available if DEBUG is defined #if DEBUG // IRedisServerDebug and AllowConnect are only available if DEBUG is defined
[Fact] [Fact]
......
...@@ -7,7 +7,7 @@ namespace StackExchange.Redis.Tests ...@@ -7,7 +7,7 @@ namespace StackExchange.Redis.Tests
{ {
public class ConnectionShutdown : TestBase public class ConnectionShutdown : TestBase
{ {
protected override string GetConfiguration() => TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort; protected override string GetConfiguration() => TestConfig.Current.MasterServerAndPort;
public ConnectionShutdown(ITestOutputHelper output) : base (output) { } public ConnectionShutdown(ITestOutputHelper output) : base (output) { }
[Fact(Skip="Unfriendly")] [Fact(Skip="Unfriendly")]
...@@ -53,4 +53,4 @@ public void ShutdownRaisesConnectionFailedAndRestore() ...@@ -53,4 +53,4 @@ public void ShutdownRaisesConnectionFailedAndRestore()
} }
} }
} }
} }
\ No newline at end of file
...@@ -42,13 +42,16 @@ public class Config ...@@ -42,13 +42,16 @@ public class Config
public string MasterServer { get; set; } = "127.0.0.1"; public string MasterServer { get; set; } = "127.0.0.1";
public int MasterPort { get; set; } = 6379; public int MasterPort { get; set; } = 6379;
public string MasterServerAndPort => MasterServer + ":" + MasterPort.ToString();
public string SlaveServer { get; set; } = "127.0.0.1"; public string SlaveServer { get; set; } = "127.0.0.1";
public int SlavePort { get; set; } = 6380; public int SlavePort { get; set; } = 6380;
public string SlaveServerAndPort => SlaveServer + ":" + SlavePort.ToString();
public string SecureServer { get; set; } = "127.0.0.1"; public string SecureServer { get; set; } = "127.0.0.1";
public int SecurePort { get; set; } = 6381; public int SecurePort { get; set; } = 6381;
public string SecurePassword { get; set; } = "changeme"; public string SecurePassword { get; set; } = "changeme";
public string SecureServerAndPort => SecureServer + ":" + SecurePort.ToString();
public string IPv4Server { get; set; } = "127.0.0.1"; public string IPv4Server { get; set; } = "127.0.0.1";
public int IPv4Port { get; set; } = 6379; public int IPv4Port { get; set; } = 6379;
......
...@@ -28,7 +28,7 @@ public void ConfigurationOptions_UnspecifiedDefaultDb() ...@@ -28,7 +28,7 @@ public void ConfigurationOptions_UnspecifiedDefaultDb()
var log = new StringWriter(); var log = new StringWriter();
try try
{ {
using (var conn = ConnectionMultiplexer.Connect($"{TestConfig.Current.MasterServer}:{TestConfig.Current.MasterPort}", log)) { using (var conn = ConnectionMultiplexer.Connect(TestConfig.Current.MasterServerAndPort, log)) {
var db = conn.GetDatabase(); var db = conn.GetDatabase();
Assert.Equal(0, db.Database); Assert.Equal(0, db.Database);
} }
...@@ -45,7 +45,7 @@ public void ConfigurationOptions_SpecifiedDefaultDb() ...@@ -45,7 +45,7 @@ public void ConfigurationOptions_SpecifiedDefaultDb()
var log = new StringWriter(); var log = new StringWriter();
try try
{ {
using (var conn = ConnectionMultiplexer.Connect($"{TestConfig.Current.MasterServer}:{TestConfig.Current.MasterPort},defaultDatabase=3", log)) { using (var conn = ConnectionMultiplexer.Connect($"{TestConfig.Current.MasterServerAndPort},defaultDatabase=3", log)) {
var db = conn.GetDatabase(); var db = conn.GetDatabase();
Assert.Equal(3, db.Database); Assert.Equal(3, db.Database);
} }
......
using System; using System;
using System.Linq; using System.Linq;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
namespace StackExchange.Redis.Tests.Issues namespace StackExchange.Redis.Tests.Issues
{ {
public class Issue182 : TestBase public class Issue182 : TestBase
{ {
protected override string GetConfiguration() => $"{TestConfig.Current.MasterServer}:{TestConfig.Current.MasterPort},responseTimeout=10000"; protected override string GetConfiguration() => $"{TestConfig.Current.MasterServerAndPort},responseTimeout=10000";
public Issue182(ITestOutputHelper output) : base (output) { } public Issue182(ITestOutputHelper output) : base (output) { }
[FactLongRunning] [FactLongRunning]
public void SetMembers() public void SetMembers()
{ {
using (var conn = Create()) using (var conn = Create())
{ {
conn.ConnectionFailed += (s, a) => conn.ConnectionFailed += (s, a) =>
{ {
Output.WriteLine(a.FailureType.ToString()); Output.WriteLine(a.FailureType.ToString());
Output.WriteLine(a.Exception.Message); Output.WriteLine(a.Exception.Message);
Output.WriteLine(a.Exception.StackTrace); Output.WriteLine(a.Exception.StackTrace);
}; };
var db = conn.GetDatabase(); var db = conn.GetDatabase();
var key = Me(); var key = Me();
const int count = (int)5e6; const int count = (int)5e6;
db.KeyDeleteAsync(key).Wait(); db.KeyDeleteAsync(key).Wait();
foreach (var _ in Enumerable.Range(0, count)) foreach (var _ in Enumerable.Range(0, count))
db.SetAdd(key, Guid.NewGuid().ToByteArray(), CommandFlags.FireAndForget); db.SetAdd(key, Guid.NewGuid().ToByteArray(), CommandFlags.FireAndForget);
Assert.Equal(count, db.SetLengthAsync(key).Result); // SCARD for set Assert.Equal(count, db.SetLengthAsync(key).Result); // SCARD for set
var task = db.SetMembersAsync(key); var task = db.SetMembersAsync(key);
task.Wait(); task.Wait();
Assert.Equal(count, task.Result.Length); // SMEMBERS result length Assert.Equal(count, task.Result.Length); // SMEMBERS result length
} }
} }
[FactLongRunning] [FactLongRunning]
public void SetUnion() public void SetUnion()
{ {
using (var conn = Create()) using (var conn = Create())
{ {
var db = conn.GetDatabase(); var db = conn.GetDatabase();
var key1 = Me() + ":1"; var key1 = Me() + ":1";
var key2 = Me() + ":2"; var key2 = Me() + ":2";
var dstkey = Me() + ":dst"; var dstkey = Me() + ":dst";
db.KeyDeleteAsync(key1).Wait(); db.KeyDeleteAsync(key1).Wait();
db.KeyDeleteAsync(key2).Wait(); db.KeyDeleteAsync(key2).Wait();
db.KeyDeleteAsync(dstkey).Wait(); db.KeyDeleteAsync(dstkey).Wait();
const int count = (int)5e6; const int count = (int)5e6;
foreach (var _ in Enumerable.Range(0, count)) foreach (var _ in Enumerable.Range(0, count))
{ {
db.SetAdd(key1, Guid.NewGuid().ToByteArray(), CommandFlags.FireAndForget); db.SetAdd(key1, Guid.NewGuid().ToByteArray(), CommandFlags.FireAndForget);
db.SetAdd(key2, Guid.NewGuid().ToByteArray(), CommandFlags.FireAndForget); db.SetAdd(key2, Guid.NewGuid().ToByteArray(), CommandFlags.FireAndForget);
} }
Assert.Equal(count, db.SetLengthAsync(key1).Result); // SCARD for set 1 Assert.Equal(count, db.SetLengthAsync(key1).Result); // SCARD for set 1
Assert.Equal(count, db.SetLengthAsync(key2).Result); // SCARD for set 2 Assert.Equal(count, db.SetLengthAsync(key2).Result); // SCARD for set 2
db.SetCombineAndStoreAsync(SetOperation.Union, dstkey, key1, key2).Wait(); db.SetCombineAndStoreAsync(SetOperation.Union, dstkey, key1, key2).Wait();
var dstLen = db.SetLength(dstkey); var dstLen = db.SetLength(dstkey);
Assert.Equal(count * 2, dstLen); // SCARD for destination set Assert.Equal(count * 2, dstLen); // SCARD for destination set
} }
} }
} }
} }
\ No newline at end of file
...@@ -29,7 +29,7 @@ public void DefaultValue_IsTrue() ...@@ -29,7 +29,7 @@ public void DefaultValue_IsTrue()
[Fact] [Fact]
public void PreserveAsyncOrder_SetConnectionMultiplexerProperty() public void PreserveAsyncOrder_SetConnectionMultiplexerProperty()
{ {
var multiplexer = ConnectionMultiplexer.Connect(TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort + ",preserveAsyncOrder=false"); var multiplexer = ConnectionMultiplexer.Connect(TestConfig.Current.MasterServerAndPort + ",preserveAsyncOrder=false");
Assert.False(multiplexer.PreserveAsyncOrder); Assert.False(multiplexer.PreserveAsyncOrder);
} }
} }
......
...@@ -7,7 +7,7 @@ namespace StackExchange.Redis.Tests.Issues ...@@ -7,7 +7,7 @@ namespace StackExchange.Redis.Tests.Issues
{ {
public class SO25567566 : TestBase public class SO25567566 : TestBase
{ {
protected override string GetConfiguration() => $"{TestConfig.Current.MasterServer}:{TestConfig.Current.MasterPort}"; protected override string GetConfiguration() => TestConfig.Current.MasterServerAndPort;
public SO25567566(ITestOutputHelper output) : base(output) { } public SO25567566(ITestOutputHelper output) : base(output) { }
[FactLongRunning] [FactLongRunning]
...@@ -70,4 +70,4 @@ private async Task<string> DoStuff(ConnectionMultiplexer conn) ...@@ -70,4 +70,4 @@ private async Task<string> DoStuff(ConnectionMultiplexer conn)
} }
} }
} }
} }
\ No newline at end of file
...@@ -34,7 +34,7 @@ public void RandomKey() ...@@ -34,7 +34,7 @@ public void RandomKey()
using (var conn = Create(allowAdmin: true)) using (var conn = Create(allowAdmin: true))
{ {
var db = conn.GetDatabase(); var db = conn.GetDatabase();
conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort).FlushDatabase(); conn.GetServer(TestConfig.Current.MasterServerAndPort).FlushDatabase();
string anyKey = db.KeyRandom(); string anyKey = db.KeyRandom();
Assert.Null(anyKey); Assert.Null(anyKey);
......
...@@ -9,7 +9,7 @@ namespace StackExchange.Redis.Tests ...@@ -9,7 +9,7 @@ namespace StackExchange.Redis.Tests
{ {
public class Locking : TestBase public class Locking : TestBase
{ {
protected override string GetConfiguration() => TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort; protected override string GetConfiguration() => TestConfig.Current.MasterServerAndPort;
public Locking(ITestOutputHelper output) : base (output) { } public Locking(ITestOutputHelper output) : base (output) { }
public enum TestMode public enum TestMode
......
...@@ -12,7 +12,7 @@ namespace StackExchange.Redis.Tests ...@@ -12,7 +12,7 @@ namespace StackExchange.Redis.Tests
public class MultiMaster : TestBase public class MultiMaster : TestBase
{ {
protected override string GetConfiguration() => protected override string GetConfiguration() =>
TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort + "," + TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort + ",password=" + TestConfig.Current.SecurePassword; TestConfig.Current.MasterServerAndPort + "," + TestConfig.Current.SecureServerAndPort + ",password=" + TestConfig.Current.SecurePassword;
public MultiMaster(ITestOutputHelper output) : base (output) { } public MultiMaster(ITestOutputHelper output) : base (output) { }
...@@ -39,8 +39,8 @@ public async Task DeslaveGoesToPrimary() ...@@ -39,8 +39,8 @@ public async Task DeslaveGoesToPrimary()
ConfigurationOptions config = GetMasterSlaveConfig(); ConfigurationOptions config = GetMasterSlaveConfig();
using (var conn = ConnectionMultiplexer.Connect(config)) using (var conn = ConnectionMultiplexer.Connect(config))
{ {
var primary = conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort); var primary = conn.GetServer(TestConfig.Current.MasterServerAndPort);
var secondary = conn.GetServer(TestConfig.Current.SlaveServer, TestConfig.Current.SlavePort); var secondary = conn.GetServer(TestConfig.Current.SlaveServerAndPort);
primary.Ping(); primary.Ping();
secondary.Ping(); secondary.Ping();
...@@ -58,7 +58,7 @@ public async Task DeslaveGoesToPrimary() ...@@ -58,7 +58,7 @@ public async Task DeslaveGoesToPrimary()
conn.Configure(writer); conn.Configure(writer);
string log = writer.ToString(); string log = writer.ToString();
Assert.True(log.Contains("tie-break is unanimous at " + TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort), "unanimous"); Assert.True(log.Contains("tie-break is unanimous at " + TestConfig.Current.MasterServerAndPort), "unanimous");
} }
// k, so we know everyone loves 6379; is that what we get? // k, so we know everyone loves 6379; is that what we get?
...@@ -89,8 +89,8 @@ public async Task DeslaveGoesToPrimary() ...@@ -89,8 +89,8 @@ public async Task DeslaveGoesToPrimary()
// server topology changes from failures to recognize those changes // server topology changes from failures to recognize those changes
using (var conn2 = ConnectionMultiplexer.Connect(config)) using (var conn2 = ConnectionMultiplexer.Connect(config))
{ {
var primary2 = conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort); var primary2 = conn.GetServer(TestConfig.Current.MasterServerAndPort);
var secondary2 = conn.GetServer(TestConfig.Current.SlaveServer, TestConfig.Current.SlavePort); var secondary2 = conn.GetServer(TestConfig.Current.SlaveServerAndPort);
Writer.WriteLine($"Check: {primary2.EndPoint}: {primary2.ServerType}, Mode: {(primary2.IsSlave ? "Slave" : "Master")}"); Writer.WriteLine($"Check: {primary2.EndPoint}: {primary2.ServerType}, Mode: {(primary2.IsSlave ? "Slave" : "Master")}");
Writer.WriteLine($"Check: {secondary2.EndPoint}: {secondary2.ServerType}, Mode: {(secondary2.IsSlave ? "Slave" : "Master")}"); Writer.WriteLine($"Check: {secondary2.EndPoint}: {secondary2.ServerType}, Mode: {(secondary2.IsSlave ? "Slave" : "Master")}");
...@@ -143,15 +143,15 @@ public void TestMultiNoTieBreak() ...@@ -143,15 +143,15 @@ public void TestMultiNoTieBreak()
public static IEnumerable<object[]> GetConnections() public static IEnumerable<object[]> GetConnections()
{ {
yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort }; yield return new object[] { TestConfig.Current.MasterServerAndPort, TestConfig.Current.MasterServerAndPort, TestConfig.Current.MasterServerAndPort };
yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort }; yield return new object[] { TestConfig.Current.SecureServerAndPort, TestConfig.Current.SecureServerAndPort, TestConfig.Current.SecureServerAndPort };
yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, null }; yield return new object[] { TestConfig.Current.SecureServerAndPort, TestConfig.Current.MasterServerAndPort, null };
yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, null }; yield return new object[] { TestConfig.Current.MasterServerAndPort, TestConfig.Current.SecureServerAndPort, null };
yield return new object[] { null, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort }; yield return new object[] { null, TestConfig.Current.MasterServerAndPort, TestConfig.Current.MasterServerAndPort };
yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, null, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort }; yield return new object[] { TestConfig.Current.MasterServerAndPort, null, TestConfig.Current.MasterServerAndPort };
yield return new object[] { null, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort }; yield return new object[] { null, TestConfig.Current.SecureServerAndPort, TestConfig.Current.SecureServerAndPort };
yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, null, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort }; yield return new object[] { TestConfig.Current.SecureServerAndPort, null, TestConfig.Current.SecureServerAndPort };
yield return new object[] { null, null, null }; yield return new object[] { null, null, null };
} }
...@@ -160,11 +160,11 @@ public void TestMultiWithTiebreak(string a, string b, string elected) ...@@ -160,11 +160,11 @@ public void TestMultiWithTiebreak(string a, string b, string elected)
{ {
const string TieBreak = "__tie__"; const string TieBreak = "__tie__";
// set the tie-breakers to the expected state // set the tie-breakers to the expected state
using (var aConn = ConnectionMultiplexer.Connect(TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort)) using (var aConn = ConnectionMultiplexer.Connect(TestConfig.Current.MasterServerAndPort))
{ {
aConn.GetDatabase().StringSet(TieBreak, a); aConn.GetDatabase().StringSet(TieBreak, a);
} }
using (var aConn = ConnectionMultiplexer.Connect(TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort + ",password=" + TestConfig.Current.SecurePassword)) using (var aConn = ConnectionMultiplexer.Connect(TestConfig.Current.SecureServerAndPort + ",password=" + TestConfig.Current.SecurePassword))
{ {
aConn.GetDatabase().StringSet(TieBreak, b); aConn.GetDatabase().StringSet(TieBreak, b);
} }
......
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
...@@ -13,7 +14,7 @@ public class PubSubNonParallel : TestBase ...@@ -13,7 +14,7 @@ public class PubSubNonParallel : TestBase
[Theory] [Theory]
[InlineData(false)] [InlineData(false)]
[InlineData(true)] [InlineData(true)]
public void SubscriptionsSurviveMasterSwitch(bool useSharedSocketManager) public async Task SubscriptionsSurviveMasterSwitchAsync(bool useSharedSocketManager)
{ {
using (var a = Create(allowAdmin: true, useSharedSocketManager: useSharedSocketManager)) using (var a = Create(allowAdmin: true, useSharedSocketManager: useSharedSocketManager))
using (var b = Create(allowAdmin: true, useSharedSocketManager: useSharedSocketManager)) using (var b = Create(allowAdmin: true, useSharedSocketManager: useSharedSocketManager))
...@@ -42,10 +43,10 @@ public void SubscriptionsSurviveMasterSwitch(bool useSharedSocketManager) ...@@ -42,10 +43,10 @@ public void SubscriptionsSurviveMasterSwitch(bool useSharedSocketManager)
Interlocked.Increment(ref bCount); Interlocked.Increment(ref bCount);
}); });
Assert.False(a.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort).IsSlave, TestConfig.Current.MasterPort + " is master via a"); Assert.False(a.GetServer(TestConfig.Current.MasterServerAndPort).IsSlave, $"{TestConfig.Current.MasterServerAndPort} should be master via a");
Assert.True(a.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.SlavePort).IsSlave, TestConfig.Current.SlavePort + " is slave via a"); Assert.True(a.GetServer(TestConfig.Current.SlaveServerAndPort).IsSlave, $"{TestConfig.Current.SlaveServerAndPort} should be slave via a");
Assert.False(b.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort).IsSlave, TestConfig.Current.MasterPort + " is master via b"); Assert.False(b.GetServer(TestConfig.Current.MasterServerAndPort).IsSlave, $"{TestConfig.Current.MasterServerAndPort} should be master via b");
Assert.True(b.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.SlavePort).IsSlave, TestConfig.Current.SlavePort + " is slave via b"); Assert.True(b.GetServer(TestConfig.Current.SlaveServerAndPort).IsSlave, $"{TestConfig.Current.SlaveServerAndPort} should be slave via b");
var epA = subA.SubscribedEndpoint(channel); var epA = subA.SubscribedEndpoint(channel);
var epB = subB.SubscribedEndpoint(channel); var epB = subB.SubscribedEndpoint(channel);
...@@ -68,18 +69,18 @@ public void SubscriptionsSurviveMasterSwitch(bool useSharedSocketManager) ...@@ -68,18 +69,18 @@ public void SubscriptionsSurviveMasterSwitch(bool useSharedSocketManager)
Output.WriteLine("Changing master..."); Output.WriteLine("Changing master...");
using (var sw = new StringWriter()) using (var sw = new StringWriter())
{ {
a.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.SlavePort).MakeMaster(ReplicationChangeOptions.All, sw); a.GetServer(TestConfig.Current.SlaveServerAndPort).MakeMaster(ReplicationChangeOptions.All, sw);
Output.WriteLine(sw.ToString()); Output.WriteLine(sw.ToString());
} }
subA.Ping(); subA.Ping();
subB.Ping(); subB.Ping();
Output.WriteLine("Pausing..."); Output.WriteLine("Pausing...");
Thread.Sleep(2000); await Task.Delay(4000).ForAwait();
Assert.True(a.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort).IsSlave, TestConfig.Current.MasterPort + " is slave via a"); Assert.True(a.GetServer(TestConfig.Current.MasterServerAndPort).IsSlave, $"{TestConfig.Current.MasterServerAndPort} should be a slave via a");
Assert.False(a.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.SlavePort).IsSlave, TestConfig.Current.SlavePort + " is master via a"); Assert.False(a.GetServer(TestConfig.Current.SlaveServerAndPort).IsSlave, $"{TestConfig.Current.SlaveServerAndPort} should be a master via a");
Assert.True(b.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort).IsSlave, TestConfig.Current.MasterPort + " is slave via b"); Assert.True(b.GetServer(TestConfig.Current.MasterServerAndPort).IsSlave, $"{TestConfig.Current.MasterServerAndPort} should be a slave via b");
Assert.False(b.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.SlavePort).IsSlave, TestConfig.Current.SlavePort + " is master via b"); Assert.False(b.GetServer(TestConfig.Current.SlaveServerAndPort).IsSlave, $"{TestConfig.Current.SlaveServerAndPort} should be a master via b");
Output.WriteLine("Pause complete"); Output.WriteLine("Pause complete");
var counters = a.GetCounters(); var counters = a.GetCounters();
...@@ -88,6 +89,7 @@ public void SubscriptionsSurviveMasterSwitch(bool useSharedSocketManager) ...@@ -88,6 +89,7 @@ public void SubscriptionsSurviveMasterSwitch(bool useSharedSocketManager)
Output.WriteLine("b outstanding: " + counters.TotalOutstanding); Output.WriteLine("b outstanding: " + counters.TotalOutstanding);
subA.Ping(); subA.Ping();
subB.Ping(); subB.Ping();
await Task.Delay(2000).ForAwait();
epA = subA.SubscribedEndpoint(channel); epA = subA.SubscribedEndpoint(channel);
epB = subB.SubscribedEndpoint(channel); epB = subB.SubscribedEndpoint(channel);
Output.WriteLine("a: " + EndPointCollection.ToString(epA)); Output.WriteLine("a: " + EndPointCollection.ToString(epA));
...@@ -108,7 +110,7 @@ public void SubscriptionsSurviveMasterSwitch(bool useSharedSocketManager) ...@@ -108,7 +110,7 @@ public void SubscriptionsSurviveMasterSwitch(bool useSharedSocketManager)
Output.WriteLine("Restoring configuration..."); Output.WriteLine("Restoring configuration...");
try try
{ {
a.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort).MakeMaster(ReplicationChangeOptions.All); a.GetServer(TestConfig.Current.MasterServerAndPort).MakeMaster(ReplicationChangeOptions.All);
} }
catch catch
{ } { }
......
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
namespace StackExchange.Redis.Tests namespace StackExchange.Redis.Tests
{ {
public class Scripting : TestBase public class Scripting : TestBase
{ {
public Scripting(ITestOutputHelper output) : base (output) { } public Scripting(ITestOutputHelper output) : base (output) { }
[Fact] [Fact]
public void TestBasicScripting() public void TestBasicScripting()
{ {
using (var conn = Create()) using (var conn = Create())
{ {
Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting);
RedisValue newId = Guid.NewGuid().ToString(); RedisValue newId = Guid.NewGuid().ToString();
RedisKey custKey = Me(); RedisKey custKey = Me();
var db = conn.GetDatabase(); var db = conn.GetDatabase();
db.KeyDelete(custKey); db.KeyDelete(custKey);
db.HashSet(custKey, "id", 123); db.HashSet(custKey, "id", 123);
var wasSet = (bool)db.ScriptEvaluate("if redis.call('hexists', KEYS[1], 'UniqueId') then return redis.call('hset', KEYS[1], 'UniqueId', ARGV[1]) else return 0 end", var wasSet = (bool)db.ScriptEvaluate("if redis.call('hexists', KEYS[1], 'UniqueId') then return redis.call('hset', KEYS[1], 'UniqueId', ARGV[1]) else return 0 end",
new RedisKey[] { custKey }, new RedisValue[] { newId }); new RedisKey[] { custKey }, new RedisValue[] { newId });
Assert.True(wasSet); Assert.True(wasSet);
wasSet = (bool)db.ScriptEvaluate("if redis.call('hexists', KEYS[1], 'UniqueId') then return redis.call('hset', KEYS[1], 'UniqueId', ARGV[1]) else return 0 end", wasSet = (bool)db.ScriptEvaluate("if redis.call('hexists', KEYS[1], 'UniqueId') then return redis.call('hset', KEYS[1], 'UniqueId', ARGV[1]) else return 0 end",
new RedisKey[] { custKey }, new RedisValue[] { newId }); new RedisKey[] { custKey }, new RedisValue[] { newId });
Assert.False(wasSet); Assert.False(wasSet);
} }
} }
[Theory] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [InlineData(false)]
public void CheckLoads(bool async) public void CheckLoads(bool async)
{ {
using (var conn0 = Create(allowAdmin: true)) using (var conn0 = Create(allowAdmin: true))
using (var conn1 = Create(allowAdmin: true)) using (var conn1 = Create(allowAdmin: true))
{ {
Skip.IfMissingFeature(conn0, nameof(RedisFeatures.Scripting), f => f.Scripting); Skip.IfMissingFeature(conn0, nameof(RedisFeatures.Scripting), f => f.Scripting);
// note that these are on different connections (so we wouldn't expect // note that these are on different connections (so we wouldn't expect
// the flush to drop the local cache - assume it is a surprise!) // the flush to drop the local cache - assume it is a surprise!)
var server = conn0.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort); var server = conn0.GetServer(TestConfig.Current.MasterServerAndPort);
var db = conn1.GetDatabase(); var db = conn1.GetDatabase();
const string script = "return 1;"; const string script = "return 1;";
// start empty // start empty
server.ScriptFlush(); server.ScriptFlush();
Assert.False(server.ScriptExists(script)); Assert.False(server.ScriptExists(script));
// run once, causes to be cached // run once, causes to be cached
Assert.True((bool)db.ScriptEvaluate(script)); Assert.True((bool)db.ScriptEvaluate(script));
Assert.True(server.ScriptExists(script)); Assert.True(server.ScriptExists(script));
// can run again // can run again
Assert.True((bool)db.ScriptEvaluate(script)); Assert.True((bool)db.ScriptEvaluate(script));
// ditch the scripts; should no longer exist // ditch the scripts; should no longer exist
db.Ping(); db.Ping();
server.ScriptFlush(); server.ScriptFlush();
Assert.False(server.ScriptExists(script)); Assert.False(server.ScriptExists(script));
db.Ping(); db.Ping();
if (async) if (async)
{ {
// now: fails the first time // now: fails the first time
try try
{ {
db.Wait(db.ScriptEvaluateAsync(script)); db.Wait(db.ScriptEvaluateAsync(script));
Assert.True(false, "ScriptEvaluateAsync should fail"); Assert.True(false, "ScriptEvaluateAsync should fail");
} }
catch (AggregateException ex) catch (AggregateException ex)
{ {
Assert.Single(ex.InnerExceptions); Assert.Single(ex.InnerExceptions);
Assert.IsType<RedisServerException>(ex.InnerExceptions[0]); Assert.IsType<RedisServerException>(ex.InnerExceptions[0]);
Assert.Equal("NOSCRIPT No matching script. Please use EVAL.", ex.InnerExceptions[0].Message); Assert.Equal("NOSCRIPT No matching script. Please use EVAL.", ex.InnerExceptions[0].Message);
} }
} }
else else
{ {
// just works; magic // just works; magic
Assert.True((bool)db.ScriptEvaluate(script)); Assert.True((bool)db.ScriptEvaluate(script));
} }
// but gets marked as unloaded, so we can use it again... // but gets marked as unloaded, so we can use it again...
Assert.True((bool)db.ScriptEvaluate(script)); Assert.True((bool)db.ScriptEvaluate(script));
// which will cause it to be cached // which will cause it to be cached
Assert.True(server.ScriptExists(script)); Assert.True(server.ScriptExists(script));
} }
} }
[Fact] [Fact]
public void CompareScriptToDirect() public void CompareScriptToDirect()
{ {
const string Script = "return redis.call('incr', KEYS[1])"; const string Script = "return redis.call('incr', KEYS[1])";
using (var conn = Create(allowAdmin: true)) using (var conn = Create(allowAdmin: true))
{ {
Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting);
var server = conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort); var server = conn.GetServer(TestConfig.Current.MasterServerAndPort);
server.FlushAllDatabases(); server.FlushAllDatabases();
server.ScriptFlush(); server.ScriptFlush();
server.ScriptLoad(Script); server.ScriptLoad(Script);
var db = conn.GetDatabase(); var db = conn.GetDatabase();
db.Ping(); // k, we're all up to date now; clean db, minimal script cache db.Ping(); // k, we're all up to date now; clean db, minimal script cache
// we're using a pipeline here, so send 1000 messages, but for timing: only care about the last // we're using a pipeline here, so send 1000 messages, but for timing: only care about the last
const int LOOP = 5000; const int LOOP = 5000;
RedisKey key = "foo"; RedisKey key = "foo";
RedisKey[] keys = new[] { key }; // script takes an array RedisKey[] keys = new[] { key }; // script takes an array
// run via script // run via script
db.KeyDelete(key); db.KeyDelete(key);
CollectGarbage(); CollectGarbage();
var watch = Stopwatch.StartNew(); var watch = Stopwatch.StartNew();
for (int i = 1; i < LOOP; i++) // the i=1 is to do all-but-one for (int i = 1; i < LOOP; i++) // the i=1 is to do all-but-one
{ {
db.ScriptEvaluate(Script, keys, flags: CommandFlags.FireAndForget); db.ScriptEvaluate(Script, keys, flags: CommandFlags.FireAndForget);
} }
var scriptResult = db.ScriptEvaluate(Script, keys); // last one we wait for (no F+F) var scriptResult = db.ScriptEvaluate(Script, keys); // last one we wait for (no F+F)
watch.Stop(); watch.Stop();
TimeSpan scriptTime = watch.Elapsed; TimeSpan scriptTime = watch.Elapsed;
// run via raw op // run via raw op
db.KeyDelete(key); db.KeyDelete(key);
CollectGarbage(); CollectGarbage();
watch = Stopwatch.StartNew(); watch = Stopwatch.StartNew();
for (int i = 1; i < LOOP; i++) // the i=1 is to do all-but-one for (int i = 1; i < LOOP; i++) // the i=1 is to do all-but-one
{ {
db.StringIncrement(key, flags: CommandFlags.FireAndForget); db.StringIncrement(key, flags: CommandFlags.FireAndForget);
} }
var directResult = db.StringIncrement(key); // last one we wait for (no F+F) var directResult = db.StringIncrement(key); // last one we wait for (no F+F)
watch.Stop(); watch.Stop();
TimeSpan directTime = watch.Elapsed; TimeSpan directTime = watch.Elapsed;
Assert.Equal(LOOP, (long)scriptResult); Assert.Equal(LOOP, (long)scriptResult);
Assert.Equal(LOOP, directResult); Assert.Equal(LOOP, directResult);
Output.WriteLine("script: {0}ms; direct: {1}ms", Output.WriteLine("script: {0}ms; direct: {1}ms",
scriptTime.TotalMilliseconds, scriptTime.TotalMilliseconds,
directTime.TotalMilliseconds); directTime.TotalMilliseconds);
} }
} }
[Fact] [Fact]
public void TestCallByHash() public void TestCallByHash()
{ {
const string Script = "return redis.call('incr', KEYS[1])"; const string Script = "return redis.call('incr', KEYS[1])";
using (var conn = Create(allowAdmin: true)) using (var conn = Create(allowAdmin: true))
{ {
Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting);
var server = conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort); var server = conn.GetServer(TestConfig.Current.MasterServerAndPort);
server.FlushAllDatabases(); server.FlushAllDatabases();
server.ScriptFlush(); server.ScriptFlush();
byte[] hash = server.ScriptLoad(Script); byte[] hash = server.ScriptLoad(Script);
var db = conn.GetDatabase(); var db = conn.GetDatabase();
RedisKey[] keys = { Me() }; RedisKey[] keys = { Me() };
string hexHash = string.Concat(hash.Select(x => x.ToString("X2"))); string hexHash = string.Concat(hash.Select(x => x.ToString("X2")));
Assert.Equal("2BAB3B661081DB58BD2341920E0BA7CF5DC77B25", hexHash); Assert.Equal("2BAB3B661081DB58BD2341920E0BA7CF5DC77B25", hexHash);
db.ScriptEvaluate(hexHash, keys); db.ScriptEvaluate(hexHash, keys);
db.ScriptEvaluate(hash, keys); db.ScriptEvaluate(hash, keys);
var count = (int)db.StringGet(keys)[0]; var count = (int)db.StringGet(keys)[0];
Assert.Equal(2, count); Assert.Equal(2, count);
} }
} }
[Fact] [Fact]
public void SimpleLuaScript() public void SimpleLuaScript()
{ {
const string Script = "return @ident"; const string Script = "return @ident";
using (var conn = Create(allowAdmin: true)) using (var conn = Create(allowAdmin: true))
{ {
Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting);
var server = conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort); var server = conn.GetServer(TestConfig.Current.MasterServerAndPort);
server.FlushAllDatabases(); server.FlushAllDatabases();
server.ScriptFlush(); server.ScriptFlush();
var prepared = LuaScript.Prepare(Script); var prepared = LuaScript.Prepare(Script);
var db = conn.GetDatabase(); var db = conn.GetDatabase();
{ {
var val = prepared.Evaluate(db, new { ident = "hello" }); var val = prepared.Evaluate(db, new { ident = "hello" });
Assert.Equal("hello", (string)val); Assert.Equal("hello", (string)val);
} }
{ {
var val = prepared.Evaluate(db, new { ident = 123 }); var val = prepared.Evaluate(db, new { ident = 123 });
Assert.Equal(123, (int)val); Assert.Equal(123, (int)val);
} }
{ {
var val = prepared.Evaluate(db, new { ident = 123L }); var val = prepared.Evaluate(db, new { ident = 123L });
Assert.Equal(123L, (long)val); Assert.Equal(123L, (long)val);
} }
{ {
var val = prepared.Evaluate(db, new { ident = 1.1 }); var val = prepared.Evaluate(db, new { ident = 1.1 });
Assert.Equal(1.1, (double)val); Assert.Equal(1.1, (double)val);
} }
{ {
var val = prepared.Evaluate(db, new { ident = true }); var val = prepared.Evaluate(db, new { ident = true });
Assert.True((bool)val); Assert.True((bool)val);
} }
{ {
var val = prepared.Evaluate(db, new { ident = new byte[] { 4, 5, 6 } }); var val = prepared.Evaluate(db, new { ident = new byte[] { 4, 5, 6 } });
Assert.True(new byte[] { 4, 5, 6 }.SequenceEqual((byte[])val)); Assert.True(new byte[] { 4, 5, 6 }.SequenceEqual((byte[])val));
} }
} }
} }
[Fact] [Fact]
public void LuaScriptWithKeys() public void LuaScriptWithKeys()
{ {
const string Script = "redis.call('set', @key, @value)"; const string Script = "redis.call('set', @key, @value)";
using (var conn = Create(allowAdmin: true)) using (var conn = Create(allowAdmin: true))
{ {
Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting);
var server = conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort); var server = conn.GetServer(TestConfig.Current.MasterServerAndPort);
server.FlushAllDatabases(); server.FlushAllDatabases();
server.ScriptFlush(); server.ScriptFlush();
var script = LuaScript.Prepare(Script); var script = LuaScript.Prepare(Script);
var db = conn.GetDatabase(); var db = conn.GetDatabase();
var p = new { key = (RedisKey)"testkey", value = 123 }; var p = new { key = (RedisKey)"testkey", value = 123 };
script.Evaluate(db, p); script.Evaluate(db, p);
var val = db.StringGet("testkey"); var val = db.StringGet("testkey");
Assert.Equal(123, (int)val); Assert.Equal(123, (int)val);
// no super clean way to extract this; so just abuse InternalsVisibleTo // no super clean way to extract this; so just abuse InternalsVisibleTo
script.ExtractParameters(p, null, out RedisKey[] keys, out RedisValue[] args); script.ExtractParameters(p, null, out RedisKey[] keys, out RedisValue[] args);
Assert.NotNull(keys); Assert.NotNull(keys);
Assert.Single(keys); Assert.Single(keys);
Assert.Equal("testkey", keys[0]); Assert.Equal("testkey", keys[0]);
} }
} }
[Fact] [Fact]
public void NoInlineReplacement() public void NoInlineReplacement()
{ {
const string Script = "redis.call('set', @key, 'hello@example')"; const string Script = "redis.call('set', @key, 'hello@example')";
using (var conn = Create(allowAdmin: true)) using (var conn = Create(allowAdmin: true))
{ {
Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting);
var server = conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort); var server = conn.GetServer(TestConfig.Current.MasterServerAndPort);
server.FlushAllDatabases(); server.FlushAllDatabases();
server.ScriptFlush(); server.ScriptFlush();
var script = LuaScript.Prepare(Script); var script = LuaScript.Prepare(Script);
Assert.Equal("redis.call('set', ARGV[1], 'hello@example')", script.ExecutableScript); Assert.Equal("redis.call('set', ARGV[1], 'hello@example')", script.ExecutableScript);
var db = conn.GetDatabase(); var db = conn.GetDatabase();
var p = new { key = (RedisKey)"key" }; var p = new { key = (RedisKey)"key" };
script.Evaluate(db, p); script.Evaluate(db, p);
var val = db.StringGet("key"); var val = db.StringGet("key");
Assert.Equal("hello@example", val); Assert.Equal("hello@example", val);
} }
} }
[Fact] [Fact]
public void EscapeReplacement() public void EscapeReplacement()
{ {
const string Script = "redis.call('set', @key, @@escapeMe)"; const string Script = "redis.call('set', @key, @@escapeMe)";
var script = LuaScript.Prepare(Script); var script = LuaScript.Prepare(Script);
Assert.Equal("redis.call('set', ARGV[1], @escapeMe)", script.ExecutableScript); Assert.Equal("redis.call('set', ARGV[1], @escapeMe)", script.ExecutableScript);
} }
[Fact] [Fact]
public void SimpleLoadedLuaScript() public void SimpleLoadedLuaScript()
{ {
const string Script = "return @ident"; const string Script = "return @ident";
using (var conn = Create(allowAdmin: true)) using (var conn = Create(allowAdmin: true))
{ {
Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting);
var server = conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort); var server = conn.GetServer(TestConfig.Current.MasterServerAndPort);
server.FlushAllDatabases(); server.FlushAllDatabases();
server.ScriptFlush(); server.ScriptFlush();
var prepared = LuaScript.Prepare(Script); var prepared = LuaScript.Prepare(Script);
var loaded = prepared.Load(server); var loaded = prepared.Load(server);
var db = conn.GetDatabase(); var db = conn.GetDatabase();
{ {
var val = loaded.Evaluate(db, new { ident = "hello" }); var val = loaded.Evaluate(db, new { ident = "hello" });
Assert.Equal("hello", (string)val); Assert.Equal("hello", (string)val);
} }
{ {
var val = loaded.Evaluate(db, new { ident = 123 }); var val = loaded.Evaluate(db, new { ident = 123 });
Assert.Equal(123, (int)val); Assert.Equal(123, (int)val);
} }
{ {
var val = loaded.Evaluate(db, new { ident = 123L }); var val = loaded.Evaluate(db, new { ident = 123L });
Assert.Equal(123L, (long)val); Assert.Equal(123L, (long)val);
} }
{ {
var val = loaded.Evaluate(db, new { ident = 1.1 }); var val = loaded.Evaluate(db, new { ident = 1.1 });
Assert.Equal(1.1, (double)val); Assert.Equal(1.1, (double)val);
} }
{ {
var val = loaded.Evaluate(db, new { ident = true }); var val = loaded.Evaluate(db, new { ident = true });
Assert.True((bool)val); Assert.True((bool)val);
} }
{ {
var val = loaded.Evaluate(db, new { ident = new byte[] { 4, 5, 6 } }); var val = loaded.Evaluate(db, new { ident = new byte[] { 4, 5, 6 } });
Assert.True(new byte[] { 4, 5, 6 }.SequenceEqual((byte[])val)); Assert.True(new byte[] { 4, 5, 6 }.SequenceEqual((byte[])val));
} }
} }
} }
[Fact] [Fact]
public void LoadedLuaScriptWithKeys() public void LoadedLuaScriptWithKeys()
{ {
const string Script = "redis.call('set', @key, @value)"; const string Script = "redis.call('set', @key, @value)";
using (var conn = Create(allowAdmin: true)) using (var conn = Create(allowAdmin: true))
{ {
Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting);
var server = conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort); var server = conn.GetServer(TestConfig.Current.MasterServerAndPort);
server.FlushAllDatabases(); server.FlushAllDatabases();
server.ScriptFlush(); server.ScriptFlush();
var script = LuaScript.Prepare(Script); var script = LuaScript.Prepare(Script);
var prepared = script.Load(server); var prepared = script.Load(server);
var db = conn.GetDatabase(); var db = conn.GetDatabase();
var p = new { key = (RedisKey)"testkey", value = 123 }; var p = new { key = (RedisKey)"testkey", value = 123 };
prepared.Evaluate(db, p); prepared.Evaluate(db, p);
var val = db.StringGet("testkey"); var val = db.StringGet("testkey");
Assert.Equal(123, (int)val); Assert.Equal(123, (int)val);
// no super clean way to extract this; so just abuse InternalsVisibleTo // no super clean way to extract this; so just abuse InternalsVisibleTo
prepared.Original.ExtractParameters(p, null, out RedisKey[] keys, out RedisValue[] args); prepared.Original.ExtractParameters(p, null, out RedisKey[] keys, out RedisValue[] args);
Assert.NotNull(keys); Assert.NotNull(keys);
Assert.Single(keys); Assert.Single(keys);
Assert.Equal("testkey", keys[0]); Assert.Equal("testkey", keys[0]);
} }
} }
[Fact] [Fact]
public void PurgeLuaScriptCache() public void PurgeLuaScriptCache()
{ {
const string Script = "redis.call('set', @PurgeLuaScriptCacheKey, @PurgeLuaScriptCacheValue)"; const string Script = "redis.call('set', @PurgeLuaScriptCacheKey, @PurgeLuaScriptCacheValue)";
var first = LuaScript.Prepare(Script); var first = LuaScript.Prepare(Script);
var fromCache = LuaScript.Prepare(Script); var fromCache = LuaScript.Prepare(Script);
Assert.True(ReferenceEquals(first, fromCache)); Assert.True(ReferenceEquals(first, fromCache));
LuaScript.PurgeCache(); LuaScript.PurgeCache();
var shouldBeNew = LuaScript.Prepare(Script); var shouldBeNew = LuaScript.Prepare(Script);
Assert.False(ReferenceEquals(first, shouldBeNew)); Assert.False(ReferenceEquals(first, shouldBeNew));
} }
private static void _PurgeLuaScriptOnFinalize(string script) private static void _PurgeLuaScriptOnFinalize(string script)
{ {
var first = LuaScript.Prepare(script); var first = LuaScript.Prepare(script);
var fromCache = LuaScript.Prepare(script); var fromCache = LuaScript.Prepare(script);
Assert.True(ReferenceEquals(first, fromCache)); Assert.True(ReferenceEquals(first, fromCache));
Assert.Equal(1, LuaScript.GetCachedScriptCount()); Assert.Equal(1, LuaScript.GetCachedScriptCount());
} }
[Fact] [Fact]
public void PurgeLuaScriptOnFinalize() public void PurgeLuaScriptOnFinalize()
{ {
const string Script = "redis.call('set', @PurgeLuaScriptOnFinalizeKey, @PurgeLuaScriptOnFinalizeValue)"; const string Script = "redis.call('set', @PurgeLuaScriptOnFinalizeKey, @PurgeLuaScriptOnFinalizeValue)";
LuaScript.PurgeCache(); LuaScript.PurgeCache();
Assert.Equal(0, LuaScript.GetCachedScriptCount()); Assert.Equal(0, LuaScript.GetCachedScriptCount());
// This has to be a separate method to guarantee that the created LuaScript objects go out of scope, // This has to be a separate method to guarantee that the created LuaScript objects go out of scope,
// and are thus available to be GC'd // and are thus available to be GC'd
_PurgeLuaScriptOnFinalize(Script); _PurgeLuaScriptOnFinalize(Script);
GC.Collect(2, GCCollectionMode.Forced, blocking: true); GC.Collect(2, GCCollectionMode.Forced, blocking: true);
GC.WaitForPendingFinalizers(); GC.WaitForPendingFinalizers();
Assert.Equal(0, LuaScript.GetCachedScriptCount()); Assert.Equal(0, LuaScript.GetCachedScriptCount());
var shouldBeNew = LuaScript.Prepare(Script); var shouldBeNew = LuaScript.Prepare(Script);
Assert.Equal(1, LuaScript.GetCachedScriptCount()); Assert.Equal(1, LuaScript.GetCachedScriptCount());
} }
[Fact] [Fact]
public void IDatabaseLuaScriptConvenienceMethods() public void IDatabaseLuaScriptConvenienceMethods()
{ {
const string Script = "redis.call('set', @key, @value)"; const string Script = "redis.call('set', @key, @value)";
using (var conn = Create(allowAdmin: true)) using (var conn = Create(allowAdmin: true))
{ {
Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting);
var script = LuaScript.Prepare(Script); var script = LuaScript.Prepare(Script);
var db = conn.GetDatabase(); var db = conn.GetDatabase();
db.ScriptEvaluate(script, new { key = (RedisKey)"key", value = "value" }); db.ScriptEvaluate(script, new { key = (RedisKey)"key", value = "value" });
var val = db.StringGet("key"); var val = db.StringGet("key");
Assert.Equal("value", val); Assert.Equal("value", val);
var prepared = script.Load(conn.GetServer(conn.GetEndPoints()[0])); var prepared = script.Load(conn.GetServer(conn.GetEndPoints()[0]));
db.ScriptEvaluate(prepared, new { key = (RedisKey)"key2", value = "value2" }); db.ScriptEvaluate(prepared, new { key = (RedisKey)"key2", value = "value2" });
var val2 = db.StringGet("key2"); var val2 = db.StringGet("key2");
Assert.Equal("value2", val2); Assert.Equal("value2", val2);
} }
} }
[Fact] [Fact]
public void IServerLuaScriptConvenienceMethods() public void IServerLuaScriptConvenienceMethods()
{ {
const string Script = "redis.call('set', @key, @value)"; const string Script = "redis.call('set', @key, @value)";
using (var conn = Create(allowAdmin: true)) using (var conn = Create(allowAdmin: true))
{ {
Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting);
var script = LuaScript.Prepare(Script); var script = LuaScript.Prepare(Script);
var server = conn.GetServer(conn.GetEndPoints()[0]); var server = conn.GetServer(conn.GetEndPoints()[0]);
var db = conn.GetDatabase(); var db = conn.GetDatabase();
var prepared = server.ScriptLoad(script); var prepared = server.ScriptLoad(script);
db.ScriptEvaluate(prepared, new { key = (RedisKey)"key3", value = "value3" }); db.ScriptEvaluate(prepared, new { key = (RedisKey)"key3", value = "value3" });
var val = db.StringGet("key3"); var val = db.StringGet("key3");
Assert.Equal("value3", val); Assert.Equal("value3", val);
} }
} }
[Fact] [Fact]
public void LuaScriptPrefixedKeys() public void LuaScriptPrefixedKeys()
{ {
const string Script = "redis.call('set', @key, @value)"; const string Script = "redis.call('set', @key, @value)";
var prepared = LuaScript.Prepare(Script); var prepared = LuaScript.Prepare(Script);
var p = new { key = (RedisKey)"key", value = "hello" }; var p = new { key = (RedisKey)"key", value = "hello" };
// no super clean way to extract this; so just abuse InternalsVisibleTo // no super clean way to extract this; so just abuse InternalsVisibleTo
prepared.ExtractParameters(p, "prefix-", out RedisKey[] keys, out RedisValue[] args); prepared.ExtractParameters(p, "prefix-", out RedisKey[] keys, out RedisValue[] args);
Assert.NotNull(keys); Assert.NotNull(keys);
Assert.Single(keys); Assert.Single(keys);
Assert.Equal("prefix-key", keys[0]); Assert.Equal("prefix-key", keys[0]);
Assert.Equal(2, args.Length); Assert.Equal(2, args.Length);
Assert.Equal("prefix-key", args[0]); Assert.Equal("prefix-key", args[0]);
Assert.Equal("hello", args[1]); Assert.Equal("hello", args[1]);
} }
[Fact] [Fact]
public void LuaScriptWithWrappedDatabase() public void LuaScriptWithWrappedDatabase()
{ {
const string Script = "redis.call('set', @key, @value)"; const string Script = "redis.call('set', @key, @value)";
using (var conn = Create(allowAdmin: true)) using (var conn = Create(allowAdmin: true))
{ {
Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting);
var db = conn.GetDatabase(0); var db = conn.GetDatabase(0);
var wrappedDb = KeyspaceIsolation.DatabaseExtensions.WithKeyPrefix(db, "prefix-"); var wrappedDb = KeyspaceIsolation.DatabaseExtensions.WithKeyPrefix(db, "prefix-");
var prepared = LuaScript.Prepare(Script); var prepared = LuaScript.Prepare(Script);
wrappedDb.ScriptEvaluate(prepared, new { key = (RedisKey)"mykey", value = 123 }); wrappedDb.ScriptEvaluate(prepared, new { key = (RedisKey)"mykey", value = 123 });
var val1 = wrappedDb.StringGet("mykey"); var val1 = wrappedDb.StringGet("mykey");
Assert.Equal(123, (int)val1); Assert.Equal(123, (int)val1);
var val2 = db.StringGet("prefix-mykey"); var val2 = db.StringGet("prefix-mykey");
Assert.Equal(123, (int)val2); Assert.Equal(123, (int)val2);
var val3 = db.StringGet("mykey"); var val3 = db.StringGet("mykey");
Assert.True(val3.IsNull); Assert.True(val3.IsNull);
} }
} }
[Fact] [Fact]
public void LoadedLuaScriptWithWrappedDatabase() public void LoadedLuaScriptWithWrappedDatabase()
{ {
const string Script = "redis.call('set', @key, @value)"; const string Script = "redis.call('set', @key, @value)";
using (var conn = Create(allowAdmin: true)) using (var conn = Create(allowAdmin: true))
{ {
Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting);
var db = conn.GetDatabase(0); var db = conn.GetDatabase(0);
var wrappedDb = KeyspaceIsolation.DatabaseExtensions.WithKeyPrefix(db, "prefix2-"); var wrappedDb = KeyspaceIsolation.DatabaseExtensions.WithKeyPrefix(db, "prefix2-");
var server = conn.GetServer(conn.GetEndPoints()[0]); var server = conn.GetServer(conn.GetEndPoints()[0]);
var prepared = LuaScript.Prepare(Script).Load(server); var prepared = LuaScript.Prepare(Script).Load(server);
wrappedDb.ScriptEvaluate(prepared, new { key = (RedisKey)"mykey", value = 123 }); wrappedDb.ScriptEvaluate(prepared, new { key = (RedisKey)"mykey", value = 123 });
var val1 = wrappedDb.StringGet("mykey"); var val1 = wrappedDb.StringGet("mykey");
Assert.Equal(123, (int)val1); Assert.Equal(123, (int)val1);
var val2 = db.StringGet("prefix2-mykey"); var val2 = db.StringGet("prefix2-mykey");
Assert.Equal(123, (int)val2); Assert.Equal(123, (int)val2);
var val3 = db.StringGet("mykey"); var val3 = db.StringGet("mykey");
Assert.True(val3.IsNull); Assert.True(val3.IsNull);
} }
} }
} }
} }
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
namespace StackExchange.Redis.Tests namespace StackExchange.Redis.Tests
{ {
[Collection(NonParallelCollection.Name)] [Collection(NonParallelCollection.Name)]
public class Secure : TestBase public class Secure : TestBase
{ {
protected override string GetConfiguration() => protected override string GetConfiguration() =>
TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort + ",password=" + TestConfig.Current.SecurePassword + ",name=MyClient"; TestConfig.Current.SecureServerAndPort + ",password=" + TestConfig.Current.SecurePassword + ",name=MyClient";
public Secure(ITestOutputHelper output) : base (output) { } public Secure(ITestOutputHelper output) : base (output) { }
[Theory] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [InlineData(false)]
public void MassiveBulkOpsFireAndForgetSecure(bool preserveOrder) public void MassiveBulkOpsFireAndForgetSecure(bool preserveOrder)
{ {
using (var muxer = Create()) using (var muxer = Create())
{ {
muxer.PreserveAsyncOrder = preserveOrder; muxer.PreserveAsyncOrder = preserveOrder;
#if DEBUG #if DEBUG
long oldAlloc = ConnectionMultiplexer.GetResultBoxAllocationCount(); long oldAlloc = ConnectionMultiplexer.GetResultBoxAllocationCount();
#endif #endif
RedisKey key = "MBOF"; RedisKey key = "MBOF";
var conn = muxer.GetDatabase(); var conn = muxer.GetDatabase();
conn.Ping(); conn.Ping();
var watch = Stopwatch.StartNew(); var watch = Stopwatch.StartNew();
for (int i = 0; i <= AsyncOpsQty; i++) for (int i = 0; i <= AsyncOpsQty; i++)
{ {
conn.StringSet(key, i, flags: CommandFlags.FireAndForget); conn.StringSet(key, i, flags: CommandFlags.FireAndForget);
} }
int val = (int)conn.StringGet(key); int val = (int)conn.StringGet(key);
Assert.Equal(AsyncOpsQty, val); Assert.Equal(AsyncOpsQty, val);
watch.Stop(); watch.Stop();
Output.WriteLine("{2}: Time for {0} ops: {1}ms ({3}); ops/s: {4}", AsyncOpsQty, watch.ElapsedMilliseconds, Me(), Output.WriteLine("{2}: Time for {0} ops: {1}ms ({3}); ops/s: {4}", AsyncOpsQty, watch.ElapsedMilliseconds, Me(),
preserveOrder ? "preserve order" : "any order", preserveOrder ? "preserve order" : "any order",
AsyncOpsQty / watch.Elapsed.TotalSeconds); AsyncOpsQty / watch.Elapsed.TotalSeconds);
#if DEBUG #if DEBUG
long newAlloc = ConnectionMultiplexer.GetResultBoxAllocationCount(); long newAlloc = ConnectionMultiplexer.GetResultBoxAllocationCount();
Output.WriteLine("ResultBox allocations: {0}", newAlloc - oldAlloc); Output.WriteLine("ResultBox allocations: {0}", newAlloc - oldAlloc);
Assert.True(newAlloc - oldAlloc <= 2, $"NewAllocs: {newAlloc}, OldAllocs: {oldAlloc}"); Assert.True(newAlloc - oldAlloc <= 2, $"NewAllocs: {newAlloc}, OldAllocs: {oldAlloc}");
#endif #endif
} }
} }
[Fact] [Fact]
public void CheckConfig() public void CheckConfig()
{ {
var config = ConfigurationOptions.Parse(GetConfiguration()); var config = ConfigurationOptions.Parse(GetConfiguration());
foreach (var ep in config.EndPoints) foreach (var ep in config.EndPoints)
{ {
Output.WriteLine(ep.ToString()); Output.WriteLine(ep.ToString());
} }
Assert.Single(config.EndPoints); Assert.Single(config.EndPoints);
Assert.Equal("changeme", config.Password); Assert.Equal("changeme", config.Password);
} }
[Fact] [Fact]
public void Connect() public void Connect()
{ {
using (var server = Create()) using (var server = Create())
{ {
server.GetDatabase().Ping(); server.GetDatabase().Ping();
} }
} }
[Theory] [Theory]
[InlineData("wrong")] [InlineData("wrong")]
[InlineData("")] [InlineData("")]
public async Task ConnectWithWrongPassword(string password) public async Task ConnectWithWrongPassword(string password)
{ {
var config = ConfigurationOptions.Parse(GetConfiguration()); var config = ConfigurationOptions.Parse(GetConfiguration());
config.Password = password; config.Password = password;
config.ConnectRetry = 0; // we don't want to retry on closed sockets in this case. config.ConnectRetry = 0; // we don't want to retry on closed sockets in this case.
var ex = await Assert.ThrowsAsync<RedisConnectionException>(async () => var ex = await Assert.ThrowsAsync<RedisConnectionException>(async () =>
{ {
SetExpectedAmbientFailureCount(-1); SetExpectedAmbientFailureCount(-1);
using (var conn = await ConnectionMultiplexer.ConnectAsync(config, Writer).ConfigureAwait(false)) using (var conn = await ConnectionMultiplexer.ConnectAsync(config, Writer).ConfigureAwait(false))
{ {
conn.GetDatabase().Ping(); conn.GetDatabase().Ping();
} }
}).ConfigureAwait(false); }).ConfigureAwait(false);
Output.WriteLine("Exception: " + ex.Message); Output.WriteLine("Exception: " + ex.Message);
Assert.Equal("It was not possible to connect to the redis server(s); to create a disconnected multiplexer, disable AbortOnConnectFail. AuthenticationFailure on PING", ex.Message); Assert.Equal("It was not possible to connect to the redis server(s); to create a disconnected multiplexer, disable AbortOnConnectFail. AuthenticationFailure on PING", ex.Message);
} }
} }
} }
...@@ -18,7 +18,7 @@ public abstract class TestBase : IDisposable ...@@ -18,7 +18,7 @@ public abstract class TestBase : IDisposable
{ {
protected ITestOutputHelper Output { get; } protected ITestOutputHelper Output { get; }
protected TextWriterOutputHelper Writer { get; } protected TextWriterOutputHelper Writer { get; }
protected virtual string GetConfiguration() => TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort + "," + TestConfig.Current.SlaveServer + ":" + TestConfig.Current.SlavePort; protected virtual string GetConfiguration() => TestConfig.Current.MasterServerAndPort + "," + TestConfig.Current.SlaveServerAndPort;
protected TestBase(ITestOutputHelper output) protected TestBase(ITestOutputHelper output)
{ {
...@@ -331,4 +331,4 @@ protected static TimeSpan RunConcurrent(Action work, int threads, int timeout = ...@@ -331,4 +331,4 @@ protected static TimeSpan RunConcurrent(Action work, int threads, int timeout =
return watch.Elapsed; return watch.Elapsed;
} }
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment