Commit 72b1cbab authored by Nick Craver's avatar Nick Craver

Tests: add logging for DeslaveGoesToPrimary

...and normalizing line endings because git sucks.
parent d5027640
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
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 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.MasterServer + ":" + TestConfig.Current.SecurePort + "," + TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort + ",password=" + TestConfig.Current.SecurePassword;
public MultiMaster(ITestOutputHelper output) : base (output) { } public MultiMaster(ITestOutputHelper output) : base (output) { }
[Fact] [Fact]
public void CannotFlushSlave() public void CannotFlushSlave()
{ {
var ex = Assert.Throws<RedisCommandException>(() => var ex = Assert.Throws<RedisCommandException>(() =>
{ {
ConfigurationOptions config = GetMasterSlaveConfig(); ConfigurationOptions config = GetMasterSlaveConfig();
using (var conn = ConnectionMultiplexer.Connect(config)) using (var conn = ConnectionMultiplexer.Connect(config))
{ {
var servers = conn.GetEndPoints().Select(e => conn.GetServer(e)); var servers = conn.GetEndPoints().Select(e => conn.GetServer(e));
var slave = servers.FirstOrDefault(x => x.IsSlave); var slave = servers.FirstOrDefault(x => x.IsSlave);
Assert.NotNull(slave); // Slave not found, ruh roh Assert.NotNull(slave); // Slave not found, ruh roh
slave.FlushDatabase(); slave.FlushDatabase();
} }
}); });
Assert.Equal("Command cannot be issued to a slave: FLUSHDB", ex.Message); Assert.Equal("Command cannot be issued to a slave: FLUSHDB", ex.Message);
} }
[Fact] [Fact]
public async Task DeslaveGoesToPrimary() 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(new IPEndPoint(IPAddress.Parse(TestConfig.Current.MasterServer), TestConfig.Current.MasterPort)); var primary = conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort);
var secondary = conn.GetServer(new IPEndPoint(IPAddress.Parse(TestConfig.Current.SlaveServer), TestConfig.Current.SlavePort)); var secondary = conn.GetServer(TestConfig.Current.SlaveServer, TestConfig.Current.SlavePort);
primary.Ping(); primary.Ping();
secondary.Ping(); secondary.Ping();
primary.MakeMaster(ReplicationChangeOptions.SetTiebreaker); primary.MakeMaster(ReplicationChangeOptions.SetTiebreaker);
secondary.MakeMaster(ReplicationChangeOptions.None); secondary.MakeMaster(ReplicationChangeOptions.None);
await Task.Delay(2000).ConfigureAwait(false); await Task.Delay(2000).ConfigureAwait(false);
primary.Ping(); primary.Ping();
secondary.Ping(); secondary.Ping();
using (var writer = new StringWriter()) using (var writer = new StringWriter())
{ {
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.MasterServer + ":" + TestConfig.Current.MasterPort), "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?
var db = conn.GetDatabase(); var db = conn.GetDatabase();
RedisKey key = Me(); RedisKey key = Me();
Assert.Equal(primary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.PreferMaster)); Assert.Equal(primary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.PreferMaster));
Assert.Equal(primary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.DemandMaster)); Assert.Equal(primary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.DemandMaster));
Assert.Equal(primary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.PreferSlave)); Assert.Equal(primary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.PreferSlave));
var ex = Assert.Throws<RedisConnectionException>(() => db.IdentifyEndpoint(key, CommandFlags.DemandSlave)); var ex = Assert.Throws<RedisConnectionException>(() => db.IdentifyEndpoint(key, CommandFlags.DemandSlave));
Assert.StartsWith("No connection is available to service this operation: EXISTS DeslaveGoesToPrimary", ex.Message); Assert.StartsWith("No connection is available to service this operation: EXISTS DeslaveGoesToPrimary", ex.Message);
primary.MakeMaster(ReplicationChangeOptions.Broadcast | ReplicationChangeOptions.EnslaveSubordinates | ReplicationChangeOptions.SetTiebreaker, Writer); primary.MakeMaster(ReplicationChangeOptions.Broadcast | ReplicationChangeOptions.EnslaveSubordinates | ReplicationChangeOptions.SetTiebreaker, Writer);
await Task.Delay(5000).ConfigureAwait(false); await Task.Delay(2000).ConfigureAwait(false);
primary.Ping(); primary.Ping();
secondary.Ping(); secondary.Ping();
Assert.True(primary.IsConnected, $"{primary.EndPoint} is not connected."); Assert.True(primary.IsConnected, $"{primary.EndPoint} is not connected.");
Assert.True(secondary.IsConnected, $"{secondary.EndPoint} is not connected."); Assert.True(secondary.IsConnected, $"{secondary.EndPoint} is not connected.");
Writer.WriteLine($"{primary.EndPoint}: {primary.ServerType}"); Writer.WriteLine($"{primary.EndPoint}: {primary.ServerType}, Mode: {(primary.IsSlave ? "Slave" : "Master")}");
Writer.WriteLine($"{secondary.EndPoint}: {secondary.ServerType}"); Writer.WriteLine($"{secondary.EndPoint}: {secondary.ServerType}, Mode: {(secondary.IsSlave ? "Slave" : "Master")}");
// Create a separate multiplexer with a valid view of the world to distinguish between failures of // Create a separate multiplexer with a valid view of the world to distinguish between failures of
// 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(new IPEndPoint(IPAddress.Parse(TestConfig.Current.MasterServer), TestConfig.Current.MasterPort)); var primary2 = conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort);
var secondary2 = conn.GetServer(new IPEndPoint(IPAddress.Parse(TestConfig.Current.SlaveServer), TestConfig.Current.SlavePort)); var secondary2 = conn.GetServer(TestConfig.Current.SlaveServer, TestConfig.Current.SlavePort);
Assert.False(primary2.IsSlave, $"{primary2.EndPoint} should be a master (verification connection)."); Writer.WriteLine($"Check: {primary2.EndPoint}: {primary2.ServerType}, Mode: {(primary2.IsSlave ? "Slave" : "Master")}");
Assert.True(secondary2.IsSlave, $"{secondary2.EndPoint} should be a slave (verification connection)."); Writer.WriteLine($"Check: {secondary2.EndPoint}: {secondary2.ServerType}, Mode: {(secondary2.IsSlave ? "Slave" : "Master")}");
var db2 = conn.GetDatabase(); Assert.False(primary2.IsSlave, $"{primary2.EndPoint} should be a master (verification connection).");
Assert.True(secondary2.IsSlave, $"{secondary2.EndPoint} should be a slave (verification connection).");
Assert.Equal(primary2.EndPoint, db2.IdentifyEndpoint(key, CommandFlags.PreferMaster));
Assert.Equal(primary2.EndPoint, db2.IdentifyEndpoint(key, CommandFlags.DemandMaster)); var db2 = conn.GetDatabase();
Assert.Equal(secondary2.EndPoint, db2.IdentifyEndpoint(key, CommandFlags.PreferSlave));
Assert.Equal(secondary2.EndPoint, db2.IdentifyEndpoint(key, CommandFlags.DemandSlave)); Assert.Equal(primary2.EndPoint, db2.IdentifyEndpoint(key, CommandFlags.PreferMaster));
} Assert.Equal(primary2.EndPoint, db2.IdentifyEndpoint(key, CommandFlags.DemandMaster));
Assert.Equal(secondary2.EndPoint, db2.IdentifyEndpoint(key, CommandFlags.PreferSlave));
Assert.False(primary.IsSlave, $"{primary.EndPoint} should be a master."); Assert.Equal(secondary2.EndPoint, db2.IdentifyEndpoint(key, CommandFlags.DemandSlave));
Assert.True(secondary.IsSlave, $"{secondary.EndPoint} should be a slave."); }
Assert.Equal(primary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.PreferMaster)); Assert.False(primary.IsSlave, $"{primary.EndPoint} should be a master.");
Assert.Equal(primary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.DemandMaster)); Assert.True(secondary.IsSlave, $"{secondary.EndPoint} should be a slave.");
Assert.Equal(secondary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.PreferSlave));
Assert.Equal(secondary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.DemandSlave)); Assert.Equal(primary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.PreferMaster));
} Assert.Equal(primary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.DemandMaster));
} Assert.Equal(secondary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.PreferSlave));
Assert.Equal(secondary.EndPoint, db.IdentifyEndpoint(key, CommandFlags.DemandSlave));
private static ConfigurationOptions GetMasterSlaveConfig() }
{ }
return new ConfigurationOptions
{ private static ConfigurationOptions GetMasterSlaveConfig()
AllowAdmin = true, {
SyncTimeout = 100000, return new ConfigurationOptions
EndPoints = {
{ AllowAdmin = true,
{ TestConfig.Current.MasterServer, TestConfig.Current.MasterPort }, SyncTimeout = 100000,
{ TestConfig.Current.SlaveServer, TestConfig.Current.SlavePort }, EndPoints =
} {
}; { TestConfig.Current.MasterServer, TestConfig.Current.MasterPort },
} { TestConfig.Current.SlaveServer, TestConfig.Current.SlavePort },
}
[Fact] };
public void TestMultiNoTieBreak() }
{
using (var log = new StringWriter()) [Fact]
using (var conn = Create(log: log, tieBreaker: "")) public void TestMultiNoTieBreak()
{ {
Output.WriteLine(log.ToString()); using (var log = new StringWriter())
Assert.Contains("Choosing master arbitrarily", log.ToString()); using (var conn = Create(log: log, tieBreaker: ""))
} {
} Output.WriteLine(log.ToString());
Assert.Contains("Choosing master arbitrarily", log.ToString());
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.MasterServer + ":" + TestConfig.Current.SecurePort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort }; public static IEnumerable<object[]> GetConnections()
yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, null }; {
yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, null }; 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.MasterServer + ":" + TestConfig.Current.SecurePort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort };
yield return new object[] { null, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort }; yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, null };
yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, null, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort }; yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, null };
yield return new object[] { null, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort };
yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, null, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort }; yield return new object[] { null, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort };
yield return new object[] { null, null, null }; yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort, null, TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort };
} yield return new object[] { null, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort };
yield return new object[] { TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort, null, TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort };
[Theory, MemberData(nameof(GetConnections))] yield return new object[] { null, null, null };
public void TestMultiWithTiebreak(string a, string b, string elected) }
{
const string TieBreak = "__tie__"; [Theory, MemberData(nameof(GetConnections))]
// set the tie-breakers to the expected state public void TestMultiWithTiebreak(string a, string b, string elected)
using (var aConn = ConnectionMultiplexer.Connect(TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort)) {
{ const string TieBreak = "__tie__";
aConn.GetDatabase().StringSet(TieBreak, a); // 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.MasterServer + ":" + TestConfig.Current.SecurePort + ",password=" + TestConfig.Current.SecurePassword)) {
{ aConn.GetDatabase().StringSet(TieBreak, a);
aConn.GetDatabase().StringSet(TieBreak, b); }
} using (var aConn = ConnectionMultiplexer.Connect(TestConfig.Current.MasterServer + ":" + TestConfig.Current.SecurePort + ",password=" + TestConfig.Current.SecurePassword))
{
// see what happens aConn.GetDatabase().StringSet(TieBreak, b);
using (var log = new StringWriter()) }
using (var conn = Create(log: log, tieBreaker: TieBreak))
{ // see what happens
string text = log.ToString(); using (var log = new StringWriter())
Output.WriteLine(text); using (var conn = Create(log: log, tieBreaker: TieBreak))
Assert.False(text.Contains("failed to nominate"), "failed to nominate"); {
if (elected != null) string text = log.ToString();
{ Output.WriteLine(text);
Assert.True(text.Contains("Elected: " + elected), "elected"); Assert.False(text.Contains("failed to nominate"), "failed to nominate");
} if (elected != null)
int nullCount = (a == null ? 1 : 0) + (b == null ? 1 : 0); {
if ((a == b && nullCount == 0) || nullCount == 1) Assert.True(text.Contains("Elected: " + elected), "elected");
{ }
Assert.True(text.Contains("tie-break is unanimous"), "unanimous"); int nullCount = (a == null ? 1 : 0) + (b == null ? 1 : 0);
Assert.False(text.Contains("Choosing master arbitrarily"), "arbitrarily"); if ((a == b && nullCount == 0) || nullCount == 1)
} {
else Assert.True(text.Contains("tie-break is unanimous"), "unanimous");
{ Assert.False(text.Contains("Choosing master arbitrarily"), "arbitrarily");
Assert.False(text.Contains("tie-break is unanimous"), "unanimous"); }
Assert.True(text.Contains("Choosing master arbitrarily"), "arbitrarily"); else
} {
} Assert.False(text.Contains("tie-break is unanimous"), "unanimous");
} Assert.True(text.Contains("Choosing master arbitrarily"), "arbitrarily");
} }
} }
\ 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