test_network_zone() {
    ensure_import_testimage
    ensure_has_localhost_remote "${INCUS_ADDR}"

    poolName=$(incus profile device get default root pool)

    # Enable the DNS server
    incus config unset core.https_address
    incus config set core.dns_address "${INCUS_ADDR}"

    # Create a network
    netName=inct$$
    incus network create "${netName}" \
        ipv4.address=192.0.2.1/24 \
        ipv6.address=fd42:4242:4242:1010::1/64

    # Create the zones
    ! incus network zone create /incus.example.net || false
    incus network zone create incus.example.net --description "Test network zone"
    incus network zone create 2.0.192.in-addr.arpa
    incus network zone create 0.1.0.1.2.4.2.4.2.4.2.4.2.4.d.f.ip6.arpa

    # Check that the description is set
    incus network zone list | grep -q -F 'Test network zone'
    incus network zone show incus.example.net | grep -q -F 'description: Test network zone'

    # Create project and forward zone in project.
    incus project create foo \
        -c features.images=false \
        -c restricted=true \
        -c restricted.networks.zones=example.net

    # Put an instance on the network in each project.
    incus init testimage c1 --network "${netName}" -d eth0,ipv4.address=192.0.2.42
    incus init testimage c2 --network "${netName}" --storage "${poolName}" -d eth0,ipv4.address=192.0.2.43 --project foo

    # Check features.networks.zones can be enabled if false in a non-empty project, but cannot be disabled again.
    incus project set foo features.networks.zones=true
    ! incus project set foo features.networks.zones=false || false

    # Check restricted.networks.zones is working.
    ! incus network zone create incus-foo.restricted.net --project foo || false

    # Create zone in project.
    incus network zone create incus-foo.example.net --project foo

    # Check all-projects column
    incus network zone list --all-projects -fcsv | grep -q default,incus.example.net || false
    incus network zone list --all-projects -fcsv | grep -q foo,incus-foo.example.net || false

    # Check associating a network to a missing zone isn't allowed.
    ! incus network set "${netName}" dns.zone.forward missing || false
    ! incus network set "${netName}" dns.zone.reverse.ipv4 missing || false
    ! incus network set "${netName}" dns.zone.reverse.ipv6 missing || false

    # Link the zones to the network
    incus network set "${netName}" \
        dns.zone.forward="incus.example.net, incus-foo.example.net" \
        dns.zone.reverse.ipv4=2.0.192.in-addr.arpa \
        dns.zone.reverse.ipv6=0.1.0.1.2.4.2.4.2.4.2.4.2.4.d.f.ip6.arpa

    # Check that associating a network to multiple forward zones from the same project isn't allowed.
    incus network zone create incus2.example.net
    ! incus network set "${netName}" dns.zone.forward "incus.example.net, incus2.example.net" || false
    incus network zone delete incus2.example.net

    # Check associating a network to multiple reverse zones isn't allowed.
    ! incus network set "${netName}" dns.zone.reverse.ipv4 "2.0.192.in-addr.arpa, incus.example.net" || false
    ! incus network set "${netName}" dns.zone.reverse.ipv6 "0.1.0.1.2.4.2.4.2.4.2.4.2.4.d.f.ip6.arpa, incus.example.net" || false

    incus start c1
    incus start c2 --project foo

    # Wait for IPv4 and IPv6 addresses
    while :; do
        sleep 1
        [ -n "$(incus list -c6 --format=csv c1)" ] || continue
        break
    done

    # Setup DNS peers
    incus network zone set incus.example.net peers.test.address=127.0.0.1
    incus network zone set incus-foo.example.net peers.test.address=127.0.0.1 --project=foo
    incus network zone set 2.0.192.in-addr.arpa peers.test.address=127.0.0.1
    incus network zone set 0.1.0.1.2.4.2.4.2.4.2.4.2.4.d.f.ip6.arpa peers.test.address=127.0.0.1

    # Check the zones
    DNS_ADDR="$(echo "${INCUS_ADDR}" | cut -d: -f1)"
    DNS_PORT="$(echo "${INCUS_ADDR}" | cut -d: -f2)"
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus.example.net
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus.example.net | grep "${netName}.gw.incus.example.net.\s\+300\s\+IN\s\+A\s\+"
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus.example.net | grep "c1.incus.example.net.\s\+300\s\+IN\s\+A\s\+"
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus.example.net | grep "${netName}.gw.incus.example.net.\s\+300\s\+IN\s\+AAAA\s\+"
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus.example.net | grep "c1.incus.example.net.\s\+300\s\+IN\s\+AAAA\s\+"

    # Check the c2 instance from project foo isn't in the forward view of incus.example.net
    ! dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus.example.net | grep "c2.incus.example.net" || false

    # Check the c2 instance is the incus-foo.example.net zone view, but not the network's gateways.
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus-foo.example.net
    ! dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus-foo.example.net | grep "${netName}.gw.incus-foo.example.net.\s\+300\s\+IN\s\+A\s\+" || false
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus-foo.example.net | grep "c2.incus-foo.example.net.\s\+300\s\+IN\s\+A\s\+"
    ! dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus-foo.example.net | grep "${netName}.gw.incus-foo.example.net.\s\+300\s\+IN\s\+AAAA\s\+" || false
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus-foo.example.net | grep "c2.incus-foo.example.net.\s\+300\s\+IN\s\+AAAA\s\+"

    # Check the c1 instance from project default isn't in the forward view of incus-foo.example.net
    ! dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus-foo.example.net | grep "c1.incus.example.net" || false

    # Check reverse zones include records from both projects associated to the relevant forward zone name.
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr 2.0.192.in-addr.arpa | grep -Fc "PTR" | grep -Fx 3
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr 2.0.192.in-addr.arpa | grep "300\s\+IN\s\+PTR\s\+${netName}.gw.incus.example.net."
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr 2.0.192.in-addr.arpa | grep "300\s\+IN\s\+PTR\s\+c1.incus.example.net."
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr 2.0.192.in-addr.arpa | grep "300\s\+IN\s\+PTR\s\+c2.incus-foo.example.net."

    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr 0.1.0.1.2.4.2.4.2.4.2.4.2.4.d.f.ip6.arpa
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr 0.1.0.1.2.4.2.4.2.4.2.4.2.4.d.f.ip6.arpa | grep -Fc "PTR" | grep -Fx 3
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr 0.1.0.1.2.4.2.4.2.4.2.4.2.4.d.f.ip6.arpa | grep "300\s\+IN\s\+PTR\s\+${netName}.gw.incus.example.net."
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr 0.1.0.1.2.4.2.4.2.4.2.4.2.4.d.f.ip6.arpa | grep "300\s\+IN\s\+PTR\s\+c1.incus.example.net."
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr 0.1.0.1.2.4.2.4.2.4.2.4.2.4.d.f.ip6.arpa | grep "300\s\+IN\s\+PTR\s\+c2.incus-foo.example.net."

    # Test extra records
    incus network zone record create incus.example.net demo user.foo=bar --description "Test network zone record"
    ! incus network zone record create incus.example.net demo user.foo=bar || false
    incus network zone record entry add incus.example.net demo A 1.1.1.1 --ttl 900
    incus network zone record entry add incus.example.net demo A 2.2.2.2
    incus network zone record entry add incus.example.net demo AAAA 1111::1111 --ttl 1800
    incus network zone record entry add incus.example.net demo AAAA 2222::2222
    incus network zone record entry add incus.example.net demo MX "1 mx1.example.net." --ttl 900
    incus network zone record entry add incus.example.net demo MX "10 mx2.example.net." --ttl 900
    incus network zone record list incus.example.net
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus.example.net | grep -Fc demo.incus.example.net | grep -Fx 6
    incus network zone record entry remove incus.example.net demo A 1.1.1.1
    incus network zone record list incus.example.net | grep -q -F "Test network zone record"
    incus network zone record show incus.example.net demo | grep -q -F "description: Test network zone record"

    incus admin sql global 'select * from networks_zones_records'
    incus network zone record create incus-foo.example.net demo user.foo=bar --project foo
    ! incus network zone record create incus-foo.example.net demo user.foo=bar --project foo || false
    incus network zone record entry add incus-foo.example.net demo A 1.1.1.1 --ttl 900 --project foo
    incus network zone record entry add incus-foo.example.net demo A 2.2.2.2 --project foo
    incus network zone record entry add incus-foo.example.net demo AAAA 1111::1111 --ttl 1800 --project foo
    incus network zone record entry add incus-foo.example.net demo AAAA 2222::2222 --project foo
    incus network zone record entry add incus-foo.example.net demo MX "1 mx1.example.net." --ttl 900 --project foo
    incus network zone record entry add incus-foo.example.net demo MX "10 mx2.example.net." --ttl 900 --project foo
    incus network zone record list incus-foo.example.net --project foo
    dig "@${DNS_ADDR}" -p "${DNS_PORT}" axfr incus-foo.example.net | grep -Fc demo.incus-foo.example.net | grep -Fx 6
    incus network zone record entry remove incus-foo.example.net demo A 1.1.1.1 --project foo

    # Cleanup
    incus delete -f c1
    incus delete -f c2 --project foo
    incus network delete "${netName}"
    incus network zone delete incus.example.net
    incus network zone delete incus-foo.example.net --project foo
    incus network zone delete 2.0.192.in-addr.arpa
    incus network zone delete 0.1.0.1.2.4.2.4.2.4.2.4.2.4.d.f.ip6.arpa
    incus project delete foo

    incus config unset core.dns_address
    incus config set core.https_address "${INCUS_ADDR}"
}
