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  }