nextog-cli 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. nextog/__init__.py +4 -0
  2. nextog/cli.py +545 -0
  3. nextog/config/__init__.py +1 -0
  4. nextog/config/settings.py +132 -0
  5. nextog/core/__init__.py +1 -0
  6. nextog/core/engine.py +193 -0
  7. nextog/core/permissions.py +129 -0
  8. nextog/core/privacy.py +130 -0
  9. nextog/core/reporter.py +204 -0
  10. nextog/core/runner.py +236 -0
  11. nextog/data/__init__.py +1 -0
  12. nextog/data/local_db.py +367 -0
  13. nextog/data/models.py +72 -0
  14. nextog/data/sync.py +65 -0
  15. nextog/engines/__init__.py +1 -0
  16. nextog/engines/api/__init__.py +1 -0
  17. nextog/engines/api/graphql.py +54 -0
  18. nextog/engines/api/rest.py +346 -0
  19. nextog/engines/api/websocket.py +59 -0
  20. nextog/engines/embedded/__init__.py +1 -0
  21. nextog/engines/embedded/firmware.py +53 -0
  22. nextog/engines/embedded/hardware.py +330 -0
  23. nextog/engines/mobile/__init__.py +1 -0
  24. nextog/engines/mobile/android.py +333 -0
  25. nextog/engines/mobile/cross.py +48 -0
  26. nextog/engines/mobile/ios.py +46 -0
  27. nextog/engines/system/__init__.py +1 -0
  28. nextog/engines/system/load.py +121 -0
  29. nextog/engines/system/performance.py +128 -0
  30. nextog/engines/system/security.py +170 -0
  31. nextog/engines/web/__init__.py +1 -0
  32. nextog/engines/web/accessibility.py +191 -0
  33. nextog/engines/web/browser.py +387 -0
  34. nextog/engines/web/elements.py +285 -0
  35. nextog/engines/web/responsive.py +79 -0
  36. nextog/live/__init__.py +1 -0
  37. nextog/live/dashboard.py +30 -0
  38. nextog/live/panel.py +325 -0
  39. nextog/reports/__init__.py +1359 -0
  40. nextog/training/__init__.py +1 -0
  41. nextog/training/learner.py +269 -0
  42. nextog/training/patterns.py +102 -0
  43. nextog/utils/__init__.py +1 -0
  44. nextog/utils/helpers.py +91 -0
  45. nextog/utils/logger.py +37 -0
  46. nextog/utils/validators.py +98 -0
  47. nextog_cli-1.0.0.dist-info/METADATA +344 -0
  48. nextog_cli-1.0.0.dist-info/RECORD +51 -0
  49. nextog_cli-1.0.0.dist-info/WHEEL +5 -0
  50. nextog_cli-1.0.0.dist-info/entry_points.txt +2 -0
  51. nextog_cli-1.0.0.dist-info/top_level.txt +1 -0
