Prefer forecast hi lo for current weather
This commit is contained in:
@@ -173,25 +173,22 @@ public sealed class OpenWeatherReportProvider(
|
|||||||
var temperature = TryReadInt(main, "temp");
|
var temperature = TryReadInt(main, "temp");
|
||||||
var high = TryReadInt(main, "temp_max");
|
var high = TryReadInt(main, "temp_max");
|
||||||
var low = TryReadInt(main, "temp_min");
|
var low = TryReadInt(main, "temp_min");
|
||||||
if (ShouldEnrichCurrentDayHighLow(temperature, high, low))
|
try
|
||||||
{
|
{
|
||||||
try
|
var enrichedBand = await TryResolveCurrentDayHighLowFromForecastAsync(
|
||||||
|
location,
|
||||||
|
useCelsius,
|
||||||
|
cancellationToken);
|
||||||
|
if (enrichedBand is not null)
|
||||||
{
|
{
|
||||||
var enrichedBand = await TryResolveCurrentDayHighLowFromForecastAsync(
|
high = enrichedBand.Value.High ?? high;
|
||||||
location,
|
low = enrichedBand.Value.Low ?? low;
|
||||||
useCelsius,
|
|
||||||
cancellationToken);
|
|
||||||
if (enrichedBand is not null)
|
|
||||||
{
|
|
||||||
high = enrichedBand.Value.High ?? high;
|
|
||||||
low = enrichedBand.Value.Low ?? low;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception exception) when (!cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
logger.LogDebug(exception, "OpenWeather forecast enrichment failed for current-day Hi/Lo.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception exception) when (!cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
logger.LogDebug(exception, "OpenWeather forecast enrichment failed for current-day Hi/Lo.");
|
||||||
|
}
|
||||||
|
|
||||||
if (temperature is null && high is null && low is null)
|
if (temperature is null && high is null && low is null)
|
||||||
{
|
{
|
||||||
@@ -492,21 +489,6 @@ public sealed class OpenWeatherReportProvider(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ShouldEnrichCurrentDayHighLow(int? temperature, int? high, int? low)
|
|
||||||
{
|
|
||||||
if (high is null || low is null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (high.Value != low.Value)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return temperature is null || high.Value == temperature.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string BuildWeatherCacheKey(LocationPoint location, bool useCelsius, int forecastDayOffset)
|
private static string BuildWeatherCacheKey(LocationPoint location, bool useCelsius, int forecastDayOffset)
|
||||||
{
|
{
|
||||||
return string.Create(
|
return string.Create(
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public sealed class ProviderCachingTests
|
|||||||
Assert.NotNull(second);
|
Assert.NotNull(second);
|
||||||
Assert.Equal(1, handler.GetCallCount("/geo/1.0/direct"));
|
Assert.Equal(1, handler.GetCallCount("/geo/1.0/direct"));
|
||||||
Assert.Equal(1, handler.GetCallCount("/data/2.5/weather"));
|
Assert.Equal(1, handler.GetCallCount("/data/2.5/weather"));
|
||||||
Assert.Equal(0, handler.GetCallCount("/data/2.5/forecast"));
|
Assert.Equal(1, handler.GetCallCount("/data/2.5/forecast"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -91,6 +91,50 @@ public sealed class ProviderCachingTests
|
|||||||
Assert.Equal(1, handler.GetCallCount("/data/2.5/forecast"));
|
Assert.Equal(1, handler.GetCallCount("/data/2.5/forecast"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task OpenWeatherReportProvider_UsesForecastHiLoForCurrentDay_WhenCurrentBandDiffers()
|
||||||
|
{
|
||||||
|
var utcStart = DateTimeOffset.UtcNow.UtcDateTime.Date;
|
||||||
|
var forecastWindowStart = new DateTimeOffset(utcStart, TimeSpan.Zero).ToUnixTimeSeconds();
|
||||||
|
var forecastWindowMid = new DateTimeOffset(utcStart.AddHours(3), TimeSpan.Zero).ToUnixTimeSeconds();
|
||||||
|
var forecastWindowLate = new DateTimeOffset(utcStart.AddHours(6), TimeSpan.Zero).ToUnixTimeSeconds();
|
||||||
|
|
||||||
|
var handler = new CountingHttpMessageHandler(message =>
|
||||||
|
{
|
||||||
|
var path = message.RequestUri?.AbsolutePath ?? string.Empty;
|
||||||
|
return path switch
|
||||||
|
{
|
||||||
|
"/geo/1.0/direct" => JsonResponse(
|
||||||
|
"""[{"name":"Boston","country":"US","lat":42.3601,"lon":-71.0589}]"""),
|
||||||
|
"/data/2.5/weather" => JsonResponse(
|
||||||
|
"""{"name":"Boston","weather":[{"main":"Clouds","description":"overcast clouds"}],"main":{"temp":70.0,"temp_max":72.0,"temp_min":66.0}}"""),
|
||||||
|
"/data/2.5/forecast" => JsonResponse(
|
||||||
|
$"{{\"city\":{{\"timezone\":0}},\"list\":[{{\"dt\":{forecastWindowStart},\"main\":{{\"temp\":76.0,\"temp_max\":81.0,\"temp_min\":70.0}}}},{{\"dt\":{forecastWindowMid},\"main\":{{\"temp\":80.0,\"temp_max\":84.0,\"temp_min\":69.0}}}},{{\"dt\":{forecastWindowLate},\"main\":{{\"temp\":78.0,\"temp_max\":79.0,\"temp_min\":67.0}}}}]}}"),
|
||||||
|
_ => new HttpResponseMessage(HttpStatusCode.NotFound)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
var provider = new OpenWeatherReportProvider(
|
||||||
|
new HttpClient(handler),
|
||||||
|
new OpenWeatherOptions
|
||||||
|
{
|
||||||
|
ApiKey = "test-key",
|
||||||
|
CurrentCacheTtlSeconds = 300,
|
||||||
|
ForecastCacheTtlSeconds = 300,
|
||||||
|
GeocodeCacheTtlSeconds = 300,
|
||||||
|
FailureCacheTtlSeconds = 30
|
||||||
|
},
|
||||||
|
NullLogger<OpenWeatherReportProvider>.Instance);
|
||||||
|
|
||||||
|
var report = await provider.GetReportAsync(new WeatherReportRequest("Boston,US", null, null, false, false, 0));
|
||||||
|
|
||||||
|
Assert.NotNull(report);
|
||||||
|
Assert.Equal(70, report!.Temperature);
|
||||||
|
Assert.Equal(84, report.HighTemperature);
|
||||||
|
Assert.Equal(67, report.LowTemperature);
|
||||||
|
Assert.Equal(1, handler.GetCallCount("/data/2.5/weather"));
|
||||||
|
Assert.Equal(1, handler.GetCallCount("/data/2.5/forecast"));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task NewsApiBriefingProvider_ReusesCachedHeadlinesForIdenticalRequests()
|
public async Task NewsApiBriefingProvider_ReusesCachedHeadlinesForIdenticalRequests()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user