openleadr-client 0.1.4

OpenADR 3.0 client
Documentation
use axum::http::StatusCode;
use openleadr_client::{Error, Filter, PaginationOptions};
use openleadr_wire::{
    program::ProgramContent,
    target::{TargetEntry, TargetMap, TargetType},
};
use sqlx::PgPool;

mod common;

fn default_content() -> ProgramContent {
    ProgramContent {
        program_name: "program_name".to_string(),
        program_long_name: Some("program_long_name".to_string()),
        retailer_name: Some("retailer_name".to_string()),
        retailer_long_name: Some("retailer_long_name".to_string()),
        program_type: None,
        country: None,
        principal_subdivision: None,
        time_zone_offset: None,
        interval_period: None,
        program_descriptions: None,
        binding_events: None,
        local_price: None,
        payload_descriptors: None,
        targets: None,
    }
}

#[sqlx::test(fixtures("users"))]
async fn get(db: PgPool) {
    let client = common::setup_client(db).await;
    let program_client = client.create_program(default_content()).await.unwrap();

    assert_eq!(program_client.content(), &default_content());
}

#[sqlx::test(fixtures("users"))]
async fn delete(db: PgPool) {
    let client = common::setup_client(db).await;

    let program1 = ProgramContent {
        program_name: "program1".to_string(),
        ..default_content()
    };
    let program2 = ProgramContent {
        program_name: "program2".to_string(),
        ..default_content()
    };
    let program3 = ProgramContent {
        program_name: "program3".to_string(),
        ..default_content()
    };

    let mut ids = vec![];
    for content in [program1, program2.clone(), program3] {
        ids.push(client.create_program(content).await.unwrap());
    }

    let program = client.get_program_by_id(ids[1].id()).await.unwrap();
    assert_eq!(program.content(), &program2);

    let removed = program.delete().await.unwrap();
    assert_eq!(removed.content, program2);

    let programs = client.get_program_list(Filter::none()).await.unwrap();
    assert_eq!(programs.len(), 2);
}

#[sqlx::test(fixtures("users"))]
async fn update(db: PgPool) {
    let client = common::setup_client(db).await;

    let program1 = ProgramContent {
        program_name: "program1".to_string(),
        ..default_content()
    };

    let mut program = client.create_program(program1).await.unwrap();
    let creation_date_time = program.modification_date_time();

    let program2 = ProgramContent {
        program_name: "program1".to_string(),
        country: Some("NO".to_string()),
        ..default_content()
    };

    *program.content_mut() = program2.clone();
    program.update().await.unwrap();

    assert_eq!(program.content(), &program2);
    assert!(program.modification_date_time() > creation_date_time);
}

#[sqlx::test(fixtures("users"))]
async fn update_same_name(db: PgPool) {
    let client = common::setup_client(db).await;

    let program1 = ProgramContent {
        program_name: "program1".to_string(),
        ..default_content()
    };

    let program2 = ProgramContent {
        program_name: "program2".to_string(),
        ..default_content()
    };

    let _program1 = client.create_program(program1).await.unwrap();
    let mut program2 = client.create_program(program2).await.unwrap();
    let creation_date_time = program2.modification_date_time();

    let content = ProgramContent {
        program_name: "program1".to_string(),
        country: Some("NO".to_string()),
        ..default_content()
    };

    *program2.content_mut() = content;

    let Error::Problem(problem) = program2.update().await.unwrap_err() else {
        unreachable!()
    };

    assert_eq!(problem.status, StatusCode::CONFLICT);
    assert_eq!(program2.modification_date_time(), creation_date_time);
}

#[sqlx::test(fixtures("users"))]
async fn create_same_name(db: PgPool) {
    let client = common::setup_client(db).await;

    let program1 = ProgramContent {
        program_name: "program1".to_string(),
        ..default_content()
    };

    let _ = client.create_program(program1.clone()).await.unwrap();
    let Error::Problem(problem) = client.create_program(program1).await.unwrap_err() else {
        unreachable!()
    };

    assert_eq!(problem.status, StatusCode::CONFLICT);
}

