|
5 | 5 |
|
6 | 6 | import sys, os |
7 | 7 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) |
8 | | - from db_test_helpers import make_db, insert_device, minutes_ago, DummyDB, down_event_macs |
| 8 | + from db_test_helpers import make_db, insert_device, minutes_ago, DummyDB, down_event_macs, make_device_dict, sync_insert_devices |
9 | 9 | """ |
10 | 10 |
|
11 | 11 | import sqlite3 |
@@ -202,6 +202,125 @@ def insert_device( |
202 | 202 | ) |
203 | 203 |
|
204 | 204 |
|
| 205 | +def make_device_dict(mac: str = "aa:bb:cc:dd:ee:ff", **overrides) -> dict: |
| 206 | + """ |
| 207 | + Return a fully-populated Devices row dict with safe defaults. |
| 208 | +
|
| 209 | + Mirrors every column in CREATE_DEVICES so callers can be inserted |
| 210 | + directly via sync_insert_devices() or similar helpers. Pass keyword |
| 211 | + arguments to override any individual field. |
| 212 | +
|
| 213 | + Computed/view-only columns (devStatus, devIsSleeping, devFlapping, |
| 214 | + rowid, …) are intentionally absent — tests that need to verify they are |
| 215 | + dropped should add them after calling this function. |
| 216 | + """ |
| 217 | + base = { |
| 218 | + "devMac": mac, |
| 219 | + "devName": "Test Device", |
| 220 | + "devOwner": "", |
| 221 | + "devType": "", |
| 222 | + "devVendor": "Acme", |
| 223 | + "devFavorite": 0, |
| 224 | + "devGroup": "", |
| 225 | + "devComments": "", |
| 226 | + "devFirstConnection": "2024-01-01 00:00:00", |
| 227 | + "devLastConnection": "2024-01-02 00:00:00", |
| 228 | + "devLastIP": "192.168.1.10", |
| 229 | + "devPrimaryIPv4": "192.168.1.10", |
| 230 | + "devPrimaryIPv6": "", |
| 231 | + "devVlan": "", |
| 232 | + "devForceStatus": "", |
| 233 | + "devStaticIP": "", |
| 234 | + "devScan": 1, |
| 235 | + "devLogEvents": 1, |
| 236 | + "devAlertEvents": 1, |
| 237 | + "devAlertDown": 1, |
| 238 | + "devCanSleep": 0, |
| 239 | + "devSkipRepeated": 0, |
| 240 | + "devLastNotification": "", |
| 241 | + "devPresentLastScan": 1, |
| 242 | + "devIsNew": 0, |
| 243 | + "devLocation": "", |
| 244 | + "devIsArchived": 0, |
| 245 | + "devParentMAC": "", |
| 246 | + "devParentPort": "", |
| 247 | + "devIcon": "", |
| 248 | + "devGUID": "test-guid-1", |
| 249 | + "devSite": "", |
| 250 | + "devSSID": "", |
| 251 | + "devSyncHubNode": "node1", |
| 252 | + "devSourcePlugin": "", |
| 253 | + "devCustomProps": "", |
| 254 | + "devFQDN": "", |
| 255 | + "devParentRelType": "", |
| 256 | + "devReqNicsOnline": 0, |
| 257 | + "devMacSource": "", |
| 258 | + "devNameSource": "", |
| 259 | + "devFQDNSource": "", |
| 260 | + "devLastIPSource": "", |
| 261 | + "devVendorSource": "", |
| 262 | + "devSSIDSource": "", |
| 263 | + "devParentMACSource": "", |
| 264 | + "devParentPortSource": "", |
| 265 | + "devParentRelTypeSource": "", |
| 266 | + "devVlanSource": "", |
| 267 | + } |
| 268 | + base.update(overrides) |
| 269 | + return base |
| 270 | + |
| 271 | + |
| 272 | +# --------------------------------------------------------------------------- |
| 273 | +# Sync insert helper (shared by test/plugins/test_sync_insert.py and |
| 274 | +# test/plugins/test_sync_protocol.py — mirrors sync.py's insert block) |
| 275 | +# --------------------------------------------------------------------------- |
| 276 | + |
| 277 | +def sync_insert_devices( |
| 278 | + conn: sqlite3.Connection, |
| 279 | + device_data: list, |
| 280 | + existing_macs: set | None = None, |
| 281 | +) -> int: |
| 282 | + """ |
| 283 | + Schema-aware device INSERT mirroring sync.py's Mode-3 insert block. |
| 284 | +
|
| 285 | + Parameters |
| 286 | + ---------- |
| 287 | + conn: |
| 288 | + In-memory (or real) SQLite connection with a Devices table. |
| 289 | + device_data: |
| 290 | + List of device dicts as received from table_devices.json or a node log. |
| 291 | + existing_macs: |
| 292 | + Set of MAC addresses already present in Devices. Rows whose devMac is |
| 293 | + in this set are skipped. Pass ``None`` (default) to insert everything. |
| 294 | +
|
| 295 | + Returns the number of rows actually inserted. |
| 296 | + """ |
| 297 | + if not device_data: |
| 298 | + return 0 |
| 299 | + |
| 300 | + cursor = conn.cursor() |
| 301 | + |
| 302 | + candidates = ( |
| 303 | + [d for d in device_data if d["devMac"] not in existing_macs] |
| 304 | + if existing_macs is not None |
| 305 | + else list(device_data) |
| 306 | + ) |
| 307 | + |
| 308 | + if not candidates: |
| 309 | + return 0 |
| 310 | + |
| 311 | + cursor.execute("PRAGMA table_info(Devices)") |
| 312 | + db_columns = {row[1] for row in cursor.fetchall()} |
| 313 | + |
| 314 | + insert_cols = [k for k in candidates[0].keys() if k in db_columns] |
| 315 | + columns = ", ".join(insert_cols) |
| 316 | + placeholders = ", ".join("?" for _ in insert_cols) |
| 317 | + sql = f"INSERT INTO Devices ({columns}) VALUES ({placeholders})" |
| 318 | + values = [tuple(d.get(col) for col in insert_cols) for d in candidates] |
| 319 | + cursor.executemany(sql, values) |
| 320 | + conn.commit() |
| 321 | + return len(values) |
| 322 | + |
| 323 | + |
205 | 324 | # --------------------------------------------------------------------------- |
206 | 325 | # Assertion helpers |
207 | 326 | # --------------------------------------------------------------------------- |
|
0 commit comments