Compare commits
	
		
			1 Commits
		
	
	
		
			master
			...
			developmen
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a46961cf80 | 
							
								
								
									
										53
									
								
								home-data-collection-tools.sln
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								home-data-collection-tools.sln
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  |  | ||||||
|  | Microsoft Visual Studio Solution File, Format Version 12.00 | ||||||
|  | # Visual Studio Version 17 | ||||||
|  | VisualStudioVersion = 17.5.002.0 | ||||||
|  | MinimumVisualStudioVersion = 10.0.40219.1 | ||||||
|  | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{A67575D5-676E-4A0C-A801-6AD47C23C9B1}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Solar.Api.Tests", "tests\Solar.Api.Tests\Solar.Api.Tests.csproj", "{38283E44-5C0D-4794-B497-43B83282C491}" | ||||||
|  | EndProject | ||||||
|  | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{7BBFB17D-BEE6-45A8-993F-A92203EF54BE}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Electricity.Migrator", "src\Electricity.Migrator\Electricity.Migrator.csproj", "{3AA85834-D70A-4064-86DC-F30571FCAC32}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Electricity.Api", "src\Electricity.Api\Electricity.Api.csproj", "{B02C4DFC-1BA8-4D54-AD5B-14008F740B0F}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Solar.Api", "src\Solar.Api\Solar.Api.csproj", "{F5D8C125-9E59-4241-8ED3-9DAC84ABEF93}" | ||||||
|  | EndProject | ||||||
|  | Global | ||||||
|  | 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||||
|  | 		Debug|Any CPU = Debug|Any CPU | ||||||
|  | 		Release|Any CPU = Release|Any CPU | ||||||
|  | 	EndGlobalSection | ||||||
|  | 	GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||||||
|  | 		{38283E44-5C0D-4794-B497-43B83282C491}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{38283E44-5C0D-4794-B497-43B83282C491}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{38283E44-5C0D-4794-B497-43B83282C491}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{38283E44-5C0D-4794-B497-43B83282C491}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{3AA85834-D70A-4064-86DC-F30571FCAC32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{3AA85834-D70A-4064-86DC-F30571FCAC32}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{3AA85834-D70A-4064-86DC-F30571FCAC32}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{3AA85834-D70A-4064-86DC-F30571FCAC32}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{B02C4DFC-1BA8-4D54-AD5B-14008F740B0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{B02C4DFC-1BA8-4D54-AD5B-14008F740B0F}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{B02C4DFC-1BA8-4D54-AD5B-14008F740B0F}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{B02C4DFC-1BA8-4D54-AD5B-14008F740B0F}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{F5D8C125-9E59-4241-8ED3-9DAC84ABEF93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{F5D8C125-9E59-4241-8ED3-9DAC84ABEF93}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{F5D8C125-9E59-4241-8ED3-9DAC84ABEF93}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{F5D8C125-9E59-4241-8ED3-9DAC84ABEF93}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 	EndGlobalSection | ||||||
|  | 	GlobalSection(SolutionProperties) = preSolution | ||||||
|  | 		HideSolutionNode = FALSE | ||||||
|  | 	EndGlobalSection | ||||||
|  | 	GlobalSection(NestedProjects) = preSolution | ||||||
|  | 		{38283E44-5C0D-4794-B497-43B83282C491} = {A67575D5-676E-4A0C-A801-6AD47C23C9B1} | ||||||
|  | 		{3AA85834-D70A-4064-86DC-F30571FCAC32} = {7BBFB17D-BEE6-45A8-993F-A92203EF54BE} | ||||||
|  | 		{B02C4DFC-1BA8-4D54-AD5B-14008F740B0F} = {7BBFB17D-BEE6-45A8-993F-A92203EF54BE} | ||||||
|  | 		{F5D8C125-9E59-4241-8ED3-9DAC84ABEF93} = {7BBFB17D-BEE6-45A8-993F-A92203EF54BE} | ||||||
|  | 	EndGlobalSection | ||||||
|  | 	GlobalSection(ExtensibilityGlobals) = postSolution | ||||||
|  | 		SolutionGuid = {BF72B2F1-30E0-4D62-8A8F-F7164218954B} | ||||||
|  | 	EndGlobalSection | ||||||
|  | EndGlobal | ||||||
							
								
								
									
										25
									
								
								src/Electricity.Api/Middlewares/IpFilterMiddleware.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/Electricity.Api/Middlewares/IpFilterMiddleware.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | using System.Net; | ||||||
|  |  | ||||||
|  | namespace Electricity.Api.Middlewares; | ||||||
|  |  | ||||||
|  | internal sealed class IpFilterMiddleware(RequestDelegate next, IConfiguration configuration) | ||||||
|  | { | ||||||
|  |     private readonly RequestDelegate _next = next; | ||||||
|  |     private readonly string AllowedHost = configuration["AllowedRequestHost"] | ||||||
|  |         ?? throw new NullReferenceException($"Configuration value AllowedRequestHost is not available"); | ||||||
|  |  | ||||||
|  |     public async Task InvokeAsync(HttpContext context) | ||||||
|  |     { | ||||||
|  |         var selfIpAddress = (await Dns.GetHostEntryAsync(AllowedHost)).AddressList.FirstOrDefault()?.MapToIPv4().ToString(); | ||||||
|  |         if (selfIpAddress == null || | ||||||
|  |             !context.Request.Headers.TryGetValue("X-Real-IP", out var realIpHeaderValue) || | ||||||
|  |             selfIpAddress != realIpHeaderValue.ToString()) | ||||||
|  |         { | ||||||
|  |             context.Response.StatusCode = (int)HttpStatusCode.Forbidden; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Call the next delegate/middleware in the pipeline. | ||||||
|  |         await _next(context); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -33,16 +33,6 @@ builder.Services.AddDbContext<DatabaseContext>((DbContextOptionsBuilder builder) | |||||||
|     builder.UseSqlite($"Data Source={sqlite3DatabaseFilePath}"); |     builder.UseSqlite($"Data Source={sqlite3DatabaseFilePath}"); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| builder.Services.AddCors(options => |  | ||||||
| { |  | ||||||
|     options.AddPolicy( |  | ||||||
|         name: "default", |  | ||||||
|         policy => |  | ||||||
|         { |  | ||||||
|             policy.WithOrigins("http://localhost:8080"); |  | ||||||
|         }); |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| builder.Services.AddControllers() | builder.Services.AddControllers() | ||||||
|     .AddJsonOptions(config => |     .AddJsonOptions(config => | ||||||
|     { |     { | ||||||
| @@ -62,6 +52,7 @@ if (app.Environment.IsDevelopment()) | |||||||
|     app.UseCors("default"); |     app.UseCors("default"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | app.UseMiddleware<Electricity.Api.Middlewares.IpFilterMiddleware>(); | ||||||
| app.UseAuthorization(); | app.UseAuthorization(); | ||||||
|  |  | ||||||
| app.MapControllers(); | app.MapControllers(); | ||||||
|   | |||||||
| @@ -5,5 +5,6 @@ | |||||||
|       "Microsoft.AspNetCore": "Warning" |       "Microsoft.AspNetCore": "Warning" | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   "AllowedHosts": "*" |   "AllowedHosts": "*", | ||||||
|  |   "AllowedRequestHost": "electricity.valkendaal.duckdns.org" | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								src/Electricity.Migrator/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								src/Electricity.Migrator/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | obj/ | ||||||
|  | bin/ | ||||||
							
								
								
									
										45
									
								
								src/Electricity.Migrator/DatabaseContext.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/Electricity.Migrator/DatabaseContext.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | using Electricity.Migrator.Entities; | ||||||
|  | using Microsoft.EntityFrameworkCore; | ||||||
|  |  | ||||||
|  | namespace Electricity.Migrator | ||||||
|  | { | ||||||
|  |     public partial class DatabaseContext : DbContext | ||||||
|  |     { | ||||||
|  |         public DatabaseContext() | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public DatabaseContext(DbContextOptions<DatabaseContext> options) | ||||||
|  |             : base(options) | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public virtual DbSet<ElectricityLog> ElectricityLogs { get; set; } = null!; | ||||||
|  |  | ||||||
|  |         protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) | ||||||
|  |         { | ||||||
|  |             if (!optionsBuilder.IsConfigured) | ||||||
|  |             { | ||||||
|  |                 optionsBuilder.UseSqlite("Data Source=test.db"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         protected override void OnModelCreating(ModelBuilder modelBuilder) | ||||||
|  |         { | ||||||
|  |             modelBuilder.Entity<ElectricityLog>(entity => | ||||||
|  |             { | ||||||
|  |                 entity.HasNoKey(); | ||||||
|  |  | ||||||
|  |                 entity.ToTable("ElectricityLog"); | ||||||
|  |  | ||||||
|  |                 entity.HasIndex(e => e.Date, "idx_Date"); | ||||||
|  |  | ||||||
|  |                 entity.HasIndex(e => e.TimeUtc, "idx_TimeUtc"); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             OnModelCreatingPartial(modelBuilder); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         partial void OnModelCreatingPartial(ModelBuilder modelBuilder); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								src/Electricity.Migrator/Electricity.Migrator.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/Electricity.Migrator/Electricity.Migrator.csproj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | <Project Sdk="Microsoft.NET.Sdk"> | ||||||
|  |  | ||||||
|  |   <PropertyGroup> | ||||||
|  |     <OutputType>Exe</OutputType> | ||||||
|  |     <TargetFramework>net7.0</TargetFramework> | ||||||
|  |     <ImplicitUsings>enable</ImplicitUsings> | ||||||
|  |     <Nullable>enable</Nullable> | ||||||
|  |   </PropertyGroup> | ||||||
|  |  | ||||||
|  |   <ItemGroup> | ||||||
|  |     <PackageReference Include="EFCore.BulkExtensions" Version="7.1.6" /> | ||||||
|  |     <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.11"> | ||||||
|  |       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||||||
|  |       <PrivateAssets>all</PrivateAssets> | ||||||
|  |     </PackageReference> | ||||||
|  |     <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.11" /> | ||||||
|  |     <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" /> | ||||||
|  |     <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> | ||||||
|  |     <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.6" /> | ||||||
|  |     <PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" /> | ||||||
|  |   </ItemGroup> | ||||||
|  |  | ||||||
|  | </Project> | ||||||
							
								
								
									
										47
									
								
								src/Electricity.Migrator/Entities/ElectricityLog.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/Electricity.Migrator/Entities/ElectricityLog.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | using System.Globalization; | ||||||
|  |  | ||||||
|  | namespace Electricity.Migrator.Entities | ||||||
|  | { | ||||||
|  |     public partial class ElectricityLog | ||||||
|  |     { | ||||||
|  |         public string Date { get; set; } = null!; | ||||||
|  |         public string TimeUtc { get; set; } = null!; | ||||||
|  |         public double CurrentPowerUsage { get; set; } | ||||||
|  |         public double TotalPowerConsumptionDay { get; set; } | ||||||
|  |         public double TotalPowerConsumptionNight { get; set; } | ||||||
|  |         public double CurrentPowerReturn { get; set; } | ||||||
|  |         public double TotalPowerReturnDay { get; set; } | ||||||
|  |         public double TotalPowerReturnNight { get; set; } | ||||||
|  |         public long DayTarifEnabled { get; set; } | ||||||
|  |         public double GasConsumptionInCubicMeters { get; set; } | ||||||
|  |  | ||||||
|  |         public DateTime GetDateTime() => DateTime | ||||||
|  |             .Parse( | ||||||
|  |                 $"{Date}T{TimeUtc}Z", | ||||||
|  |                 null, | ||||||
|  |                 System.Globalization.DateTimeStyles.AssumeUniversal) | ||||||
|  |             .ToUniversalTime(); | ||||||
|  |  | ||||||
|  |         public static ElectricityLog CreateFromLine(string line) | ||||||
|  |         { | ||||||
|  |             // Example | ||||||
|  |             // 0                   1    2     3     4 5      6      7         8             9 | ||||||
|  |             // 2018-03-30T10:25:08,0.08,69.47,52.62,0,20.519,56.158,day-tarif,180330102013S,188.593 | ||||||
|  |             var parts = line.Split(','); | ||||||
|  |             var dateTimeParts = parts[0].Split('T'); | ||||||
|  |             return new ElectricityLog | ||||||
|  |             { | ||||||
|  |                 Date = dateTimeParts[0], | ||||||
|  |                 TimeUtc = dateTimeParts[1], | ||||||
|  |                 CurrentPowerUsage = double.Parse(parts[1], CultureInfo.InvariantCulture), | ||||||
|  |                 TotalPowerConsumptionDay = double.Parse(parts[2], CultureInfo.InvariantCulture), | ||||||
|  |                 TotalPowerConsumptionNight = double.Parse(parts[3], CultureInfo.InvariantCulture), | ||||||
|  |                 CurrentPowerReturn = double.Parse(parts[4], CultureInfo.InvariantCulture), | ||||||
|  |                 TotalPowerReturnDay = double.Parse(parts[5], CultureInfo.InvariantCulture), | ||||||
|  |                 TotalPowerReturnNight = double.Parse(parts[6], CultureInfo.InvariantCulture), | ||||||
|  |                 DayTarifEnabled = parts[7] == "day-tarif" ? 1 : 0, | ||||||
|  |                 GasConsumptionInCubicMeters = double.Parse(parts[9], CultureInfo.InvariantCulture), | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										52
									
								
								src/Electricity.Migrator/MigratorHostedService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/Electricity.Migrator/MigratorHostedService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | |||||||
|  |  | ||||||
|  | using EFCore.BulkExtensions; | ||||||
|  | using Electricity.Migrator.Entities; | ||||||
|  | using Electricity.Migrator.Options; | ||||||
|  | using Microsoft.Extensions.Hosting; | ||||||
|  |  | ||||||
|  | namespace Electricity.Migrator; | ||||||
|  |  | ||||||
|  | internal class MigratorHostedService : IHostedService | ||||||
|  | { | ||||||
|  |     private readonly DatabaseContext database; | ||||||
|  |     private readonly LogFileOption logFileOption; | ||||||
|  |  | ||||||
|  |     public MigratorHostedService(DatabaseContext database, LogFileOption logFileOption) | ||||||
|  |     { | ||||||
|  |         this.database = database; | ||||||
|  |         this.logFileOption = logFileOption; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task StartAsync(CancellationToken cancellationToken) | ||||||
|  |     { | ||||||
|  |         database.ChangeTracker.AutoDetectChangesEnabled = false; | ||||||
|  |         await database.Database.EnsureCreatedAsync(); | ||||||
|  |  | ||||||
|  |         foreach (var directory in Directory.EnumerateDirectories(logFileOption.Path).OrderBy(d => d)) | ||||||
|  |         { | ||||||
|  |             foreach (var file in Directory.EnumerateFiles($"{logFileOption.Path}/{directory}").OrderBy(f => f)) | ||||||
|  |             { | ||||||
|  |                 var entities = new List<ElectricityLog>(); | ||||||
|  |                 foreach (var line in await File.ReadAllLinesAsync(file)) | ||||||
|  |                 { | ||||||
|  |                     entities.Add(ElectricityLog.CreateFromLine(line)); | ||||||
|  |  | ||||||
|  |                     if (entities.Count >= 1000) | ||||||
|  |                     { | ||||||
|  |                         await database.BulkInsertAsync(entities); | ||||||
|  |                         entities.Clear(); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 await database.BulkInsertAsync(entities); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             await database.SaveChangesAsync(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public Task StopAsync(CancellationToken cancellationToken) | ||||||
|  |     { | ||||||
|  |         return Task.CompletedTask; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								src/Electricity.Migrator/Options/LogFileOption.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/Electricity.Migrator/Options/LogFileOption.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | namespace Electricity.Migrator.Options; | ||||||
|  |  | ||||||
|  | internal record LogFileOption(string Path); | ||||||
							
								
								
									
										45
									
								
								src/Electricity.Migrator/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/Electricity.Migrator/Program.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | using System.CommandLine; | ||||||
|  | using Electricity.Migrator; | ||||||
|  | using Electricity.Migrator.Options; | ||||||
|  | using Microsoft.EntityFrameworkCore; | ||||||
|  | using Microsoft.Extensions.DependencyInjection; | ||||||
|  | using Microsoft.Extensions.Hosting; | ||||||
|  |  | ||||||
|  | var rootCommand = new RootCommand("This is a migrator tool to migrate file logs to an Sqlite3 database"); | ||||||
|  |  | ||||||
|  | var connectionStringArgument = new Option<string>( | ||||||
|  |     name: "--connection-string", | ||||||
|  |     description: "Filepath to the Sqlite3 database file (*.db) to create"); | ||||||
|  | rootCommand.AddOption(connectionStringArgument); | ||||||
|  |  | ||||||
|  | var logFilePathArgument = new Option<string>( | ||||||
|  |     name: "--log-files", | ||||||
|  |     description: "Filepath directory containing the year directories of the log files"); | ||||||
|  | rootCommand.AddOption(logFilePathArgument); | ||||||
|  |  | ||||||
|  | var result = rootCommand.Parse(args); | ||||||
|  |  | ||||||
|  | if (result.Errors.Any()) | ||||||
|  | { | ||||||
|  |     foreach (var error in result.Errors) | ||||||
|  |     { | ||||||
|  |         Console.WriteLine(error.Message); | ||||||
|  |     } | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var builder = Host.CreateApplicationBuilder(args); | ||||||
|  | builder.Services.AddDbContext<DatabaseContext>((DbContextOptionsBuilder builder) => | ||||||
|  | { | ||||||
|  |     builder.UseSqlite($"Data Source={result.GetValueForOption(connectionStringArgument)}"); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | builder.Services.AddSingleton(new LogFileOption(result.GetValueForOption(logFilePathArgument))); | ||||||
|  |  | ||||||
|  | builder.Services.AddHostedService<MigratorHostedService>(); | ||||||
|  |  | ||||||
|  | var host = builder.Build(); | ||||||
|  |  | ||||||
|  | host.Run(); | ||||||
|  |  | ||||||
|  | return 0; | ||||||
							
								
								
									
										2
									
								
								tests/Solar.Api.Tests/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/Solar.Api.Tests/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | bin/ | ||||||
|  | obj/ | ||||||
							
								
								
									
										20
									
								
								tests/Solar.Api.Tests/Controllers/SolarLogController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								tests/Solar.Api.Tests/Controllers/SolarLogController.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | using Solar.Api.Models; | ||||||
|  |  | ||||||
|  | namespace Solar.Api.Tests.Controllers; | ||||||
|  |  | ||||||
|  | [Collection("Default")] | ||||||
|  | public class SolarLogController | ||||||
|  | { | ||||||
|  |     private readonly DefaultWebApplicationFactory applicationFactory; | ||||||
|  |  | ||||||
|  |     public SolarLogController(DefaultWebApplicationFactory applicationFactory) | ||||||
|  |     { | ||||||
|  |         this.applicationFactory = applicationFactory; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [Fact] | ||||||
|  |     public void GetDayDetails_returns_for_existing_data() | ||||||
|  |     { | ||||||
|  |         var client = applicationFactory.CreateClient(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								tests/Solar.Api.Tests/DefaultCollectionDefinition.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tests/Solar.Api.Tests/DefaultCollectionDefinition.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | namespace Solar.Api.Tests; | ||||||
|  |  | ||||||
|  | [CollectionDefinition("Default")] | ||||||
|  | public class DefaultCollectionDefinition : ICollectionFixture<DefaultWebApplicationFactory> | ||||||
|  | { | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								tests/Solar.Api.Tests/DefaultWebApplicationFactory.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								tests/Solar.Api.Tests/DefaultWebApplicationFactory.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | using Microsoft.AspNetCore.Hosting; | ||||||
|  | using Microsoft.AspNetCore.Mvc.Testing; | ||||||
|  | using Microsoft.AspNetCore.TestHost; | ||||||
|  | using Microsoft.EntityFrameworkCore; | ||||||
|  | using Microsoft.Extensions.DependencyInjection; | ||||||
|  |  | ||||||
|  | namespace Solar.Api.Tests; | ||||||
|  |  | ||||||
|  | public class DefaultWebApplicationFactory : WebApplicationFactory<Program> | ||||||
|  | { | ||||||
|  |     protected override void ConfigureWebHost(IWebHostBuilder builder) | ||||||
|  |     { | ||||||
|  |         builder.ConfigureTestServices(services => | ||||||
|  |         { | ||||||
|  |             services.AddDbContext<DatabaseContext>(options => | ||||||
|  |             { | ||||||
|  |                 options.UseSqlite("Data Source=test.db"); | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         builder.ConfigureServices(services => | ||||||
|  |         { | ||||||
|  |             using var provider = services.BuildServiceProvider(); | ||||||
|  |             using var scope = provider.CreateScope(); | ||||||
|  |             using var databaseContext = scope.ServiceProvider.GetRequiredService<DatabaseContext>(); | ||||||
|  |  | ||||||
|  |             databaseContext.Database.EnsureCreated(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								tests/Solar.Api.Tests/Extensions/HttpClientExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								tests/Solar.Api.Tests/Extensions/HttpClientExtensions.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | using System.Text.Json; | ||||||
|  | using Shouldly; | ||||||
|  |  | ||||||
|  | namespace Solar.Api.Tests.Extensions; | ||||||
|  |  | ||||||
|  | public static class HttpClientExtensions | ||||||
|  | { | ||||||
|  |     public static async Task<T> FetchJson<T>(this HttpClient client, string path) where T : class | ||||||
|  |     { | ||||||
|  |         var response = await client.GetAsync(path); | ||||||
|  |         response.EnsureSuccessStatusCode(); | ||||||
|  |  | ||||||
|  |         var result = JsonSerializer.Deserialize<T>(await response.Content.ReadAsStringAsync()); | ||||||
|  |         result.ShouldNotBeNull(); | ||||||
|  |  | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								tests/Solar.Api.Tests/Solar.Api.Tests.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								tests/Solar.Api.Tests/Solar.Api.Tests.csproj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | <Project Sdk="Microsoft.NET.Sdk"> | ||||||
|  |  | ||||||
|  |   <PropertyGroup> | ||||||
|  |     <TargetFramework>net7.0</TargetFramework> | ||||||
|  |     <ImplicitUsings>enable</ImplicitUsings> | ||||||
|  |     <Nullable>enable</Nullable> | ||||||
|  |  | ||||||
|  |     <IsPackable>false</IsPackable> | ||||||
|  |   </PropertyGroup> | ||||||
|  |  | ||||||
|  |   <ItemGroup> | ||||||
|  |     <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.1" /> | ||||||
|  |     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" /> | ||||||
|  |     <PackageReference Include="Shouldly" Version="4.1.0" /> | ||||||
|  |     <PackageReference Include="xunit" Version="2.4.2" /> | ||||||
|  |     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> | ||||||
|  |       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||||||
|  |       <PrivateAssets>all</PrivateAssets> | ||||||
|  |     </PackageReference> | ||||||
|  |     <PackageReference Include="coverlet.collector" Version="3.1.2"> | ||||||
|  |       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||||||
|  |       <PrivateAssets>all</PrivateAssets> | ||||||
|  |     </PackageReference> | ||||||
|  |   </ItemGroup> | ||||||
|  |  | ||||||
|  |   <ItemGroup> | ||||||
|  |     <ProjectReference Include="..\..\src\Solar.Api\Solar.Api.csproj" /> | ||||||
|  |   </ItemGroup> | ||||||
|  |  | ||||||
|  | </Project> | ||||||
							
								
								
									
										2
									
								
								tests/Solar.Api.Tests/Usings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/Solar.Api.Tests/Usings.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | global using Xunit; | ||||||
|  | global using Solar.Api.Tests.Extensions; | ||||||
							
								
								
									
										
											BIN
										
									
								
								tests/Solar.Api.Tests/test.db
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								tests/Solar.Api.Tests/test.db
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Reference in New Issue
	
	Block a user