diff --git a/TestApp/MyService.cs b/TestApp/MyService.cs new file mode 100644 index 0000000..d19afa6 --- /dev/null +++ b/TestApp/MyService.cs @@ -0,0 +1,21 @@ +using System; +using ZeroLevel; +using ZeroLevel.Services.Applications; + +namespace TestApp +{ + public class MyService + : BaseZeroService + { + protected override void StartAction() + { + Log.Info("Started"); + Sheduller.RemindEvery(TimeSpan.FromSeconds(5), () => Log.Info("Still alive")); + } + + protected override void StopAction() + { + Log.Info("Stopped"); + } + } +} diff --git a/TestApp/Program.cs b/TestApp/Program.cs new file mode 100644 index 0000000..663a17b --- /dev/null +++ b/TestApp/Program.cs @@ -0,0 +1,13 @@ +using ZeroLevel; + +namespace TestApp +{ + internal static class Program + { + private static void Main(string[] args) + { + Log.AddConsoleLogger(); + Bootstrap.Startup(args); + } + } +} diff --git a/TestApp/TestApp.csproj b/TestApp/TestApp.csproj new file mode 100644 index 0000000..3a4521e --- /dev/null +++ b/TestApp/TestApp.csproj @@ -0,0 +1,12 @@ + + + + Exe + netcoreapp2.2 + + + + + + + diff --git a/ZeroLevel.Discovery/DiscoveryService.cs b/ZeroLevel.Discovery/DiscoveryService.cs new file mode 100644 index 0000000..50f12e1 --- /dev/null +++ b/ZeroLevel.Discovery/DiscoveryService.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using ZeroLevel.Models; +using ZeroLevel.Network; +using ZeroLevel.Services.Applications; + +namespace ZeroLevel.Discovery +{ + public sealed class DiscoveryService + : BaseZeroService + { + private IExService _exInbox; + + public DiscoveryService() + : base("Discovery") + { + } + + protected override void StartAction() + { + var routeTable = new RouteTable(); + + Injector.Default.Register(routeTable); + + var socketPort = Configuration.Default.First("socketport"); + _exInbox = ExchangeTransportFactory.GetServer(socketPort); + _exInbox.RegisterInbox>("services", (_, __) => routeTable.Get()); + _exInbox.RegisterInbox("register", (info, _, client) => routeTable.Append(info, client)); + + Log.Info($"TCP server started {_exInbox.Endpoint.Address}:{socketPort}"); + } + + protected override void StopAction() + { + _exInbox.Dispose(); + } + } +} \ No newline at end of file diff --git a/ZeroLevel.Discovery/Program.cs b/ZeroLevel.Discovery/Program.cs new file mode 100644 index 0000000..d9c28d2 --- /dev/null +++ b/ZeroLevel.Discovery/Program.cs @@ -0,0 +1,11 @@ +namespace ZeroLevel.Discovery +{ + internal static class Program + { + private static void Main(string[] args) + { + Log.AddConsoleLogger(Services.Logging.LogLevel.System | Services.Logging.LogLevel.FullDebug); + Bootstrap.Startup(args); + } + } +} \ No newline at end of file diff --git a/ZeroLevel.Discovery/RouteTable.cs b/ZeroLevel.Discovery/RouteTable.cs new file mode 100644 index 0000000..662efeb --- /dev/null +++ b/ZeroLevel.Discovery/RouteTable.cs @@ -0,0 +1,222 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using ZeroLevel.Models; +using ZeroLevel.Network; + +namespace ZeroLevel.Discovery +{ + public class RouteTable + : IDisposable + { + private readonly Dictionary _table = new Dictionary(); + private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); + + public RouteTable() + { + Load(); + Sheduller.RemindEvery(TimeSpan.FromSeconds(10), Heartbeat); + } + + #region Snapshot + + private static readonly object _snapshot_lock = new object(); + + private void Save() + { + string snapshot; + _lock.EnterReadLock(); + try + { + snapshot = JsonConvert.SerializeObject(_table); + } + catch (Exception ex) + { + Log.Error(ex, "Fault make snapshot"); + return; + } + finally + { + _lock.ExitReadLock(); + } + try + { + var snapshot_path = Path.Combine(Configuration.BaseDirectory, "snapshot.snp"); + lock (_snapshot_lock) + { + File.WriteAllText(snapshot_path, snapshot); + } + } + catch (Exception ex) + { + Log.Error(ex, "Fault save shapshot"); + } + } + + private void Load() + { + try + { + var path = Path.Combine(Configuration.BaseDirectory, "snapshot.snp"); + if (File.Exists(path)) + { + var snapshot = File.ReadAllText(path); + if (string.IsNullOrWhiteSpace(snapshot) == false) + { + var restored = JsonConvert.DeserializeObject>(snapshot); + _lock.EnterWriteLock(); + try + { + _table.Clear(); + foreach (var r in restored) + { + _table.Add(r.Key, r.Value); + } + } + finally + { + _lock.ExitWriteLock(); + } + } + } + } + catch (Exception ex) + { + Log.Error(ex, "Fault load snapshot"); + } + } + + #endregion Snapshot + private void Heartbeat(long taskid) + { + try + { + var removeEntities = new Dictionary>(); + _lock.EnterReadLock(); + try + { + foreach (var pair in _table) + { + var endpointsToRemove = new List(); + foreach (var e in pair.Value.Endpoints) + { + if (NetUtils.TestConnection(NetUtils.CreateIPEndPoint(e)) == false) + { + if (false == removeEntities.ContainsKey(pair.Key)) + { + removeEntities.Add(pair.Key, new List()); + } + removeEntities[pair.Key].Add(e); + } + } + } + } + finally + { + _lock.ExitReadLock(); + } + _lock.EnterWriteLock(); + try + { + foreach (var pair in removeEntities) + { + foreach (var ep in pair.Value) + { + _table[pair.Key].Endpoints.Remove(ep); + } + } + var badKeys = _table.Where(f => f.Value.Endpoints.Count == 0) + .Select(pair => pair.Key) + .ToList(); + foreach (var badKey in badKeys) + { + _table.Remove(badKey); + } + } + finally + { + _lock.ExitWriteLock(); + } + } + catch (Exception ex) + { + Log.Error(ex, "Fault heartbeat"); + } + Save(); + } + + public InvokeResult Append(ExServiceInfo serviceInfo, IZBackward client) + { + InvokeResult result = null; + var endpoint = $"{client.Endpoint.Address}:{serviceInfo.Port}"; + Log.Info($"Regiter request from {endpoint}. Service {serviceInfo?.ServiceKey}"); + if (NetUtils.TestConnection(NetUtils.CreateIPEndPoint(endpoint))) + { + var key = $"{serviceInfo.ServiceGroup}:{serviceInfo.ServiceType}:{serviceInfo.ServiceKey.Trim().ToLowerInvariant()}"; + _lock.EnterWriteLock(); + try + { + if (false == _table.ContainsKey(key)) + { + _table.Add(key, new ServiceEndpointsInfo + { + ServiceKey = serviceInfo.ServiceKey, + Version = serviceInfo.Version, + ServiceGroup = serviceInfo.ServiceGroup, + ServiceType = serviceInfo.ServiceType, + Endpoints = new List() + }); + _table[key].Endpoints.Add(endpoint); + Log.Info($"The service '{serviceInfo.ServiceKey}' registered on endpoint: {endpoint}"); + } + else + { + var exists = _table[key]; + if (exists.Endpoints.Contains(endpoint) == false) + { + Log.Info($"The service '{serviceInfo.ServiceKey}' register endpoint: {endpoint}"); + exists.Endpoints.Add(endpoint); + } + } + } + catch (Exception ex) + { + Log.Error(ex, $"Fault append service ({serviceInfo.ServiceKey} {serviceInfo.Version}) endpoint '{endpoint}'"); + result = InvokeResult.Fault(ex.Message); + } + finally + { + _lock.ExitWriteLock(); + } + Save(); + result = InvokeResult.Succeeding(); + } + else + { + result = InvokeResult.Fault($"Appending endpoint '{endpoint}' canceled for service {serviceInfo.ServiceKey} ({serviceInfo.Version}) because endpoind no avaliable"); + } + return result; + } + + public IEnumerable Get() + { + _lock.EnterReadLock(); + try + { + return _table.Values.ToList(); + } + finally + { + _lock.ExitReadLock(); + } + } + + public void Dispose() + { + _lock.Dispose(); + } + } +} \ No newline at end of file diff --git a/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj b/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj new file mode 100644 index 0000000..3a7cb5b --- /dev/null +++ b/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj @@ -0,0 +1,16 @@ + + + + Exe + netcoreapp2.2 + + + + + + + + + + + diff --git a/ZeroLevel.Discovery/app.config b/ZeroLevel.Discovery/app.config new file mode 100644 index 0000000..bc53553 --- /dev/null +++ b/ZeroLevel.Discovery/app.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ZeroLevel.UnitTests/ArrayToolsTest.cs b/ZeroLevel.UnitTests/ArrayToolsTest.cs index 54f28ca..7ff8558 100644 --- a/ZeroLevel.UnitTests/ArrayToolsTest.cs +++ b/ZeroLevel.UnitTests/ArrayToolsTest.cs @@ -27,6 +27,11 @@ namespace ZeroArrayExtensionsTest if (string.Compare(this.Title, other.Title, StringComparison.OrdinalIgnoreCase) != 0) return false; return this.Num == other.Num; } + + public override int GetHashCode() + { + return Num.GetHashCode(); + } } [Fact] diff --git a/ZeroLevel.UnitTests/InvokingTest.cs b/ZeroLevel.UnitTests/InvokingTest.cs index e6b1f96..6f7809e 100644 --- a/ZeroLevel.UnitTests/InvokingTest.cs +++ b/ZeroLevel.UnitTests/InvokingTest.cs @@ -20,11 +20,11 @@ namespace ZeroInvokingTest var identityGetDateTime = invoker.GetInvokerIdentity("GetDateTime", new Type[] { typeof(DateTime) }); var identityGetHelp = invoker.GetInvokerIdentity("GetHelp", null); // Assert - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetString, new object[] { "hello" }), "hello"); - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 }), 100); + Assert.Equal("hello", invoker.Invoke(new FakeClass(), identityGetString, new object[] { "hello" })); + Assert.Equal(100, invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 })); var date = DateTime.Now; - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date }), date); - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetHelp), "help"); + Assert.Equal(date, invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date })); + Assert.Equal("help", invoker.Invoke(new FakeClass(), identityGetHelp)); } [Fact] @@ -42,10 +42,10 @@ namespace ZeroInvokingTest var identityGetDateTime = invoker.GetInvokerIdentity("GetDateTime", new Type[] { typeof(DateTime) }); var identityGetHelp = invoker.GetInvokerIdentity("GetHelp", null); // Assert - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 }), 100); + Assert.Equal(100, invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 })); var date = DateTime.Now; - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date }), date); - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetHelp), "help"); + Assert.Equal(date, invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date })); + Assert.Equal("help", invoker.Invoke(new FakeClass(), identityGetHelp)); } [Fact] @@ -61,9 +61,9 @@ namespace ZeroInvokingTest var identityGetHelp = invoker.GetInvokerIdentity("GetHelp", null); // Assert var date = DateTime.Now; - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date }), date); - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 }), 100); - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetHelp), "help"); + Assert.Equal(date, invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date })); + Assert.Equal(100, invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 })); + Assert.Equal("help", invoker.Invoke(new FakeClass(), identityGetHelp)); } [Fact] @@ -84,11 +84,11 @@ namespace ZeroInvokingTest var identityGetDateTime = invoker.GetInvokerIdentity("GetDateTime", new Type[] { typeof(DateTime) }); var identityGetHelp = invoker.GetInvokerIdentity("GetHelp", null); // Assert - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetString, new object[] { "hello" }), "hello"); - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 }), 100); + Assert.Equal("hello", invoker.Invoke(new FakeClass(), identityGetString, new object[] { "hello" })); + Assert.Equal(100, invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 })); var date = DateTime.Now; - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date }), date); - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetHelp), "help"); + Assert.Equal(date, invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date })); + Assert.Equal("help", invoker.Invoke(new FakeClass(), identityGetHelp)); } [Fact] @@ -106,11 +106,11 @@ namespace ZeroInvokingTest var identityGetDateTime = invoker.GetInvokerIdentity("GetDateTime", new Type[] { typeof(DateTime) }); var identityGetHelp = invoker.GetInvokerIdentity("GetHelp", null); // Assert - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetString, new object[] { "hello" }), "hello"); - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 }), 100); + Assert.Equal("hello", invoker.Invoke(new FakeClass(), identityGetString, new object[] { "hello" })); + Assert.Equal(100, invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 })); var date = DateTime.Now; - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date }), date); - Assert.Equal(invoker.Invoke(new FakeClass(), identityGetHelp), "help"); + Assert.Equal(date, invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date })); + Assert.Equal("help", invoker.Invoke(new FakeClass(), identityGetHelp)); } [Fact] @@ -126,8 +126,8 @@ namespace ZeroInvokingTest var identityGetNumber = invoker.GetInvokerIdentity("GetNumber", new Type[] { typeof(int) }); var identityGetDateTime = invoker.GetInvokerIdentity("GetDateTime", new Type[] { typeof(DateTime) }); // Assert - Assert.Equal(invoker.InvokeStatic(identityGetString, new object[] { "hello" }), "hello"); - Assert.Equal(invoker.InvokeStatic(identityGetNumber, new object[] { 100 }), 100); + Assert.Equal("hello", invoker.InvokeStatic(identityGetString, new object[] { "hello" })); + Assert.Equal(100, invoker.InvokeStatic(identityGetNumber, new object[] { 100 })); var date = DateTime.Now; Assert.Equal(invoker.InvokeStatic(identityGetDateTime, new object[] { date }), date); } diff --git a/ZeroLevel.UnitTests/MappingTest.cs b/ZeroLevel.UnitTests/MappingTest.cs index 782b5bc..987f2d2 100644 --- a/ZeroLevel.UnitTests/MappingTest.cs +++ b/ZeroLevel.UnitTests/MappingTest.cs @@ -22,17 +22,17 @@ namespace ZeroMappingTest Assert.True(mapper.Exists("Title")); Assert.True(mapper.Exists("Description")); - Assert.True(list.Contains("Id")); - Assert.True(list.Contains("Title")); - Assert.True(list.Contains("Description")); + Assert.Contains(list, s => s.Equals("Id", StringComparison.Ordinal)); + Assert.Contains(list, s => s.Equals("Title", StringComparison.Ordinal)); + Assert.Contains(list, s => s.Equals("Description", StringComparison.Ordinal)); Assert.False(mapper.Exists("Version")); Assert.False(mapper.Exists("Created")); - Assert.False(list.Contains("Version")); - Assert.False(list.Contains("Created")); + Assert.DoesNotContain(list, s => s.Equals("Version", StringComparison.Ordinal)); + Assert.DoesNotContain(list, s => s.Equals("Created", StringComparison.Ordinal)); - Assert.Equal(mapper.EntityType, typeof(BaseClass)); + Assert.Equal(typeof(BaseClass), mapper.EntityType); } [Fact] @@ -52,25 +52,25 @@ namespace ZeroMappingTest Assert.True(mapper.Exists("ReadOnlyProperty")); Assert.True(mapper.Exists("WriteOnlyProperty")); - Assert.True(list.Contains("Id")); - Assert.True(list.Contains("Title")); - Assert.True(list.Contains("Description")); - Assert.True(list.Contains("Number")); - Assert.True(list.Contains("Balance")); - Assert.True(list.Contains("ReadOnlyProperty")); - Assert.True(list.Contains("WriteOnlyProperty")); + Assert.Contains(list, s => s.Equals("Id", StringComparison.Ordinal)); + Assert.Contains(list, s => s.Equals("Title", StringComparison.Ordinal)); + Assert.Contains(list, s => s.Equals("Description", StringComparison.Ordinal)); + Assert.Contains(list, s => s.Equals("Number", StringComparison.Ordinal)); + Assert.Contains(list, s => s.Equals("Balance", StringComparison.Ordinal)); + Assert.Contains(list, s => s.Equals("ReadOnlyProperty", StringComparison.Ordinal)); + Assert.Contains(list, s => s.Equals("WriteOnlyProperty", StringComparison.Ordinal)); Assert.False(mapper.Exists("HiddenField")); Assert.False(mapper.Exists("Version")); Assert.False(mapper.Exists("Created")); - Assert.False(list.Contains("HiddenField")); - Assert.False(list.Contains("Version")); - Assert.False(list.Contains("Created")); + Assert.DoesNotContain(list, s => s.Equals("HiddenField", StringComparison.Ordinal)); + Assert.DoesNotContain(list, s => s.Equals("Version", StringComparison.Ordinal)); + Assert.DoesNotContain(list, s => s.Equals("Created", StringComparison.Ordinal)); - Assert.Equal(mapper.EntityType, typeof(ChildClass)); + Assert.Equal(typeof(ChildClass), mapper.EntityType); } - + [Fact] public void TestAbstractClassMapping() { @@ -93,13 +93,13 @@ namespace ZeroMappingTest mapper.Set(instance, "Title", title); mapper.Set(instance, "Description", description); // Assert - Assert.Equal(mapper.Get(instance, "Id"), id); - Assert.Equal(mapper.Get(instance, "Title"), title); - Assert.Equal(mapper.Get(instance, "Description"), description); + Assert.Equal(id, mapper.Get(instance, "Id")); + Assert.Equal(title, mapper.Get(instance, "Title")); + Assert.Equal(description, mapper.Get(instance, "Description")); - Assert.Equal(mapper.Get(instance, "Id"), id); - Assert.Equal(mapper.Get(instance, "Title"), title); - Assert.Equal(mapper.Get(instance, "Description"), description); + Assert.Equal(id, mapper.Get(instance, "Id")); + Assert.Equal(title, mapper.Get(instance, "Title")); + Assert.Equal(description, mapper.Get(instance, "Description")); try { @@ -110,7 +110,7 @@ namespace ZeroMappingTest { } } - + [Fact] public void TestInheritedClassMapping() { @@ -140,8 +140,8 @@ namespace ZeroMappingTest mapper.Set(instance, "Balance", balance); // Assert Assert.Equal(mapper.Get(instance, "Id"), id); - Assert.Equal(mapper.Get(instance, "Title"), title); - Assert.Equal(mapper.Get(instance, "Description"), description); + Assert.Equal(mapper.Get(instance, "Title"), title); + Assert.Equal(mapper.Get(instance, "Description"), description); Assert.Equal(mapper.Get(instance, "Number"), number); Assert.Equal(mapper.Get(instance, "Balance"), balance); @@ -183,9 +183,9 @@ namespace ZeroMappingTest try { - mapper.Get(instance, "Number"); + mapper.Get(instance, "Number"); } - catch(Exception ex) + catch (Exception ex) { Assert.True(false, ex.Message); } @@ -214,15 +214,15 @@ namespace ZeroMappingTest var obj = new PocoFields { Id = 1000, Date = date, Title = "Caption" }; // Assert - Assert.Equal(mapper.EntityType, typeof(PocoFields)); + Assert.Equal(typeof(PocoFields), mapper.EntityType); Assert.True(mapper.Exists("Id")); Assert.True(mapper.Exists("Date")); Assert.True(mapper.Exists("Title")); - Assert.Equal(mapper.Get(obj, "Id"), (long)1000); - Assert.Equal(mapper.Get(obj, "Date"), date); - Assert.Equal(mapper.Get(obj, "Title"), "Caption"); + Assert.Equal((long)1000, mapper.Get(obj, "Id")); + Assert.Equal(date, mapper.Get(obj, "Date")); + Assert.Equal("Caption", mapper.Get(obj, "Title")); mapper.Set(obj, "Id", 1001); Assert.Equal(mapper.Get(obj, "Id"), (long)1001); @@ -237,15 +237,15 @@ namespace ZeroMappingTest var obj = new PocoProperties { Id = 1000, Date = date, Title = "Caption" }; // Assert - Assert.Equal(mapper.EntityType, typeof(PocoProperties)); + Assert.Equal(typeof(PocoProperties), mapper.EntityType); Assert.True(mapper.Exists("Id")); Assert.True(mapper.Exists("Date")); Assert.True(mapper.Exists("Title")); - Assert.Equal(mapper.Get(obj, "Id"), (long)1000); - Assert.Equal(mapper.Get(obj, "Date"), date); - Assert.Equal(mapper.Get(obj, "Title"), "Caption"); + Assert.Equal((long)1000, mapper.Get(obj, "Id")); + Assert.Equal(date, mapper.Get(obj, "Date")); + Assert.Equal("Caption", mapper.Get(obj, "Title")); mapper.Set(obj, "Id", 1001); Assert.Equal(mapper.Get(obj, "Id"), (long)1001); diff --git a/ZeroLevel.UnitTests/QueriesTests.cs b/ZeroLevel.UnitTests/QueriesTests.cs index a2d7540..9f978cb 100644 --- a/ZeroLevel.UnitTests/QueriesTests.cs +++ b/ZeroLevel.UnitTests/QueriesTests.cs @@ -57,11 +57,11 @@ namespace ZeroSpecificationPatternsTest Title = "Title #3" }); Assert.True(a1.Success); - Assert.Equal(a1.Count, 1); + Assert.Equal(1, a1.Count); Assert.True(a2.Success); - Assert.Equal(a2.Count, 1); + Assert.Equal(1, a2.Count); Assert.True(a3.Success); - Assert.Equal(a3.Count, 1); + Assert.Equal(1, a3.Count); } [Fact] @@ -100,7 +100,7 @@ namespace ZeroSpecificationPatternsTest { var ar = storage.Post(i); Assert.True(ar.Success); - Assert.Equal(ar.Count, 1); + Assert.Equal(1, ar.Count); } // Test equals set and storage data foreach (var i in storage.Get()) @@ -156,7 +156,7 @@ namespace ZeroSpecificationPatternsTest { var ar = storage.Post(i); Assert.True(ar.Success); - Assert.Equal(ar.Count, 1); + Assert.Equal(1, ar.Count); } // Test equals set and storage data foreach (var i in storage.Get()) @@ -168,21 +168,21 @@ namespace ZeroSpecificationPatternsTest Assert.True(set.Exists(dto => TestDTOEqual(i, dto))); } var result_eq = storage.Get(Query.EQ("Title", "Title #1")); - Assert.Equal(result_eq.Count(), 1); + Assert.Single(result_eq); Assert.True(TestDTOEqual(set[0], result_eq.First())); var result_neq = storage.Get(Query.NEQ("Title", "Title #1")); - Assert.Equal(result_neq.Count(), 2); + Assert.Equal(2, result_neq.Count()); Assert.True(TestDTOEqual(set[1], result_neq.First())); Assert.True(TestDTOEqual(set[2], result_neq.Skip(1).First())); var result_gt = storage.Get(Query.GT("Number", 1)); - Assert.Equal(result_gt.Count(), 2); + Assert.Equal(2, result_gt.Count()); Assert.True(TestDTOEqual(set[0], result_gt.First())); Assert.True(TestDTOEqual(set[2], result_gt.Skip(1).First())); var result_lt = storage.Get(Query.LT("Number", 1)); - Assert.Equal(result_lt.Count(), 1); + Assert.Single(result_lt); Assert.True(TestDTOEqual(set[1], result_lt.First())); } } diff --git a/ZeroLevel.sln b/ZeroLevel.sln index 6fc4804..aa25193 100644 --- a/ZeroLevel.sln +++ b/ZeroLevel.sln @@ -5,7 +5,11 @@ VisualStudioVersion = 15.0.28307.421 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZeroLevel", "ZeroLevel\ZeroLevel.csproj", "{06C9E60E-D449-41A7-9BF0-A829AAF5D214}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZeroLevel.UnitTests", "ZeroLevel.UnitTests\ZeroLevel.UnitTests.csproj", "{E5595DE0-B177-4078-AD10-8D3135014838}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZeroLevel.UnitTests", "ZeroLevel.UnitTests\ZeroLevel.UnitTests.csproj", "{E5595DE0-B177-4078-AD10-8D3135014838}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApp", "TestApp\TestApp.csproj", "{674561F2-A3E2-40E6-8E5B-AD94276AD856}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZeroLevel.Discovery", "ZeroLevel.Discovery\ZeroLevel.Discovery.csproj", "{5CE51CC9-7884-4E21-9D68-2321CA14312E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,6 +25,14 @@ Global {E5595DE0-B177-4078-AD10-8D3135014838}.Debug|Any CPU.Build.0 = Debug|Any CPU {E5595DE0-B177-4078-AD10-8D3135014838}.Release|Any CPU.ActiveCfg = Release|Any CPU {E5595DE0-B177-4078-AD10-8D3135014838}.Release|Any CPU.Build.0 = Release|Any CPU + {674561F2-A3E2-40E6-8E5B-AD94276AD856}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {674561F2-A3E2-40E6-8E5B-AD94276AD856}.Debug|Any CPU.Build.0 = Debug|Any CPU + {674561F2-A3E2-40E6-8E5B-AD94276AD856}.Release|Any CPU.ActiveCfg = Release|Any CPU + {674561F2-A3E2-40E6-8E5B-AD94276AD856}.Release|Any CPU.Build.0 = Release|Any CPU + {5CE51CC9-7884-4E21-9D68-2321CA14312E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5CE51CC9-7884-4E21-9D68-2321CA14312E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5CE51CC9-7884-4E21-9D68-2321CA14312E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5CE51CC9-7884-4E21-9D68-2321CA14312E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ZeroLevel/Models/InvokeResult.cs b/ZeroLevel/Models/InvokeResult.cs index 819f23f..a063ce2 100644 --- a/ZeroLevel/Models/InvokeResult.cs +++ b/ZeroLevel/Models/InvokeResult.cs @@ -64,6 +64,15 @@ namespace ZeroLevel.Models /// public static InvokeResult Succeeding() { return _successResultWitoutComment; } + public static InvokeResult Succeeding(T value, string comment = "") + { + return new InvokeResult(value, true, comment); + } + + public static InvokeResult Fault(string comment) + { + return new InvokeResult(false, comment); + } #endregion Fabric methods public virtual void Serialize(IBinaryWriter writer) @@ -102,20 +111,6 @@ namespace ZeroLevel.Models #endregion Ctor - #region Fabric methods - - public static InvokeResult Succeeding(T value, string comment = "") - { - return new InvokeResult(value, true, comment); - } - - public static InvokeResult Fault(string comment) - { - return new InvokeResult(false, comment); - } - - #endregion Fabric methods - public override void Serialize(IBinaryWriter writer) { writer.WriteBoolean(this.Success);