Browse Source

Add missing tests for the GenHTTP framework (except for the caching tests) (#6008)

Andreas Nägeli 5 years ago
parent
commit
5f1094b317

+ 15 - 3
frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj

@@ -5,7 +5,6 @@
     <TargetFramework>net5.0</TargetFramework>
 
     <LangVersion>8.0</LangVersion>
-    <Nullable>enable</Nullable>
     
     <AssemblyTitle>GenHTTP Benchmarks</AssemblyTitle>
     <Description>Test suite to be executed with TechEmpower FrameworkBenchmarks.</Description>
@@ -17,10 +16,23 @@
     <TieredCompilation>false</TieredCompilation>
     
   </PropertyGroup>
+  
+  <ItemGroup>
+    <None Remove="Resources\Fortunes.html" />
+    <None Remove="Resources\Template.html" />
+  </ItemGroup>
+  
+  <ItemGroup>
+    <EmbeddedResource Include="Resources\Template.html" />
+    <EmbeddedResource Include="Resources\Fortunes.html" />
+  </ItemGroup>
     
   <ItemGroup>
-    <PackageReference Include="GenHTTP.Core" Version="3.2.1" />
-    <PackageReference Include="GenHTTP.Modules.Webservices" Version="3.2.1" />
+    <PackageReference Include="GenHTTP.Core" Version="3.2.2" />
+    <PackageReference Include="GenHTTP.Modules.Scriban" Version="3.2.2" />
+    <PackageReference Include="GenHTTP.Modules.Webservices" Version="3.2.2" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.8" />
+    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
   </ItemGroup>
   
 </Project>

+ 39 - 0
frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContext.cs

@@ -0,0 +1,39 @@
+using Microsoft.EntityFrameworkCore;
+
+namespace Benchmarks.Model
+{
+
+    public sealed class DatabaseContext : DbContext
+    {
+        private static DbContextOptions<DatabaseContext> _Options;
+
+        #region Factory
+
+        public static DatabaseContext Create()
+        {
+            return new DatabaseContext(_Options ??= GetOptions());
+        }
+
+        private static DbContextOptions<DatabaseContext> GetOptions()
+        {
+            var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
+            optionsBuilder.UseNpgsql("Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=64;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3");
+
+            return optionsBuilder.Options;
+        }
+
+        private DatabaseContext(DbContextOptions options) : base(options) { }
+
+        #endregion
+
+        #region Entities
+
+        public DbSet<World> World { get; set; }
+
+        public DbSet<Fortune> Fortune { get; set; }
+
+        #endregion
+
+    }
+
+}

+ 25 - 0
frameworks/CSharp/genhttp/Benchmarks/Model/Fortune.cs

@@ -0,0 +1,25 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace Benchmarks.Model
+{
+
+    [Table("fortune")]
+    public class Fortune : IComparable<Fortune>, IComparable
+    {
+
+        [Column("id")]
+        public int Id { get; set; }
+
+        [Column("message")]
+        [StringLength(2048)]
+        public string Message { get; set; }
+
+        public int CompareTo(object obj) => CompareTo((Fortune)obj);
+
+        public int CompareTo(Fortune other) => string.CompareOrdinal(Message, other.Message);
+
+    }
+
+}

+ 18 - 0
frameworks/CSharp/genhttp/Benchmarks/Model/World.cs

@@ -0,0 +1,18 @@
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace Benchmarks.Model
+{
+
+    [Table("world")]
+    public class World
+    {
+
+        [Column("id")]
+        public int Id { get; set; }
+
+        [Column("randomnumber")]
+        public int RandomNumber { get; set; }
+
+    }
+
+}

+ 6 - 1
frameworks/CSharp/genhttp/Benchmarks/Program.cs

@@ -3,6 +3,7 @@ using GenHTTP.Modules.Core;
 using GenHTTP.Modules.Webservices;
 
 using Benchmarks.Tests;
+using GenHTTP.Modules.Scriban;
 
 namespace Benchmarks
 {
@@ -14,7 +15,11 @@ namespace Benchmarks
         {
             var tests = Layout.Create()
                               .Add("plaintext", Content.From("Hello, World!"))
-                              .Add<JsonResource>("json");
+                              .Add("fortunes", new FortuneHandlerBuilder())
+                              .Add<JsonResource>("json")
+                              .Add<DbResource>("db")
+                              .Add<QueryResource>("queries")
+                              .Add<UpdateResource>("updates");
 
             return Host.Create()
                        .Handler(tests)

+ 6 - 0
frameworks/CSharp/genhttp/Benchmarks/Resources/Fortunes.html

@@ -0,0 +1,6 @@
+<table>
+    <tr><th>id</th><th>message</th></tr>
+    {{~ for cookie in cookies ~}}
+    <tr><td>{{cookie.id}}</td><td>{{cookie.message | html.escape}}</td></tr>
+    {{~ end ~}}
+</table>

+ 9 - 0
frameworks/CSharp/genhttp/Benchmarks/Resources/Template.html

@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>{{ title }}</title>
+</head>
+<body>
+    {{ content }}
+</body>
+</html>

+ 27 - 0
frameworks/CSharp/genhttp/Benchmarks/Tests/DbResource.cs

@@ -0,0 +1,27 @@
+using System;
+
+using GenHTTP.Modules.Webservices;
+
+using Benchmarks.Model;
+using System.Linq;
+
+namespace Benchmarks.Tests
+{
+
+    public class DbResource
+    {
+        private static Random _Random = new Random();
+
+        [Method]
+        public World GetRandomWorld()
+        {
+            var id = _Random.Next(1, 10001);
+
+            using var context = DatabaseContext.Create();
+
+            return context.World.First(w => w.Id == id);
+        }
+
+    }
+
+}

+ 103 - 0
frameworks/CSharp/genhttp/Benchmarks/Tests/FortuneHandler.cs

@@ -0,0 +1,103 @@
+using Benchmarks.Model;
+using GenHTTP.Api.Content;
+using GenHTTP.Api.Content.Templating;
+using GenHTTP.Api.Protocol;
+using GenHTTP.Modules.Core;
+using GenHTTP.Modules.Scriban;
+using Npgsql;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Benchmarks.Tests
+{
+
+    #region Factory
+
+    public class FortuneHandlerBuilder : IHandlerBuilder
+    {
+
+        public IHandler Build(IHandler parent)
+        {
+            return new FortuneHandler(parent);
+        }
+
+    }
+
+    #endregion
+
+    public class FortuneHandler : IHandler, IPageRenderer
+    {
+
+        #region Get-/Setters
+
+        public IHandler Parent { get; }
+
+        private IHandler Page { get; }
+
+        private IRenderer<TemplateModel> Template { get; }
+
+        #endregion
+
+        #region Supporting data structures
+
+        public class FortuneModel : PageModel
+        {
+
+            public List<Fortune> Cookies { get; }
+
+            public FortuneModel(IRequest request, IHandler handler, List<Fortune> cookies) : base(request, handler)
+            {
+                Cookies = cookies;
+            }
+
+        }
+
+        #endregion
+
+        #region Initialization
+
+        public FortuneHandler(IHandler parent)
+        {
+            Parent = parent;
+
+            Page = ModScriban.Page(Data.FromResource("Fortunes.html"), (r, h) => GetFortunes(r, h))
+                             .Title("Fortunes")
+                             .Build(this);
+
+            Template = ModScriban.Template<TemplateModel>(Data.FromResource("Template.html")).Build();
+        }
+
+        #endregion
+
+        #region Functionality
+
+        public IResponse Handle(IRequest request) => Page.Handle(request);
+
+        public IEnumerable<ContentElement> GetContent(IRequest request) => Enumerable.Empty<ContentElement>();
+
+        public IResponseBuilder Render(TemplateModel model)
+        {
+            return model.Request.Respond()
+                                .Content(Template.Render(model))
+                                .Header("Content-Type", "text/html; charset=utf-8");
+        }
+
+        private FortuneModel GetFortunes(IRequest request, IHandler handler)
+        {
+            using var context = DatabaseContext.Create();
+
+            var fortunes = context.Fortune.ToList();
+
+            fortunes.Add(new Fortune() { Message = "Additional fortune added at request time." });
+
+            fortunes.Sort();
+
+            return new FortuneModel(request, handler, fortunes);
+        }
+
+        #endregion
+
+    }
+
+}

+ 1 - 1
frameworks/CSharp/genhttp/Benchmarks/Tests/JsonResource.cs

@@ -6,7 +6,7 @@ namespace Benchmarks.Tests
     public class JsonResult
     {
 
-        public string? Message { get; set; }
+        public string Message { get; set; }
 
     }
 

+ 45 - 0
frameworks/CSharp/genhttp/Benchmarks/Tests/QueryResource.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Benchmarks.Model;
+
+using GenHTTP.Modules.Webservices;
+
+namespace Benchmarks.Tests
+{
+
+    public class QueryResource
+    {
+        private static Random _Random = new Random();
+
+        [Method(":queries")]
+        public List<World> GetWorldsFromPath(string queries) => GetWorlds(queries);
+
+        [Method]
+        public List<World> GetWorlds(string queries)
+        {
+            var count = 1;
+
+            int.TryParse(queries, out count);
+
+            if (count < 1) count = 1;
+            else if (count > 500) count = 500;
+
+            var result = new List<World>(count);
+
+            using var context = DatabaseContext.Create();
+
+            for (int _ = 0; _ < count; _++)
+            {
+                var id = _Random.Next(1, 10001);
+
+                result.Add(context.World.First(w => w.Id == id));
+            }
+
+            return result;
+        }
+
+    }
+
+}

+ 57 - 0
frameworks/CSharp/genhttp/Benchmarks/Tests/UpdateResource.cs

@@ -0,0 +1,57 @@
+using Benchmarks.Model;
+using GenHTTP.Modules.Webservices;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Benchmarks.Tests
+{
+
+    public class UpdateResource
+    {
+        private static Random _Random = new Random();
+
+        [Method(":queries")]
+        public List<World> UpdateWorldsFromPath(string queries) => UpdateWorlds(queries);
+
+        [Method]
+        public List<World> UpdateWorlds(string queries)
+        {
+            var count = 1;
+
+            int.TryParse(queries, out count);
+
+            if (count < 1) count = 1;
+            else if (count > 500) count = 500;
+
+            var result = new List<World>(count);
+
+            using (var context = DatabaseContext.Create())
+            {
+                var ids = Enumerable.Range(1, 10000).Select(x => _Random.Next(1, 10001)).Distinct().Take(count).ToArray();
+
+                foreach (var id in ids)
+                {
+                    var record = context.World.First(w => w.Id == id);
+
+                    var old = record.RandomNumber;
+
+                    do
+                    {
+                        record.RandomNumber = _Random.Next(1, 10001);
+                    }
+                    while (old == record.RandomNumber);
+
+                    result.Add(record);
+                }
+
+                context.SaveChanges();
+            }
+
+
+            return result;
+        }
+
+    }
+
+}

+ 4 - 0
frameworks/CSharp/genhttp/README.md

@@ -20,3 +20,7 @@ See the [GenHTTP website](https://genhttp.org) for more information.
 
 * [Plaintext](Benchmarks/Program.cs): "/plaintext"
 * [JSON](Benchmarks/Tests/JsonResource.cs): "/json"
+* [DB](Benchmarks/Tests/DbResource.cs): "/db"
+* [Queries](Benchmarks/Tests/QueryResource.cs): "/queries"
+* [Updates](Benchmarks/Tests/UpdateResource.cs): "/updates"
+* [Fortunes](Benchmarks/Tests/FortuneHandler.cs): "/fortunes"

+ 5 - 1
frameworks/CSharp/genhttp/benchmark_config.json

@@ -4,10 +4,14 @@
     "default": {
       "plaintext_url": "/plaintext",
       "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries/",
+      "update_url": "/updates/",
+      "fortune_url": "/fortunes",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Fullstack",
-      "database": "None",
+      "database": "Postgres",
       "framework": "GenHTTP",
       "language": "C#",
       "orm": "Raw",