forked from GoCodeAlone/modular
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtenant_composite_test.go
More file actions
170 lines (140 loc) · 5.17 KB
/
tenant_composite_test.go
File metadata and controls
170 lines (140 loc) · 5.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package reverseproxy
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"github.com/CrisisTextLine/modular"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
// TestTenantCompositeRoutes tests that tenant-specific composite routes are properly handled
func TestTenantCompositeRoutes(t *testing.T) {
// Create a mock tenant application with mock functionality
mockTenantApp := NewMockTenantApplicationWithMock()
mockConfigProvider := &MockConfigProvider{}
// Set up global config
globalConfig := &ReverseProxyConfig{
BackendServices: map[string]string{
"backend1": "http://127.0.0.1:9003",
"backend2": "http://127.0.0.1:9004",
},
CompositeRoutes: map[string]CompositeRoute{
"/global/composite": {
Pattern: "/global/composite",
Backends: []string{"backend1", "backend2"},
Strategy: "json-merge",
},
"/shared/route": {
Pattern: "/shared/route",
Backends: []string{"backend1"},
Strategy: "json-merge",
},
},
TenantIDHeader: "X-Tenant-ID",
}
mockConfigProvider.On("GetConfig").Return(globalConfig)
mockTenantApp.On("GetConfigSection", "reverseproxy").Return(mockConfigProvider, nil)
// Set up tenant-specific config
tenant1ID := modular.TenantID("tenant1")
tenant1Config := &ReverseProxyConfig{
BackendServices: map[string]string{
"backend1": "http://127.0.0.1:9005",
"backend2": "http://127.0.0.1:9006",
},
CompositeRoutes: map[string]CompositeRoute{
"/tenant/composite": {
Pattern: "/tenant/composite",
Backends: []string{"backend1", "backend2"},
Strategy: "json-merge",
},
"/shared/route": {
Pattern: "/shared/route",
Backends: []string{"backend2"}, // Override the global route
Strategy: "json-merge",
},
},
}
tenant1ConfigProvider := &MockConfigProvider{}
tenant1ConfigProvider.On("GetConfig").Return(tenant1Config)
mockTenantApp.On("GetTenantConfig", tenant1ID, "reverseproxy").Return(tenant1ConfigProvider, nil)
// Create a mock router
mockRouter := &MockRouter{}
// Set up mock expectations
mockRouter.On("Use", mock.Anything).Return()
// Create the reverse proxy module
module := NewModule()
// Register config and set app
err := module.RegisterConfig(mockTenantApp)
require.NoError(t, err)
// Initialize the module
err = module.Init(mockTenantApp)
require.NoError(t, err)
// Register tenant
module.OnTenantRegistered(tenant1ID)
// Set up router through constructor
constructor := module.Constructor()
services := map[string]any{
"router": mockRouter,
}
_, err = constructor(mockTenantApp, services)
require.NoError(t, err)
// Capture the routes registered with the router
var registeredRoutes []string
var routeHandlers map[string]http.HandlerFunc
mockRouter.On("HandleFunc", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
pattern := args.String(0)
handler := args.Get(1).(http.HandlerFunc)
registeredRoutes = append(registeredRoutes, pattern)
if routeHandlers == nil {
routeHandlers = make(map[string]http.HandlerFunc)
}
routeHandlers[pattern] = handler
})
// Start the module to set up routes
err = module.Start(context.Background())
require.NoError(t, err)
// Make sure our composite routes were registered
assert.Contains(t, registeredRoutes, "/global/composite")
assert.Contains(t, registeredRoutes, "/tenant/composite")
assert.Contains(t, registeredRoutes, "/shared/route")
// Now let's test the handlers to verify tenant routing works correctly
// Test 1: Global composite route without tenant ID
req1 := httptest.NewRequest(http.MethodGet, "/global/composite", nil)
recorder1 := httptest.NewRecorder()
// Since we can't properly test the actual backend responses, we'll mock the createCompositeHandler
// function to return a handler that records which backends were used
if handler, ok := routeHandlers["/global/composite"]; ok {
handler(recorder1, req1)
// The request should proceed without error
assert.NotEqual(t, http.StatusBadRequest, recorder1.Code)
}
// Test 2: Global composite route with tenant ID
req2 := httptest.NewRequest(http.MethodGet, "/global/composite", nil)
req2.Header.Set("X-Tenant-ID", "tenant1")
recorder2 := httptest.NewRecorder()
if handler, ok := routeHandlers["/global/composite"]; ok {
handler(recorder2, req2)
// The request should proceed without error
assert.NotEqual(t, http.StatusBadRequest, recorder2.Code)
}
// Test 3: Tenant-specific route with tenant ID
req3 := httptest.NewRequest(http.MethodGet, "/tenant/composite", nil)
req3.Header.Set("X-Tenant-ID", "tenant1")
recorder3 := httptest.NewRecorder()
if handler, ok := routeHandlers["/tenant/composite"]; ok {
handler(recorder3, req3)
// The request should proceed without error
assert.NotEqual(t, http.StatusBadRequest, recorder3.Code)
}
// Test 4: Shared route with tenant ID (should use tenant-specific backend)
req4 := httptest.NewRequest(http.MethodGet, "/shared/route", nil)
req4.Header.Set("X-Tenant-ID", "tenant1")
recorder4 := httptest.NewRecorder()
if handler, ok := routeHandlers["/shared/route"]; ok {
handler(recorder4, req4)
// The request should proceed without error
assert.NotEqual(t, http.StatusBadRequest, recorder4.Code)
}
}