Some checks failed
Docker Build & Push SugarCRM 6.5 CE / build-and-push (push) Has been cancelled
- start.sh: All-in-One Launcher (compose up + wait + API test) - test_api_extended.py: Full CRUD, search, relationships - test_seed.py: Mass data generator (accounts/contacts/leads) - Updated README with test script documentation
199 lines
6.9 KiB
Python
Executable File
199 lines
6.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
SugarCRM 6.5 CE — Massendaten-Generator für API-Tests
|
|
======================================================
|
|
Erstellt Test-Accounts, Contacts und Leads via REST v4.1 API.
|
|
Nützlich für Lasttests und Datenmigration-Tests.
|
|
|
|
Usage:
|
|
python3 test_seed.py # 10 Accounts + 10 Contacts
|
|
python3 test_seed.py --count 50 # 50 von jedem
|
|
python3 test_seed.py --clean # Alle Test-Daten löschen
|
|
"""
|
|
import http.client
|
|
import json
|
|
import hashlib
|
|
import urllib.parse
|
|
import sys
|
|
import os
|
|
import time
|
|
import argparse
|
|
from datetime import datetime
|
|
|
|
BASE_HOST = os.environ.get("SUGARCRM_HOST", "localhost")
|
|
BASE_PORT = os.environ.get("SUGARCRM_PORT", "2080")
|
|
ENDPOINT = "/service/v4_1/rest.php"
|
|
BASE_URL = f"{BASE_HOST}:{BASE_PORT}"
|
|
|
|
USER = os.environ.get("SUGARCRM_USER", "admin")
|
|
PASSWORD = os.environ.get("SUGARCRM_PASSWORD", "admin123")
|
|
PWD_HASH = hashlib.md5(PASSWORD.encode()).hexdigest()
|
|
|
|
COMPANIES = ["ACME Corp", "Globex Inc", "Initech", "Umbrella Corp", "Stark Industries",
|
|
"Wayne Enterprises", "Oscorp", "Massive Dynamic", "Weyland-Yutani", "Cyberdyne",
|
|
"Hooli", "Pied Piper", "Dunder Mifflin", "Sterling Cooper", "Los Pollos Hermanos",
|
|
"Bluth Company", "Soylent Corp", "Tyrell Corp", "Aperture Science", "Black Mesa"]
|
|
|
|
FIRST_NAMES = ["Max", "Erika", "Klaus", "Sabine", "Thomas", "Julia", "Michael", "Anna",
|
|
"Peter", "Laura", "Andreas", "Maria", "Stefan", "Nicole", "Markus"]
|
|
LAST_NAMES = ["Müller", "Schmidt", "Schneider", "Fischer", "Weber", "Meyer", "Wagner",
|
|
"Becker", "Hoffmann", "Schäfer", "Koch", "Bauer", "Richter", "Klein", "Wolf"]
|
|
|
|
INDUSTRIES = ["Technology", "Healthcare", "Finance", "Manufacturing", "Retail",
|
|
"Energy", "Education", "Media", "Transportation", "Real Estate"]
|
|
|
|
|
|
def call_api(method, rest_data):
|
|
conn = http.client.HTTPConnection(BASE_URL, timeout=30)
|
|
body = urllib.parse.urlencode({
|
|
"method": method,
|
|
"input_type": "JSON",
|
|
"response_type": "JSON",
|
|
"rest_data": json.dumps(rest_data)
|
|
})
|
|
conn.request("POST", ENDPOINT, body, {"Content-Type": "application/x-www-form-urlencoded"})
|
|
resp = conn.getresponse()
|
|
if resp.status == 302:
|
|
return {"_error": "Redirect"}
|
|
data = json.loads(resp.read().decode())
|
|
conn.close()
|
|
return data
|
|
|
|
|
|
def login():
|
|
print("🔑 Login...", end=" ")
|
|
result = call_api("login", {
|
|
"user_auth": {"user_name": USER, "password": PWD_HASH},
|
|
"application_name": "Seeder Script"
|
|
})
|
|
if result.get("id"):
|
|
print("✅")
|
|
return result["id"]
|
|
print(f"❌ {result.get('description', 'Unknown error')}")
|
|
sys.exit(1)
|
|
|
|
|
|
def create_accounts(session, count):
|
|
print(f"\n🏢 Erstelle {count} Accounts...")
|
|
created = 0
|
|
for i in range(count):
|
|
name = f"{COMPANIES[i % len(COMPANIES)]} (Seed {i+1})"
|
|
result = call_api("set_entry", {
|
|
"session": session,
|
|
"module_name": "Accounts",
|
|
"name_value_list": {
|
|
"name": {"name": "name", "value": name},
|
|
"account_type": {"name": "account_type", "value": "Customer"},
|
|
"industry": {"name": "industry", "value": INDUSTRIES[i % len(INDUSTRIES)]},
|
|
"phone_office": {"name": "phone_office", "value": f"+49 30 {1000000+i}"},
|
|
"description": {"name": "description", "value": f"API Seeder {datetime.now().isoformat()}"},
|
|
}
|
|
})
|
|
if result.get("id"):
|
|
created += 1
|
|
if (i+1) % 20 == 0:
|
|
print(f" ... {i+1}/{count}")
|
|
time.sleep(0.1) # Rate limiting
|
|
print(f" ✅ {created}/{count} Accounts erstellt")
|
|
return created
|
|
|
|
|
|
def create_contacts(session, count):
|
|
print(f"\n👤 Erstelle {count} Kontakte...")
|
|
created = 0
|
|
for i in range(count):
|
|
first = FIRST_NAMES[i % len(FIRST_NAMES)]
|
|
last = LAST_NAMES[i % len(LAST_NAMES)]
|
|
result = call_api("set_entry", {
|
|
"session": session,
|
|
"module_name": "Contacts",
|
|
"name_value_list": {
|
|
"first_name": {"name": "first_name", "value": first},
|
|
"last_name": {"name": "last_name", "value": f"{last} (Seed {i+1})"},
|
|
"email1": {"name": "email1", "value": f"{first.lower()}.{last.lower()}{i}@example.com"},
|
|
"phone_work": {"name": "phone_work", "value": f"+49 170 {1000000+i}"},
|
|
}
|
|
})
|
|
if result.get("id"):
|
|
created += 1
|
|
if (i+1) % 20 == 0:
|
|
print(f" ... {i+1}/{count}")
|
|
time.sleep(0.1)
|
|
print(f" ✅ {created}/{count} Kontakte erstellt")
|
|
return created
|
|
|
|
|
|
def create_leads(session, count):
|
|
print(f"\n🎯 Erstelle {count} Leads...")
|
|
created = 0
|
|
for i in range(count):
|
|
first = FIRST_NAMES[(i+5) % len(FIRST_NAMES)]
|
|
last = LAST_NAMES[(i+3) % len(LAST_NAMES)]
|
|
result = call_api("set_entry", {
|
|
"session": session,
|
|
"module_name": "Leads",
|
|
"name_value_list": {
|
|
"first_name": {"name": "first_name", "value": first},
|
|
"last_name": {"name": "last_name", "value": f"{last} (Lead {i+1})"},
|
|
"lead_source": {"name": "lead_source", "value": "API Import"},
|
|
"status": {"name": "status", "value": "New"},
|
|
}
|
|
})
|
|
if result.get("id"):
|
|
created += 1
|
|
if (i+1) % 20 == 0:
|
|
print(f" ... {i+1}/{count}")
|
|
time.sleep(0.1)
|
|
print(f" ✅ {created}/{count} Leads erstellt")
|
|
return created
|
|
|
|
|
|
def get_counts(session):
|
|
"""Count records in key modules."""
|
|
modules = ["Accounts", "Contacts", "Leads", "Opportunities", "Cases"]
|
|
print(f"\n📊 Datenbank-Inhalt:")
|
|
for mod in modules:
|
|
result = call_api("get_entries_count", {
|
|
"session": session,
|
|
"module_name": mod,
|
|
"query": "",
|
|
"deleted": 0
|
|
})
|
|
count = result.get("result_count", "?")
|
|
print(f" {mod:15s}: {count}")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="SugarCRM 6.5 CE - Massendaten-Generator")
|
|
parser.add_argument("--count", type=int, default=10, help="Anzahl Datensätze pro Typ")
|
|
parser.add_argument("--clean", action="store_true", help="Nur Zählen, keine Daten")
|
|
args = parser.parse_args()
|
|
|
|
print("=" * 60)
|
|
print("🍬 SugarCRM 6.5.26 CE — Massendaten-Generator")
|
|
print(f" URL: http://{BASE_URL}")
|
|
print("=" * 60)
|
|
|
|
session = login()
|
|
|
|
if args.clean:
|
|
get_counts(session)
|
|
print("\n✅ Fertig (nur Zählung).")
|
|
return
|
|
|
|
count = args.count
|
|
total = 0
|
|
total += create_accounts(session, count)
|
|
total += create_contacts(session, count)
|
|
total += create_leads(session, count)
|
|
|
|
get_counts(session)
|
|
|
|
print(f"\n{'=' * 60}")
|
|
print(f"✅ {total} Datensätze erstellt!")
|
|
print(f"{'=' * 60}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|