github.com/PDOK/gokoala@v0.50.6/internal/ogc/styles/main_test.go (about) 1 package styles 2 3 import ( 4 "context" 5 "log" 6 "net" 7 "net/http" 8 "net/http/httptest" 9 "net/url" 10 "os" 11 "path" 12 "runtime" 13 "testing" 14 15 "github.com/PDOK/gokoala/config" 16 "github.com/go-chi/chi/v5" 17 18 "github.com/PDOK/gokoala/internal/engine" 19 "golang.org/x/text/language" 20 21 "github.com/stretchr/testify/assert" 22 ) 23 24 func init() { 25 // change working dir to root, to mimic behavior of 'go run' in order to resolve template files. 26 _, filename, _, _ := runtime.Caller(0) 27 dir := path.Join(path.Dir(filename), "../../../") 28 err := os.Chdir(dir) 29 if err != nil { 30 panic(err) 31 } 32 } 33 34 func TestNewStyles(t *testing.T) { 35 type args struct { 36 e *engine.Engine 37 } 38 tests := []struct { 39 name string 40 args args 41 }{ 42 { 43 name: "Test render templates with OGC Styles config", 44 args: args{ 45 e: engine.NewEngineWithConfig(&config.Config{ 46 Version: "0.4.0", 47 Title: "Test API", 48 Abstract: "Test API description", 49 Resources: &config.Resources{ 50 Directory: ptrTo("/fakedirectory"), 51 }, 52 AvailableLanguages: []config.Language{{Tag: language.Dutch}}, 53 BaseURL: config.URL{URL: &url.URL{Scheme: "https", Host: "api.foobar.example", Path: "/"}}, 54 OgcAPI: config.OgcAPI{ 55 GeoVolumes: nil, 56 Tiles: &config.OgcAPITiles{ 57 TileServer: config.URL{URL: &url.URL{Scheme: "https", Host: "tiles.foobar.example", Path: "/somedataset"}}, 58 Types: []config.TilesType{config.TilesTypeVector}, 59 SupportedSrs: []config.SupportedSrs{ 60 { 61 Srs: "EPSG:28992", 62 ZoomLevelRange: config.ZoomLevelRange{ 63 Start: 12, 64 End: 12, 65 }, 66 }, 67 }, 68 }, 69 Styles: &config.OgcAPIStyles{ 70 Default: "foo", 71 SupportedStyles: []config.Style{ 72 { 73 ID: "foo", 74 Title: "bar", 75 }, 76 }, 77 }, 78 }, 79 }, "", false, true), 80 }, 81 }, 82 } 83 for _, test := range tests { 84 t.Run(test.name, func(t *testing.T) { 85 styles := NewStyles(test.args.e) 86 assert.NotEmpty(t, styles.engine.Templates.RenderedTemplates) 87 }) 88 } 89 } 90 91 func TestStyles_Style(t *testing.T) { 92 type fields struct { 93 configFile string 94 url string 95 style string 96 } 97 type want struct { 98 bodyContains []string 99 statusCode int 100 } 101 tests := []struct { 102 name string 103 fields fields 104 want want 105 }{ 106 { 107 name: "styles/default__netherlandsrdnewquad", 108 fields: fields{ 109 configFile: "internal/ogc/styles/testdata/config_minimal_styles.yaml", 110 url: "http://localhost:8080/styles/:style", 111 style: "default__netherlandsrdnewquad", 112 }, 113 want: want{ 114 bodyContains: []string{"\"id\": \"default\"", "tiles/NetherlandsRDNewQuad/{z}/{y}/{x}?f=mvt"}, 115 statusCode: http.StatusOK, 116 }, 117 }, 118 { 119 name: "styles/default__webmercatorquad", 120 fields: fields{ 121 configFile: "internal/ogc/styles/testdata/config_minimal_styles.yaml", 122 url: "http://localhost:8080/styles/:style", 123 style: "default__webmercatorquad", 124 }, 125 want: want{ 126 bodyContains: []string{"\"id\": \"default\"", "tiles/WebMercatorQuad/{z}/{y}/{x}?f=mvt"}, 127 statusCode: http.StatusOK, 128 }, 129 }, 130 { 131 name: "styles/default (backwards comp)", 132 fields: fields{ 133 configFile: "internal/ogc/styles/testdata/config_minimal_styles.yaml", 134 url: "http://localhost:8080/styles/:style", 135 style: "default", 136 }, 137 want: want{ 138 bodyContains: []string{"\"id\": \"default\"", "tiles/NetherlandsRDNewQuad/{z}/{y}/{x}?f=mvt"}, 139 statusCode: http.StatusOK, 140 }, 141 }, 142 } 143 for _, tt := range tests { 144 t.Run(tt.name, func(t *testing.T) { 145 req, err := createStyleRequest(tt.fields.url, tt.fields.style) 146 if err != nil { 147 log.Fatal(err) 148 } 149 rr, ts := createMockServer() 150 defer ts.Close() 151 152 newEngine, err := engine.NewEngine(tt.fields.configFile, "", false, true) 153 assert.NoError(t, err) 154 styles := NewStyles(newEngine) 155 handler := styles.Style() 156 handler.ServeHTTP(rr, req) 157 158 assert.Equal(t, tt.want.statusCode, rr.Code) 159 for _, c := range tt.want.bodyContains { 160 assert.Contains(t, rr.Body.String(), c) 161 } 162 }) 163 } 164 } 165 166 func TestStyles_StyleMetadata(t *testing.T) { 167 type fields struct { 168 configFile string 169 url string 170 style string 171 } 172 type want struct { 173 bodyContains []string 174 statusCode int 175 } 176 tests := []struct { 177 name string 178 fields fields 179 want want 180 }{ 181 { 182 name: "styles/default__netherlandsrdnewquad", 183 fields: fields{ 184 configFile: "internal/ogc/styles/testdata/config_minimal_styles.yaml", 185 url: "http://localhost:8080/styles/:style/metadata", 186 style: "default__netherlandsrdnewquad", 187 }, 188 want: want{ 189 bodyContains: []string{"\"id\": \"default\"", "\"title\": \"Mapbox Style\"", "default__netherlandsrdnewquad"}, 190 statusCode: http.StatusOK, 191 }, 192 }, 193 { 194 name: "styles/default__webmercatorquad", 195 fields: fields{ 196 configFile: "internal/ogc/styles/testdata/config_minimal_styles.yaml", 197 url: "http://localhost:8080/styles/:style/metadata", 198 style: "default__webmercatorquad", 199 }, 200 want: want{ 201 bodyContains: []string{"\"id\": \"default\"", "\"title\": \"Mapbox Style\"", "default__webmercatorquad"}, 202 statusCode: http.StatusOK, 203 }, 204 }, 205 { 206 name: "styles/default (backwards comp)", 207 fields: fields{ 208 configFile: "internal/ogc/styles/testdata/config_minimal_styles.yaml", 209 url: "http://localhost:8080/styles/:style/metadata", 210 style: "default", 211 }, 212 want: want{ 213 bodyContains: []string{"\"id\": \"default\"", "\"title\": \"Mapbox Style\"", "default__netherlandsrdnewquad"}, 214 statusCode: http.StatusOK, 215 }, 216 }, 217 } 218 for _, tt := range tests { 219 t.Run(tt.name, func(t *testing.T) { 220 req, err := createStyleRequest(tt.fields.url, tt.fields.style) 221 if err != nil { 222 log.Fatal(err) 223 } 224 rr, ts := createMockServer() 225 defer ts.Close() 226 227 newEngine, err := engine.NewEngine(tt.fields.configFile, "", false, true) 228 assert.NoError(t, err) 229 styles := NewStyles(newEngine) 230 handler := styles.StyleMetadata() 231 handler.ServeHTTP(rr, req) 232 233 assert.Equal(t, tt.want.statusCode, rr.Code) 234 for _, c := range tt.want.bodyContains { 235 assert.Contains(t, rr.Body.String(), c) 236 } 237 }) 238 } 239 } 240 241 func TestTile_Styles(t *testing.T) { 242 type fields struct { 243 configFile string 244 url string 245 } 246 type want struct { 247 bodyContains string 248 statusCode int 249 } 250 tests := []struct { 251 name string 252 fields fields 253 want want 254 }{ 255 { 256 name: "test NetherlandsRDNewQuad present", 257 fields: fields{ 258 configFile: "internal/ogc/styles/testdata/config_minimal_styles.yaml", 259 url: "http://localhost:8080/styles", 260 }, 261 want: want{ 262 bodyContains: "Test style (NetherlandsRDNewQuad)", 263 statusCode: http.StatusOK, 264 }, 265 }, 266 { 267 name: "test WebMercatorQuad present", 268 fields: fields{ 269 configFile: "internal/ogc/styles/testdata/config_minimal_styles.yaml", 270 url: "http://localhost:8080/styles", 271 }, 272 want: want{ 273 bodyContains: "Test style (WebMercatorQuad)", 274 statusCode: http.StatusOK, 275 }, 276 }, 277 } 278 for _, tt := range tests { 279 t.Run(tt.name, func(t *testing.T) { 280 req, err := createStylesRequest(tt.fields.url) 281 if err != nil { 282 log.Fatal(err) 283 } 284 rr, ts := createMockServer() 285 defer ts.Close() 286 287 newEngine, err := engine.NewEngine(tt.fields.configFile, "", false, true) 288 assert.NoError(t, err) 289 styles := NewStyles(newEngine) 290 handler := styles.Styles() 291 handler.ServeHTTP(rr, req) 292 293 assert.Equal(t, tt.want.statusCode, rr.Code) 294 assert.Contains(t, rr.Body.String(), tt.want.bodyContains) 295 }) 296 } 297 } 298 299 func createMockServer() (*httptest.ResponseRecorder, *httptest.Server) { 300 rr := httptest.NewRecorder() 301 l, err := net.Listen("tcp", "localhost:10090") 302 if err != nil { 303 log.Fatal(err) 304 } 305 ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 306 engine.SafeWrite(w.Write, []byte(r.URL.String())) 307 })) 308 ts.Listener.Close() 309 ts.Listener = l 310 ts.Start() 311 return rr, ts 312 } 313 314 func createStyleRequest(url string, style string) (*http.Request, error) { 315 req, err := http.NewRequest(http.MethodGet, url, nil) 316 rctx := chi.NewRouteContext() 317 rctx.URLParams.Add("style", style) 318 319 req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) 320 return req, err 321 } 322 323 func createStylesRequest(url string) (*http.Request, error) { 324 req, err := http.NewRequest(http.MethodGet, url, nil) 325 rctx := chi.NewRouteContext() 326 327 req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) 328 return req, err 329 } 330 331 func ptrTo[T any](val T) *T { 332 return &val 333 }