Skip to content

Commit

Permalink
Merge pull request #37 from Team-Wilhelm/main
Browse files Browse the repository at this point in the history
data refresh update
  • Loading branch information
juuwel authored May 29, 2024
2 parents 8d432fb + d821085 commit 243740c
Show file tree
Hide file tree
Showing 36 changed files with 659 additions and 343 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,4 @@ jobs:
MQTT_CLIENT_ID: ${{ secrets.MQTT_CLIENT_ID }}
MQTT_SUBSCRIBE_TOPIC: ${{ secrets.MQTT_SUBSCRIBE_TOPIC }}
MQTT_PUBLISH_TOPIC: ${{ secrets.MQTT_PUBLISH_TOPIC }}

AZURE_VISION_KEY: ${{ secrets.AZURE_VISION_KEY }}
AZURE_VISION_ENDPOINT: ${{ secrets.AZURE_VISION_ENDPOINT }}
run: cd Tests && dotnet test
168 changes: 0 additions & 168 deletions Infrastructure/ApplicationDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,172 +54,4 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)

base.OnModelCreating(modelBuilder);
}

public async Task SeedDevelopmentDataAsync(IServiceScope scope, string defaultPlantImage)
{
var userRepository = scope.ServiceProvider.GetRequiredService<UserRepository>();
await userRepository.CreateUser(new RegisterUserDto
{
Email = "[email protected]",
Password = "password",
Username = "bob"
});

var collectionsRepository = scope.ServiceProvider.GetRequiredService<CollectionsRepository>();
var collection1 = await collectionsRepository.CreateCollection(
new Collection
{
CollectionId = Guid.NewGuid(),
Name = "Succulents",
UserEmail = "[email protected]",
}
);
var collection2 = await collectionsRepository.CreateCollection(
new Collection
{
CollectionId = Guid.NewGuid(),
Name = "Cacti",
UserEmail = "[email protected]",
}
);

var plantRepository = scope.ServiceProvider.GetRequiredService<PlantRepository>();
await plantRepository.CreatePlant(
new Plant
{
PlantId = Guid.NewGuid(),
Nickname = "Aloe Vera",
UserEmail = "[email protected]",
ImageUrl = defaultPlantImage,
CollectionId = collection1.CollectionId,
LatestChange = DateTime.UtcNow.Subtract(TimeSpan.FromDays(5))
}
);

await plantRepository.CreatePlant(
new Plant
{
PlantId = Guid.NewGuid(),
Nickname = "Prickly Pear",
UserEmail = "[email protected]",
ImageUrl = defaultPlantImage,
CollectionId = collection2.CollectionId,
LatestChange = DateTime.UtcNow.Subtract(TimeSpan.FromDays(7))
}
);

await plantRepository.CreatePlant(
new Plant
{
PlantId = Guid.NewGuid(),
Nickname = "Dying plant",
UserEmail = "[email protected]",
ImageUrl = defaultPlantImage,
CollectionId = collection2.CollectionId,
LatestChange = DateTime.UtcNow
}
);

var plants = await plantRepository.GetPlantsForUser("[email protected]", 1, 5);

var requirementsRepository = scope.ServiceProvider.GetRequiredService<RequirementsRepository>();
await requirementsRepository.CreateRequirements(
new Requirements
{
RequirementsId = Guid.NewGuid(),
PlantId = plants.First(p => p.Nickname == "Aloe Vera").PlantId,
LightLevel = RequirementLevel.Low,
SoilMoistureLevel = RequirementLevel.Medium,
HumidityLevel = RequirementLevel.High,
TemperatureLevel = 22,
}
);

await requirementsRepository.CreateRequirements(
new Requirements
{
RequirementsId = Guid.NewGuid(),
PlantId = plants.First(p => p.Nickname == "Prickly Pear").PlantId,
LightLevel = RequirementLevel.High,
SoilMoistureLevel = RequirementLevel.Low,
HumidityLevel = RequirementLevel.Low,
TemperatureLevel = 27,
}
);

await requirementsRepository.CreateRequirements(
new Requirements
{
RequirementsId = Guid.NewGuid(),
PlantId = plants.First(p => p.Nickname == "Dying plant").PlantId,
LightLevel = RequirementLevel.High,
SoilMoistureLevel = RequirementLevel.Low,
HumidityLevel = RequirementLevel.Medium,
TemperatureLevel = 24,
}
);

var conditionsLogRepository = scope.ServiceProvider.GetRequiredService<ConditionsLogsRepository>();

for (var i = 0; i < 100; i++)
{
await conditionsLogRepository.CreateConditionsLogAsync(
GetRandomConditionsLog(plants.First(p => p.Nickname == "Prickly Pear").PlantId, i * 6)
);
await conditionsLogRepository.CreateConditionsLogAsync(
GetRandomConditionsLog(plants.First(p => p.Nickname == "Aloe Vera").PlantId, i * 6)
);
}

await conditionsLogRepository.CreateConditionsLogAsync(
new ConditionsLog()
{
ConditionsId = Guid.NewGuid(),
PlantId = plants.First(p => p.Nickname == "Dying plant").PlantId,
TimeStamp = DateTime.UtcNow,
Mood = 0,
SoilMoisture = 55,
Light = 13,
Humidity = 68,
Temperature = 25,
}
);

Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Seeded development data");
Console.ResetColor();
}

