Skip to content

Commit

Permalink
Add 404 handler and tests for invalid names
Browse files Browse the repository at this point in the history
Signed-off-by: Maximilian Pohl <[email protected]>
  • Loading branch information
pohlm01 committed Oct 18, 2024
1 parent a9d8e1c commit b84371c
Show file tree
Hide file tree
Showing 9 changed files with 343 additions and 69 deletions.
58 changes: 58 additions & 0 deletions openadr-vtn/src/api/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,15 @@ mod test {
Router,
};
use http_body_util::BodyExt;
use openadr_wire::{
event::{EventPayloadDescriptor, EventType, Priority},
problem::Problem,
};
use openadr_wire::event::Priority;
use reqwest::Method;
use sqlx::PgPool;
use tower::{Service, ServiceExt};
use openadr_wire::problem::Problem;

fn default_event_content() -> EventContent {
EventContent {
Expand Down Expand Up @@ -461,6 +466,59 @@ mod test {
assert_eq!(programs.len(), 1);
}

#[ignore = "Depends on https://github.com/oadr3-org/openadr3-vtn-reference-implementation/issues/104"]
#[sqlx::test]
async fn name_constraint_validation(db: PgPool) {
let test = ApiTest::new(db, vec![AuthRole::AnyBusiness]);

let events = [
EventContent {
event_name: Some("".to_string()),
..default_event_content()
},
EventContent {
event_name: Some("This is more than 128 characters long and should be rejected This is more than 128 characters long and should be rejected asdfasd".to_string()),
..default_event_content()
},
EventContent {
payload_descriptors: Some(vec![
EventPayloadDescriptor{
payload_type: EventType::Private("".to_string()),
units: None,
currency: None,
}
]),
..default_event_content()
},
EventContent {
payload_descriptors: Some(vec![
EventPayloadDescriptor{
payload_type: EventType::Private("This is more than 128 characters long and should be rejected This is more than 128 characters long and should be rejected asdfasd".to_string()),
units: None,
currency: None,
}
]),
..default_event_content()
},
];

for event in &events {
let (status, error) = test
.request::<Problem>(
http::Method::POST,
"/events",
Body::from(serde_json::to_vec(&event).unwrap()),
)
.await;

assert_eq!(status, StatusCode::BAD_REQUEST);
assert!(error
.detail
.unwrap()
.contains("outside of allowed range 1..=128"))
}
}

#[sqlx::test(fixtures("programs"))]
async fn ordered_by_priority(db: PgPool) {
let test = ApiTest::new(db, vec![AuthRole::AnyBusiness]);
Expand Down
72 changes: 31 additions & 41 deletions openadr-vtn/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ mod test {
use axum::{
body::Body,
http::{self, Request, StatusCode},
response::Response,
Router,
};
use http_body_util::BodyExt;
use openadr_wire::problem::Problem;
use reqwest::Method;
use serde::de::DeserializeOwned;
use sqlx::PgPool;
use tower::ServiceExt;
Expand Down Expand Up @@ -128,10 +128,10 @@ mod test {

pub(crate) async fn request<T: DeserializeOwned>(
&self,
method: http::Method,
method: Method,
path: &str,
body: Body,
) -> (http::StatusCode, T) {
) -> (StatusCode, T) {
let response = self
.router
.clone()
Expand Down Expand Up @@ -174,65 +174,55 @@ mod test {
AppState::new(store, JwtManager::from_base64_secret("test").unwrap())
}

async fn into_problem(response: Response<Body>) -> Problem {
let body = response.into_body().collect().await.unwrap().to_bytes();
serde_json::from_slice(&body).unwrap()
}

#[sqlx::test]
async fn unsupported_media_type(db: PgPool) {
let state = state(db).await;
let token = jwt_test_token(&state, vec![AuthRole::AnyBusiness, AuthRole::UserManager]);
let mut app = state.into_router();
let mut test = ApiTest::new(
db.clone(),
vec![AuthRole::AnyBusiness, AuthRole::UserManager],
);

let response = (&mut app)
let response = (&mut test.router)
.oneshot(
Request::builder()
.method(http::Method::POST)
.method(Method::POST)
.uri("/programs")
.header(http::header::AUTHORIZATION, format!("Bearer {}", token))
.header(
http::header::AUTHORIZATION,
format!("Bearer {}", test.token),
)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();

assert_eq!(response.status(), StatusCode::UNSUPPORTED_MEDIA_TYPE);
into_problem(response).await;

let response = app
.oneshot(
Request::builder()
.method(http::Method::POST)
.uri("/auth/token")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
let (status, _) = test
.request::<Problem>(Method::POST, "/auth/token", Body::empty())
.await;

assert_eq!(response.status(), StatusCode::UNSUPPORTED_MEDIA_TYPE);
into_problem(response).await;
assert_eq!(status, StatusCode::UNSUPPORTED_MEDIA_TYPE);
}

#[sqlx::test]
async fn method_not_allowed(db: PgPool) {
let state = state(db).await;
let app = state.into_router();
let test = ApiTest::new(db.clone(), vec![]);

let response = app
.oneshot(
Request::builder()
.method(http::Method::DELETE)
.uri("/programs")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
let (status, _) = test
.request::<Problem>(Method::DELETE, "/programs", Body::empty())
.await;

assert_eq!(response.status(), StatusCode::METHOD_NOT_ALLOWED);
assert_eq!(status, StatusCode::METHOD_NOT_ALLOWED);
}

#[sqlx::test]
async fn not_found(db: PgPool) {
let test = ApiTest::new(db.clone(), vec![AuthRole::VenManager]);

into_problem(response).await;
let (status, _) = test
.request::<Problem>(Method::GET, "/not-existent", Body::empty())
.await;
assert_eq!(status, StatusCode::NOT_FOUND);
}
}
60 changes: 58 additions & 2 deletions openadr-vtn/src/api/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,18 @@ mod test {
Router,
};
use http_body_util::BodyExt;
use openadr_wire::Event;
use openadr_wire::{
problem::Problem,
target::{TargetEntry, TargetMap},
Event,
};
use sqlx::PgPool;
use tower::{Service, ServiceExt};
// for `call`, `oneshot`, and `ready`

fn default_content() -> ProgramContent {
ProgramContent {
object_type: None,
object_type: Default::default(),
program_name: "program_name".to_string(),
program_long_name: Some("program_long_name".to_string()),
retailer_name: Some("retailer_name".to_string()),
Expand Down Expand Up @@ -356,6 +360,58 @@ mod test {
assert_eq!(response.status(), StatusCode::CONFLICT);
}

#[sqlx::test]
async fn name_constraint_validation(db: PgPool) {
let test = ApiTest::new(db, vec![AuthRole::AnyBusiness]);

let programs = [
ProgramContent {
program_name: "".to_string(),
..default_content()
},
ProgramContent {
program_name: "This is more than 128 characters long and should be rejected This is more than 128 characters long and should be rejected asdfasd".to_string(),
..default_content()
},
ProgramContent {
targets: Some(TargetMap(
vec![
TargetEntry {
label: TargetLabel::Private("".to_string()),
values: ["test".to_string()]
}
])),
..default_content()
},
ProgramContent {
targets: Some(TargetMap(
vec![
TargetEntry {
label: TargetLabel::Private("This is more than 128 characters long and should be rejected This is more than 128 characters long and should be rejected asdfasd".to_string()),
values: ["test".to_string()]
}
])),
..default_content()
}];

for program in &programs {
let (status, error) = test
.request::<Problem>(
http::Method::POST,
"/programs",
Body::from(serde_json::to_vec(&program).unwrap()),
)
.await;

assert_eq!(status, StatusCode::BAD_REQUEST);
let detail = error.detail.unwrap();
assert!(
detail.contains("outside of allowed range 1..=128")
|| detail.contains("data did not match any variant")
);
}
}

async fn retrieve_all_with_filter_help(
app: &mut Router,
query_params: &str,
Expand Down
80 changes: 80 additions & 0 deletions openadr-vtn/src/api/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,83 @@ pub struct QueryParams {
fn get_50() -> i64 {
50
}

#[cfg(test)]
#[cfg(feature = "live-db-test")]
mod test {
use crate::{api::test::ApiTest, jwt::AuthRole};
use axum::{body::Body, http, http::StatusCode};
use openadr_wire::{
problem::Problem,
report::{ReportContent, ReportPayloadDescriptor, ReportType},
};
use sqlx::PgPool;

fn default() -> ReportContent {
ReportContent {
object_type: None,
program_id: "asdf".parse().unwrap(),
event_id: "asdf".parse().unwrap(),
client_name: "".to_string(),
report_name: None,
payload_descriptors: None,
resources: vec![],
}
}

#[sqlx::test]
async fn name_constraint_validation(db: PgPool) {
let test = ApiTest::new(db, vec![AuthRole::VEN("ven-1".parse().unwrap())]);

let reports = [
ReportContent {
report_name: Some("".to_string()),
..default()
},
ReportContent {
report_name: Some("This is more than 128 characters long and should be rejected This is more than 128 characters long and should be rejected asdfasd".to_string()),
..default()
},
ReportContent {
payload_descriptors: Some(vec![
ReportPayloadDescriptor{
payload_type: ReportType::Private("".to_string()),
reading_type: Default::default(),
units: None,
accuracy: None,
confidence: None,
}
]),
..default()
},
ReportContent {
payload_descriptors: Some(vec![
ReportPayloadDescriptor{
payload_type: ReportType::Private("This is more than 128 characters long and should be rejected This is more than 128 characters long and should be rejected asdfasd".to_string()),
reading_type: Default::default(),
units: None,
accuracy: None,
confidence: None,
}
]),
..default()
},
];

for report in &reports {
let (status, error) = test
.request::<Problem>(
http::Method::POST,
"/reports",
Body::from(serde_json::to_vec(&report).unwrap()),
)
.await;

assert_eq!(status, StatusCode::BAD_REQUEST);
assert!(error
.detail
.unwrap()
.contains("outside of allowed range 1..=128"))
}
}
}
Loading

0 comments on commit b84371c

Please sign in to comment.