github.com/avenga/couper@v1.12.2/server/multi_files_test.go (about)

     1  package server_test
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net/http"
     7  	"path/filepath"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/avenga/couper/config/configload"
    12  	"github.com/avenga/couper/internal/test"
    13  )
    14  
    15  func TestMultiFiles_Server(t *testing.T) {
    16  	helper := test.New(t)
    17  	client := newClient()
    18  
    19  	shutdown, hook := newCouperMultiFiles(
    20  		"testdata/multi/server/couper.hcl",
    21  		"testdata/multi/server/couper.d",
    22  		helper,
    23  	)
    24  	defer shutdown()
    25  
    26  	for _, entry := range hook.AllEntries() {
    27  		t.Log(entry.String())
    28  	}
    29  
    30  	req, err := http.NewRequest(http.MethodGet, "http://example.com:8080/", nil)
    31  	helper.Must(err)
    32  
    33  	_, err = client.Do(req)
    34  	if err == nil || err.Error() != `Get "http://example.com:8080/": dial tcp4 127.0.0.1:8080: connect: connection refused` {
    35  		t.Error("Expected hosts port override to 9080")
    36  	}
    37  
    38  	type testcase struct {
    39  		url       string
    40  		header    test.Header
    41  		expStatus int
    42  		expBody   string
    43  	}
    44  
    45  	token := "eyJhbGciOiJSUzI1NiIsImtpZCI6InJzMjU2IiwidHlwIjoiSldUIn0.eyJzdWIiOjEyMzQ1Njc4OTB9.AZ0gZVqPe9TjjjJO0GnlTvERBXhPyxW_gTn050rCoEkseFRlp4TYry7WTQ7J4HNrH3btfxaEQLtTv7KooVLXQyMDujQbKU6cyuYH6MZXaM0Co3Bhu0awoX-2GVk997-7kMZx2yvwIR5ypd1CERIbNs5QcQaI4sqx_8oGrjO5ZmOWRqSpi4Mb8gJEVVccxurPu65gPFq9esVWwTf4cMQ3GGzijatnGDbRWs_igVGf8IAfmiROSVd17fShQtfthOFd19TGUswVAleOftC7-DDeJgAK8Un5xOHGRjv3ypK_6ZLRonhswaGXxovE0kLq4ZSzumQY2hOFE6x_BbrR1WKtGw"
    46  
    47  	for _, tc := range []testcase{
    48  		{"http://example.com:9080/", nil, http.StatusOK, "<body>RIGHT INCLUDE</body>\n"},
    49  		{"http://example.com:9080/free", nil, http.StatusForbidden, ""},
    50  		{"http://example.com:9080/errors/", test.Header{"Authorization": "Bearer " + token}, http.StatusTeapot, ""},
    51  		{"http://example.com:9080/api-111", nil, http.StatusUnauthorized, ""},
    52  		{"http://example.com:9080/api-3", nil, http.StatusTeapot, ""},
    53  		{"http://example.com:9080/api-4/ep", nil, http.StatusNoContent, ""},
    54  		{"http://example.com:9081/", nil, http.StatusOK, ""},
    55  		{"http://example.com:8082/", nil, http.StatusOK, ""},
    56  		{"http://example.com:8083/", nil, http.StatusNotFound, ""},
    57  		{"http://example.com:9084/", nil, http.StatusNotFound, ""},
    58  	} {
    59  		req, err = http.NewRequest(http.MethodGet, tc.url, nil)
    60  		helper.Must(err)
    61  
    62  		for k, v := range tc.header {
    63  			req.Header.Set(k, v)
    64  		}
    65  
    66  		res, err := client.Do(req)
    67  		helper.Must(err)
    68  
    69  		if res.StatusCode != tc.expStatus {
    70  			t.Errorf("request %q: want status %d, got %d", tc.url, tc.expStatus, res.StatusCode)
    71  		}
    72  
    73  		if tc.expBody == "" {
    74  			continue
    75  		}
    76  
    77  		var resBytes []byte
    78  		resBytes, err = io.ReadAll(res.Body)
    79  		helper.Must(err)
    80  		_ = res.Body.Close()
    81  
    82  		if string(resBytes) != tc.expBody {
    83  			t.Errorf("request %q unexpected content: %s", tc.url, resBytes)
    84  		}
    85  	}
    86  }
    87  
    88  func TestMultiFiles_SettingsAndDefaults(t *testing.T) {
    89  	helper := test.New(t)
    90  	client := newClient()
    91  
    92  	shutdown, _ := newCouperMultiFiles(
    93  		"testdata/multi/settings/couper.hcl",
    94  		"testdata/multi/settings/couper.d",
    95  		helper,
    96  	)
    97  	defer shutdown()
    98  
    99  	req, err := http.NewRequest(http.MethodGet, "http://example.com:8080/", nil)
   100  	helper.Must(err)
   101  
   102  	res, err := client.Do(req)
   103  	helper.Must(err)
   104  
   105  	resBytes, err := io.ReadAll(res.Body)
   106  	helper.Must(err)
   107  	_ = res.Body.Close()
   108  
   109  	if !strings.Contains(string(resBytes), `"Req-Id-Be-Hdr":["`) {
   110  		t.Errorf("%s", resBytes)
   111  	}
   112  
   113  	if res.Header.Get("Req-Id-Cl-Hdr") == "" {
   114  		t.Errorf("Missing 'Req-Id-Cl-Hdr' header")
   115  	}
   116  
   117  	if res.Header.Get("X") != "X" {
   118  		t.Errorf("Invalid 'X' header given")
   119  	}
   120  
   121  	if res.Header.Get("Y") != "Y" {
   122  		t.Errorf("Invalid 'Y' header given")
   123  	}
   124  
   125  	// Call health route
   126  	req, err = http.NewRequest(http.MethodGet, "http://example.com:8080/xyz", nil)
   127  	helper.Must(err)
   128  
   129  	res, err = client.Do(req)
   130  	helper.Must(err)
   131  
   132  	resBytes, err = io.ReadAll(res.Body)
   133  	helper.Must(err)
   134  	_ = res.Body.Close()
   135  
   136  	if s := string(resBytes); s != "healthy" {
   137  		t.Errorf("Unexpected body given: %s", s)
   138  	}
   139  }
   140  
   141  func TestMultiFiles_Definitions(t *testing.T) {
   142  	helper := test.New(t)
   143  	client := newClient()
   144  
   145  	shutdown, _ := newCouperMultiFiles(
   146  		"testdata/multi/definitions/couper.hcl",
   147  		"testdata/multi/definitions/couper.d",
   148  		helper,
   149  	)
   150  	defer shutdown()
   151  
   152  	req, err := http.NewRequest(http.MethodGet, "http://example.com:8080/", nil)
   153  	helper.Must(err)
   154  
   155  	res, err := client.Do(req)
   156  	helper.Must(err)
   157  
   158  	resBytes, err := io.ReadAll(res.Body)
   159  	helper.Must(err)
   160  	_ = res.Body.Close()
   161  
   162  	if s := string(resBytes); s != "1234567890" {
   163  		t.Errorf("Unexpected body given: %s", s)
   164  	}
   165  
   166  	// Call protected route
   167  	req, err = http.NewRequest(http.MethodGet, "http://example.com:8080/added", nil)
   168  	helper.Must(err)
   169  
   170  	res, err = client.Do(req)
   171  	helper.Must(err)
   172  
   173  	resBytes, err = io.ReadAll(res.Body)
   174  	helper.Must(err)
   175  	_ = res.Body.Close()
   176  
   177  	if s := string(resBytes); !strings.Contains(s, "401 access control error") {
   178  		t.Errorf("Unexpected body given: %s", s)
   179  	}
   180  }
   181  
   182  func TestMultiFiles_MultipleBackends(t *testing.T) {
   183  	type testCase struct {
   184  		config string
   185  		blType string
   186  	}
   187  
   188  	for _, tc := range []testCase{
   189  		{"testdata/multi/backends/errors/jwt.hcl", "jwt"},
   190  		{"testdata/multi/backends/errors/beta_oauth2.hcl", "beta_oauth2"},
   191  		{"testdata/multi/backends/errors/oidc.hcl", "oidc"},
   192  		{"testdata/multi/backends/errors/ac_eh.hcl", "proxy"},
   193  		{"testdata/multi/backends/errors/ep_proxy.hcl", "proxy"},
   194  		{"testdata/multi/backends/errors/ep_request.hcl", "request"},
   195  		{"testdata/multi/backends/errors/api_ep.hcl", "proxy"},
   196  		{"testdata/multi/backends/errors/defined_backend_oauth2.hcl", "oauth2"},
   197  		{"testdata/multi/backends/errors/defined_backend_token_request.hcl", "beta_token_request"},
   198  		{"testdata/multi/backends/errors/anonymous_backend_oauth2.hcl", "oauth2"},
   199  		{"testdata/multi/backends/errors/anonymous_backend_token_request.hcl", "beta_token_request"},
   200  	} {
   201  		t.Run(tc.config, func(st *testing.T) {
   202  			_, err := configload.LoadFile(filepath.Join(testWorkingDir, tc.config), "")
   203  
   204  			if !strings.Contains(err.Error(), tc.config+":") {
   205  				st.Errorf("Missing config file path: %s", err.Error())
   206  			}
   207  
   208  			if !strings.HasSuffix(err.Error(), fmt.Sprintf(": Multiple definitions of backend are not allowed in %s.; ", tc.blType)) {
   209  				st.Errorf("Unexpected error: %s", err.Error())
   210  			}
   211  		})
   212  	}
   213  }
   214  
   215  func Test_MultipleLabels(t *testing.T) {
   216  	type testCase struct {
   217  		name       string
   218  		configPath string
   219  		expError   string
   220  	}
   221  
   222  	for _, tc := range []testCase{
   223  		{
   224  			"server with multiple labels",
   225  			"testdata/multi/errors/couper_01.hcl",
   226  			"testdata/multi/errors/couper_01.hcl:1,12-15: Extraneous label for server; Only 1 labels (name) are expected for server blocks.",
   227  		},
   228  		{
   229  			"api with multiple labels",
   230  			"testdata/multi/errors/couper_02.hcl",
   231  			"testdata/multi/errors/couper_02.hcl:2,11-14: Extraneous label for api; Only 1 labels (name) are expected for api blocks.",
   232  		},
   233  		{
   234  			"spa with multiple labels",
   235  			"testdata/multi/errors/couper_04.hcl",
   236  			"testdata/multi/errors/couper_04.hcl:2,11-14: Extraneous label for spa; Only 1 labels (name) are expected for spa blocks.",
   237  		},
   238  		{
   239  			"files with multiple labels",
   240  			"testdata/multi/errors/couper_05.hcl",
   241  			"testdata/multi/errors/couper_05.hcl:2,13-16: Extraneous label for files; Only 1 labels (name) are expected for files blocks.",
   242  		},
   243  		{
   244  			"api, spa, files and server without labels",
   245  			"testdata/multi/errors/couper_03.hcl",
   246  			"",
   247  		},
   248  	} {
   249  		t.Run(tc.name, func(st *testing.T) {
   250  			_, err := configload.LoadFile(filepath.Join(testWorkingDir, tc.configPath), "")
   251  
   252  			if (err != nil && tc.expError == "") ||
   253  				(tc.expError != "" && (err == nil || !strings.Contains(err.Error(), tc.expError))) {
   254  				st.Errorf("Unexpected error: %v", err)
   255  			}
   256  		})
   257  	}
   258  }
   259  
   260  func TestMultiFiles_SPAs(t *testing.T) {
   261  	helper := test.New(t)
   262  	client := newClient()
   263  
   264  	shutdown, _ := newCouperMultiFiles("", "testdata/multi/server/spa.d", helper)
   265  	defer shutdown()
   266  
   267  	type testcase struct {
   268  		path        string
   269  		expStatus   int
   270  		expContains string
   271  	}
   272  
   273  	for _, tc := range []testcase{
   274  		{"/", http.StatusNotFound, ""},
   275  		{"/app", http.StatusOK, "02_spa.hcl"},
   276  		{"/another", http.StatusOK, "03_spa.hcl"},
   277  	} {
   278  		t.Run(tc.path, func(st *testing.T) {
   279  			h := test.New(st)
   280  			req, err := http.NewRequest(http.MethodGet, "http://couper.local:8080"+tc.path, nil)
   281  			h.Must(err)
   282  
   283  			res, err := client.Do(req)
   284  			h.Must(err)
   285  
   286  			if res.StatusCode != tc.expStatus {
   287  				st.Errorf("want status: %d, got: %d", tc.expStatus, res.StatusCode)
   288  			}
   289  
   290  			b, err := io.ReadAll(res.Body)
   291  			h.Must(err)
   292  
   293  			h.Must(res.Body.Close())
   294  
   295  			if tc.expContains != "" && !strings.Contains(string(b), tc.expContains) {
   296  				st.Errorf("want %q, got:\n%q", tc.expContains, string(b))
   297  			}
   298  		})
   299  	}
   300  }
   301  
   302  func TestMultiFiles_Files(t *testing.T) {
   303  	helper := test.New(t)
   304  	client := newClient()
   305  
   306  	shutdown, _ := newCouperMultiFiles("", "testdata/multi/server/files.d", helper)
   307  	defer shutdown()
   308  
   309  	type testcase struct {
   310  		path        string
   311  		expStatus   int
   312  		expContains string
   313  	}
   314  
   315  	for _, tc := range []testcase{
   316  		{"/", http.StatusNotFound, ""},
   317  		{"/app", http.StatusOK, "<app/>\n"},
   318  		{"/another", http.StatusOK, "<another/>\n"},
   319  	} {
   320  		t.Run(tc.path, func(st *testing.T) {
   321  			h := test.New(st)
   322  			req, err := http.NewRequest(http.MethodGet, "http://couper.local:8080"+tc.path, nil)
   323  			h.Must(err)
   324  
   325  			res, err := client.Do(req)
   326  			h.Must(err)
   327  
   328  			if res.StatusCode != tc.expStatus {
   329  				st.Errorf("want status: %d, got: %d", tc.expStatus, res.StatusCode)
   330  			}
   331  
   332  			b, err := io.ReadAll(res.Body)
   333  			h.Must(err)
   334  
   335  			h.Must(res.Body.Close())
   336  
   337  			if tc.expContains != "" && !strings.Contains(string(b), tc.expContains) {
   338  				st.Errorf("want %q, got:\n%q", tc.expContains, string(b))
   339  			}
   340  		})
   341  	}
   342  }