nextog/live/panel.py ADDED
@@ -0,0 +1,325 @@
1
+ """
2
+ Live Testing Panel - Real-time testing dashboard
3
+ Uses FastAPI + WebSocket for live updates
4
+ """
5
+
6
+ import asyncio
7
+ import json
8
+ import webbrowser
9
+ import threading
10
+ from typing import Dict, Any, Optional
11
+ from datetime import datetime
12
+ from pathlib import Path
13
+ from rich.console import Console
14
+
15
+ console = Console()
16
+
17
+
18
+ class LivePanel:
19
+ """Real-time testing dashboard with WebSocket updates"""
20
+
21
+ def __init__(self, settings, db, privacy):
22
+ self.settings = settings
23
+ self.db = db
24
+ self.privacy = privacy
25
+ self.connected_clients = []
26
+ self.running = False
27
+
28
+ def start(self, host: str = "127.0.0.1", port: int = 8080, open_browser: bool = True):
29
+ """Start the live dashboard"""
30
+ console.print(f"[bold green]🚀 Starting Live Dashboard on http://{host}:{port}[/bold green]")
31
+ console.print("[dim]Press Ctrl+C to stop[/dim]")
32
+
33
+ if open_browser:
34
+ threading.Timer(1.5, lambda: webbrowser.open(f"http://{host}:{port}")).start()
35
+
36
+ self._start_server(host, port)
37
+
38
+ def _start_server(self, host: str, port: int):
39
+ """Start FastAPI server with WebSocket support"""
40
+ from fastapi import FastAPI, WebSocket, WebSocketDisconnect
41
+ from fastapi.responses import HTMLResponse
42
+ import uvicorn
43
+
44
+ app = FastAPI(title="nextOG Live Dashboard")
45
+
46
+ @app.get("/", response_class=HTMLResponse)
47
+ async def dashboard():
48
+ return self._get_dashboard_html()
49
+
50
+ @app.get("/api/status")
51
+ async def status():
52
+ return {
53
+ "status": "running",
54
+ "coverage": self._get_current_coverage(),
55
+ "timestamp": datetime.now().isoformat(),
56
+ "active_tests": 0,
57
+ }
58
+
59
+ @app.get("/api/coverage")
60
+ async def coverage():
61
+ return self._get_current_coverage()
62
+
63
+ @app.get("/api/results")
64
+ async def results():
65
+ return self.db.get_latest_results()
66
+
67
+ @app.websocket("/ws")
68
+ async def websocket_endpoint(websocket: WebSocket):
69
+ await websocket.accept()
70
+ self.connected_clients.append(websocket)
71
+ try:
72
+ while True:
73
+ data = await websocket.receive_text()
74
+ # Handle client messages
75
+ if data == "ping":
76
+ await websocket.send_json({"type": "pong"})
77
+ elif data == "status":
78
+ await websocket.send_json(self._get_current_coverage())
79
+ except WebSocketDisconnect:
80
+ self.connected_clients.remove(websocket)
81
+
82
+ # Run server
83
+ uvicorn.run(app, host=host, port=port, log_level="warning")
84
+
85
+ def _get_current_coverage(self) -> Dict:
86
+ """Get current coverage data"""
87
+ from nextog.core.reporter import CoverageReporter
88
+ reporter = CoverageReporter(self.db, self.settings)
89
+ return reporter.get_coverage()
90
+
91
+ def _get_dashboard_html(self) -> str:
92
+ """Generate dashboard HTML"""
93
+ return """<!DOCTYPE html>
94
+ <html lang="en">
95
+ <head>
96
+ <meta charset="UTF-8">
97
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
98
+ <title>nextOG Live Dashboard</title>
99
+ <style>
100
+ * { margin: 0; padding: 0; box-sizing: border-box; }
101
+ body {
102
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
103
+ background: #0f172a;
104
+ color: #e2e8f0;
105
+ min-height: 100vh;
106
+ }
107
+ .header {
108
+ background: linear-gradient(135deg, #1e293b, #0f172a);
109
+ padding: 20px 40px;
110
+ border-bottom: 1px solid #334155;
111
+ display: flex;
112
+ justify-content: space-between;
113
+ align-items: center;
114
+ }
115
+ .header h1 { font-size: 1.5rem; color: #38bdf8; }
116
+ .status-badge {
117
+ padding: 4px 12px;
118
+ border-radius: 20px;
119
+ font-size: 0.8rem;
120
+ font-weight: bold;
121
+ }
122
+ .status-running { background: #065f46; color: #6ee7b7; }
123
+ .container { padding: 30px 40px; max-width: 1400px; margin: 0 auto; }
124
+ .stats-grid {
125
+ display: grid;
126
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
127
+ gap: 20px;
128
+ margin-bottom: 30px;
129
+ }
130
+ .stat-card {
131
+ background: #1e293b;
132
+ border-radius: 12px;
133
+ padding: 24px;
134
+ border: 1px solid #334155;
135
+ }
136
+ .stat-card h3 { font-size: 0.85rem; color: #94a3b8; margin-bottom: 8px; }
137
+ .stat-card .value { font-size: 2rem; font-weight: bold; }
138
+ .stat-card .value.green { color: #22c55e; }
139
+ .stat-card .value.blue { color: #38bdf8; }
140
+ .stat-card .value.yellow { color: #eab308; }
141
+ .coverage-section {
142
+ background: #1e293b;
143
+ border-radius: 12px;
144
+ padding: 30px;
145
+ border: 1px solid #334155;
146
+ margin-bottom: 20px;
147
+ }
148
+ .coverage-bar {
149
+ background: #334155;
150
+ border-radius: 8px;
151
+ height: 24px;
152
+ overflow: hidden;
153
+ margin: 15px 0;
154
+ }
155
+ .coverage-fill {
156
+ height: 100%;
157
+ border-radius: 8px;
158
+ transition: width 1s ease;
159
+ background: linear-gradient(90deg, #22c55e, #38bdf8);
160
+ }
161
+ .phases { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-top: 20px; }
162
+ .phase {
163
+ background: #0f172a;
164
+ border-radius: 8px;
165
+ padding: 16px;
166
+ border: 1px solid #334155;
167
+ }
168
+ .phase-header { display: flex; justify-content: space-between; margin-bottom: 8px; }
169
+ .phase-bar { background: #334155; border-radius: 4px; height: 6px; overflow: hidden; }
170
+ .phase-fill { height: 100%; border-radius: 4px; background: #38bdf8; transition: width 0.5s; }
171
+ .log-section {
172
+ background: #1e293b;
173
+ border-radius: 12px;
174
+ padding: 20px;
175
+ border: 1px solid #334155;
176
+ max-height: 300px;
177
+ overflow-y: auto;
178
+ }
179
+ .log-entry {
180
+ padding: 8px 0;
181
+ border-bottom: 1px solid #334155;
182
+ font-family: 'Fira Code', monospace;
183
+ font-size: 0.85rem;
184
+ }
185
+ .log-time { color: #64748b; }
186
+ .log-pass { color: #22c55e; }
187
+ .log-fail { color: #ef4444; }
188
+ .log-info { color: #38bdf8; }
189
+ .ws-status { font-size: 0.8rem; color: #64748b; }
190
+ .ws-connected { color: #22c55e; }
191
+ </style>
192
+ </head>
193
+ <body>
194
+ <div class="header">
195
+ <h1>🚀 nextOG Live Dashboard</h1>
196
+ <div>
197
+ <span class="status-badge status-running">● LIVE</span>
198
+ <span class="ws-status" id="ws-status">Connecting...</span>
199
+ </div>
200
+ </div>
201
+
202
+ <div class="container">
203
+ <div class="stats-grid">
204
+ <div class="stat-card">
205
+ <h3>Total Coverage</h3>
206
+ <div class="value green" id="total-coverage">0%</div>
207
+ </div>
208
+ <div class="stat-card">
209
+ <h3>Tests Passed</h3>
210
+ <div class="value blue" id="tests-passed">0</div>
211
+ </div>
212
+ <div class="stat-card">
213
+ <h3>Tests Failed</h3>
214
+ <div class="value yellow" id="tests-failed">0</div>
215
+ </div>
216
+ <div class="stat-card">
217
+ <h3>Active Sessions</h3>
218
+ <div class="value blue" id="active-sessions">1</div>
219
+ </div>
220
+ </div>
221
+
222
+ <div class="coverage-section">
223
+ <h2>📊 Coverage Progress (0% → 90%)</h2>
224
+ <div class="coverage-bar">
225
+ <div class="coverage-fill" id="coverage-fill" style="width: 0%"></div>
226
+ </div>
227
+
228
+ <div class="phases">
229
+ <div class="phase">
230
+ <div class="phase-header">
231
+ <span>🔥 Smoke Tests</span>
232
+ <span id="phase1-pct">0%</span>
233
+ </div>
234
+ <div class="phase-bar"><div class="phase-fill" id="phase1-bar" style="width: 0%"></div></div>
235
+ </div>
236
+ <div class="phase">
237
+ <div class="phase-header">
238
+ <span>⚡ Functional Tests</span>
239
+ <span id="phase2-pct">0%</span>
240
+ </div>
241
+ <div class="phase-bar"><div class="phase-fill" id="phase2-bar" style="width: 0%"></div></div>
242
+ </div>
243
+ <div class="phase">
244
+ <div class="phase-header">
245
+ <span>🔗 Integration Tests</span>
246
+ <span id="phase3-pct">0%</span>
247
+ </div>
248
+ <div class="phase-bar"><div class="phase-fill" id="phase3-bar" style="width: 0%"></div></div>
249
+ </div>
250
+ <div class="phase">
251
+ <div class="phase-header">
252
+ <span>🛡️ Performance & Security</span>
253
+ <span id="phase4-pct">0%</span>
254
+ </div>
255
+ <div class="phase-bar"><div class="phase-fill" id="phase4-bar" style="width: 0%"></div></div>
256
+ </div>
257
+ </div>
258
+ </div>
259
+
260
+ <div class="log-section">
261
+ <h3>📋 Live Test Log</h3>
262
+ <div id="log-entries">
263
+ <div class="log-entry"><span class="log-info">[INFO]</span> Dashboard connected. Waiting for test results...</div>
264
+ </div>
265
+ </div>
266
+ </div>
267
+
268
+ <script>
269
+ // WebSocket connection
270
+ const ws = new WebSocket(`ws://${window.location.host}/ws`);
271
+
272
+ ws.onopen = () => {
273
+ document.getElementById('ws-status').textContent = '● Connected';
274
+ document.getElementById('ws-status').className = 'ws-status ws-connected';
275
+ };
276
+
277
+ ws.onmessage = (event) => {
278
+ const data = JSON.parse(event.data);
279
+ updateDashboard(data);
280
+ };
281
+
282
+ ws.onclose = () => {
283
+ document.getElementById('ws-status').textContent = '● Disconnected';
284
+ };
285
+
286
+ // Poll for updates
287
+ async function fetchStatus() {
288
+ try {
289
+ const resp = await fetch('/api/status');
290
+ const data = await resp.json();
291
+ updateDashboard(data);
292
+ } catch(e) {}
293
+ }
294
+
295
+ function updateDashboard(data) {
296
+ const coverage = data.coverage?.total_coverage || data.total_coverage || 0;
297
+
298
+ document.getElementById('total-coverage').textContent = coverage + '%';
299
+ document.getElementById('coverage-fill').style.width = coverage + '%';
300
+
301
+ // Update phases if available
302
+ const phases = data.coverage?.phases || {};
303
+ let i = 1;
304
+ for (const [name, phaseData] of Object.entries(phases)) {
305
+ const pct = phaseData.coverage || 0;
306
+ document.getElementById(`phase${i}-pct`).textContent = pct + '%';
307
+ document.getElementById(`phase${i}-bar`).style.width = pct + '%';
308
+ i++;
309
+ }
310
+ }
311
+
312
+ // Auto-refresh every 3 seconds
313
+ setInterval(fetchStatus, 3000);
314
+ fetchStatus();
315
+ </script>
316
+ </body>
317
+ </html>"""
318
+
319
+ async def broadcast(self, message: Dict):
320
+ """Send message to all connected clients"""
321
+ for client in self.connected_clients:
322
+ try:
323
+ await client.send_json(message)
324
+ except Exception:
325
+ pass