Commit 48a0a99d authored by Nick Craver's avatar Nick Craver Committed by GitHub

Unit Test Fixes and Upgrades (#700)

Before converting most of the project to C# 7, `netstandard2.0`, etc. I want to get unit tests in shape. There's a fair bit of complication to doing so in that we need to test against:
- Different versions
- Clusters
- Master/Slave setups
- Multiple-test unfriendly tests (like SHUTDOWN commands)
- Simulate remote (read: latent) connections

This work does a few things:
- Moves all unit tests and assertions to xUnit
- Enables parallelization for tests
- Utilizes the xUnit output semantics, which means things like connection logs are on the test in VS, console output, build servers, etc. (it was a giant pool of `Console.WriteLine` mixed before)
- Cleans up the `\packages` folder completely (it wasn't used for anything but the `redis-*.exe` binaries
- Cleans up all test code formatting in general
- Re-enables `net462` in testing (was only `netcoreapp1.0` before)
- Allows overrides via `TestConfig.json`
- Updates all the RedisConfig\ scripts for easy test running
- Adds a StackExchange.Redis.Tests\README.md
- Fixes many tests

Remaining Long-term TODOs
- Look at Redis 4.0 on Windows via WSL
- Configure endpoints in a `.json` config override that's in `.gitignore`
- Find a way to handle master/slave breaks on underpowered machines better
parent 2578b224
......@@ -15,9 +15,10 @@ Mono/
*.aof
*.orig
redis-cli.exe
Redis Configs/*.dat
RedisConfigs/*.dat
RedisQFork*.dat
StackExchange.Redis.*.zip
.vs/
*.lock.json
packages/
\ No newline at end of file
packages/
StackExchange.Redis.Tests/*Config.json
syntax: glob
*/bin/
.git
*/obj/
Tests/bin/
Tests/obj/
*.suo
Async/bin/
Async/obj/
*.user
*.nupkg
packages/NuGet.CommandLine.*
*.sln.docstates
_ReSharper.*
Mono/
*.sln.ide
*.rdb
*.orig
redis-cli.exe
Redis Configs/*.dat
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NuGet.CommandLine" version="2.8.5" />
<package id="Redis-64" version="2.8.19" />
</packages>
\ No newline at end of file
......@@ -2,8 +2,7 @@
<PropertyGroup>
<Description>StackExchange.Redis.BasicTest .NET Core</Description>
<TargetFramework>netcoreapp1.1</TargetFramework>
<TargetFrameworks>$(TargetFramework)</TargetFrameworks>
<TargetFrameworks>netcoreapp1.1</TargetFrameworks>
<AssemblyName>BasicTest</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>BasicTest</PackageId>
......
......@@ -22,23 +22,8 @@
<DefaultLanguage>en-US</DefaultLanguage>
<IncludeSymbols>false</IncludeSymbols>
<LibraryTargetFrameworks>net45;net46;netstandard1.5</LibraryTargetFrameworks><!--net40;-->
<LibraryTargetFrameworks>net45;net46;netstandard1.5</LibraryTargetFrameworks>
<CoreFxVersion>4.3.0</CoreFxVersion>
<xUnitVersion>2.3.0-beta5-build3750</xUnitVersion>
</PropertyGroup>
<!-- Workarounds for https://github.com/NuGet/Home/issues/4853 -->
<PropertyGroup Condition="'$(TargetFramework)' == 'net40' OR '$(TargetFramework)' == 'net45' OR '$(TargetFramework)' == 'net46'">
<DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
<AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net40' OR '$(TargetFramework)' == 'net45' OR '$(TargetFramework)' == 'net46'">
<Reference Include="System.Core" Pack="false" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SourceLink.Create.GitHub" Version="2.0.2" PrivateAssets="All" />
<PackageReference Include="NuGet.Build.Tasks.Pack" Version="4.3.0-preview1-4045" PrivateAssets="All" />
<DotNetCliToolReference Include="dotnet-sourcelink" Version="2.0.2" />
<DotNetCliToolReference Include="dotnet-sourcelink-git" Version="2.0.2" />
</ItemGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>MigratedBookSleeveTestSuite</Description>
<TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
<AssemblyName>MigratedBookSleeveTestSuite</AssemblyName>
<PackageId>MigratedBookSleeveTestSuite</PackageId>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);portable-net45+win8</PackageTargetFallback>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
</PropertyGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StackExchange.Redis\StackExchange.Redis.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0-preview-20170106-08" />
<PackageReference Include="nunit" Version="3.4.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">
<DefineConstants>$(DefineConstants);PLAT_SAFE_CONTINUATIONS;CORE_CLR</DefineConstants>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">
<PackageReference Include="System.Console" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Diagnostics.Debug" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Diagnostics.TraceSource" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Linq.Expressions" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Reflection.Extensions" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Runtime.InteropServices" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Threading.Tasks.Parallel" Version="$(CoreFxVersion)" />
<PackageReference Include="Microsoft.CSharp" Version="$(CoreFxVersion)" />
<PackageReference Include="dotnet-test-nunit" Version="3.4.0-beta-1" />
</ItemGroup>
</Project>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using NUnit.Framework;
namespace Tests
{
class Program
{
// static void Main()
// {
// try
// {
// Main2();
// }
// catch (Exception ex)
// {
// Console.WriteLine();
// Console.WriteLine("CRAZY ERRORS: " + ex);
// }
// finally
// {
// Console.WriteLine("Press any key to exit");
// Console.ReadKey();
// }
// }
static void Main2()
{
#if !CORE_CLR
// why is this here? because some dumbass forgot to install a decent test-runner before going to the airport
var epicFail = new List<string>();
var testTypes = from type in typeof(Program).Assembly.GetTypes()
where Attribute.IsDefined(type, typeof(TestFixtureAttribute))
&& !Attribute.IsDefined(type, typeof(IgnoreAttribute))
let methods = type.GetMethods()
select new
{
Type = type,
Methods = methods,
ActiveMethods = methods.Where(x => Attribute.IsDefined(x, typeof(ActiveTestAttribute))).ToArray(),
Setup = methods.SingleOrDefault(x => Attribute.IsDefined(x, typeof(OneTimeSetUpAttribute))),
TearDown = methods.SingleOrDefault(x => Attribute.IsDefined(x, typeof(OneTimeTearDownAttribute)))
};
int pass = 0, fail = 0;
bool activeOnly = testTypes.SelectMany(x => x.ActiveMethods).Any();
TaskScheduler.UnobservedTaskException += (sender, args) =>
{
args.SetObserved();
//if (args.Exception is AggregateException)
//{
// foreach (var ex in ((AggregateException)args.Exception).InnerExceptions)
// {
// Console.WriteLine(ex.Message);
// }
//}
//else
//{
// Console.WriteLine(args.Exception.Message);
//}
};
foreach (var type in testTypes)
{
var tests = (from method in (activeOnly ? type.ActiveMethods : type.Methods)
where Attribute.IsDefined(method, typeof(TestAttribute))
&& !Attribute.IsDefined(method, typeof(IgnoreAttribute))
select method).ToArray();
if (tests.Length == 0) continue;
Console.WriteLine(type.Type.FullName);
object obj;
try
{
obj = Activator.CreateInstance(type.Type);
if (obj == null) throw new InvalidOperationException("the world has gone mad");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
continue;
}
using (obj as IDisposable)
{
if (type.Setup != null)
{
try
{ type.Setup.Invoke(obj, null); }
catch (Exception ex)
{
Console.WriteLine("Test fixture startup failed: " + ex.Message);
fail++;
epicFail.Add(type.Setup.DeclaringType.FullName + "." + type.Setup.Name);
continue;
}
}
foreach (var test in tests)
{
Console.Write(test.Name + ": ");
Exception err = null;
try
{
int count = 1;
if (activeOnly)
{
var ata = test.GetCustomAttribute(typeof(ActiveTestAttribute)) as ActiveTestAttribute;
if (ata != null) count = ata.Count;
}
while (count-- > 0)
{
test.Invoke(obj, null);
}
}
catch (TargetInvocationException ex)
{
err = ex.InnerException;
}
catch (Exception ex)
{
err = ex;
}
if (err is AggregateException && ((AggregateException)err).InnerExceptions.Count == 1)
{
err = ((AggregateException)err).InnerExceptions[0];
}
if (err == null)
{
Console.WriteLine("pass");
pass++;
}
else
{
Console.WriteLine(err.Message);
fail++;
epicFail.Add(test.DeclaringType.FullName + "." + test.Name);
}
}
if (type.TearDown != null)
{
try
{ type.TearDown.Invoke(obj, null); }
catch (Exception ex)
{
Console.WriteLine("Test fixture teardown failed: " + ex.Message);
fail++;
epicFail.Add(type.TearDown.DeclaringType.FullName + "." + type.TearDown.Name);
}
}
}
}
Console.WriteLine("Passed: {0}; Failed: {1}", pass, fail);
foreach (var msg in epicFail) Console.WriteLine(msg);
//#if DEBUG
// Console.WriteLine();
// Console.WriteLine("Callbacks: {0:###,###,##0} sync, {1:###,###,##0} async",
// BookSleeve.RedisConnectionBase.AllSyncCallbacks, BookSleeve.RedisConnectionBase.AllAsyncCallbacks);
//#endif
#endif
}
}
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class ActiveTestAttribute : Attribute
{
public int Count { get; }
public ActiveTestAttribute() : this(1) { }
public ActiveTestAttribute(int count) { this.Count = count; }
}
\ No newline at end of file
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("MigratedBookSleeveTestSuite")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MigratedBookSleeveTestSuite")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("350d3b30-78dd-4b74-a76d-bb593a05e8d1")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
using System;
using Xunit;
using StackExchange.Redis;
using NRediSearch;
using System.Collections.Generic;
using System.Linq;
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
<ProjectReference Include="..\NRediSearch\NRediSearch.csproj" />
<ProjectReference Include="..\StackExchange.Redis\StackExchange.Redis.csproj" />
<ProjectReference Include="..\NRediSearch\NRediSearch.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="xunit" Version="$(xUnitVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(xUnitVersion)" />
<DotNetCliToolReference Include="dotnet-xunit" Version="$(xUnitVersion)" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
</Project>
</Project>
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(LibraryTargetFrameworks)</TargetFrameworks>
<VersionPrefix>0.1</VersionPrefix>
......
......@@ -2,6 +2,7 @@
<configuration>
<packageSources>
<clear/>
<add key="xUnit" value="https://www.myget.org/F/xunit/api/v3/index.json" />
<add key="NuGet" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
\ No newline at end of file
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
\ No newline at end of file
@..\packages\Redis-64.3.0.503\redis-cli.exe -h 127.0.0.1 -p 7000
@..\packages\Redis-64.3.0.503\redis-cli.exe -h 127.0.0.1 -p 7001
@..\packages\Redis-64.3.0.503\redis-cli.exe -h 127.0.0.1 -p 7002
@..\packages\Redis-64.3.0.503\redis-cli.exe -h 127.0.0.1 -p 7003
@..\packages\Redis-64.3.0.503\redis-cli.exe -h 127.0.0.1 -p 7004
@..\packages\Redis-64.3.0.503\redis-cli.exe -h 127.0.0.1 -p 7005
@..\packages\Redis-64.3.0.503\redis-cli.exe -p 6379
@..\packages\Redis-64.3.0.503\redis-cli.exe -p 6381
@..\packages\Redis-64.3.0.503\redis-cli.exe -p 6380
@start ..\packages\Redis-64.3.0.503\redis-server.exe master.conf
@start ..\packages\Redis-64.3.0.503\redis-server.exe slave.conf
@start ..\packages\Redis-64.3.0.503\redis-server.exe secure.conf
@echo off
pushd Cluster\7000
@start /min ..\..\..\packages\Redis-64.3.0.503\redis-server.exe redis.conf --port 7000
popd
pushd Cluster\7001
@start /min ..\..\..\packages\Redis-64.3.0.503\redis-server.exe redis.conf --port 7001
popd
pushd Cluster\7002
@start /min ..\..\..\packages\Redis-64.3.0.503\redis-server.exe redis.conf --port 7002
popd
pushd Cluster\7003
@start /min ..\..\..\packages\Redis-64.3.0.503\redis-server.exe redis.conf --port 7003
popd
pushd Cluster\7004
@start /min ..\..\..\packages\Redis-64.3.0.503\redis-server.exe redis.conf --port 7004
popd
pushd Cluster\7005
@start /min ..\..\..\packages\Redis-64.3.0.503\redis-server.exe redis.conf --port 7005
popd
\ No newline at end of file
@..\packages\Redis-64.3.0.503\redis-server.exe master.conf
@..\packages\Redis-64.3.0.503\redis-server.exe secure.conf
@..\packages\Redis-64.3.0.503\redis-server.exe slave.conf
This diff is collapsed.
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
......
port 7001
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
......
port 7002
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
......
port 7003
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
......
port 7004
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
\ No newline at end of file
port 7005
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
\ No newline at end of file
@%~dp0\3.0.503\redis-cli.exe -h 127.0.0.1 -p 7000
@%~dp0\3.0.503\redis-cli.exe -h 127.0.0.1 -p 7001
@%~dp0\3.0.503\redis-cli.exe -h 127.0.0.1 -p 7002
@%~dp0\3.0.503\redis-cli.exe -h 127.0.0.1 -p 7003
@%~dp0\3.0.503\redis-cli.exe -h 127.0.0.1 -p 7004
@%~dp0\3.0.503\redis-cli.exe -h 127.0.0.1 -p 7005
@%~dp0\3.0.503\redis-cli.exe -p 6379
@%~dp0\3.0.503\redis-cli.exe -p 6381
@%~dp0\3.0.503\redis-cli.exe -p 6380
......@@ -2,4 +2,5 @@ port 6379
dbfilename master.rdb
databases 2000
maxmemory 6gb
appendonly no
save ""
\ No newline at end of file
......@@ -3,4 +3,5 @@ slaveof 127.0.0.1 6379
dbfilename slave.rdb
databases 2000
maxmemory 2gb
appendonly no
save ""
\ No newline at end of file
@echo off
echo Starting Cluster: 7000-7005
pushd %~dp0\Cluster\7000
@start "Redis (Cluster): 7000" /min ..\..\3.0.503\redis-server.exe redis.conf
popd
pushd %~dp0\Cluster\7001
@start "Redis (Cluster): 7001" /min ..\..\3.0.503\redis-server.exe redis.conf
popd
pushd %~dp0\Cluster\7002
@start "Redis (Cluster): 7002" /min ..\..\3.0.503\redis-server.exe redis.conf
popd
pushd %~dp0\Cluster\7003
@start "Redis (Cluster): 7003" /min ..\..\3.0.503\redis-server.exe redis.conf
popd
pushd %~dp0\Cluster\7004
@start "Redis (Cluster): 7004" /min ..\..\3.0.503\redis-server.exe redis.conf
popd
pushd %~dp0\Cluster\7005
@start "Redis (Cluster): 7005" /min ..\..\3.0.503\redis-server.exe redis.conf
popd
\ No newline at end of file
@echo off
echo Starting Redis servers on 6379, 6780, 6381, and 7000-7005
@start "Redis (Master): 6379" /min %~dp0\3.0.503\redis-server.exe %~dp0\master.conf
@start "Redis (Slave): 6380" /min %~dp0\3.0.503\redis-server.exe %~dp0\slave.conf
@start "Redis (Secure): 6381" /min %~dp0\3.0.503\redis-server.exe %~dp0\secure.conf
call %~dp0\start-cluster.cmd
echo Servers started (minimized).
@%~dp0\3.0.503\redis-server.exe %~dp0\master.conf
@%~dp0\3.0.503\redis-server.exe %~dp0\secure.conf
@%~dp0\3.0.503\redis-server.exe %~dp0\slave.conf
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(LibraryTargetFrameworks)</TargetFrameworks>
<Description>High performance Redis client, incorporating both synchronous and asynchronous usage.</Description>
......@@ -13,30 +12,16 @@
</PropertyGroup>
<ItemGroup>
<Compile Remove="..\StackExchange.Redis\obj\**\*;..\StackExchange.Redis\Properties\AssemblyInfo.cs" />
<Compile Include="..\StackExchange.Redis\**\*.cs" Exclude="..\StackExchange.Redis\obj\**\*;bin\**;obj\**;**\*.xproj;packages\**;..\StackExchange.Redis\Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net40' ">
<PackageReference Include="Microsoft.Bcl" Version="1.1.10" />
<PackageReference Include="Microsoft.Bcl.Async" Version="1.0.168" />
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
<Compile Include="..\StackExchange.Redis\**\*.cs" Exclude="..\StackExchange.Redis\obj\**\*" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' OR '$(TargetFramework)' == 'net46' ">
<Reference Include="System.IO.Compression" />
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net46' ">
<Reference Include="System.IO.Compression" />
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net40' or '$(TargetFramework)' == 'net45' or '$(TargetFramework)' == 'net46'">
<PropertyGroup Condition=" '$(TargetFramework)' == 'net45' or '$(TargetFramework)' == 'net46'">
<DefineConstants>$(DefineConstants);FEATURE_SERIALIZATION;FEATURE_SOCKET_MODE_POLL</DefineConstants>
</PropertyGroup>
......@@ -45,28 +30,13 @@
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.5' ">
<PackageReference Include="System.Collections" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Collections.Concurrent" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Collections.NonGeneric" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Diagnostics.Tools" Version="$(CoreFxVersion)" />
<PackageReference Include="System.IO.Compression" Version="$(CoreFxVersion)" />
<PackageReference Include="System.IO.FileSystem" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Linq" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Net.NameResolution" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Net.Security" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Net.Sockets" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Reflection.Emit" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Reflection.TypeExtensions" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Runtime.Extensions" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Security.Cryptography.Algorithms" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Security.Cryptography.X509Certificates" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Text.RegularExpressions" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Threading" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Threading.Thread" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Threading.ThreadPool" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Threading.Timer" Version="$(CoreFxVersion)" />
</ItemGroup>
</Project>
</Project>
\ No newline at end of file
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Xunit.Abstractions;
namespace StackExchange.Redis.Tests
{
[TestFixture]
public class AdhocTests : TestBase
{
[Test]
public AdhocTests(ITestOutputHelper output) : base (output) { }
[Fact]
public void TestAdhocCommandsAPI()
{
using (var conn = Create())
......@@ -25,10 +24,9 @@ public void TestAdhocCommandsAPI()
db.Execute("del", key);
db.Execute("set", key, "12");
db.Execute("incrby", key, 4);
int i = (int) db.Execute("get", key);
Assert.AreEqual(16, i);
int i = (int)db.Execute("get", key);
Assert.Equal(16, i);
}
}
}
......
using System.Linq;
using NUnit.Framework;
using Xunit;
using Xunit.Abstractions;
namespace StackExchange.Redis.Tests
{
[TestFixture]
public class AsyncTests : TestBase
{
protected override string GetConfiguration()
{
return PrimaryServer + ":" + PrimaryPortString;
}
public AsyncTests(ITestOutputHelper output) : base (output) { }
protected override string GetConfiguration() => TestConfig.Current.MasterServer + ":" + TestConfig.Current.MasterPort;
#if DEBUG // IRedisServerDebug and AllowConnect are only available if DEBUG is defined
[Test]
[Fact]
public void AsyncTasksReportFailureIfServerUnavailable()
{
SetExpectedAmbientFailureCount(-1); // this will get messy
using(var conn = Create(allowAdmin: true))
using (var conn = Create(allowAdmin: true))
{
var server = conn.GetServer(PrimaryServer, PrimaryPort);
var server = conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort);
RedisKey key = Me();
var db = conn.GetDatabase();
......@@ -27,17 +26,17 @@ public void AsyncTasksReportFailureIfServerUnavailable()
var a = db.SetAddAsync(key, "a");
var b = db.SetAddAsync(key, "b");
Assert.AreEqual(true, conn.Wait(a));
Assert.AreEqual(true, conn.Wait(b));
Assert.True(conn.Wait(a));
Assert.True(conn.Wait(b));
conn.AllowConnect = false;
server.SimulateConnectionFailure();
var c = db.SetAddAsync(key, "c");
Assert.IsTrue(c.IsFaulted, "faulted");
Assert.True(c.IsFaulted, "faulted");
var ex = c.Exception.InnerExceptions.Single();
Assert.IsInstanceOf<RedisConnectionException>(ex);
Assert.AreEqual("No connection is available to service this operation: SADD AsyncTasksReportFailureIfServerUnavailable", ex.Message);
Assert.IsType<RedisConnectionException>(ex);
Assert.StartsWith("No connection is available to service this operation: SADD AsyncTasksReportFailureIfServerUnavailable", ex.Message);
}
}
#endif
......
This diff is collapsed.
#if FEATURE_MOQ
using Moq;
using NUnit.Framework;
using StackExchange.Redis.KeyspaceIsolation;
using System.Text;
using Xunit;
namespace StackExchange.Redis.Tests
{
[TestFixture]
public sealed class BatchWrapperTests
{
private Mock<IBatch> mock;
private BatchWrapper wrapper;
private readonly Mock<IBatch> mock;
private readonly BatchWrapper wrapper;
//[TestFixtureSetUp]
[OneTimeSetUpAttribute]
public void Initialize()
public BatchWrapperTests()
{
mock = new Mock<IBatch>();
wrapper = new BatchWrapper(mock.Object, Encoding.UTF8.GetBytes("prefix:"));
}
[Test]
[Fact]
public void Execute()
{
wrapper.Execute();
......
using NUnit.Framework;
using Xunit;
using Xunit.Abstractions;
namespace StackExchange.Redis.Tests
{
[TestFixture]
public class Bits : TestBase
{
[Test]
public Bits(ITestOutputHelper output) : base (output) { }
[Fact]
public void BasicOps()
{
using (var conn = Create())
......
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NUnit.Framework;
using Xunit;
using Xunit.Abstractions;
namespace Tests
namespace StackExchange.Redis.Tests.Booksleeve
{
[TestFixture]
public class Batches
public class Batches : BookSleeveTestBase
{
[Test]
public Batches(ITestOutputHelper output) : base(output) { }
[Fact]
public void TestBatchNotSent()
{
using (var muxer = Config.GetUnsecuredConnection())
using (var muxer = GetUnsecuredConnection())
{
var conn = muxer.GetDatabase(0);
conn.KeyDeleteAsync("batch");
conn.StringSetAsync("batch", "batch-not-sent");
var tasks = new List<Task>();
var batch = conn.CreateBatch();
tasks.Add(batch.KeyDeleteAsync("batch"));
tasks.Add(batch.SetAddAsync("batch", "a"));
tasks.Add(batch.SetAddAsync("batch", "b"));
tasks.Add(batch.SetAddAsync("batch", "c"));
Assert.AreEqual("batch-not-sent", (string)conn.StringGet("batch"));
Assert.Equal("batch-not-sent", conn.StringGet("batch"));
}
}
[Test]
[Fact]
public void TestBatchSent()
{
using (var muxer = Config.GetUnsecuredConnection())
using (var muxer = GetUnsecuredConnection())
{
var conn = muxer.GetDatabase(0);
conn.KeyDeleteAsync("batch");
......@@ -43,17 +45,17 @@ public void TestBatchSent()
tasks.Add(batch.SetAddAsync("batch", "b"));
tasks.Add(batch.SetAddAsync("batch", "c"));
batch.Execute();
var result = conn.SetMembersAsync("batch");
tasks.Add(result);
Task.WhenAll(tasks.ToArray());
var arr = result.Result;
Array.Sort(arr, (x, y) => string.Compare(x, y));
Assert.AreEqual(3, arr.Length);
Assert.AreEqual("a", (string)arr[0]);
Assert.AreEqual("b", (string)arr[1]);
Assert.AreEqual("c", (string)arr[2]);
Assert.Equal(3, arr.Length);
Assert.Equal("a", arr[0]);
Assert.Equal("b", arr[1]);
Assert.Equal("c", arr[2]);
}
}
}
......
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
namespace StackExchange.Redis.Tests.Booksleeve
{
public class BookSleeveTestBase
{
public ITestOutputHelper Output { get; }
public BookSleeveTestBase(ITestOutputHelper output) => Output = output;
static BookSleeveTestBase()
{
TaskScheduler.UnobservedTaskException += (sender, args) =>
{
Trace.WriteLine(args.Exception, "UnobservedTaskException");
args.SetObserved();
};
}
public static string CreateUniqueName() => Guid.NewGuid().ToString("N");
internal static IServer GetServer(ConnectionMultiplexer conn) => conn.GetServer(conn.GetEndPoints()[0]);
private static readonly SocketManager socketManager = new SocketManager();
internal static ConnectionMultiplexer GetRemoteConnection(bool open = true, bool allowAdmin = false, bool waitForOpen = false, int syncTimeout = 5000, int ioTimeout = 5000)
{
return GetConnection(TestConfig.Current.RemoteServer, TestConfig.Current.RemotePort, open, allowAdmin, waitForOpen, syncTimeout, ioTimeout);
}
private static ConnectionMultiplexer GetConnection(string host, int port, bool open = true, bool allowAdmin = false, bool waitForOpen = false, int syncTimeout = 5000, int ioTimeout = 5000)
{
var options = new ConfigurationOptions
{
EndPoints = { { host, port } },
AllowAdmin = allowAdmin,
SyncTimeout = syncTimeout,
SocketManager = socketManager,
ResponseTimeout = ioTimeout
};
var conn = ConnectionMultiplexer.Connect(options);
conn.InternalError += (s, args) => Trace.WriteLine(args.Exception.Message, args.Origin);
if (open && waitForOpen)
{
conn.GetDatabase().Ping();
}
return conn;
}
internal static ConnectionMultiplexer GetUnsecuredConnection(bool open = true, bool allowAdmin = false, bool waitForOpen = false, int syncTimeout = 5000, int ioTimeout = 5000)
{
return GetConnection(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort, open, allowAdmin, waitForOpen, syncTimeout, ioTimeout);
}
internal static ConnectionMultiplexer GetSecuredConnection()
{
Skip.IfNoConfig(nameof(TestConfig.Config.SecureServer), TestConfig.Current.SecureServer);
var options = new ConfigurationOptions
{
EndPoints = { { TestConfig.Current.SecureServer, TestConfig.Current.SecurePort } },
Password = "changeme",
SyncTimeout = 6000,
SocketManager = socketManager
};
var conn = ConnectionMultiplexer.Connect(options);
conn.InternalError += (s, args) => Trace.WriteLine(args.Exception.Message, args.Origin);
return conn;
}
internal static RedisFeatures GetFeatures(ConnectionMultiplexer muxer) => GetServer(muxer).Features;
internal static void AssertNearlyEqual(double x, double y)
{
if (Math.Abs(x - y) > 0.00001) Assert.Equal(x, y);
}
}
}
using System.Threading.Tasks;
using NUnit.Framework;
using StackExchange.Redis;
using Xunit;
using Xunit.Abstractions;
namespace Tests
namespace StackExchange.Redis.Tests.Booksleeve
{
[TestFixture]
public class Constraints
public class Constraints : BookSleeveTestBase
{
[Test]
public Constraints(ITestOutputHelper output) : base(output) { }
[Fact]
public void ValueEquals()
{
RedisValue x = 1, y = "1";
Assert.IsTrue(x.Equals(y), "equals");
Assert.IsTrue(x == y, "operator");
Assert.True(x.Equals(y), "equals");
Assert.True(x == y, "operator");
}
[Test]
[Fact]
public void TestManualIncr()
{
using (var muxer = Config.GetUnsecuredConnection(syncTimeout: 120000)) // big timeout while debugging
using (var muxer = GetUnsecuredConnection(syncTimeout: 120000)) // big timeout while debugging
{
var conn = muxer.GetDatabase(0);
for (int i = 0; i < 200; i++)
{
conn.KeyDelete("foo");
Assert.AreEqual(1, conn.Wait(ManualIncr(conn, "foo")));
Assert.AreEqual(2, conn.Wait(ManualIncr(conn, "foo")));
Assert.AreEqual(2, (long)conn.StringGet("foo"));
Assert.Equal(1, conn.Wait(ManualIncr(conn, "foo")));
Assert.Equal(2, conn.Wait(ManualIncr(conn, "foo")));
Assert.Equal(2, (long)conn.StringGet("foo"));
}
}
}
public async Task<long?> ManualIncr(IDatabase connection, string key)
{
var oldVal = (long?)await connection.StringGetAsync(key).ConfigureAwait(false);
var oldVal = (long?)await connection.StringGetAsync(key).ForAwait();
var newVal = (oldVal ?? 0) + 1;
var tran = connection.CreateTransaction();
{ // check hasn't changed
#pragma warning disable 4014
tran.AddCondition(Condition.StringEqual(key, oldVal));
tran.StringSetAsync(key, newVal);
#pragma warning restore 4014
if (!await tran.ExecuteAsync().ConfigureAwait(false)) return null; // aborted
if (!await tran.ExecuteAsync().ForAwait()) return null; // aborted
return newVal;
}
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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