private double GetRandomLevelValue()
{
var random = new Random();
return random.NextDouble() * 100;
}

private int GetRandomMood()
{
var random = new Random();
return random.Next(0, 5);
}

private int GetRandomTemperature()
{
var random = new Random();
return random.Next(-20, 45);
}

private ConditionsLog GetRandomConditionsLog(Guid plantId, int hoursAgo = 0)
{
return new ConditionsLog
{
ConditionsId = Guid.NewGuid(),
PlantId = plantId,
TimeStamp = DateTime.UtcNow.Subtract(TimeSpan.FromHours(hoursAgo)),
Mood = GetRandomMood(),
SoilMoisture = GetRandomLevelValue(),
Light = GetRandomLevelValue(),
Temperature = GetRandomTemperature(),
Humidity = GetRandomLevelValue(),
};
}
}
7 changes: 0 additions & 7 deletions Infrastructure/Repositories/CollectionsRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,4 @@ public async Task RemovePlantFromCollection(Collection collection, Plant plant)
collection.Plants.Remove(plant);
await applicationDbContext.SaveChangesAsync();
}

public async Task<int> GetTotalCollectionsCount(string email)
{
await using var applicationDbContext = await dbContextFactory.CreateDbContextAsync();
return await applicationDbContext.Collections
.CountAsync(collection => collection.UserEmail == email);
}
}
29 changes: 19 additions & 10 deletions Infrastructure/Repositories/PlantRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@ public class PlantRepository(IDbContextFactory<ApplicationDbContext> dbContextFa
public async Task CreatePlant(Plant plant)
{
await using var context = await dbContextFactory.CreateDbContextAsync();

await context.Plants.AddAsync(plant);
await context.SaveChangesAsync();
}

public async Task<bool> DoesDeviceIdExist(string deviceId)
{
await using var context = await dbContextFactory.CreateDbContextAsync();
return await context.Plants.AnyAsync(p => p.DeviceId == deviceId);
}

public async Task<Plant?> GetPlantById(Guid id)
{
Expand Down Expand Up @@ -98,7 +105,7 @@ public async Task<List<Plant>> GetCriticalPlants(string requesterEmail)
await using var context = await dbContextFactory.CreateDbContextAsync();
return await context.Plants
.Include(plant => plant.Requirements)
.Include(plant => plant.ConditionsLogs)
.Include(plant => plant.ConditionsLogs.OrderByDescending(log => log.TimeStamp).Take(1))
.Where(p => p.UserEmail == requesterEmail && p.ConditionsLogs.Count != 0)
.Select(p => new
{
Expand All @@ -114,20 +121,22 @@ public async Task<List<Plant>> GetCriticalPlants(string requesterEmail)
.Select(p => p.Plant)
.ToListAsync();
}

public async Task<int> GetHappyPlantsCount(string userEmail)
public async Task<Stats> GetStats(string userEmail)
{
await using var context = await dbContextFactory.CreateDbContextAsync();
return await context.Plants
var totalPlants = await context.Plants.CountAsync(p => p.UserEmail == userEmail);
var happyPlants = await context.Plants
.Include(plant => plant.ConditionsLogs)
.Where(p => p.UserEmail == userEmail && p.ConditionsLogs.Count != 0)
.CountAsync(p => p.ConditionsLogs.OrderByDescending(log => log.TimeStamp).FirstOrDefault()!.Mood > 2);
}
var collections = await context.Collections.CountAsync(c => c.UserEmail == userEmail);

public async Task<int> GetTotalPlantsCount(string userEmail)
{
await using var context = await dbContextFactory.CreateDbContextAsync();
return await context.Plants
.CountAsync(p => p.UserEmail == userEmail);
return new Stats
{
TotalPlants = totalPlants,
HappyPlants = happyPlants,
Collections = collections
};
}
}
2 changes: 1 addition & 1 deletion Shared/Dtos/CreateConditionsLogDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ public class CreateConditionsLogDto
public double Light { get; set; }
public double Temperature { get; set; }
public double Humidity { get; set; }
public long DeviceId { get; set; }
public required string DeviceId { get; set; }
}
8 changes: 8 additions & 0 deletions Shared/Models/Stats.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Shared.Models;

public class Stats
{
public int TotalPlants { get; set; }
public int HappyPlants { get; set; }
public int Collections { get; set; }
}
17 changes: 12 additions & 5 deletions Tests/PlantTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using api.Events.Collections.Server;
using api.Events.PlantEvents.Client;
using api.Events.PlantEvents.Server;
using lib;
Expand All @@ -15,16 +14,24 @@ public async Task CreatePlant()
{
var jwtAndEmail = await SignUpAndLogIn();
var jwt = jwtAndEmail[DictionaryKeys.Jwt];
var email = jwtAndEmail[DictionaryKeys.Email];
var createPlantDto = GenerateRandomCreatePlantDto(email);
var createPlantDto = GenerateRandomCreatePlantDto();

var webSocketTestClient = await new WebSocketTestClient().ConnectAsync();

await webSocketTestClient.DoAndAssert(new ClientWantsToCreatePlantDto { CreatePlantDto = createPlantDto, Jwt = jwt }, receivedMessages =>
{
return receivedMessages.Count(e => e.eventType == nameof(ServerSavesPlant)) == 1;
});

}

[Test]
public async Task GetAllPlants()
{
var jwtAndEmail = await SignUpAndLogIn();
var jwt = jwtAndEmail[DictionaryKeys.Jwt];

var webSocketTestClient = await new WebSocketTestClient().ConnectAsync();

await webSocketTestClient.DoAndAssert(new ClientWantsAllPlantsDto
{
Jwt = jwt,
Expand All @@ -36,7 +43,7 @@ await webSocketTestClient.DoAndAssert(new ClientWantsAllPlantsDto
});
}

private CreatePlantDto GenerateRandomCreatePlantDto(string email)
private CreatePlantDto GenerateRandomCreatePlantDto()
{
var createPlantDto = new CreatePlantDto
{
Expand Down
4 changes: 3 additions & 1 deletion Tests/TestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ await webSocketTestClient.DoAndAssert(new ClientWantsToSignUpDto { RegisterUserD

var jwtSubscription = webSocketTestClient.Client.MessageReceived.Subscribe(msg =>
{
var eventType = JsonSerializer.Deserialize<BaseDto>(msg.Text).eventType;
if (eventType != nameof(ServerAuthenticatesUser)) return;
var serverAuthenticates = JsonSerializer.Deserialize<ServerAuthenticatesUser>(msg.Text, options: new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
jwt = serverAuthenticates.Jwt;
jwt = serverAuthenticates!.Jwt;
});
webSocketTestClient.Send(new ClientWantsToLogInDto { LoginDto = loginDto });

Expand Down
69 changes: 69 additions & 0 deletions Tests/WebSocketTestClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.Text.Json;
using api.Events.Global;
using lib;
using Websocket.Client;

namespace Tests
{
public class WebSocketTestClient
{
public readonly WebsocketClient Client;
public readonly List<BaseDto> ReceivedMessages = [];
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
{
PropertyNameCaseInsensitive = true
};

public WebSocketTestClient(string? url = null)
{
Client = url == null ? new WebsocketClient(new Uri("ws://localhost:" + (Environment.GetEnvironmentVariable("FULLSTACK_API_PORT") ?? "8181"))) : new WebsocketClient(new Uri(url));
Client.MessageReceived.Subscribe(msg =>
{
BaseDto baseDto = JsonSerializer.Deserialize<BaseDto>(msg.Text, JsonSerializerOptions);

if (baseDto.eventType == "ServerSendsErrorMessage" || baseDto.eventType.Contains("ServerResponds") ||
baseDto.eventType.Contains("ServerRejects"))
{
var error = JsonSerializer.Deserialize<ServerSendsErrorMessage>(msg.Text, JsonSerializerOptions);
Console.WriteLine("Error: " + error!.Error);
}

lock (ReceivedMessages)
ReceivedMessages.Add(baseDto);
});
}

public async Task<WebSocketTestClient> ConnectAsync()
{
await Client.Start();
if (!Client.IsRunning)
throw new Exception("Could not start client!");
return this;
}

public void Send<T>(T dto) where T : BaseDto
{
Client.Send(JsonSerializer.Serialize(dto));
}

public async Task DoAndAssert<T>(T? action = null, Func<List<BaseDto>, bool>? condition = null) where T : BaseDto
{
if ((object) (T) action != null)
Send(action);
if (condition != null)
{
DateTime startTime = DateTime.UtcNow;
while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(5.0))
{
lock (ReceivedMessages)
{
if (condition(ReceivedMessages))
return;
}
await Task.Delay(100);
}
throw new TimeoutException("Condition not met: ");
}
}
}
}
Loading

0 comments on commit 243740c

Please sign in to comment.