using System.Net; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using TheLivingWorld.Core.Geo; using TheLivingWorld.Osm; using TheLivingWorld.Osm.Overpass; namespace TheLivingWorld.Tests; public class OverpassClientTests : IDisposable { private static readonly GeoBounds Bounds = GeoBounds.FromCenter(new GeoPoint(31.8966010, -100.4858591), 1000); private readonly string _cacheDirectory = Path.Combine(Path.GetTempPath(), $"tlw-osm-cache-{Guid.NewGuid():n}"); [Fact] public async Task Caches_the_response_and_serves_it_again_without_a_second_request() { var handler = new StubHandler((_, _) => Json("""{"elements":[]}""")); var client = CreateClient(handler); var first = await client.FetchAsync(Bounds, forceRefresh: false); var second = await client.FetchAsync(Bounds, forceRefresh: false); Assert.Equal(first, second); Assert.Equal(1, handler.Requests); Assert.Equal("""{"elements":[]}""", await File.ReadAllTextAsync(first)); } [Fact] public async Task Refetches_when_asked_to_refresh() { var handler = new StubHandler((_, _) => Json("""{"elements":[]}""")); var client = CreateClient(handler); await client.FetchAsync(Bounds, forceRefresh: false); await client.FetchAsync(Bounds, forceRefresh: true); Assert.Equal(2, handler.Requests); } [Fact] public async Task Falls_back_to_the_next_mirror_after_a_retryable_failure() { var handler = new StubHandler((request, _) => request.RequestUri!.Host == "first.example" ? new HttpResponseMessage(HttpStatusCode.TooManyRequests) { Content = new StringContent("busy") } : Json("""{"elements":[]}""")); var client = CreateClient(handler, "https://first.example/api", "https://second.example/api"); var path = await client.FetchAsync(Bounds, forceRefresh: false); Assert.True(File.Exists(path)); Assert.Equal(2, handler.Requests); } [Fact] public async Task Rejects_an_html_error_page_served_under_a_200() { // An overloaded Overpass instance answers "the server is probably too busy" as HTML with status 200. var handler = new StubHandler((_, _) => new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("
too busy", System.Text.Encoding.UTF8, "text/html"), }); var client = CreateClient(handler); var failure = await Assert.ThrowsAsyncgateway is down
"), }); var client = CreateClient(handler); var failure = await Assert.ThrowsAsync