#[sqlx::test(fixtures("users"))]
async fn retrieve_all_with_filter(db: PgPool) {
    let client = common::setup_client(db).await;

    let program1 = ProgramContent {
        program_name: "program1".to_string(),
        ..default_content()
    };
    let program2 = ProgramContent {
        program_name: "program2".to_string(),
        targets: Some(TargetMap(vec![TargetEntry {
            label: TargetType::Group,
            values: vec!["Group 2".to_string()],
        }])),
        ..default_content()
    };
    let program3 = ProgramContent {
        program_name: "program3".to_string(),
        targets: Some(TargetMap(vec![TargetEntry {
            label: TargetType::Group,
            values: vec!["Group 1".to_string()],
        }])),
        ..default_content()
    };
    let program4 = ProgramContent {
        program_name: "program4".to_string(),
        targets: Some(TargetMap(vec![TargetEntry {
            label: TargetType::Group,
            values: vec!["Group 1".to_string(), "Group 3".to_string()],
        }])),
        ..default_content()
    };

    for content in [program1, program2, program3, program4] {
        let _ = client.create_program(content).await.unwrap();
    }

    let programs = client
        .get_programs(Filter::none(), PaginationOptions { skip: 0, limit: 50 })
        .await
        .unwrap();
    assert_eq!(programs.len(), 4);

    // skip
    let programs = client
        .get_programs(Filter::none(), PaginationOptions { skip: 1, limit: 50 })
        .await
        .unwrap();
    assert_eq!(programs.len(), 3);

    // limit
    let programs = client
        .get_programs(Filter::none(), PaginationOptions { skip: 0, limit: 2 })
        .await
        .unwrap();
    assert_eq!(programs.len(), 2);

    // program name
    let err = client
        .get_programs(
            Filter::<&'static str>::By(TargetType::Private("NONSENSE".to_string()), &[]),
            PaginationOptions { skip: 0, limit: 2 },
        )
        .await
        .unwrap_err();
    let Error::Problem(problem) = err else {
        unreachable!()
    };
    assert_eq!(
        problem.status,
        StatusCode::BAD_REQUEST,
        "Do return BAD_REQUEST on empty targetValue"
    );

    let err = client
        .get_programs(
            Filter::By(TargetType::Private("NONSENSE".to_string()), &[""]),
            PaginationOptions { skip: 0, limit: 2 },
        )
        .await
        .unwrap_err();
    let Error::Problem(problem) = err else {
        unreachable!()
    };
    assert_eq!(
        problem.status,
        StatusCode::BAD_REQUEST,
        "Do return BAD_REQUEST on empty targetValue"
    );

    let programs = client
        .get_programs(
            Filter::By(TargetType::Private("NONSENSE".to_string()), &["test"]),
            PaginationOptions { skip: 0, limit: 50 },
        )
        .await
        .unwrap();
    assert_eq!(programs.len(), 0);

    let programs = client
        .get_programs(
            Filter::By(TargetType::Group, &["Group 1", "Group 2"]),
            PaginationOptions { skip: 0, limit: 50 },
        )
        .await
        .unwrap();
    assert_eq!(programs.len(), 3);

    let programs = client
        .get_programs(
            Filter::By(TargetType::Group, &["Group 1", "Group 3"]),
            PaginationOptions { skip: 0, limit: 50 },
        )
        .await
        .unwrap();
    assert_eq!(programs.len(), 2);

    let programs = client
        .get_programs(
            Filter::By(TargetType::Group, &["Group 2", "Group 3"]),
            PaginationOptions { skip: 0, limit: 50 },
        )
        .await
        .unwrap();
    assert_eq!(programs.len(), 2);

    let programs = client
        .get_programs(
            Filter::By(TargetType::Group, &["Group 3"]),
            PaginationOptions { skip: 0, limit: 50 },
        )
        .await
        .unwrap();
    assert_eq!(programs.len(), 1);

    let programs = client
        .get_programs(
            Filter::By(TargetType::Group, &["Group 1"]),
            PaginationOptions { skip: 0, limit: 50 },
        )
        .await
        .unwrap();
    assert_eq!(programs.len(), 2);

    let programs = client
        .get_programs(
            Filter::By(TargetType::Group, &["Group 2"]),
            PaginationOptions { skip: 0, limit: 50 },
        )
        .await
        .unwrap();
    assert_eq!(programs.len(), 1);

    let programs = client
        .get_programs(
            Filter::By(TargetType::Group, &["Not existent"]),
            PaginationOptions { skip: 0, limit: 50 },
        )
        .await
        .unwrap();
    assert_eq!(programs.len(), 0);
}