diff options
Diffstat (limited to 'test/test_upstreams_rr.py')
-rw-r--r-- | test/test_upstreams_rr.py | 282 |
1 files changed, 197 insertions, 85 deletions
diff --git a/test/test_upstreams_rr.py b/test/test_upstreams_rr.py index 2bc2d90a..7045318a 100644 --- a/test/test_upstreams_rr.py +++ b/test/test_upstreams_rr.py @@ -16,10 +16,10 @@ class TestUpstreamsRR(TestApplicationPython): { "listeners": { "*:7080": {"pass": "upstreams/one"}, - "*:7081": {"pass": "applications/ups_0"}, - "*:7082": {"pass": "applications/ups_1"}, - "*:7083": {"pass": "applications/ups_2"}, "*:7090": {"pass": "upstreams/two"}, + "*:7081": {"pass": "routes/one"}, + "*:7082": {"pass": "routes/two"}, + "*:7083": {"pass": "routes/three"}, }, "upstreams": { "one": { @@ -35,32 +35,12 @@ class TestUpstreamsRR(TestApplicationPython): }, }, }, - "applications": { - "ups_0": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/upstreams/0", - "working_directory": self.current_dir - + "/python/upstreams/0", - "module": "wsgi", - }, - "ups_1": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/upstreams/1", - "working_directory": self.current_dir - + "/python/upstreams/1", - "module": "wsgi", - }, - "ups_2": { - "type": "python", - "processes": {"spare": 0}, - "path": self.current_dir + "/python/upstreams/2", - "working_directory": self.current_dir - + "/python/upstreams/2", - "module": "wsgi", - }, + "routes": { + "one": [{"action": {"return": 200}}], + "two": [{"action": {"return": 201}}], + "three": [{"action": {"return": 202}}], }, + "applications": {}, }, ), 'upstreams initial configuration', @@ -70,15 +50,17 @@ class TestUpstreamsRR(TestApplicationPython): def get_resps(self, req=100, port=7080): resps = [0] + for _ in range(req): - headers = self.get(port=port)['headers'] - if 'X-Upstream' in headers: - ups = int(headers['X-Upstream']) + status = self.get(port=port)['status'] + if 200 > status or status > 209: + continue - if ups > len(resps) - 1: - resps.extend([0] * (ups - len(resps) + 1)) + ups = status % 10 + if ups > len(resps) - 1: + resps.extend([0] * (ups - len(resps) + 1)) - resps[ups] += 1 + resps[ups] += 1 return resps @@ -97,16 +79,19 @@ Connection: close """ resp = self.http(to_send, raw_resp=True, raw=True, port=port) - ups = re.findall('X-Upstream: (\d+)', resp) - resps = [0] * (int(max(ups)) + 1) + status = re.findall(r'HTTP\/\d\.\d\s(\d\d\d)', resp) + status = list(filter(lambda x: x[:2] == '20', status)) + ups = list(map(lambda x: int(x[-1]), status)) + resps = [0] * (max(ups) + 1) for i in range(len(ups)): - resps[int(ups[i])] += 1 + resps[ups[i]] += 1 return resps def test_upstreams_rr_no_weight(self): resps = self.get_resps() + self.assertEqual(sum(resps), 100, 'no weight sum') self.assertLessEqual( abs(resps[0] - resps[1]), self.cpu_count, 'no weight' ) @@ -127,6 +112,7 @@ Connection: close ) resps = self.get_resps() + self.assertEqual(sum(resps), 100, 'no weight 3 sum') self.assertLessEqual( abs(resps[0] - resps[1]), self.cpu_count, 'no weight 3' ) @@ -138,6 +124,7 @@ Connection: close ) resps = self.get_resps() + self.assertEqual(sum(resps), 100, 'no weight 4 sum') self.assertLessEqual( max(resps) - min(resps), self.cpu_count, 'no weight 4' ) @@ -193,6 +180,67 @@ Connection: close self.assertEqual(resps[0], 60, 'weight 2 0') self.assertEqual(resps[2], 40, 'weight 2 1') + def test_upstreams_rr_weight_rational(self): + def set_weights(w1, w2): + self.assertIn( + 'success', + self.conf( + { + "127.0.0.1:7081": {"weight": w1}, + "127.0.0.1:7082": {"weight": w2}, + }, + 'upstreams/one/servers', + ), + 'configure weights', + ) + + def check_reqs(w1, w2, reqs=10): + resps = self.get_resps_sc(req=reqs) + self.assertEqual(resps[0], reqs * w1 / (w1 + w2), 'weight 1') + self.assertEqual(resps[1], reqs * w2 / (w1 + w2), 'weight 2') + + def check_weights(w1, w2): + set_weights(w1, w2) + check_reqs(w1, w2) + + check_weights(0, 1) + check_weights(0, 999999.0123456) + check_weights(1, 9) + check_weights(100000, 900000) + check_weights(1, .25) + check_weights(1, 0.25) + check_weights(0.2, .8) + check_weights(1, 1.5) + check_weights(1e-3, 1E-3) + check_weights(1e-20, 1e-20) + check_weights(1e4, 1e4) + check_weights(1000000, 1000000) + + set_weights(0.25, 0.25) + self.assertIn( + 'success', + self.conf_delete('upstreams/one/servers/127.0.0.1:7081/weight'), + 'delete weight', + ) + check_reqs(1, 0.25) + + self.assertIn( + 'success', + self.conf( + { + "127.0.0.1:7081": {"weight": 0.1}, + "127.0.0.1:7082": {"weight": 1}, + "127.0.0.1:7083": {"weight": 0.9}, + }, + 'upstreams/one/servers', + ), + 'configure weights', + ) + resps = self.get_resps_sc(req=20) + self.assertEqual(resps[0], 1, 'weight 3 1') + self.assertEqual(resps[1], 10, 'weight 3 2') + self.assertEqual(resps[2], 9, 'weight 3 3') + def test_upstreams_rr_independent(self): def sum_resps(*args): sum = [0] * len(args[0]) @@ -234,33 +282,71 @@ Connection: close r_one = sum_resps(r_one, self.get_resps(req=10)) r_two = sum_resps(r_two, self.get_resps(req=10, port=7090)) + + self.assertEqual(sum(r_one), 100, 'dep one mix sum') self.assertLessEqual( abs(r_one[0] - r_one[1]), self.cpu_count, 'dep one mix' ) + self.assertEqual(sum(r_two), 100, 'dep two mix sum') self.assertLessEqual( abs(r_two[0] - r_two[1]), self.cpu_count, 'dep two mix' ) def test_upstreams_rr_delay(self): - headers_delay_1 = { - 'Connection': 'close', - 'Host': 'localhost', - 'Content-Length': '0', - 'X-Delay': '1', - } - headers_no_delay = { - 'Connection': 'close', - 'Host': 'localhost', - 'Content-Length': '0', - } + self.assertIn( + 'success', + self.conf( + { + "listeners": { + "*:7080": {"pass": "upstreams/one"}, + "*:7081": {"pass": "routes"}, + "*:7082": {"pass": "routes"}, + }, + "upstreams": { + "one": { + "servers": { + "127.0.0.1:7081": {}, + "127.0.0.1:7082": {}, + }, + }, + }, + "routes": [ + { + "match": {"destination": "*:7081"}, + "action": {"pass": "applications/delayed"}, + }, + { + "match": {"destination": "*:7082"}, + "action": {"return": 201}, + }, + ], + "applications": { + "delayed": { + "type": "python", + "processes": {"spare": 0}, + "path": self.current_dir + "/python/delayed", + "working_directory": self.current_dir + + "/python/delayed", + "module": "wsgi", + } + }, + }, + ), + 'upstreams initial configuration', + ) req = 50 socks = [] for i in range(req): - headers = headers_delay_1 if i % 5 == 0 else headers_no_delay + delay = 1 if i % 5 == 0 else 0 _, sock = self.get( - headers=headers, + headers={ + 'Host': 'localhost', + 'Content-Length': '0', + 'X-Delay': str(delay), + 'Connection': 'close', + }, start=True, no_recv=True, ) @@ -271,12 +357,12 @@ Connection: close resp = self.recvall(socks[i]).decode() socks[i].close() - m = re.search('X-Upstream: (\d+)', resp) + m = re.search('HTTP/1.1 20(\d)', resp) + self.assertIsNotNone(m, 'status') resps[int(m.group(1))] += 1 - self.assertLessEqual( - abs(resps[0] - resps[1]), self.cpu_count, 'dep two mix' - ) + self.assertEqual(sum(resps), req, 'delay sum') + self.assertLessEqual(abs(resps[0] - resps[1]), self.cpu_count, 'delay') def test_upstreams_rr_active_req(self): conns = 5 @@ -303,7 +389,7 @@ Connection: close # Send one more request and read response to make sure that previous # requests had enough time to reach server. - self.assertEqual(self.get()['status'], 200) + self.assertEqual(self.get()['body'], '') self.assertIn( 'success', @@ -327,13 +413,17 @@ Connection: close ) for i in range(conns): - resp = self.recvall(socks[i]).decode() - socks[i].close() - - self.assertRegex(resp, r'X-Upstream', 'active req GET') + self.assertEqual( + self.http(b'', sock=socks[i], raw=True)['body'], + '', + 'active req GET', + ) - resp = self.http(b"""0123456789""", sock=socks2[i], raw=True) - self.assertEqual(resp['status'], 200, 'active req POST') + self.assertEqual( + self.http(b"""0123456789""", sock=socks2[i], raw=True)['body'], + '', + 'active req POST', + ) def test_upstreams_rr_bad_server(self): self.assertIn( @@ -356,14 +446,11 @@ Connection: close def test_upstreams_rr_post(self): resps = [0, 0] for _ in range(50): - resps[ - int(self.post(body='0123456789')['headers']['X-Upstream']) - ] += 1 - resps[int(self.get()['headers']['X-Upstream'])] += 1 + resps[self.get()['status'] % 10] += 1 + resps[self.post(body='0123456789')['status'] % 10] += 1 - self.assertLessEqual( - abs(resps[0] - resps[1]), self.cpu_count, 'post' - ) + self.assertEqual(sum(resps), 100, 'post sum') + self.assertLessEqual(abs(resps[0] - resps[1]), self.cpu_count, 'post') def test_upstreams_rr_unix(self): addr_0 = self.testdir + '/sock_0' @@ -374,8 +461,8 @@ Connection: close self.conf( { "*:7080": {"pass": "upstreams/one"}, - "unix:" + addr_0: {"pass": "applications/ups_0"}, - "unix:" + addr_1: {"pass": "applications/ups_1"}, + "unix:" + addr_0: {"pass": "routes/one"}, + "unix:" + addr_1: {"pass": "routes/two"}, }, 'listeners', ), @@ -385,7 +472,7 @@ Connection: close self.assertIn( 'success', self.conf( - {"unix:" + addr_0: {}, "unix:" + addr_1: {},}, + {"unix:" + addr_0: {}, "unix:" + addr_1: {}}, 'upstreams/one/servers', ), 'configure servers unix', @@ -402,8 +489,8 @@ Connection: close self.conf( { "*:7080": {"pass": "upstreams/one"}, - "[::1]:7081": {"pass": "applications/ups_0"}, - "[::1]:7082": {"pass": "applications/ups_1"}, + "[::1]:7081": {"pass": "routes/one"}, + "[::1]:7082": {"pass": "routes/two"}, }, 'listeners', ), @@ -413,7 +500,7 @@ Connection: close self.assertIn( 'success', self.conf( - {"[::1]:7081": {}, "[::1]:7082": {},}, 'upstreams/one/servers' + {"[::1]:7081": {}, "[::1]:7082": {}}, 'upstreams/one/servers' ), 'configure servers ipv6', ) @@ -429,9 +516,29 @@ Connection: close self.conf({}, 'upstreams/one/servers'), 'configure servers empty', ) - self.assertEqual(self.get()['status'], 502, 'servers empty') + self.assertIn( + 'success', + self.conf( + {"127.0.0.1:7081": {"weight": 0}}, 'upstreams/one/servers' + ), + 'configure servers empty one', + ) + self.assertEqual(self.get()['status'], 502, 'servers empty one') + self.assertIn( + 'success', + self.conf( + { + "127.0.0.1:7081": {"weight": 0}, + "127.0.0.1:7082": {"weight": 0}, + }, + 'upstreams/one/servers', + ), + 'configure servers empty two', + ) + self.assertEqual(self.get()['status'], 502, 'servers empty two') + def test_upstreams_rr_invalid(self): self.assertIn( 'error', self.conf({}, 'upstreams'), 'upstreams empty', @@ -449,16 +556,21 @@ Connection: close self.conf({}, 'upstreams/one/servers/127.0.0.1:7081/blah'), 'invalid server option', ) - self.assertIn( - 'error', - self.conf({}, 'upstreams/one/servers/127.0.0.1:7081/weight'), - 'invalid weight option', - ) - self.assertIn( - 'error', - self.conf('-1', 'upstreams/one/servers/127.0.0.1:7081/weight'), - 'invalid negative weight', - ) + + def check_weight(w): + self.assertIn( + 'error', + self.conf(w, 'upstreams/one/servers/127.0.0.1:7081/weight'), + 'invalid weight option', + ) + check_weight({}) + check_weight('-1') + check_weight('1.') + check_weight('1.1.') + check_weight('.') + check_weight('.01234567890123') + check_weight('1000001') + check_weight('2e6') if __name__ == '__main__': |