async-graphql/tests/guard.rs

324 lines
7.9 KiB
Rust
Raw Normal View History

2020-05-01 23:57:34 +00:00
use async_graphql::guard::Guard;
use async_graphql::*;
use futures::{Stream, StreamExt};
use std::sync::Arc;
2020-05-02 03:03:04 +00:00
#[derive(Eq, PartialEq, Copy, Clone)]
enum Role {
Admin,
Guest,
}
struct RoleGuard {
role: Role,
}
2020-05-01 23:57:34 +00:00
2020-05-02 03:03:04 +00:00
#[async_trait::async_trait]
impl Guard for RoleGuard {
async fn check(&self, ctx: &Context<'_>) -> FieldResult<()> {
if ctx.data_opt::<Role>() == Some(&self.role) {
Ok(())
} else {
Err("Forbidden".into())
}
2020-05-01 23:57:34 +00:00
}
2020-05-02 03:03:04 +00:00
}
2020-05-01 23:57:34 +00:00
2020-05-02 03:03:04 +00:00
struct Username(String);
struct UserGuard {
username: String,
}
#[async_trait::async_trait]
impl Guard for UserGuard {
async fn check(&self, ctx: &Context<'_>) -> FieldResult<()> {
if ctx.data_opt::<Username>().map(|name| &name.0).as_deref() == Some(&self.username) {
Ok(())
} else {
Err("Forbidden".into())
2020-05-01 23:57:34 +00:00
}
}
2020-05-02 03:03:04 +00:00
}
2020-05-01 23:57:34 +00:00
2020-05-02 03:03:04 +00:00
#[async_std::test]
pub async fn test_guard() {
2020-05-01 23:57:34 +00:00
#[SimpleObject]
struct MyObj {
#[field(guard(RoleGuard(role = "Role::Admin")))]
value: i32,
}
struct Query;
#[Object]
impl Query {
#[field(guard(RoleGuard(role = "Role::Admin")))]
2020-05-05 05:02:24 +00:00
async fn value(&self) -> i32 {
1
2020-05-01 23:57:34 +00:00
}
async fn obj(&self) -> MyObj {
MyObj { value: 99 }
}
}
struct Subscription;
#[Subscription]
impl Subscription {
#[field(guard(RoleGuard(role = "Role::Admin")))]
2020-05-05 05:02:24 +00:00
async fn values(&self) -> impl Stream<Item = i32> {
2020-05-01 23:57:34 +00:00
futures::stream::iter(vec![1, 2, 3])
}
}
let schema = Schema::new(Query, EmptyMutation, Subscription);
let query = "{ obj { value } }";
assert_eq!(
QueryBuilder::new(query)
.data(Role::Admin)
.execute(&schema)
.await
.unwrap()
.data,
serde_json::json!({
"obj": {"value": 99}
})
);
let query = "{ obj { value } }";
assert_eq!(
QueryBuilder::new(query)
.data(Role::Guest)
.execute(&schema)
.await
.unwrap_err(),
Error::Query {
pos: Pos { line: 1, column: 9 },
path: Some(serde_json::json!(["obj", "value"])),
err: QueryError::FieldError {
err: "Forbidden".to_string(),
extended_error: None,
},
}
);
2020-05-05 05:02:24 +00:00
let query = "{ value }";
2020-05-01 23:57:34 +00:00
assert_eq!(
QueryBuilder::new(query)
.data(Role::Admin)
.execute(&schema)
.await
.unwrap()
.data,
serde_json::json!({
2020-05-05 05:02:24 +00:00
"value": 1,
2020-05-01 23:57:34 +00:00
})
);
2020-05-05 05:02:24 +00:00
let query = "{ value }";
2020-05-01 23:57:34 +00:00
assert_eq!(
QueryBuilder::new(query)
.data(Role::Guest)
.execute(&schema)
.await
.unwrap_err(),
Error::Query {
pos: Pos { line: 1, column: 3 },
2020-05-05 05:02:24 +00:00
path: Some(serde_json::json!(["value"])),
2020-05-01 23:57:34 +00:00
err: QueryError::FieldError {
err: "Forbidden".to_string(),
extended_error: None,
},
}
);
assert_eq!(
schema
.create_subscription_stream(
2020-05-05 05:02:24 +00:00
"subscription { values }",
2020-05-01 23:57:34 +00:00
None,
Variables::default(),
Some(Arc::new({
let mut data = Data::default();
data.insert(Role::Admin);
data
})),
)
.await
.unwrap()
.collect::<Vec<_>>()
.await,
vec![
2020-05-05 05:02:24 +00:00
Ok(serde_json::json! ({"values": 1})),
Ok(serde_json::json! ({"values": 2})),
Ok(serde_json::json! ({"values": 3}))
2020-05-01 23:57:34 +00:00
]
);
assert_eq!(
schema
.create_subscription_stream(
2020-05-05 05:02:24 +00:00
"subscription { values }",
2020-05-01 23:57:34 +00:00
None,
Variables::default(),
Some(Arc::new({
let mut data = Data::default();
data.insert(Role::Guest);
data
})),
)
.await
.err()
.unwrap(),
Error::Query {
pos: Pos {
line: 1,
column: 16
},
2020-05-05 05:02:24 +00:00
path: Some(serde_json::json!(["values"])),
2020-05-01 23:57:34 +00:00
err: QueryError::FieldError {
err: "Forbidden".to_string(),
extended_error: None,
},
}
);
}
2020-05-02 03:03:04 +00:00
#[async_std::test]
pub async fn test_multiple_guards() {
#[SimpleObject]
struct Query {
#[field(guard(RoleGuard(role = "Role::Admin"), UserGuard(username = r#""test""#)))]
value: i32,
}
let schema = Schema::new(Query { value: 10 }, EmptyMutation, EmptySubscription);
let query = "{ value }";
assert_eq!(
QueryBuilder::new(query)
.data(Role::Admin)
.data(Username("test".to_string()))
.execute(&schema)
.await
.unwrap()
.data,
serde_json::json!({"value": 10})
);
let query = "{ value }";
assert_eq!(
QueryBuilder::new(query)
.data(Role::Guest)
.data(Username("test".to_string()))
.execute(&schema)
.await
.unwrap_err(),
Error::Query {
pos: Pos { line: 1, column: 3 },
path: Some(serde_json::json!(["value"])),
err: QueryError::FieldError {
err: "Forbidden".to_string(),
extended_error: None,
},
}
);
let query = "{ value }";
assert_eq!(
QueryBuilder::new(query)
.data(Role::Admin)
.data(Username("test1".to_string()))
.execute(&schema)
.await
.unwrap_err(),
Error::Query {
pos: Pos { line: 1, column: 3 },
path: Some(serde_json::json!(["value"])),
err: QueryError::FieldError {
err: "Forbidden".to_string(),
extended_error: None,
},
}
);
let query = "{ value }";
assert_eq!(
QueryBuilder::new(query)
.data(Role::Guest)
.data(Username("test1".to_string()))
.execute(&schema)
.await
.unwrap_err(),
Error::Query {
pos: Pos { line: 1, column: 3 },
path: Some(serde_json::json!(["value"])),
err: QueryError::FieldError {
err: "Forbidden".to_string(),
extended_error: None,
},
}
);
}
#[async_std::test]
pub async fn test_guard_forward_arguments() {
2020-06-03 06:50:06 +00:00
struct UserGuard {
id: ID,
}
#[async_trait::async_trait]
2020-06-03 06:50:06 +00:00
impl Guard for UserGuard {
async fn check(&self, ctx: &Context<'_>) -> FieldResult<()> {
2020-06-03 06:50:06 +00:00
if ctx.data_opt::<ID>() != Some(&self.id) {
Err("Forbidden".into())
} else {
Ok(())
}
}
}
struct QueryRoot;
#[Object]
impl QueryRoot {
#[field(guard(UserGuard(id = "@id")))]
async fn user(&self, id: ID) -> ID {
id
}
}
let schema = Schema::new(QueryRoot, EmptyMutation, EmptySubscription);
let query = r#"{ user(id: "abc") }"#;
assert_eq!(
QueryBuilder::new(query)
.data(ID::from("abc"))
.execute(&schema)
.await
.unwrap()
.data,
serde_json::json!({"user": "abc"})
);
let query = r#"{ user(id: "abc") }"#;
assert_eq!(
QueryBuilder::new(query)
.data(ID::from("aaa"))
.execute(&schema)
.await
.unwrap_err(),
Error::Query {
pos: Pos { line: 1, column: 3 },
path: Some(serde_json::json!(["user"])),
err: QueryError::FieldError {
err: "Forbidden".to_string(),
extended_error: None,
},
}
);
}