246 lines
8.3 KiB
C#
246 lines
8.3 KiB
C#
using System.Text.Json.Nodes;
|
|
using Microsoft.Extensions.Options;
|
|
using TileServer.Application.Configuration;
|
|
using TileServer.Application.Extracts;
|
|
using TileServer.Application.Styles;
|
|
using TileServer.Application.Tiles;
|
|
using TileServer.Domain.Extracts;
|
|
using TileServer.Domain.Tiles;
|
|
|
|
namespace TileServer.UnitTests;
|
|
|
|
public sealed class StyleServiceTests
|
|
{
|
|
[Fact]
|
|
public void Get_BindsAbsoluteTilesAndSourceMaxZoom()
|
|
{
|
|
var extract = new Extract
|
|
{
|
|
Id = "central-fed-district",
|
|
Name = "ЦФО",
|
|
Url = new Uri("https://download.geofabrik.de/russia/central-fed-district-latest.osm.pbf"),
|
|
CenterLon = 37.6,
|
|
CenterLat = 55.7,
|
|
MinZoom = 0,
|
|
MaxZoom = 14
|
|
};
|
|
|
|
var metadata = new TilesetMetadata(
|
|
extract.Id,
|
|
extract.Name,
|
|
"pbf",
|
|
29.2,
|
|
48.7,
|
|
47.6,
|
|
59.6,
|
|
38.4,
|
|
54.2,
|
|
5,
|
|
0,
|
|
14,
|
|
[]);
|
|
|
|
var template = new JsonObject
|
|
{
|
|
["version"] = 8,
|
|
["name"] = "OSM Bright",
|
|
["sources"] = new JsonObject
|
|
{
|
|
["openmaptiles"] = new JsonObject
|
|
{
|
|
["type"] = "vector",
|
|
["url"] = "/api/v1/tiles/central-fed-district.json"
|
|
}
|
|
}
|
|
};
|
|
|
|
var service = new StyleService(
|
|
new MemoryStyleCatalog(template),
|
|
new MemoryExtractCatalog(extract),
|
|
new MemoryTileStore(metadata),
|
|
Options.Create(new TileServerOptions
|
|
{
|
|
GlyphsUrl = "https://fonts.example/{fontstack}/{range}.pbf"
|
|
}));
|
|
|
|
var style = service.Get("osm-bright", extract.Id, "https://tile-server.ru");
|
|
var source = style["sources"]!["openmaptiles"]!.AsObject();
|
|
|
|
Assert.Null(source["url"]);
|
|
Assert.Equal(0, source["minzoom"]!.GetValue<int>());
|
|
Assert.Equal(14, source["maxzoom"]!.GetValue<int>());
|
|
Assert.Equal("xyz", source["scheme"]!.GetValue<string>());
|
|
Assert.Equal(
|
|
"https://tile-server.ru/api/v1/tiles/central-fed-district/{z}/{x}/{y}.pbf?v=3",
|
|
source["tiles"]!.AsArray()[0]!.GetValue<string>());
|
|
Assert.Null(source["bounds"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void Bind_UsesPersonalTileUrlAndToken()
|
|
{
|
|
var extract = new Extract
|
|
{
|
|
Id = "central-fed-district",
|
|
Name = "ЦФО",
|
|
Url = new Uri("https://download.geofabrik.de/russia/central-fed-district-latest.osm.pbf"),
|
|
CenterLon = 37.6,
|
|
CenterLat = 55.7,
|
|
MinZoom = 0,
|
|
MaxZoom = 14
|
|
};
|
|
|
|
var metadata = new TilesetMetadata(
|
|
extract.Id,
|
|
extract.Name,
|
|
"pbf",
|
|
29.2,
|
|
48.7,
|
|
47.6,
|
|
59.6,
|
|
38.4,
|
|
54.2,
|
|
5,
|
|
0,
|
|
14,
|
|
[]);
|
|
|
|
var template = new JsonObject
|
|
{
|
|
["version"] = 8,
|
|
["sources"] = new JsonObject
|
|
{
|
|
["openmaptiles"] = new JsonObject
|
|
{
|
|
["type"] = "vector"
|
|
}
|
|
}
|
|
};
|
|
|
|
var service = new StyleService(
|
|
new MemoryStyleCatalog(template),
|
|
new MemoryExtractCatalog(extract),
|
|
new MemoryTileStore(metadata),
|
|
Options.Create(new TileServerOptions()));
|
|
|
|
var tilesUrl = "https://tile-server.ru/u/alice/tiles/central-fed-district/{z}/{x}/{y}.pbf?v=3&token=ts_abc";
|
|
var style = service.Bind(template, extract.Id, tilesUrl);
|
|
var tile = style["sources"]!["openmaptiles"]!["tiles"]!.AsArray()[0]!.GetValue<string>();
|
|
|
|
Assert.Contains("/u/alice/", tile, StringComparison.Ordinal);
|
|
Assert.Contains("token=ts_abc", tile, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void Bind_MultipleExtracts_AddsSourcesAndClonesLayers()
|
|
{
|
|
var central = SampleExtract("central-fed-district", 37.6, 55.7);
|
|
var volga = SampleExtract("volga-fed-district", 45, 57);
|
|
var template = new JsonObject
|
|
{
|
|
["version"] = 8,
|
|
["sources"] = new JsonObject
|
|
{
|
|
["openmaptiles"] = new JsonObject { ["type"] = "vector" }
|
|
},
|
|
["layers"] = new JsonArray
|
|
{
|
|
new JsonObject
|
|
{
|
|
["id"] = "background",
|
|
["type"] = "background",
|
|
["paint"] = new JsonObject { ["background-color"] = "#000" }
|
|
},
|
|
new JsonObject
|
|
{
|
|
["id"] = "water",
|
|
["type"] = "fill",
|
|
["source"] = "openmaptiles",
|
|
["source-layer"] = "water"
|
|
}
|
|
}
|
|
};
|
|
|
|
var service = new StyleService(
|
|
new MemoryStyleCatalog(template),
|
|
new MemoryExtractCatalog(central, volga),
|
|
new MemoryTileStore(SampleMetadata(central)),
|
|
Options.Create(new TileServerOptions()));
|
|
|
|
var style = service.Bind(template, [
|
|
new BoundExtract(central.Id, "https://tile-server.ru/u/alice/tiles/central-fed-district/{z}/{x}/{y}.pbf?token=ts"),
|
|
new BoundExtract(volga.Id, "https://tile-server.ru/u/alice/tiles/volga-fed-district/{z}/{x}/{y}.pbf?token=ts")
|
|
]);
|
|
|
|
var sources = style["sources"]!.AsObject();
|
|
Assert.True(sources.ContainsKey("openmaptiles"));
|
|
Assert.True(sources.ContainsKey("openmaptiles__volga-fed-district"));
|
|
Assert.Contains("volga-fed-district", sources["openmaptiles__volga-fed-district"]!["tiles"]![0]!.GetValue<string>(), StringComparison.Ordinal);
|
|
|
|
var layers = style["layers"]!.AsArray();
|
|
Assert.Equal(3, layers.Count);
|
|
Assert.Equal("water__volga-fed-district", layers[2]!["id"]!.GetValue<string>());
|
|
Assert.Equal("openmaptiles__volga-fed-district", layers[2]!["source"]!.GetValue<string>());
|
|
Assert.Null(layers[0]!["source"]);
|
|
}
|
|
|
|
private static Extract SampleExtract(string id, double lon, double lat)
|
|
=> new()
|
|
{
|
|
Id = id,
|
|
Name = id,
|
|
Url = new Uri($"https://download.geofabrik.de/russia/{id}-latest.osm.pbf"),
|
|
CenterLon = lon,
|
|
CenterLat = lat,
|
|
MinZoom = 0,
|
|
MaxZoom = 14
|
|
};
|
|
|
|
private static TilesetMetadata SampleMetadata(Extract extract)
|
|
=> new(extract.Id, extract.Name, "pbf", 0, 0, 1, 1, 0, 0, 5, 0, 14, []);
|
|
|
|
private sealed class MemoryStyleCatalog(JsonObject style) : IStyleCatalog
|
|
{
|
|
public IReadOnlyList<MapStyleInfo> List() => [new("osm-bright", DateTimeOffset.UnixEpoch)];
|
|
|
|
public JsonObject GetRequired(string name)
|
|
=> JsonNode.Parse(style.ToJsonString())!.AsObject();
|
|
|
|
public Task SaveAsync(string name, JsonObject incoming, CancellationToken ct) => Task.CompletedTask;
|
|
|
|
public Task SeedDefaultsAsync(CancellationToken ct) => Task.CompletedTask;
|
|
}
|
|
|
|
private sealed class MemoryExtractCatalog(params Extract[] extracts) : IExtractCatalog
|
|
{
|
|
public IReadOnlyList<Extract> GetAll() => extracts;
|
|
|
|
public Extract? Find(string id) => extracts.FirstOrDefault(item => item.Id == id);
|
|
|
|
public Extract GetRequired(string id)
|
|
=> Find(id) ?? throw new InvalidOperationException(id);
|
|
|
|
public Task AddOrUpdateAsync(Extract incoming, CancellationToken ct) => Task.CompletedTask;
|
|
|
|
public Task RemoveAsync(string id, CancellationToken ct) => Task.CompletedTask;
|
|
}
|
|
|
|
private sealed class MemoryTileStore(TilesetMetadata metadata) : ITileStore
|
|
{
|
|
public bool Exists(string extractId) => true;
|
|
|
|
public Task<TileData?> GetTileAsync(string extractId, TileCoordinate tile, CancellationToken ct)
|
|
=> Task.FromResult<TileData?>(null);
|
|
|
|
public TilesetMetadata? GetMetadata(string extractId) => metadata;
|
|
|
|
public string GetActivePath(string extractId) => extractId;
|
|
|
|
public string GetStagingPath(string extractId) => extractId + ".building.mbtiles";
|
|
|
|
public void Activate(string extractId, string stagingPath)
|
|
{
|
|
}
|
|
}
|
|
}
|