technitium 0.4.0

Typed async Rust client for the Technitium DNS Server API
Documentation
mod common;

use technitium::{Error, ZoneType};

const TEST_ZONE: &str = "test-zones.example.com";
const CLONE_ZONE: &str = "test-zones-clone.example.com";

#[tokio::test]
#[ignore = "requires running Technitium server"]
async fn zone_lifecycle() {
    let client = common::authenticated_client().await;

    // Cleanup from prior runs
    let _ = client.delete_zone(TEST_ZONE).await;
    let _ = client.delete_zone(CLONE_ZONE).await;

    // Create
    let zone = client
        .create_zone(TEST_ZONE, ZoneType::Primary)
        .await
        .expect("create_zone should succeed");
    assert_eq!(zone.name, TEST_ZONE);
    assert_eq!(zone.zone_type, ZoneType::Primary);

    // List and verify present
    let zones = client
        .list_zones()
        .await
        .expect("list_zones should succeed");
    assert!(
        zones.iter().any(|z| z.name == TEST_ZONE),
        "created zone should appear in list"
    );

    // Disable
    client
        .disable_zone(TEST_ZONE)
        .await
        .expect("disable_zone should succeed");

    // Enable
    client
        .enable_zone(TEST_ZONE)
        .await
        .expect("enable_zone should succeed");

    // Export
    let export = client
        .export_zone(TEST_ZONE)
        .await
        .expect("export_zone should succeed");
    assert!(!export.is_empty(), "exported zone file should not be empty");

    // Clone
    client
        .clone_zone(TEST_ZONE, CLONE_ZONE)
        .await
        .expect("clone_zone should succeed");

    // Verify clone exists
    let zones = client
        .list_zones()
        .await
        .expect("list_zones should succeed");
    assert!(
        zones.iter().any(|z| z.name == CLONE_ZONE),
        "cloned zone should appear in list"
    );

    // Cleanup
    client
        .delete_zone(CLONE_ZONE)
        .await
        .expect("delete cloned zone should succeed");
    client
        .delete_zone(TEST_ZONE)
        .await
        .expect("delete test zone should succeed");
}

#[tokio::test]
#[ignore = "requires running Technitium server"]
async fn delete_nonexistent_zone() {
    let client = common::authenticated_client().await;
    let result = client.delete_zone("nonexistent.invalid.zone").await;
    assert!(
        matches!(&result, Err(Error::Server { .. })),
        "deleting nonexistent zone should return server error, got: {result:?}"
    );
}