summaryrefslogtreecommitdiff
path: root/test_balancing.py
diff options
context:
space:
mode:
Diffstat (limited to 'test_balancing.py')
-rw-r--r--test_balancing.py154
1 files changed, 154 insertions, 0 deletions
diff --git a/test_balancing.py b/test_balancing.py
new file mode 100644
index 0000000..0f7933d
--- /dev/null
+++ b/test_balancing.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+"""Real-world load balancing test for vpnem API."""
+import urllib.request
+import json
+import sys
+
+BASE = "https://vpn.em-sysadmin.xyz"
+
+def req(path, method="GET", data=None, headers=None):
+ """Make HTTP request."""
+ url = BASE + path
+ h = headers or {}
+ h["Content-Type"] = "application/json"
+ body = json.dumps(data).encode() if data else None
+ rq = urllib.request.Request(url, data=body, headers=h, method=method)
+ try:
+ resp = urllib.request.urlopen(rq, timeout=10)
+ return json.loads(resp.read().decode())
+ except urllib.error.HTTPError as e:
+ print(f" ERROR {e.code}: {e.read().decode()[:200]}")
+ return None
+ except Exception as e:
+ print(f" ERROR: {e}")
+ return None
+
+def get_recommend(client_ip):
+ """Get recommendation for a client IP."""
+ return req("/api/v1/recommend", headers={"X-Forwarded-For": client_ip})
+
+def connect(client_ip, server_ip, node_id):
+ """Report connection."""
+ return req("/api/v1/connect", method="POST", data={
+ "server_ip": server_ip, "node_id": node_id
+ }, headers={"X-Forwarded-For": client_ip})
+
+def disconnect(client_ip):
+ """Report disconnection."""
+ return req("/api/v1/disconnect", method="POST", data={
+ "server_ip": ""
+ }, headers={"X-Forwarded-For": client_ip})
+
+def main():
+ print("=" * 70)
+ print("VPNEM Load Balancing — Real Server Test")
+ print("=" * 70)
+ print()
+
+ # Step 1: Test recommendations for multiple "studios"
+ print("[1] Testing recommendations for 5 different studios...")
+ print()
+ studios = [
+ ("195.10.20.1", "Barnaul Studio 1"),
+ ("195.10.20.2", "Barnaul Studio 2"),
+ ("91.50.60.1", "Moscow Studio"),
+ ("46.30.20.1", "Novosibirsk Studio"),
+ ("178.120.1.1", "Test Studio"),
+ ]
+
+ recommendations = {}
+ for ip, name in studios:
+ rec = get_recommend(ip)
+ if rec:
+ server = rec.get("recommended_server_ip", "none")
+ reason = rec.get("reason", "unknown")
+ load = rec.get("load_info", "no info")
+ recommendations[ip] = server
+ print(f" {name:25s} → {server:15s} ({reason})")
+ print(f" Load: {load}")
+ else:
+ print(f" {name:25s} → ERROR")
+
+ print()
+
+ # Step 2: Check distribution — do different studios get different servers?
+ print("[2] Distribution check...")
+ servers_used = list(recommendations.values())
+ unique = set(servers_used)
+ print(f" Studios: {len(studios)}, Recommended IPs: {len(unique)}")
+ print(f" Servers used: {', '.join(unique)}")
+ if len(unique) > 1:
+ print(" ✅ GOOD — different studios get different servers")
+ else:
+ print(" ⚠️ All studios got the same server (possible if load is equal)")
+
+ print()
+
+ # Step 3: Simulate connections
+ print("[3] Simulating connections...")
+ nodes = {
+ "5.180.97.181": "nl-multi-181",
+ "5.180.97.197": "nl-multi-197",
+ "5.180.97.198": "nl-multi-198",
+ "5.180.97.199": "nl-multi-199",
+ }
+ for ip, name in studios:
+ srv = recommendations.get(ip)
+ nid = nodes.get(srv, "nl-multi-181")
+ resp = connect(ip, srv, nid)
+ if resp:
+ rec_srv = resp.get("recommended_server_ip", "none")
+ print(f" {name:25s} connected → {srv:15s} (next rec: {rec_srv})")
+ else:
+ print(f" {name:25s} connect FAILED")
+
+ print()
+
+ # Step 4: Check recommendations AFTER connections (should shift)
+ print("[4] Recommendations AFTER connections (should re-balance)...")
+ new_ip = "100.100.100.1"
+ rec = get_recommend(new_ip)
+ if rec:
+ srv = rec.get("recommended_server_ip", "none")
+ reason = rec.get("reason", "unknown")
+ load = rec.get("load_info", "no info")
+ print(f" New Studio ({new_ip}) → {srv:15s} ({reason})")
+ print(f" Load: {load}")
+ # The new studio should NOT get the most loaded server
+ else:
+ print(f" ERROR getting recommendation")
+
+ print()
+
+ # Step 5: Disconnect one studio, check if recommendation changes
+ print("[5] Disconnecting first studio and checking rebalance...")
+ disc_ip = studios[0][0]
+ disconnect(disc_ip)
+ print(f" Disconnected {studios[0][1]} ({disc_ip})")
+
+ rec = get_recommend("200.200.200.1")
+ if rec:
+ srv = rec.get("recommended_server_ip", "none")
+ load = rec.get("load_info", "no info")
+ print(f" New Studio (200.200.200.1) → {srv:15s}")
+ print(f" Load: {load}")
+ else:
+ print(" ERROR")
+
+ print()
+
+ # Step 6: Clean up
+ print("[6] Cleaning up — disconnecting all test studios...")
+ for ip, name in studios:
+ disconnect(ip)
+ disconnect(new_ip)
+ disconnect("200.200.200.1")
+ print(" Done")
+
+ print()
+ print("=" * 70)
+ print("Test complete.")
+ print("=" * 70)
+
+if __name__ == "__main__":
+ main()