#[macro_use]
extern crate log;
extern crate rocket;
extern crate aw_datastore;
extern crate aw_server;
#[cfg(test)]
mod api_tests {
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Mutex;
use chrono::{DateTime, Utc};
use rocket::http::{ContentType, Header, Status};
use aw_server::config;
use aw_server::endpoints;
use aw_models::KeyValue;
use aw_models::{Bucket, BucketsExport};
use rocket::local::Client;
fn setup_testserver() -> rocket::Rocket {
let state = endpoints::ServerState {
datastore: Mutex::new(aw_datastore::Datastore::new_in_memory(false)),
asset_path: PathBuf::from("aw-webui/dist"),
device_id: "test_id".to_string(),
};
let aw_config = config::AWConfig::default();
endpoints::build_rocket(state, aw_config)
}
#[test]
fn test_bucket() {
let server = setup_testserver();
let client = rocket::local::Client::new(server).expect("valid instance");
let mut res = client
.get("/api/0/buckets/")
.header(ContentType::JSON)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
let buckets: HashMap<String, Bucket> =
serde_json::from_str(&res.body_string().unwrap()).unwrap();
assert_eq!(buckets.len(), 0);
res = client
.get("/api/0/buckets/id")
.header(ContentType::JSON)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::NotFound);
res = client
.post("/api/0/buckets/id")
.header(ContentType::JSON)
.body(
r#"{
"id": "id",
"type": "type",
"client": "client",
"hostname": "hostname"
}"#,
)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
res = client
.post("/api/0/buckets/id")
.header(ContentType::JSON)
.body(
r#"{
"id": "id",
"type": "type",
"client": "client",
"hostname": "hostname"
}"#,
)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::NotModified);
assert_eq!(
res.body_string().unwrap(),
r#"{"message":"Bucket 'id' already exists"}"#
);
res = client
.get("/api/0/buckets/")
.header(ContentType::JSON)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
let buckets: HashMap<String, Bucket> =
serde_json::from_str(&res.body_string().unwrap()).unwrap();
assert_eq!(buckets.len(), 1);
let bucket = buckets.get("id").unwrap();
assert_eq!(bucket.id, "id");
assert_eq!(bucket._type, "type");
assert_eq!(bucket.client, "client");
assert_eq!(bucket.hostname, "hostname");
assert_eq!(bucket.events, None);
assert_eq!(bucket.metadata.start, None);
assert_eq!(bucket.metadata.end, None);
res = client
.get("/api/0/buckets/id")
.header(ContentType::JSON)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
let bucket: Bucket = serde_json::from_str(&res.body_string().unwrap()).unwrap();
assert_eq!(bucket.id, "id");
assert_eq!(bucket._type, "type");
assert_eq!(bucket.client, "client");
assert_eq!(bucket.hostname, "hostname");
assert_eq!(bucket.events, None);
assert_eq!(bucket.metadata.start, None);
assert_eq!(bucket.metadata.end, None);
res = client
.get("/api/0/buckets/invalid_bucket")
.header(ContentType::JSON)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::NotFound);
res = client
.delete("/api/0/buckets/id")
.header(ContentType::JSON)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
res = client
.get("/api/0/buckets/id")
.header(ContentType::JSON)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::NotFound);
let mut res = client
.get("/api/0/buckets/")
.header(ContentType::JSON)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
let buckets: HashMap<String, Bucket> =
serde_json::from_str(&res.body_string().unwrap()).unwrap();
assert_eq!(buckets.len(), 0);
}
#[test]
fn test_events() {
let server = setup_testserver();
let client = rocket::local::Client::new(server).expect("valid instance");
let mut res = client
.post("/api/0/buckets/id")
.header(ContentType::JSON)
.body(
r#"{
"id": "id",
"type": "type",
"client": "client",
"hostname": "hostname"
}"#,
)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
res = client
.post("/api/0/buckets/id/events")
.header(ContentType::JSON)
.body(
r#"[{
"timestamp": "2018-01-01T01:01:01Z",
"duration": 1.0,
"data": {}
}]"#,
)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(
res.body_string().unwrap(),
r#"[{"id":1,"timestamp":"2018-01-01T01:01:01Z","duration":1.0,"data":{}}]"#
);
assert_eq!(res.status(), rocket::http::Status::Ok);
res = client
.get("/api/0/buckets/id/events")
.header(ContentType::JSON)
.dispatch();
assert_eq!(
res.body_string().unwrap(),
r#"[{"id":1,"timestamp":"2018-01-01T01:01:01Z","duration":1.0,"data":{}}]"#
);
assert_eq!(res.status(), rocket::http::Status::Ok);
res = client
.post("/api/0/buckets/id/heartbeat?pulsetime=2")
.header(ContentType::JSON)
.body(
r#"{
"timestamp": "2018-01-01T01:01:02Z",
"duration": 1.0,
"data": {}
}"#,
)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
assert_eq!(
res.body_string().unwrap(),
r#"{"id":null,"timestamp":"2018-01-01T01:01:01Z","duration":2.0,"data":{}}"#
);
res = client
.get("/api/0/buckets/id/events")
.header(ContentType::JSON)
.dispatch();
assert_eq!(
res.body_string().unwrap(),
r#"[{"id":1,"timestamp":"2018-01-01T01:01:01Z","duration":2.0,"data":{}}]"#
);
assert_eq!(res.status(), rocket::http::Status::Ok);
client.delete("/api/0/buckets/id/events/1").dispatch();
res = client
.get("/api/0/buckets/id/events/count")
.header(ContentType::JSON)
.dispatch();
assert_eq!(res.body_string().unwrap(), "0");
assert_eq!(res.status(), rocket::http::Status::Ok);
res = client
.delete("/api/0/buckets/id")
.header(ContentType::JSON)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
}
#[test]
fn test_import_export() {
let server = setup_testserver();
let client = rocket::local::Client::new(server).expect("valid instance");
let mut res = client
.post("/api/0/import")
.header(ContentType::JSON)
.body(
r#"{"buckets":
{"id1": {
"id": "id1",
"type": "type",
"client": "client",
"hostname": "hostname",
"events": [{
"timestamp":"2000-01-01T00:00:00Z",
"duration":1.0,
"data": {}
}]
}}}"#,
)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
let mut res = client
.post("/api/0/import")
.header(ContentType::JSON)
.body(
r#"{"buckets":
{"id1": {
"id": "id1",
"type": "type",
"client": "client",
"hostname": "hostname",
"events": [{
"timestamp":"2000-01-01T00:00:00Z",
"duration":1.0,
"data": {}
}]
}}}"#,
)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::InternalServerError);
assert_eq!(
res.body_string().unwrap(),
r#"{"message":"Failed to import bucket: BucketAlreadyExists(\"id1\")"}"#
);
let mut res = client
.get("/api/0/buckets/id1/export")
.header(ContentType::JSON)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
let export: BucketsExport = serde_json::from_str(&res.body_string().unwrap()).unwrap();
res = client
.delete("/api/0/buckets/id1")
.header(ContentType::JSON)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
let start = b"--a\r\nContent-Disposition: form-data; name=\"test\"\r\n\r\n";
let content = serde_json::to_vec(&export).unwrap();
let end = b"--a--";
let sum = [&start[..], &content[..], &end[..]].concat();
let mut res = client
.post("/api/0/import")
.header(Header::new(
"Content-Type",
"multipart/form-data; boundary=a",
))
.body(&sum[..])
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
let mut res = client
.get("/api/0/buckets/id1")
.header(ContentType::JSON)
.dispatch();
println!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
let mut res = client
.get("/api/0/export")
.header(ContentType::JSON)
.dispatch();
debug!("{:?}", res.body_string());
assert_eq!(res.status(), rocket::http::Status::Ok);
let export: BucketsExport = serde_json::from_str(&res.body_string().unwrap()).unwrap();
let mut buckets = export.buckets;
assert_eq!(buckets.len(), 1);
let b = buckets.remove("id1").unwrap();
assert_eq!(b.events.unwrap().len(), 1);
assert_eq!(buckets.len(), 0);
}
#[test]
fn test_query() {
let server = setup_testserver();
let client = rocket::local::Client::new(server).expect("valid instance");
let mut res = client
.post("/api/0/query")
.header(ContentType::JSON)
.body(
r#"{
"timeperiods": ["2000-01-01T00:00:00Z/2020-01-01T00:00:00Z"],
"query": ["return 1;"]
}"#,
)
.dispatch();
assert_eq!(res.body_string().unwrap(), r#"[1.0]"#);
assert_eq!(res.status(), rocket::http::Status::Ok);
let mut res = client
.post("/api/0/buckets/id")
.header(ContentType::JSON)
.body(
r#"{
"id": "id",
"type": "type",
"client": "client",
"hostname": "hostname"
}"#,
)
.dispatch();
assert_eq!(res.status(), rocket::http::Status::Ok);
res = client
.post("/api/0/buckets/id/events")
.header(ContentType::JSON)
.body(
r#"[{
"timestamp": "2018-01-01T01:01:01Z",
"duration": 1.0,
"data": {}
}]"#,
)
.dispatch();
assert_eq!(res.status(), rocket::http::Status::Ok);
let mut res = client
.post("/api/0/query")
.header(ContentType::JSON)
.body(
r#"{
"timeperiods": ["2000-01-01T00:00:00Z/2020-01-01T00:00:00Z"],
"query": ["return query_bucket(\"id\");"]
}"#,
)
.dispatch();
assert_eq!(res.status(), rocket::http::Status::Ok);
assert_eq!(
res.body_string().unwrap(),
r#"[[{"data":{},"duration":1.0,"id":1,"timestamp":"2018-01-01T01:01:01Z"}]]"#
);
let mut res = client
.post("/api/0/query")
.header(ContentType::JSON)
.body(
r#"{
"timeperiods": ["2000-01-01T00:00:00Z/2020-01-01T00:00:00Z"],
"query": [""]
}"#,
)
.dispatch();
assert_eq!(res.status(), rocket::http::Status::InternalServerError);
assert_eq!(res.body_string().unwrap(), r#"{"message":"EmptyQuery"}"#);
}
fn set_setting_request(client: &Client, key: &str, value: &str) -> Status {
let body = serde_json::to_string(&KeyValue {
key: key.to_string(),
value: value.to_string(),
timestamp: None,
})
.unwrap();
let res = client
.post("/api/0/settings/")
.header(ContentType::JSON)
.body(body)
.dispatch();
res.status()
}
fn _equal_and_timestamp_in_range(before: DateTime<Utc>, first: KeyValue, second: KeyValue) {
assert_eq!(first.key, second.key);
assert_eq!(first.value, second.value);
assert!(
first.timestamp.unwrap().timestamp() >= before.timestamp(),
"{} wasn't after {}",
first.timestamp.unwrap().timestamp(),
before.timestamp()
);
assert!(
first.timestamp < second.timestamp,
"{} wasn't before {}",
first.timestamp.unwrap(),
second.timestamp.unwrap()
);
}
#[test]
fn test_illegally_long_key() {
let server = setup_testserver();
let client = rocket::local::Client::new(server).expect("valid instance");
let res = set_setting_request(&client, "thisisaverylongkthisisaverylongkthisisaverylongkthisisaverylongkthisisaverylongkthisisaverylongkthisisaverylongkthisisaverylongk", "");
assert_eq!(res, rocket::http::Status::BadRequest);
}
#[test]
fn test_setting_setting() {
let server = setup_testserver();
let client = rocket::local::Client::new(server).expect("valid instance");
let response_status = set_setting_request(&client, "test_key", "test_value");
assert_eq!(response_status, rocket::http::Status::Created);
}
#[test]
fn test_getting_not_found_value() {
let server = setup_testserver();
let client = rocket::local::Client::new(server).expect("valid instance");
let res = client.get("/api/0/settings/non_existent_key").dispatch();
assert_eq!(res.status(), rocket::http::Status::NotFound);
}
#[test]
fn settings_list_get() {
let server = setup_testserver();
let client = rocket::local::Client::new(server).expect("valid instance");
let response1_status = set_setting_request(&client, "test_key", "");
assert_eq!(response1_status, rocket::http::Status::Created);
let response2_status = set_setting_request(&client, "test_key_2", "");
assert_eq!(response2_status, rocket::http::Status::Created);
let mut res = client.get("/api/0/settings/").dispatch();
assert_eq!(res.status(), rocket::http::Status::Ok);
assert_eq!(
res.body_string().unwrap(),
r#"[{"key":"settings.test_key"},{"key":"settings.test_key_2"}]"#
);
}
#[test]
fn test_getting_setting() {
let server = setup_testserver();
let client = rocket::local::Client::new(server).expect("valid instance");
let timestamp = Utc::now();
let response_status = set_setting_request(&client, "test_key", "test_value");
assert_eq!(response_status, rocket::http::Status::Created);
let mut res = client.get("/api/0/settings/test_key").dispatch();
assert_eq!(res.status(), rocket::http::Status::Ok);
let deserialized: KeyValue = serde_json::from_str(&res.body_string().unwrap()).unwrap();
_equal_and_timestamp_in_range(
timestamp,
deserialized,
KeyValue::new("settings.test_key", "test_value", Utc::now()),
);
}
#[test]
fn test_updating_setting() {
let server = setup_testserver();
let client = rocket::local::Client::new(server).expect("valid instance");
let timestamp = Utc::now();
let post_1_status = set_setting_request(&client, "test_key", "test_value");
assert_eq!(post_1_status, rocket::http::Status::Created);
let mut res = client.get("/api/0/settings/test_key").dispatch();
assert_eq!(res.status(), rocket::http::Status::Ok);
let deserialized: KeyValue = serde_json::from_str(&res.body_string().unwrap()).unwrap();
_equal_and_timestamp_in_range(
timestamp,
deserialized,
KeyValue::new("settings.test_key", "test_value", Utc::now()),
);
let timestamp_2 = Utc::now();
let post_2_status = set_setting_request(&client, "test_key", "changed_test_value");
assert_eq!(post_2_status, rocket::http::Status::Created);
let mut res = client.get("/api/0/settings/test_key").dispatch();
assert_eq!(res.status(), rocket::http::Status::Ok);
let new_deserialized: KeyValue = serde_json::from_str(&res.body_string().unwrap()).unwrap();
_equal_and_timestamp_in_range(
timestamp_2,
new_deserialized,
KeyValue::new("settings.test_key", "changed_test_value", Utc::now()),
);
}
#[test]
fn test_deleting_setting() {
let server = setup_testserver();
let client = rocket::local::Client::new(server).expect("valid instance");
let response_status = set_setting_request(&client, "test_key", "");
assert_eq!(response_status, rocket::http::Status::Created);
let res = client.delete("/api/0/settings/test_key").dispatch();
assert_eq!(res.status(), rocket::http::Status::Ok);
let res = client.get("/api/0/settings/test_key").dispatch();
assert_eq!(res.status(), rocket::http::Status::NotFound);
}
}