From 393c34055d72b90e373edee37fcf0d5853bf0b7b Mon Sep 17 00:00:00 2001 From: Jacob Dubin Date: Sat, 16 May 2026 10:01:40 -0500 Subject: [PATCH] Prefer forecast hi lo for current weather --- .../Weather/OpenWeatherReportProvider.cs | 42 +++++------------ .../Infrastructure/ProviderCachingTests.cs | 46 ++++++++++++++++++- 2 files changed, 57 insertions(+), 31 deletions(-) diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Weather/OpenWeatherReportProvider.cs b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Weather/OpenWeatherReportProvider.cs index cc0bb75..64a72bc 100644 --- a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Weather/OpenWeatherReportProvider.cs +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Weather/OpenWeatherReportProvider.cs @@ -173,25 +173,22 @@ public sealed class OpenWeatherReportProvider( var temperature = TryReadInt(main, "temp"); var high = TryReadInt(main, "temp_max"); 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( - location, - 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."); + 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."); + } if (temperature is null && high is null && low is null) { @@ -492,21 +489,6 @@ public sealed class OpenWeatherReportProvider( 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) { return string.Create( diff --git a/OpenJibo/tests/Jibo.Cloud.Tests/Infrastructure/ProviderCachingTests.cs b/OpenJibo/tests/Jibo.Cloud.Tests/Infrastructure/ProviderCachingTests.cs index 19dfb04..49a74b7 100644 --- a/OpenJibo/tests/Jibo.Cloud.Tests/Infrastructure/ProviderCachingTests.cs +++ b/OpenJibo/tests/Jibo.Cloud.Tests/Infrastructure/ProviderCachingTests.cs @@ -44,7 +44,7 @@ public sealed class ProviderCachingTests Assert.NotNull(second); Assert.Equal(1, handler.GetCallCount("/geo/1.0/direct")); 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] @@ -91,6 +91,50 @@ public sealed class ProviderCachingTests 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.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] public async Task NewsApiBriefingProvider_ReusesCachedHeadlinesForIdenticalRequests() {