M11: Übersicht-Tab — IST-Zustand-Diagramm des Routers
Neuer Tab zeigt die komplette aktuelle Router-Konfiguration als grafisches Diagramm: Interfaces, IP-Adressen, DHCP/Pools, Routen und Firewall/NAT in Spalten, verbunden durch Linien, die RouterOS' eigene Referenzfelder abbilden (VLAN->Basis-Interface, DHCP-Server->Pool, Firewall-Regel-> Interface/Adress-Liste usw.), nicht geraten. Rein lesend, kein apply(). Verbindungsarten sind farblich getrennt (8 Kategorien), Hover/Klick auf eine Karte hebt ihre Linien hervor und blendet den Rest ab. Detail-Panel zeigt Rohfelder + Verbindungen; Legende erklärt Spalten, Farben und listet bewusst nicht gegraphte Bereiche (VPN, WLAN-Sicherheitsprofile, Queues, System, Werkzeuge, Mangle/Raw), die weiterhin im Experte-Tab erreichbar bleiben. OverviewViewModel.buildGraph ist eine reine, nonisolated Funktion, getestet in OverviewGraphTests (6 Fälle: IP/Interface, VLAN-Parent, DHCP->Pool, DHCP-Netzwerk->passende IP-Adresse über RouterOS' eigenes "network"-Feld, Route nur bei Interface-Gateway, Firewall->Interface/ Adress-Liste). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CTgRxJTzaQwaRkngbaE1GJ
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import XCTest
|
||||
@testable import RouterOSAssistant
|
||||
|
||||
final class OverviewGraphTests: XCTestCase {
|
||||
private func item(_ fields: [String: String], id: String = "*1") -> RouterOSMenuItem {
|
||||
RouterOSMenuItem(id: id, fields: fields)
|
||||
}
|
||||
|
||||
func testInterfaceToIPAddressEdge() {
|
||||
let graph = OverviewViewModel.buildGraph(
|
||||
interfaces: [item(["name": "ether1", "type": "ether"])],
|
||||
bridgePorts: [], vlans: [], wireguardPeers: [],
|
||||
addresses: [item(["address": "192.168.88.1/24", "interface": "ether1", "network": "192.168.88.0"])],
|
||||
pools: [], dhcpServers: [], dhcpNetworks: [], dhcpClients: [], routes: [],
|
||||
filterRules: [], natRules: [], addressLists: []
|
||||
)
|
||||
|
||||
XCTAssertTrue(graph.nodes.contains { $0.id == "Interfaces:ether1" })
|
||||
XCTAssertTrue(graph.nodes.contains { $0.id == "IP-Adressen:192.168.88.1/24" })
|
||||
XCTAssertTrue(graph.edges.contains { $0.from == "Interfaces:ether1" && $0.to == "IP-Adressen:192.168.88.1/24" })
|
||||
}
|
||||
|
||||
func testVlanEdgeToParentInterface() {
|
||||
let graph = OverviewViewModel.buildGraph(
|
||||
interfaces: [
|
||||
item(["name": "ether5", "type": "ether"]),
|
||||
item(["name": "vlan20", "type": "vlan"])
|
||||
],
|
||||
bridgePorts: [],
|
||||
vlans: [item(["name": "vlan20", "vlan-id": "20", "interface": "ether5"])],
|
||||
wireguardPeers: [], addresses: [], pools: [], dhcpServers: [], dhcpNetworks: [],
|
||||
dhcpClients: [], routes: [], filterRules: [], natRules: [], addressLists: []
|
||||
)
|
||||
|
||||
XCTAssertTrue(graph.edges.contains { $0.from == "Interfaces:ether5" && $0.to == "Interfaces:vlan20" })
|
||||
let vlanNode = graph.nodes.first { $0.id == "Interfaces:vlan20" }
|
||||
XCTAssertEqual(vlanNode?.subtitle, "VLAN 20")
|
||||
}
|
||||
|
||||
func testDhcpServerEdgesToInterfaceAndPool() {
|
||||
let graph = OverviewViewModel.buildGraph(
|
||||
interfaces: [item(["name": "ether2", "type": "ether"])],
|
||||
bridgePorts: [], vlans: [], wireguardPeers: [], addresses: [],
|
||||
pools: [item(["name": "pool1", "ranges": "192.168.88.10-192.168.88.254"])],
|
||||
dhcpServers: [item(["name": "dhcp1", "interface": "ether2", "address-pool": "pool1"])],
|
||||
dhcpNetworks: [], dhcpClients: [], routes: [], filterRules: [], natRules: [], addressLists: []
|
||||
)
|
||||
|
||||
XCTAssertTrue(graph.edges.contains { $0.from == "Interfaces:ether2" && $0.to == "Pools & DHCP:dhcp:dhcp1" })
|
||||
XCTAssertTrue(graph.edges.contains { $0.from == "Pools & DHCP:dhcp:dhcp1" && $0.to == "Pools & DHCP:pool:pool1" })
|
||||
}
|
||||
|
||||
func testDhcpNetworkLinksViaAddressNetworkField() {
|
||||
let graph = OverviewViewModel.buildGraph(
|
||||
interfaces: [item(["name": "ether2", "type": "ether"])],
|
||||
bridgePorts: [], vlans: [], wireguardPeers: [],
|
||||
addresses: [item(["address": "192.168.88.1/24", "interface": "ether2", "network": "192.168.88.0"])],
|
||||
pools: [], dhcpServers: [],
|
||||
dhcpNetworks: [item(["address": "192.168.88.0/24", "gateway": "192.168.88.1"])],
|
||||
dhcpClients: [], routes: [], filterRules: [], natRules: [], addressLists: []
|
||||
)
|
||||
|
||||
XCTAssertTrue(graph.edges.contains {
|
||||
$0.from == "IP-Adressen:192.168.88.1/24" && $0.to == "Pools & DHCP:dhcpnet:192.168.88.0/24"
|
||||
})
|
||||
}
|
||||
|
||||
func testRouteLinksToInterfaceOnlyWhenGatewayIsAnInterfaceName() {
|
||||
let graph = OverviewViewModel.buildGraph(
|
||||
interfaces: [item(["name": "ether1", "type": "ether"])],
|
||||
bridgePorts: [], vlans: [], wireguardPeers: [], addresses: [], pools: [],
|
||||
dhcpServers: [], dhcpNetworks: [], dhcpClients: [],
|
||||
routes: [
|
||||
item(["dst-address": "0.0.0.0/0", "gateway": "ether1"]),
|
||||
item(["dst-address": "10.0.0.0/24", "gateway": "192.168.88.254"])
|
||||
],
|
||||
filterRules: [], natRules: [], addressLists: []
|
||||
)
|
||||
|
||||
XCTAssertTrue(graph.edges.contains { $0.from == "Interfaces:ether1" && $0.to == "route:0" })
|
||||
XCTAssertFalse(graph.edges.contains { $0.to == "route:1" })
|
||||
}
|
||||
|
||||
func testFirewallFilterEdgesToInterfacesAndAddressList() {
|
||||
let graph = OverviewViewModel.buildGraph(
|
||||
interfaces: [
|
||||
item(["name": "ether1", "type": "ether"]),
|
||||
item(["name": "ether2", "type": "ether"])
|
||||
],
|
||||
bridgePorts: [], vlans: [], wireguardPeers: [], addresses: [], pools: [],
|
||||
dhcpServers: [], dhcpNetworks: [], dhcpClients: [], routes: [],
|
||||
filterRules: [item([
|
||||
"chain": "forward", "action": "drop",
|
||||
"in-interface": "ether1", "out-interface": "ether2",
|
||||
"src-address-list": "gesperrt"
|
||||
])],
|
||||
natRules: [],
|
||||
addressLists: [item(["list": "gesperrt", "address": "10.0.0.5"])]
|
||||
)
|
||||
|
||||
XCTAssertTrue(graph.edges.contains { $0.from == "Interfaces:ether1" && $0.to == "filter:0" })
|
||||
XCTAssertTrue(graph.edges.contains { $0.from == "filter:0" && $0.to == "Interfaces:ether2" })
|
||||
XCTAssertTrue(graph.edges.contains { $0.from == "Firewall & NAT:addrlist:gesperrt" && $0.to == "filter:0" })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user