PiHoleV6
PiHole V6 integration using the new REST API. PiHole is a network-level advertisement and Internet tracker blocking application which acts as a DNS sinkhole.
IT Services · PiHole
Details
| ID | PiHoleV6 |
|---|---|
| Provider | Open Source |
| Category | IT Services |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
PiHole v6 integration using the new REST API. PiHole is a network-level advertisement and Internet tracker blocking application which acts as a DNS sinkhole and optionally a DHCP server, intended for use on a private network.
This integration was integrated and tested with PiHole v6.0 API.
Configure PiHole v6 in Cortex
| Parameter | Description | Required |
|---|---|---|
| url | Server URL (e.g. https://192.168.1.25) | True |
| password | PiHole admin password for API authentication | True |
| insecure | Trust any certificate (not secure) | False |
| proxy | Use system proxy settings | False |
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
pihole-get-summary
Get overview of PiHole activity including query stats, client counts, and gravity info.
Base Command
pihole-get-summary
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Summary.queries | Unknown | Query statistics including total, blocked, cached, forwarded counts. |
| PiHoleV6.Summary.clients | Unknown | Client statistics. |
| PiHoleV6.Summary.gravity | Unknown | Gravity list statistics. |
pihole-get-top-domains
Get top permitted or blocked domains.
Base Command
pihole-get-top-domains
Input
| Argument Name | Description | Required |
|---|---|---|
| count | Number of top domains to return. Default is 10. | Optional |
| blocked | If true, return top blocked domains instead of top permitted domains. Possible values are: true, false. Default is false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.TopDomains.domains | Unknown | Array of top domains with counts. |
| PiHoleV6.TopDomains.total_queries | Number | Total number of queries. |
pihole-get-top-clients
Get top clients by query count.
Base Command
pihole-get-top-clients
Input
| Argument Name | Description | Required |
|---|---|---|
| count | Number of top clients to return. Default is 10. | Optional |
| blocked | If true, return top blocked clients instead of top active clients. Possible values are: true, false. Default is false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.TopClients.clients | Unknown | Array of top clients with counts. |
| PiHoleV6.TopClients.total_queries | Number | Total number of queries. |
pihole-get-upstreams
Get metrics about upstream DNS destinations.
Base Command
pihole-get-upstreams
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Upstreams.upstreams | Unknown | Array of upstream destinations with query counts and response times. |
| PiHoleV6.Upstreams.forwarded_queries | Number | Number of forwarded queries. |
pihole-get-query-types
Get breakdown of DNS query types.
Base Command
pihole-get-query-types
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.QueryTypes.types | Unknown | Query type counts (A, AAAA, MX, etc). |
pihole-get-recent-blocked
Get most recently blocked domain(s).
Base Command
pihole-get-recent-blocked
Input
| Argument Name | Description | Required |
|---|---|---|
| count | Number of recently blocked domains to return. Default is 1. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.RecentBlocked.blocked | Unknown | List of recently blocked domains. |
pihole-get-history
Get activity graph data (queries over time).
Base Command
pihole-get-history
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.History.history | Unknown | Activity over time data with timestamps, total, cached, blocked, forwarded counts. |
pihole-get-history-clients
Get per-client activity graph data.
Base Command
pihole-get-history-clients
Input
| Argument Name | Description | Required |
|---|---|---|
| N | Maximum number of clients to return. 0 returns all. Default is 20. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.HistoryClients.clients | Unknown | Client information with query counts. |
| PiHoleV6.HistoryClients.history | Unknown | Per-client activity over time. |
pihole-get-queries
Get DNS query log with optional filtering.
Base Command
pihole-get-queries
Input
| Argument Name | Description | Required |
|---|---|---|
| length | Number of queries to return. Default is 100. | Optional |
| domain | Filter by domain (wildcards supported). | Optional |
| client_ip | Filter by client IP (wildcards supported). | Optional |
| client_name | Filter by client hostname (wildcards supported). | Optional |
| upstream | Filter by upstream server. | Optional |
| type | Filter by query type (A, AAAA, etc). | Optional |
| status | Filter by status (GRAVITY, FORWARDED, CACHE, etc). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Queries.queries | Unknown | Array of DNS query records. |
| PiHoleV6.Queries.recordsTotal | Number | Total number of available queries. |
pihole-get-blocking-status
Get current PiHole blocking status.
Base Command
pihole-get-blocking-status
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Blocking.blocking | String | Current blocking status (enabled/disabled). |
| PiHoleV6.Blocking.timer | Number | Remaining seconds until blocking mode changes automatically. Null if permanent. |
pihole-set-blocking
Enable or disable PiHole blocking, optionally with a timer.
Base Command
pihole-set-blocking
Input
| Argument Name | Description | Required |
|---|---|---|
| blocking | Enable or disable blocking. Possible values are: true, false. | Required |
| timer | Seconds until blocking mode automatically reverts. Leave empty for permanent change. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Blocking.blocking | String | New blocking status. |
| PiHoleV6.Blocking.timer | Number | Timer value if set. |
pihole-get-domains
Get domains from allow/deny lists. Filter by type and kind.
Base Command
pihole-get-domains
Input
| Argument Name | Description | Required |
|---|---|---|
| type | Domain type filter. Possible values are: allow, deny. | Optional |
| kind | Domain kind filter. Possible values are: exact, regex. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Domains.domains | Unknown | Array of domain entries. |
pihole-add-domain
Add a domain to allow/deny list.
Base Command
pihole-add-domain
Input
| Argument Name | Description | Required |
|---|---|---|
| type | Domain type. Possible values are: allow, deny. | Required |
| kind | Domain kind. Possible values are: exact, regex. | Required |
| domain | Domain to add. | Required |
| comment | Optional comment. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Domains.domains | Unknown | Added domain details. |
pihole-delete-domain
Delete a domain from allow/deny list.
Base Command
pihole-delete-domain
Input
| Argument Name | Description | Required |
|---|---|---|
| type | Domain type. Possible values are: allow, deny. | Required |
| kind | Domain kind. Possible values are: exact, regex. | Required |
| domain | Domain to delete. | Required |
Context Output
There is no context output for this command.
pihole-get-version
Get PiHole component versions.
Base Command
pihole-get-version
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Version | Unknown | Version information for all PiHole components. |
pihole-get-system-info
Get system information from PiHole host.
Base Command
pihole-get-system-info
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.SystemInfo | Unknown | System information (CPU, memory, disk, uptime, etc). |
pihole-get-ftl-info
Get FTL (Faster Than Light) engine information.
Base Command
pihole-get-ftl-info
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.FTLInfo | Unknown | FTL engine information. |
pihole-get-host-info
Get host information.
Base Command
pihole-get-host-info
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.HostInfo | Unknown | Host information. |
pihole-get-sensors
Get sensor information from PiHole host.
Base Command
pihole-get-sensors
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Sensors | Unknown | Sensor readings (temperature, etc). |
pihole-run-gravity
Update PiHole gravity (pull latest adlists).
Base Command
pihole-run-gravity
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Gravity.output | String | Gravity update output. |
pihole-restart-dns
Restart the pihole-FTL DNS service.
Base Command
pihole-restart-dns
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.RestartDNS | Unknown | Restart result. |
pihole-flush-logs
Flush DNS logs and purge last 24 hours from database.
Base Command
pihole-flush-logs
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.FlushLogs | Unknown | Flush result. |
pihole-flush-network
Flush the network table (remove all known devices and addresses).
Base Command
pihole-flush-network
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.FlushNetwork | Unknown | Flush result. |
pihole-get-network-devices
Get network devices known to PiHole.
Base Command
pihole-get-network-devices
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.NetworkDevices | Unknown | Network device information. |
pihole-get-network-gateway
Get network gateway information.
Base Command
pihole-get-network-gateway
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Gateway | Unknown | Gateway information. |
pihole-search-domain
Search for a domain across all PiHole lists and configuration.
Base Command
pihole-search-domain
Input
| Argument Name | Description | Required |
|---|---|---|
| domain | Domain to search for. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Search | Unknown | Search results showing where the domain appears in PiHole configuration. |
pihole-get-dhcp-leases
Get current DHCP leases.
Base Command
pihole-get-dhcp-leases
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.DHCPLeases | Unknown | DHCP lease information. |
pihole-get-groups
Get all groups.
Base Command
pihole-get-groups
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Groups | Unknown | Group information. |
pihole-add-group
Create a new group.
Base Command
pihole-add-group
Input
| Argument Name | Description | Required |
|---|---|---|
| name | Group name. | Required |
| comment | Optional comment. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Groups | Unknown | Created group details. |
pihole-delete-group
Delete a group.
Base Command
pihole-delete-group
Input
| Argument Name | Description | Required |
|---|---|---|
| name | Group name to delete. | Required |
Context Output
There is no context output for this command.
pihole-get-lists
Get all configured adlists.
Base Command
pihole-get-lists
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Lists | Unknown | Adlist information. |
pihole-add-list
Add a new adlist.
Base Command
pihole-add-list
Input
| Argument Name | Description | Required |
|---|---|---|
| address | URL of the adlist to add. | Required |
| comment | Optional comment. | Optional |
| enabled | Whether the list should be enabled. Possible values are: true, false. Default is true. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PiHoleV6.Lists | Unknown | Added list details. |
pihole-delete-list
Delete an adlist.
Base Command
pihole-delete-list
Input
| Argument Name | Description | Required |
|---|---|---|
| address | URL of the adlist to delete. | Required |
Context Output
There is no context output for this command.
Configuration parameters
url— Server URL (required)password— Password (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (33)
-
pihole-add-domainAdd a domain to allow/deny list.
-
pihole-add-groupCreate a new group.
-
pihole-add-listAdd a new adlist.
-
pihole-delete-domainDelete a domain from allow/deny list.
-
pihole-delete-groupDelete a group.
-
pihole-delete-listDelete an adlist.
-
pihole-flush-logsFlush DNS logs and purge last 24 hours from database.
-
pihole-flush-networkFlush the network table (remove all known devices and addresses).
-
pihole-get-blocking-statusGet current PiHole blocking status.
-
pihole-get-dhcp-leasesGet current DHCP leases.
-
pihole-get-domainsGet domains from allow/deny lists. Filter by type and kind.
-
pihole-get-ftl-infoGet FTL (Faster Than Light) engine information.
-
pihole-get-groupsGet all groups.
-
pihole-get-historyGet activity graph data (queries over time).
-
pihole-get-history-clientsGet per-client activity graph data.
-
pihole-get-host-infoGet host information.
-
pihole-get-listsGet all configured adlists.
-
pihole-get-network-devicesGet network devices known to PiHole.
-
pihole-get-network-gatewayGet network gateway information.
-
pihole-get-queriesGet DNS query log with optional filtering.
-
pihole-get-query-typesGet breakdown of DNS query types.
-
pihole-get-recent-blockedGet most recently blocked domain(s).
-
pihole-get-sensorsGet sensor information from PiHole host.
-
pihole-get-summaryGet overview of PiHole activity including query stats, client counts, and gravity info.
-
pihole-get-system-infoGet system information from PiHole host.
-
pihole-get-top-clientsGet top clients by query count.
-
pihole-get-top-domainsGet top permitted or blocked domains.
-
pihole-get-upstreamsGet metrics about upstream DNS destinations.
-
pihole-get-versionGet PiHole component versions.
-
pihole-restart-dnsRestart the pihole-FTL DNS service.
-
pihole-run-gravityUpdate PiHole gravity (pull latest adlists).
-
pihole-search-domainSearch for a domain across all PiHole lists and configuration.
-
pihole-set-blockingEnable or disable PiHole blocking, optionally with a timer.
"""PiHole V6 Integration - Unit Tests Pytest Unit Tests: all function names must start with "test_" Uses demistomock and mocker for mocking API calls. """ import pytest from CommonServerPython import DemistoException from PiHoleV6 import ( PiHoleV6Client, test_module, get_summary_command, get_top_domains_command, get_top_clients_command, get_upstreams_command, get_query_types_command, get_recent_blocked_command, get_history_command, get_history_clients_command, get_queries_command, get_blocking_status_command, set_blocking_command, get_domains_command, add_domain_command, delete_domain_command, get_version_command, get_system_info_command, get_ftl_info_command, get_host_info_command, get_sensors_command, run_gravity_command, restart_dns_command, flush_logs_command, flush_network_command, get_network_devices_command, get_network_gateway_command, search_domain_command, get_dhcp_leases_command, get_groups_command, add_group_command, delete_group_command, get_lists_command, add_list_command, delete_list_command, ) BASE_URL = "https://pihole.example.com/api" AUTH_RESPONSE = {"session": {"valid": True, "sid": "test-session-id"}} @pytest.fixture def client(mocker) -> PiHoleV6Client: """Fixture to create a PiHoleV6Client instance with mocked authentication.""" c = PiHoleV6Client(base_url=BASE_URL, password="testpass", verify=False, proxy=False) mocker.patch.object(c, "authenticate") c.sid = "test-session-id" return c def test_test_module(mocker): """ Given: - A PiHoleV6 client with valid credentials. When: - Running the test-module command. Then: - Should return 'ok' after successful authentication and logout. """ client = PiHoleV6Client(base_url=BASE_URL, password="testpass", verify=False, proxy=False) mocker.patch.object(client, "authenticate") mocker.patch.object(client, "logout") result = test_module(client) assert result == "ok" client.authenticate.assert_called_once() client.logout.assert_called_once() def test_authenticate_success(mocker): """ Given: - Valid PiHole credentials. When: - Authenticating with the API. Then: - Should set the session ID. """ client = PiHoleV6Client(base_url=BASE_URL, password="testpass", verify=False, proxy=False) mocker.patch.object(client, "_http_request", return_value=AUTH_RESPONSE) client.authenticate() assert client.sid == "test-session-id" def test_authenticate_failure(mocker): """ Given: - Invalid PiHole credentials. When: - Authenticating with the API. Then: - Should raise a DemistoException. """ client = PiHoleV6Client(base_url=BASE_URL, password="wrong", verify=False, proxy=False) mocker.patch.object(client, "_http_request", return_value={"session": {"valid": False, "message": "Invalid password"}}) with pytest.raises(DemistoException, match="Authentication failed"): client.authenticate() def test_get_summary_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-summary command. Then: - Should return summary data with queries and gravity info. """ mock_data = { "queries": {"total": 1000, "blocked": 200, "cached": 300, "forwarded": 500}, "clients": {"total": 10, "active": 5}, "gravity": {"domains_being_blocked": 50000}, } mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_summary_command(client) results.assert_called_once() cmd_results = results.call_args[0][0] assert cmd_results.outputs["queries"]["total"] == 1000 assert "Summary" in cmd_results.readable_output def test_get_top_domains_command(client, mocker): """ Given: - A connected PiHoleV6 client with count and blocked arguments. When: - Running pihole-get-top-domains command. Then: - Should return top domains data. """ mock_data = {"domains": [{"domain": "example.com", "count": 100}], "total_queries": 1000} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_top_domains_command(client, {"count": "5", "blocked": "false"}) results.assert_called_once() client.api_request.assert_called_with("GET", "/stats/top_domains", params={"count": 5, "blocked": False}) def test_get_top_clients_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-top-clients command. Then: - Should return top clients data. """ mock_data = {"clients": [{"name": "pc1", "ip": "192.168.1.10", "count": 50}], "total_queries": 500} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_top_clients_command(client, {"count": "10", "blocked": "true"}) results.assert_called_once() client.api_request.assert_called_with("GET", "/stats/top_clients", params={"count": 10, "blocked": True}) def test_get_upstreams_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-upstreams command. Then: - Should return upstream DNS data. """ mock_data = {"upstreams": [{"ip": "8.8.8.8", "count": 300}], "forwarded_queries": 300} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_upstreams_command(client) results.assert_called_once() def test_get_query_types_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-query-types command. Then: - Should return query type breakdown. """ mock_data = {"types": [{"name": "A", "count": 500}, {"name": "AAAA", "count": 200}]} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_query_types_command(client) results.assert_called_once() def test_get_recent_blocked_command(client, mocker): """ Given: - A connected PiHoleV6 client with count argument. When: - Running pihole-get-recent-blocked command. Then: - Should return recently blocked domains. """ mock_data = {"blocked": [{"domain": "ads.example.com"}]} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_recent_blocked_command(client, {"count": "5"}) results.assert_called_once() client.api_request.assert_called_with("GET", "/stats/recent_blocked", params={"count": 5}) def test_get_history_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-history command. Then: - Should return history data. """ mock_data = {"history": [{"timestamp": 1000, "total": 100, "blocked": 10}]} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_history_command(client) results.assert_called_once() def test_get_history_clients_command(client, mocker): """ Given: - A connected PiHoleV6 client with N argument. When: - Running pihole-get-history-clients command. Then: - Should return per-client history data. """ mock_data = {"clients": [{"name": "pc1"}], "history": []} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_history_clients_command(client, {"N": "5"}) results.assert_called_once() client.api_request.assert_called_with("GET", "/history/clients", params={"N": 5}) def test_get_queries_command(client, mocker): """ Given: - A connected PiHoleV6 client with filter arguments. When: - Running pihole-get-queries command. Then: - Should return filtered query log. """ mock_data = {"queries": [{"domain": "example.com", "type": "A"}], "recordsTotal": 1} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_queries_command(client, {"length": "10", "domain": "example.com"}) results.assert_called_once() client.api_request.assert_called_with("GET", "/queries", params={"length": 10, "domain": "example.com"}) def test_get_blocking_status_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-blocking-status command. Then: - Should return current blocking status. """ mock_data = {"blocking": "enabled", "timer": None} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_blocking_status_command(client) results.assert_called_once() cmd_results = results.call_args[0][0] assert cmd_results.outputs["blocking"] == "enabled" assert "Blocking Status" in cmd_results.readable_output def test_set_blocking_command(client, mocker): """ Given: - A connected PiHoleV6 client with blocking and timer arguments. When: - Running pihole-set-blocking command. Then: - Should set blocking status and return result. """ mock_data = {"blocking": "enabled", "timer": 60} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") set_blocking_command(client, {"blocking": "true", "timer": "60"}) results.assert_called_once() client.api_request.assert_called_with("POST", "/dns/blocking", json_data={"blocking": True, "timer": 60}) def test_set_blocking_permanent(client, mocker): """ Given: - A connected PiHoleV6 client with blocking but no timer. When: - Running pihole-set-blocking without a timer. Then: - Should set blocking permanently (timer=None). """ mock_data = {"blocking": "disabled", "timer": None} mocker.patch.object(client, "api_request", return_value=mock_data) mocker.patch("PiHoleV6.return_results") set_blocking_command(client, {"blocking": "false"}) client.api_request.assert_called_with("POST", "/dns/blocking", json_data={"blocking": False, "timer": None}) def test_get_domains_command(client, mocker): """ Given: - A connected PiHoleV6 client with type and kind filters. When: - Running pihole-get-domains command. Then: - Should return filtered domain list. """ mock_data = {"domains": [{"domain": "ads.com", "type": "deny", "kind": "exact"}]} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_domains_command(client, {"type": "deny", "kind": "exact"}) results.assert_called_once() client.api_request.assert_called_with("GET", "/domains/deny/exact") def test_get_domains_no_filter(client, mocker): """ Given: - A connected PiHoleV6 client with no filters. When: - Running pihole-get-domains command without type/kind. Then: - Should return all domains. """ mock_data = {"domains": []} mocker.patch.object(client, "api_request", return_value=mock_data) mocker.patch("PiHoleV6.return_results") get_domains_command(client, {}) client.api_request.assert_called_with("GET", "/domains") def test_add_domain_command(client, mocker): """ Given: - A connected PiHoleV6 client with domain details. When: - Running pihole-add-domain command. Then: - Should add the domain and return result. """ mock_data = {"domains": [{"domain": "ads.com", "comment": "block ads"}]} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") add_domain_command(client, {"type": "deny", "kind": "exact", "domain": "ads.com", "comment": "block ads"}) results.assert_called_once() client.api_request.assert_called_with("POST", "/domains/deny/exact", json_data={"domain": "ads.com", "comment": "block ads"}) def test_delete_domain_command(client, mocker): """ Given: - A connected PiHoleV6 client with a domain to delete. When: - Running pihole-delete-domain command. Then: - Should delete the domain and return confirmation. """ mocker.patch.object(client, "api_request") results = mocker.patch("PiHoleV6.return_results") delete_domain_command(client, {"type": "deny", "kind": "exact", "domain": "ads.com"}) results.assert_called_once() cmd_results = results.call_args[0][0] assert "ads.com" in cmd_results.readable_output assert "deleted" in cmd_results.readable_output def test_get_version_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-version command. Then: - Should return version info for all components. """ mock_data = { "core": {"local": {"version": "v6.0"}}, "web": {"local": {"version": "v6.0"}}, "ftl": {"local": {"version": "v6.0"}}, } mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_version_command(client) results.assert_called_once() cmd_results = results.call_args[0][0] assert "Version" in cmd_results.readable_output def test_get_system_info_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-system-info command. Then: - Should return system information. """ mock_data = {"cpu": {"percent": 5.0}, "memory": {"percent": 30.0}} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_system_info_command(client) results.assert_called_once() def test_get_ftl_info_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-ftl-info command. Then: - Should return FTL engine information. """ mock_data = {"version": "v6.0", "database": {"queries": 50000}} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_ftl_info_command(client) results.assert_called_once() def test_get_host_info_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-host-info command. Then: - Should return host information. """ mock_data = {"hostname": "pihole", "uname": "Linux"} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_host_info_command(client) results.assert_called_once() def test_get_sensors_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-sensors command. Then: - Should return sensor readings. """ mock_data = {"cpu_temp": 45.5} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_sensors_command(client) results.assert_called_once() def test_run_gravity_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-run-gravity command. Then: - Should trigger gravity update and return output. """ mocker.patch.object(client, "api_request", return_value="Gravity update completed") results = mocker.patch("PiHoleV6.return_results") run_gravity_command(client) results.assert_called_once() cmd_results = results.call_args[0][0] assert "Gravity" in cmd_results.readable_output def test_restart_dns_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-restart-dns command. Then: - Should restart DNS and return result. """ mock_data = {"status": "restarted"} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") restart_dns_command(client) results.assert_called_once() def test_flush_logs_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-flush-logs command. Then: - Should flush logs and return result. """ mock_data = {"status": "flushed"} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") flush_logs_command(client) results.assert_called_once() def test_flush_network_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-flush-network command. Then: - Should flush network table and return result. """ mock_data = {"status": "flushed"} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") flush_network_command(client) results.assert_called_once() def test_get_network_devices_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-network-devices command. Then: - Should return network devices. """ mock_data = {"devices": [{"ip": "192.168.1.10", "mac": "AA:BB:CC:DD:EE:FF"}]} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_network_devices_command(client) results.assert_called_once() def test_get_network_gateway_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-network-gateway command. Then: - Should return gateway information. """ mock_data = {"ip": "192.168.1.1"} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_network_gateway_command(client) results.assert_called_once() def test_search_domain_command(client, mocker): """ Given: - A connected PiHoleV6 client with a domain to search. When: - Running pihole-search-domain command. Then: - Should return search results for the domain. """ mock_data = {"results": [{"domain": "example.com", "list": "gravity"}]} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") search_domain_command(client, {"domain": "example.com"}) results.assert_called_once() client.api_request.assert_called_with("GET", "/search/example.com") def test_get_dhcp_leases_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-dhcp-leases command. Then: - Should return DHCP lease information. """ mock_data = {"leases": [{"ip": "192.168.1.100", "mac": "AA:BB:CC:DD:EE:FF", "hostname": "device1"}]} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_dhcp_leases_command(client) results.assert_called_once() def test_get_groups_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-groups command. Then: - Should return all groups. """ mock_data = {"groups": [{"name": "default", "enabled": True}]} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_groups_command(client) results.assert_called_once() def test_add_group_command(client, mocker): """ Given: - A connected PiHoleV6 client with group details. When: - Running pihole-add-group command. Then: - Should create the group and return result. """ mock_data = {"groups": [{"name": "test-group", "comment": "test"}]} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") add_group_command(client, {"name": "test-group", "comment": "test"}) results.assert_called_once() client.api_request.assert_called_with("POST", "/groups", json_data={"name": "test-group", "comment": "test"}) def test_delete_group_command(client, mocker): """ Given: - A connected PiHoleV6 client with a group to delete. When: - Running pihole-delete-group command. Then: - Should delete the group and return confirmation. """ mocker.patch.object(client, "api_request") results = mocker.patch("PiHoleV6.return_results") delete_group_command(client, {"name": "test-group"}) results.assert_called_once() cmd_results = results.call_args[0][0] assert "test-group" in cmd_results.readable_output assert "deleted" in cmd_results.readable_output def test_get_lists_command(client, mocker): """ Given: - A connected PiHoleV6 client. When: - Running pihole-get-lists command. Then: - Should return all adlists. """ mock_data = {"lists": [{"address": "https://adlist.example.com", "enabled": True}]} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") get_lists_command(client) results.assert_called_once() def test_add_list_command(client, mocker): """ Given: - A connected PiHoleV6 client with adlist details. When: - Running pihole-add-list command. Then: - Should add the adlist and return result. """ mock_data = {"lists": [{"address": "https://adlist.example.com", "enabled": True}]} mocker.patch.object(client, "api_request", return_value=mock_data) results = mocker.patch("PiHoleV6.return_results") add_list_command(client, {"address": "https://adlist.example.com", "comment": "ads", "enabled": "true"}) results.assert_called_once() client.api_request.assert_called_with( "POST", "/lists", json_data={"address": "https://adlist.example.com", "comment": "ads", "enabled": True} ) def test_delete_list_command(client, mocker): """ Given: - A connected PiHoleV6 client with an adlist to delete. When: - Running pihole-delete-list command. Then: - Should delete the adlist and return confirmation. """ mocker.patch.object(client, "api_request") results = mocker.patch("PiHoleV6.return_results") delete_list_command(client, {"address": "https://adlist.example.com"}) results.assert_called_once() cmd_results = results.call_args[0][0] assert "adlist.example.com" in cmd_results.readable_output assert "deleted" in cmd_results.readable_output