Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/refactor-processing' into downlo…
Browse files Browse the repository at this point in the history
…ad-data
  • Loading branch information
tschumpr committed Apr 24, 2024
2 parents b6b1992 + a06f011 commit e67e9c9
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 129 deletions.
119 changes: 26 additions & 93 deletions Geodatenbezug.Test/GeodiensteApiTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ namespace Geodatenbezug;
[DeploymentItem("testdata/lwb_perimeter_terrassenreben_lv95_no_gpkg.zip", "testdata")]
public class GeodiensteApiTest
{
private readonly Topic topic = new ()
{
BaseTopic = BaseTopic.lwb_perimeter_ln_sf,
TopicTitle = "Perimeter LN- und Sömmerungsflächen",
Canton = Canton.ZG,
UpdatedAt = DateTime.Now.AddHours(-23),
};

private Mock<ILogger<GeodiensteApi>> loggerMock;
private Mock<IHttpClientFactory> httpClientFactoryMock;
private HttpTestMessageHandler httpTestMessageHandler;
Expand Down Expand Up @@ -42,15 +50,13 @@ public async Task RequestTopicInfoAsync()
new Topic
{
BaseTopic = BaseTopic.lwb_perimeter_ln_sf,
TopicName = "lwb_perimeter_ln_sf_v2_0",
TopicTitle = "Perimeter LN- und Sömmerungsflächen",
Canton = Canton.ZG,
UpdatedAt = DateTime.Now.AddHours(-23),
},
new Topic
{
BaseTopic = BaseTopic.lwb_rebbaukataster,
TopicName = "lwb_rebbaukataster_v2_0",
TopicTitle = "Rebbaukataster",
Canton = Canton.ZG,
UpdatedAt = null,
Expand Down Expand Up @@ -87,14 +93,6 @@ public async Task RequestTopicInfoAsyncFails()
[TestMethod]
public async Task StartExportAsync()
{
var topic = new Topic
{
BaseTopic = BaseTopic.lwb_perimeter_ln_sf,
TopicName = "lwb_perimeter_ln_sf_v2_0",
TopicTitle = "Perimeter LN- und Sömmerungsflächen",
Canton = Canton.ZG,
UpdatedAt = DateTime.Now.AddHours(-23),
};
httpTestMessageHandler.SetTestMessageResponses(
[
new () { Code = HttpStatusCode.NotFound, Content = "{\"error\":\"Cannot start data export because there is another data export pending\"}" },
Expand All @@ -103,28 +101,14 @@ public async Task StartExportAsync()
httpClientFactoryMock.Setup(cf => cf.CreateClient(It.IsAny<string>())).Returns(httpTestMessageHandler.ToHttpClient()).Verifiable();
loggerMock.Setup(LogLevel.Information, "Starte den Datenexport für Perimeter LN- und Sömmerungsflächen (ZG) mit https://geodienste.ch/downloads/lwb_perimeter_ln_sf/1234567890/export.json...", Times.Once());
loggerMock.Setup(LogLevel.Information, "Es läuft gerade ein anderer Export. Versuche es in 1 Minute erneut.", Times.Once());
var mockGeodiensteApi = new Mock<GeodiensteApi>(loggerMock.Object, httpClientFactoryMock.Object)
{
CallBase = true,
};
mockGeodiensteApi.Setup(api => api.GetWaitDuration()).Returns(TimeSpan.Zero);
mockGeodiensteApi.Setup(api => api.GetToken(It.IsAny<BaseTopic>(), It.IsAny<Canton>())).Returns("1234567890");

var result = await mockGeodiensteApi.Object.StartExportAsync(topic);
var result = await CreateGeodiensteApiMock().StartExportAsync(topic);
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
}

[TestMethod]
public async Task StartExportAsyncTimeout()
{
var topic = new Topic
{
BaseTopic = BaseTopic.lwb_perimeter_ln_sf,
TopicName = "lwb_perimeter_ln_sf_v2_0",
TopicTitle = "Perimeter LN- und Sömmerungsflächen",
Canton = Canton.ZG,
UpdatedAt = DateTime.Now.AddHours(-23),
};
httpTestMessageHandler.SetTestMessageResponses(
[
new () { Code = HttpStatusCode.NotFound, Content = "{\"error\":\"Cannot start data export because there is another data export pending\"}" },
Expand All @@ -143,56 +127,28 @@ public async Task StartExportAsyncTimeout()
loggerMock.Setup(LogLevel.Information, "Starte den Datenexport für Perimeter LN- und Sömmerungsflächen (ZG) mit https://geodienste.ch/downloads/lwb_perimeter_ln_sf/1234567890/export.json...", Times.Once());
loggerMock.Setup(LogLevel.Information, "Es läuft gerade ein anderer Export. Versuche es in 1 Minute erneut.", Times.Exactly(9));
loggerMock.Setup(LogLevel.Error, "Es läuft bereits ein anderer Export. Zeitlimite überschritten.", Times.Once());
var mockGeodiensteApi = new Mock<GeodiensteApi>(loggerMock.Object, httpClientFactoryMock.Object)
{
CallBase = true,
};
mockGeodiensteApi.Setup(api => api.GetWaitDuration()).Returns(TimeSpan.Zero);
mockGeodiensteApi.Setup(api => api.GetToken(It.IsAny<BaseTopic>(), It.IsAny<Canton>())).Returns("1234567890");

var result = await mockGeodiensteApi.Object.StartExportAsync(topic);
var result = await CreateGeodiensteApiMock().StartExportAsync(topic);
Assert.AreEqual(HttpStatusCode.NotFound, result.StatusCode);
}

[TestMethod]
public async Task StartExportAsyncFails()
{
var topic = new Topic
{
BaseTopic = BaseTopic.lwb_perimeter_ln_sf,
TopicName = "lwb_perimeter_ln_sf_v2_0",
TopicTitle = "Perimeter LN- und Sömmerungsflächen",
Canton = Canton.ZG,
UpdatedAt = DateTime.Now.AddHours(-23),
};
httpTestMessageHandler.SetTestMessageResponses(
[
new () { Code = HttpStatusCode.Unauthorized },
]);
httpClientFactoryMock.Setup(cf => cf.CreateClient(It.IsAny<string>())).Returns(httpTestMessageHandler.ToHttpClient()).Verifiable();
loggerMock.Setup(LogLevel.Information, "Starte den Datenexport für Perimeter LN- und Sömmerungsflächen (ZG) mit https://geodienste.ch/downloads/lwb_perimeter_ln_sf/1234567890/export.json...", Times.Once());
var mockGeodiensteApi = new Mock<GeodiensteApi>(loggerMock.Object, httpClientFactoryMock.Object)
{
CallBase = true,
};
mockGeodiensteApi.Setup(api => api.GetWaitDuration()).Returns(TimeSpan.Zero);
mockGeodiensteApi.Setup(api => api.GetToken(It.IsAny<BaseTopic>(), It.IsAny<Canton>())).Returns("1234567890");

var result = await mockGeodiensteApi.Object.StartExportAsync(topic);
var result = await CreateGeodiensteApiMock().StartExportAsync(topic);
Assert.AreEqual(HttpStatusCode.Unauthorized, result.StatusCode);
}

[TestMethod]
public async Task CheckExportStatusAsync()
{
var topic = new Topic
{
BaseTopic = BaseTopic.lwb_perimeter_ln_sf,
TopicName = "lwb_perimeter_ln_sf_v2_0",
TopicTitle = "Perimeter LN- und Sömmerungsflächen",
Canton = Canton.ZG,
UpdatedAt = DateTime.Now.AddHours(-23),
};
var responseJson1 = new GeodiensteStatusSuccess()
{
Status = GeodiensteStatus.Queued,
Expand All @@ -218,29 +174,15 @@ public async Task CheckExportStatusAsync()
loggerMock.Setup(LogLevel.Information, "Prüfe den Status des Datenexports für Perimeter LN- und Sömmerungsflächen (ZG) mit https://geodienste.ch/downloads/lwb_perimeter_ln_sf/1234567890/status.json...", Times.Once());
loggerMock.Setup(LogLevel.Information, "Export ist in der Warteschlange. Versuche es in 1 Minute erneut.", Times.Once());
loggerMock.Setup(LogLevel.Information, "Export ist in Bearbeitung. Versuche es in 1 Minute erneut.", Times.Once());
var mockGeodiensteApi = new Mock<GeodiensteApi>(loggerMock.Object, httpClientFactoryMock.Object)
{
CallBase = true,
};
mockGeodiensteApi.Setup(api => api.GetWaitDuration()).Returns(TimeSpan.Zero);
mockGeodiensteApi.Setup(api => api.GetToken(It.IsAny<BaseTopic>(), It.IsAny<Canton>())).Returns("1234567890");

var result = await mockGeodiensteApi.Object.CheckExportStatusAsync(topic);
var result = await CreateGeodiensteApiMock().CheckExportStatusAsync(topic);
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
Assert.AreEqual(GeodiensteStatus.Success, JsonSerializer.Deserialize<GeodiensteStatusSuccess>(await result.Content.ReadAsStringAsync()).Status);
}

[TestMethod]
public async Task CheckExportStatusAsyncTimeout()
{
var topic = new Topic
{
BaseTopic = BaseTopic.lwb_perimeter_ln_sf,
TopicName = "lwb_perimeter_ln_sf_v2_0",
TopicTitle = "Perimeter LN- und Sömmerungsflächen",
Canton = Canton.ZG,
UpdatedAt = DateTime.Now.AddHours(-23),
};
httpTestMessageHandler.SetTestMessageResponses(
[
new () { Code = HttpStatusCode.OK, Content = "{\"status\":\"queued\",\"info\":\"Try again later.\",\"download_url\":null,\"exported_at\":null}" },
Expand All @@ -260,43 +202,23 @@ public async Task CheckExportStatusAsyncTimeout()
loggerMock.Setup(LogLevel.Information, "Export ist in der Warteschlange. Versuche es in 1 Minute erneut.", Times.Exactly(7));
loggerMock.Setup(LogLevel.Information, "Export ist in Bearbeitung. Versuche es in 1 Minute erneut.", Times.Exactly(2));
loggerMock.Setup(LogLevel.Error, "Zeitlimite überschritten. Status ist in Bearbeitung", Times.Once());
var mockGeodiensteApi = new Mock<GeodiensteApi>(loggerMock.Object, httpClientFactoryMock.Object)
{
CallBase = true,
};
mockGeodiensteApi.Setup(api => api.GetWaitDuration()).Returns(TimeSpan.Zero);
mockGeodiensteApi.Setup(api => api.GetToken(It.IsAny<BaseTopic>(), It.IsAny<Canton>())).Returns("1234567890");

var result = await mockGeodiensteApi.Object.CheckExportStatusAsync(topic);
var result = await CreateGeodiensteApiMock().CheckExportStatusAsync(topic);
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
Assert.AreEqual(GeodiensteStatus.Working, JsonSerializer.Deserialize<GeodiensteStatusSuccess>(await result.Content.ReadAsStringAsync()).Status);
}

[TestMethod]
public async Task CheckExportStatusAsyncFails()
{
var topic = new Topic
{
BaseTopic = BaseTopic.lwb_perimeter_ln_sf,
TopicName = "lwb_perimeter_ln_sf_v2_0",
TopicTitle = "Perimeter LN- und Sömmerungsflächen",
Canton = Canton.ZG,
UpdatedAt = DateTime.Now.AddHours(-23),
};
httpTestMessageHandler.SetTestMessageResponses(
[
new () { Code = HttpStatusCode.Unauthorized },
]);
httpClientFactoryMock.Setup(cf => cf.CreateClient(It.IsAny<string>())).Returns(httpTestMessageHandler.ToHttpClient()).Verifiable();
loggerMock.Setup(LogLevel.Information, "Prüfe den Status des Datenexports für Perimeter LN- und Sömmerungsflächen (ZG) mit https://geodienste.ch/downloads/lwb_perimeter_ln_sf/1234567890/status.json...", Times.Once());
var mockGeodiensteApi = new Mock<GeodiensteApi>(loggerMock.Object, httpClientFactoryMock.Object)
{
CallBase = true,
};
mockGeodiensteApi.Setup(api => api.GetWaitDuration()).Returns(TimeSpan.Zero);
mockGeodiensteApi.Setup(api => api.GetToken(It.IsAny<BaseTopic>(), It.IsAny<Canton>())).Returns("1234567890");

var result = await mockGeodiensteApi.Object.CheckExportStatusAsync(topic);
var result = await CreateGeodiensteApiMock().CheckExportStatusAsync(topic);
Assert.AreEqual(HttpStatusCode.Unauthorized, result.StatusCode);
}

Expand Down Expand Up @@ -365,9 +287,20 @@ public void GetTokenFailsNoKey()
}

[TestMethod]
public void GetTokenFailsNoTokens()
public void GetTokenFailsWithMissingTokenForTopic()
{
var api = new GeodiensteApi(loggerMock.Object, httpClientFactoryMock.Object);
Assert.ThrowsException<InvalidOperationException>(() => api.GetToken(BaseTopic.lwb_bewirtschaftungseinheit, Canton.AI), "No tokens available for topic lwb_bewirtschaftungseinheit");
}

private GeodiensteApi CreateGeodiensteApiMock()
{
var mockGeodiensteApi = new Mock<GeodiensteApi>(loggerMock.Object, httpClientFactoryMock.Object)
{
CallBase = true,
};
mockGeodiensteApi.Setup(api => api.GetWaitDuration()).Returns(TimeSpan.Zero);
mockGeodiensteApi.Setup(api => api.GetToken(It.IsAny<BaseTopic>(), It.IsAny<Canton>())).Returns("1234567890");
return mockGeodiensteApi.Object;
}
}
4 changes: 0 additions & 4 deletions Geodatenbezug.Test/ProcessingTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,31 +36,27 @@ public async Task GetTopicsToUpdate()
new ()
{
BaseTopic = BaseTopic.lwb_perimeter_ln_sf,
TopicName = "lwb_perimeter_ln_sf_v2_0",
TopicTitle = "Perimeter LN- und Sömmerungsflächen",
Canton = Canton.SH,
UpdatedAt = datestring_delta4,
},
new ()
{
BaseTopic = BaseTopic.lwb_perimeter_ln_sf,
TopicName = "lwb_perimeter_ln_sf_v2_0",
TopicTitle = "Perimeter LN- und Sömmerungsflächen",
Canton = Canton.ZG,
UpdatedAt = datestring_delta23,
},
new ()
{
BaseTopic = BaseTopic.lwb_rebbaukataster,
TopicName = "lwb_rebbaukataster_v2_0",
TopicTitle = "Rebbaukataster",
Canton = Canton.SH,
UpdatedAt = datestring_delta30,
},
new ()
{
BaseTopic = BaseTopic.lwb_rebbaukataster,
TopicName = "lwb_rebbaukataster_v2_0",
TopicTitle = "Rebbaukataster",
Canton = Canton.ZG,
UpdatedAt = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public class NutzungsflaechenProcessorTest
{
TopicTitle = BaseTopic.lwb_nutzungsflaechen.GetDescription(),
Canton = Canton.AG,
TopicName = BaseTopic.lwb_nutzungsflaechen.ToString() + "_v2_0",
BaseTopic = BaseTopic.lwb_nutzungsflaechen,
UpdatedAt = DateTime.Now,
};
Expand Down Expand Up @@ -42,7 +41,6 @@ public async Task PrepareDataAsync()
{
TopicTitle = BaseTopic.lwb_bewirtschaftungseinheit.GetDescription(),
Canton = topic.Canton,
TopicName = BaseTopic.lwb_bewirtschaftungseinheit.ToString() + "_v2_0",
BaseTopic = BaseTopic.lwb_bewirtschaftungseinheit,
};

Expand Down
2 changes: 0 additions & 2 deletions Geodatenbezug.Test/Processors/TopicProcessorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public class TopicProcessorTest
{
TopicTitle = BaseTopic.lwb_rebbaukataster.GetDescription(),
Canton = Canton.AG,
TopicName = BaseTopic.lwb_rebbaukataster.ToString() + "_v2_0",
BaseTopic = BaseTopic.lwb_rebbaukataster,
UpdatedAt = DateTime.Now,
};
Expand Down Expand Up @@ -100,7 +99,6 @@ public async Task ExportTopicStartExportFails()
loggerMock.Setup(LogLevel.Information, $"Exportiere {topic.TopicTitle} ({topic.Canton})...");
loggerMock.Setup(LogLevel.Error, $"Fehler beim Starten des Exports für Thema {topic.TopicTitle} ({topic.Canton}): {HttpStatusCode.NotFound} - Data export information not found. Invalid token?");

// TODO: Check processingResult
await Assert.ThrowsExceptionAsync<InvalidOperationException>(async () => await processor.ExportTopicAsync(topic), "Export failed");
Assert.AreEqual(processingResult.Code, processor.ProcessingResult.Code);
Assert.AreEqual(processingResult.Reason, processor.ProcessingResult.Reason);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Geodatenbezug;
/// <summary>
/// Provides helper methods for <c>enum</c> handling.
/// </summary>
public static class EnumHelper
public static class EnumExtensions
{
/// <summary>
/// Retrieves the description of the given <c>enum</c> value. If the <c>enum</c> value does not have a <c>DescriptionAttribute</c>, the <c>enum</c> value itself is returned.
Expand Down
6 changes: 0 additions & 6 deletions Geodatenbezug/Models/Topic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ public record Topic
[JsonConverter(typeof(JsonStringEnumConverter))]
required public Canton Canton { get; set; }

/// <summary>
/// Topic name, usually base topic name plus version.
/// </summary>
[JsonPropertyName("topic")]
required public string TopicName { get; set; }

/// <summary>
/// Topic title.
/// </summary>
Expand Down
41 changes: 20 additions & 21 deletions Geodatenbezug/Processors/NutzungsflaechenProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,25 @@ protected internal override async Task PrepareDataAsync()
{
Logger.LogInformation($"Bereite Daten für die Prozessierung von {Topic.TopicTitle} ({Topic.Canton}) vor...");

var tasks = new List<Task>
{
Task.Run(async () =>
{
var downloadUrl = await ExportTopicAsync(Topic).ConfigureAwait(false);
InputDataPath = await GeodiensteApi.DownloadExportAsync(downloadUrl, DataDirectory).ConfigureAwait(false);
}),
Task.Run(async () =>
{
var bewirtschaftungseinheitTopic = new Topic()
{
TopicTitle = BaseTopic.lwb_bewirtschaftungseinheit.GetDescription(),
Canton = Topic.Canton,
TopicName = BaseTopic.lwb_bewirtschaftungseinheit.ToString() + "_v2_0",
BaseTopic = BaseTopic.lwb_bewirtschaftungseinheit,
};
var downloadUrl = await ExportTopicAsync(bewirtschaftungseinheitTopic).ConfigureAwait(false);
bewirtschaftungseinheitDataPath = await GeodiensteApi.DownloadExportAsync(downloadUrl, DataDirectory).ConfigureAwait(false);
}),
};
await Task.WhenAll(tasks).ConfigureAwait(false);
var exportInputTopic = PrepareTopic(Topic);

var bewirtschaftungseinheitTopic = new Topic()
{
TopicTitle = BaseTopic.lwb_bewirtschaftungseinheit.GetDescription(),
Canton = Topic.Canton,
BaseTopic = BaseTopic.lwb_bewirtschaftungseinheit,
};
var exportBewirtschaftungseinheitTopic = PrepareTopic(bewirtschaftungseinheitTopic);

var downloadUrls = await Task.WhenAll(exportInputTopic, exportBewirtschaftungseinheitTopic).ConfigureAwait(false);

InputDataPath = downloadUrls[0];
bewirtschaftungseinheitDataPath = downloadUrls[1];
}

private async Task<string> PrepareTopic(Topic topic)
{
var downloadUrl = await ExportTopicAsync(topic).ConfigureAwait(false);
return await GeodiensteApi.DownloadExportAsync(downloadUrl, DataDirectory).ConfigureAwait(false);
}
}

0 comments on commit e67e9c9

Please sign in to comment.