Some checks failed
Build / ubuntu-latest (push) Failing after 5s
Build / Android (push) Failing after 2s
Build / Code coverage (push) Failing after 2s
Lint / format (push) Failing after 3s
Lint / clippy (push) Failing after 3s
Build / macOS-latest (push) Has been cancelled
Build / windows-latest (push) Has been cancelled
915 lines
32 KiB
Rust
915 lines
32 KiB
Rust
extern crate log;
|
|
|
|
extern crate rocket;
|
|
|
|
extern crate aw_datastore;
|
|
extern crate aw_server;
|
|
|
|
#[cfg(test)]
|
|
mod api_tests {
|
|
use std::collections::HashMap;
|
|
|
|
use rocket::http::{ContentType, Header, Status};
|
|
use serde_json::{json, Value};
|
|
|
|
use aw_server::config;
|
|
use aw_server::endpoints;
|
|
|
|
use aw_models::{Bucket, BucketsExport};
|
|
use rocket::local::blocking::Client;
|
|
|
|
fn setup_testserver() -> rocket::Rocket<rocket::Build> {
|
|
let state = endpoints::ServerState {
|
|
datastore: aw_datastore::Datastore::new_in_memory(false),
|
|
asset_resolver: endpoints::AssetResolver::new(None),
|
|
device_id: "test_id".to_string(),
|
|
};
|
|
let aw_config = config::AWConfig::default();
|
|
endpoints::build_rocket(state, aw_config)
|
|
}
|
|
|
|
#[test]
|
|
fn export_includes_pending_writes_and_preserves_headers_and_missing_bucket_errors() {
|
|
let server = setup_testserver();
|
|
let datastore = server
|
|
.state::<endpoints::ServerState>()
|
|
.unwrap()
|
|
.datastore
|
|
.clone();
|
|
let bucket: Bucket = serde_json::from_value(json!({
|
|
"id": "live", "type": "test", "client": "test", "hostname": "test"
|
|
}))
|
|
.unwrap();
|
|
datastore.create_bucket(&bucket).unwrap();
|
|
let event = aw_models::Event::default();
|
|
let inserted = datastore.insert_events("live", &[event]).unwrap();
|
|
// No force_commit: exports must see writes acknowledged by the worker.
|
|
let client = Client::untracked(server).unwrap();
|
|
for path in ["/api/0/export", "/api/0/buckets/live/export"] {
|
|
let response = client
|
|
.get(path)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(response.status(), Status::Ok);
|
|
assert_eq!(response.content_type(), Some(ContentType::JSON));
|
|
assert_eq!(
|
|
response.headers().get_one("Content-Disposition"),
|
|
Some("attachment; filename=aw-bucket-export_live.json")
|
|
);
|
|
let body: Value = serde_json::from_str(&response.into_string().unwrap()).unwrap();
|
|
assert_eq!(
|
|
body["buckets"]["live"]["events"],
|
|
serde_json::to_value(&inserted).unwrap()
|
|
);
|
|
}
|
|
let response = client
|
|
.get("/api/0/buckets/missing/export")
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(response.status(), Status::NotFound);
|
|
let body: Value = serde_json::from_str(&response.into_string().unwrap()).unwrap();
|
|
assert!(body["message"].as_str().unwrap().contains("does not exist"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_bucket() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
// Get empty list of buckets
|
|
let mut res = client
|
|
.get("/api/0/buckets/")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
let buckets: HashMap<String, Bucket> =
|
|
serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
assert_eq!(buckets.len(), 0);
|
|
|
|
// Try to fetch non-existing bucket
|
|
res = client
|
|
.get("/api/0/buckets/id")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::NotFound);
|
|
|
|
// Create bucket
|
|
res = client
|
|
.post("/api/0/buckets/id")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{
|
|
"id": "id",
|
|
"type": "type",
|
|
"client": "client",
|
|
"hostname": "hostname"
|
|
}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
// Try to create bucket which already exists
|
|
res = client
|
|
.post("/api/0/buckets/id")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{
|
|
"id": "id",
|
|
"type": "type",
|
|
"client": "client",
|
|
"hostname": "hostname"
|
|
}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::NotModified);
|
|
assert_eq!(
|
|
res.into_string().unwrap(),
|
|
r#"{"message":"Bucket 'id' already exists"}"#
|
|
);
|
|
|
|
// Get list of buckets (1 bucket)
|
|
res = client
|
|
.get("/api/0/buckets/")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
let buckets: HashMap<String, Bucket> =
|
|
serde_json::from_str(&res.into_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!(bucket.events.is_none());
|
|
assert_eq!(bucket.metadata.start, None);
|
|
assert_eq!(bucket.metadata.end, None);
|
|
|
|
// Get newly created bucket
|
|
res = client
|
|
.get("/api/0/buckets/id")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
// Validate output
|
|
let bucket: Bucket = serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
assert_eq!(bucket.id, "id");
|
|
assert_eq!(bucket._type, "type");
|
|
assert_eq!(bucket.client, "client");
|
|
assert_eq!(bucket.hostname, "hostname");
|
|
assert!(bucket.events.is_none());
|
|
assert_eq!(bucket.metadata.start, None);
|
|
assert_eq!(bucket.metadata.end, None);
|
|
|
|
// Get non-existing bucket
|
|
res = client
|
|
.get("/api/0/buckets/invalid_bucket")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::NotFound);
|
|
|
|
// Delete bucket
|
|
res = client
|
|
.delete("/api/0/buckets/id")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
// Try (and fail) to get deleted bucket
|
|
res = client
|
|
.get("/api/0/buckets/id")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::NotFound);
|
|
|
|
// Get empty list of buckets
|
|
let res = client
|
|
.get("/api/0/buckets/")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
let buckets: HashMap<String, Bucket> =
|
|
serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
assert_eq!(buckets.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_bucket_hostname_validation() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
// A client-supplied hostname containing whitespace is rejected
|
|
let res = client
|
|
.post("/api/0/buckets/spacey")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{
|
|
"id": "spacey",
|
|
"type": "type",
|
|
"client": "client",
|
|
"hostname": "my phone"
|
|
}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::BadRequest);
|
|
assert_eq!(
|
|
res.into_string().unwrap(),
|
|
r#"{"message":"Invalid hostname \"my phone\": hostname may not contain whitespace"}"#
|
|
);
|
|
|
|
// The rejected bucket was not created
|
|
let res = client
|
|
.get("/api/0/buckets/spacey")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::NotFound);
|
|
|
|
// An already-existing bucket keeps the established "already exists" response
|
|
// even if the re-create payload carries a whitespace hostname. Watchers
|
|
// idempotently re-create their bucket on startup, so a legacy bucket stored
|
|
// under a spacey hostname must not start hard-failing every boot.
|
|
let res = client
|
|
.post("/api/0/buckets/existing")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{
|
|
"id": "existing",
|
|
"type": "type",
|
|
"client": "client",
|
|
"hostname": "hostname"
|
|
}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
let res = client
|
|
.post("/api/0/buckets/existing")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{
|
|
"id": "existing",
|
|
"type": "type",
|
|
"client": "client",
|
|
"hostname": "my phone"
|
|
}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::NotModified);
|
|
|
|
// The "!local" sentinel bypasses validation (resolved server-side)
|
|
let res = client
|
|
.post("/api/0/buckets/localbucket")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{
|
|
"id": "localbucket",
|
|
"type": "type",
|
|
"client": "client",
|
|
"hostname": "!local"
|
|
}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
}
|
|
#[test]
|
|
fn test_events() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
// Create bucket
|
|
let res = client
|
|
.post("/api/0/buckets/id")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{
|
|
"id": "id",
|
|
"type": "type",
|
|
"client": "client",
|
|
"hostname": "hostname"
|
|
}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
// Insert a single event
|
|
let res = client
|
|
.post("/api/0/buckets/id/events")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"[{
|
|
"timestamp": "2018-01-01T01:01:01Z",
|
|
"duration": 1.0,
|
|
"data": {}
|
|
}]"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
assert_eq!(
|
|
res.into_string().unwrap(),
|
|
r#"[{"id":1,"timestamp":"2018-01-01T01:01:01Z","duration":1.0,"data":{}}]"#
|
|
);
|
|
|
|
// Get inserted event
|
|
let res = client
|
|
.get("/api/0/buckets/id/events")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
assert_eq!(
|
|
res.into_string().unwrap(),
|
|
r#"[{"id":1,"timestamp":"2018-01-01T01:01:01Z","duration":1.0,"data":{}}]"#
|
|
);
|
|
|
|
// Heartbeat
|
|
let res = client
|
|
.post("/api/0/buckets/id/heartbeat?pulsetime=2")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{
|
|
"timestamp": "2018-01-01T01:01:02Z",
|
|
"duration": 1.0,
|
|
"data": {}
|
|
}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
// After the fix for #559, the heartbeat response includes the DB event ID
|
|
assert_eq!(
|
|
res.into_string().unwrap(),
|
|
r#"{"id":1,"timestamp":"2018-01-01T01:01:01Z","duration":2.0,"data":{}}"#
|
|
);
|
|
|
|
// Get heartbeat event
|
|
let res = client
|
|
.get("/api/0/buckets/id/events")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
assert_eq!(
|
|
res.into_string().unwrap(),
|
|
r#"[{"id":1,"timestamp":"2018-01-01T01:01:01Z","duration":2.0,"data":{}}]"#
|
|
);
|
|
|
|
// Delete event
|
|
client
|
|
.delete("/api/0/buckets/id/events/1")
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
|
|
// Get eventcount
|
|
let res = client
|
|
.get("/api/0/buckets/id/events/count")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
assert_eq!(res.into_string().unwrap(), "0");
|
|
|
|
// Delete bucket
|
|
let res = client
|
|
.delete("/api/0/buckets/id")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
}
|
|
|
|
#[test]
|
|
fn test_import_export() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
// Import bucket
|
|
let res = client
|
|
.post("/api/0/import")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{"buckets":
|
|
{"id1": {
|
|
"id": "id1",
|
|
"type": "type",
|
|
"client": "client",
|
|
"hostname": "hostname",
|
|
"events": [{
|
|
"timestamp":"2000-01-01T00:00:00Z",
|
|
"duration":1.0,
|
|
"data": {}
|
|
}]
|
|
}}}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
// Import already existing bucket with a new event — should merge instead of fail
|
|
let res = client
|
|
.post("/api/0/import")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{"buckets":
|
|
{"id1": {
|
|
"id": "id1",
|
|
"type": "type",
|
|
"client": "client",
|
|
"hostname": "hostname",
|
|
"events": [{
|
|
"timestamp":"2000-01-02T00:00:00Z",
|
|
"duration":1.0,
|
|
"data": {}
|
|
}]
|
|
}}}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
// Verify events were merged — bucket should now have 2 events
|
|
let res = client
|
|
.get("/api/0/buckets/id1/events")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
let events: serde_json::Value = serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
assert_eq!(events.as_array().unwrap().len(), 2);
|
|
|
|
// Re-import the first event again — should be idempotent (no duplicate created)
|
|
let res = client
|
|
.post("/api/0/import")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{"buckets":
|
|
{"id1": {
|
|
"id": "id1",
|
|
"type": "type",
|
|
"client": "client",
|
|
"hostname": "hostname",
|
|
"events": [{
|
|
"timestamp":"2000-01-01T00:00:00Z",
|
|
"duration":1.0,
|
|
"data": {}
|
|
}]
|
|
}}}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
// Count should still be 2, not 3 — re-import is idempotent
|
|
let res = client
|
|
.get("/api/0/buckets/id1/events")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
let events: serde_json::Value = serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
assert_eq!(
|
|
events.as_array().unwrap().len(),
|
|
2,
|
|
"Re-importing the same event should be idempotent"
|
|
);
|
|
|
|
// Import a narrower event fully contained within an existing longer event.
|
|
// This should be preserved as a distinct event, not dropped by clipped dedup.
|
|
let res = client
|
|
.post("/api/0/import")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{"buckets":
|
|
{"id1": {
|
|
"id": "id1",
|
|
"type": "type",
|
|
"client": "client",
|
|
"hostname": "hostname",
|
|
"events": [{
|
|
"timestamp":"2000-01-01T00:00:30Z",
|
|
"duration":30.0,
|
|
"data": {}
|
|
}]
|
|
}}}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
let res = client
|
|
.get("/api/0/buckets/id1/events")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
let events: serde_json::Value = serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
assert_eq!(
|
|
events.as_array().unwrap().len(),
|
|
3,
|
|
"Contained event should not be dropped by clipped dedup"
|
|
);
|
|
|
|
// Export single created bucket
|
|
let res = client
|
|
.get("/api/0/buckets/id1/export")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
let export: BucketsExport = serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
|
|
// Delete bucket so we can import it again
|
|
let res = client
|
|
.delete("/api/0/buckets/id1")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
// Import exported bucket again but with multipart/form-data
|
|
let boundary_start = b"--a\r\n";
|
|
let disposition = b"Content-Disposition: form-data; name=\"buckets.json\"\r\n";
|
|
let content_type = b"Content-Type: application/json\r\n";
|
|
let data_start = b"\r\n";
|
|
let content = serde_json::to_vec(&export).unwrap();
|
|
let boundary_end = b"\r\n--a--";
|
|
let sum = [
|
|
&boundary_start[..],
|
|
&disposition[..],
|
|
&content_type[..],
|
|
&data_start[..],
|
|
&content[..],
|
|
&boundary_end[..],
|
|
]
|
|
.concat();
|
|
|
|
let res = client
|
|
.post("/api/0/import")
|
|
.header(Header::new(
|
|
"Content-Type",
|
|
"multipart/form-data; boundary=a",
|
|
))
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(&sum[..])
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
// Get created bucket
|
|
let res = client
|
|
.get("/api/0/buckets/id1")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
println!("{:?}", res.into_string());
|
|
|
|
// Export all buckets
|
|
let res = client
|
|
.get("/api/0/export")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
let export: BucketsExport = serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
let mut buckets = export.buckets;
|
|
assert_eq!(buckets.len(), 1);
|
|
let b = buckets.remove("id1").unwrap();
|
|
assert_eq!(
|
|
b.events.unwrap().take_inner().len(),
|
|
3,
|
|
"Export should preserve the contained event added during merge testing"
|
|
);
|
|
|
|
assert_eq!(buckets.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_query() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
// Minimal query
|
|
let res = client
|
|
.post("/api/0/query")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{
|
|
"timeperiods": ["2000-01-01T00:00:00Z/2020-01-01T00:00:00Z"],
|
|
"query": ["return 1;"]
|
|
}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
assert_eq!(res.into_string().unwrap(), r#"[1.0]"#);
|
|
|
|
// Create bucket to query later
|
|
let res = client
|
|
.post("/api/0/buckets/id")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{
|
|
"id": "id",
|
|
"type": "type",
|
|
"client": "client",
|
|
"hostname": "hostname"
|
|
}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
// Insert a event to query later
|
|
let res = client
|
|
.post("/api/0/buckets/id/events")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"[{
|
|
"timestamp": "2018-01-01T01:01:01Z",
|
|
"duration": 1.0,
|
|
"data": {}
|
|
}]"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
// Query events
|
|
let res = client
|
|
.post("/api/0/query")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.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.into_string().unwrap(),
|
|
r#"[[{"data":{},"duration":1.0,"id":1,"timestamp":"2018-01-01T01:01:01Z"}]]"#
|
|
);
|
|
|
|
// Test error
|
|
let res = client
|
|
.post("/api/0/query")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(
|
|
r#"{
|
|
"timeperiods": ["2000-01-01T00:00:00Z/2020-01-01T00:00:00Z"],
|
|
"query": [""]
|
|
}"#,
|
|
)
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::BadRequest);
|
|
assert_eq!(res.into_string().unwrap(), r#"{"message":"EmptyQuery"}"#);
|
|
}
|
|
|
|
fn set_setting_request(client: &Client, key: &str, value: &Value) -> Status {
|
|
let body = serde_json::to_string(value).unwrap();
|
|
let res = client
|
|
.post(format!("/api/0/settings/{}", key))
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.body(body)
|
|
.dispatch();
|
|
res.status()
|
|
}
|
|
|
|
#[test]
|
|
fn test_illegally_long_key() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
// Test getting not found (getting nonexistent key)
|
|
let key = "thisisaverylongkthisisaverylongkthisisaverylongkthisisaverylongkthisisaverylongkthisisaverylongkthisisaverylongkthisisaverylongk";
|
|
let value = json!("test_value");
|
|
let res = set_setting_request(&client, key, &value);
|
|
assert_eq!(res, rocket::http::Status::BadRequest);
|
|
}
|
|
|
|
#[test]
|
|
fn test_setting_setting() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
// Test value creation
|
|
let key = "test_key";
|
|
let value = json!("test_value");
|
|
let response_status = set_setting_request(&client, key, &value);
|
|
assert_eq!(response_status, rocket::http::Status::Created);
|
|
}
|
|
|
|
#[test]
|
|
fn test_get_unset_setting() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
// Test getting not found (getting nonexistent key)
|
|
let key = "non_existent_key";
|
|
let res = client
|
|
.get(format!("/api/0/settings/{}", key))
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
assert_eq!(res.into_string().unwrap(), "null")
|
|
}
|
|
|
|
#[test]
|
|
fn test_get_settings() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
let key1 = "test_key";
|
|
let key2 = "test_key_2";
|
|
let value = json!("test_value");
|
|
let response1_status = set_setting_request(&client, key1, &value);
|
|
assert_eq!(response1_status, rocket::http::Status::Created);
|
|
let response2_status = set_setting_request(&client, key2, &value);
|
|
assert_eq!(response2_status, rocket::http::Status::Created);
|
|
|
|
let res = client
|
|
.get("/api/0/settings")
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
let deserialized: Value = serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
let expected: Value =
|
|
serde_json::from_str(r#"{"test_key_2":"test_value","test_key":"test_value"}"#).unwrap();
|
|
assert_eq!(deserialized, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn test_get_setting() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
let key = "test_key";
|
|
let value = json!("test_value");
|
|
let response_status = set_setting_request(&client, key, &value);
|
|
assert_eq!(response_status, rocket::http::Status::Created);
|
|
|
|
// Test getting
|
|
let res = client
|
|
.get(format!("/api/0/settings/{}", key))
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
let deserialized: Value = serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
assert_eq!(deserialized, value);
|
|
}
|
|
|
|
#[test]
|
|
fn test_get_setting_dotted_key() {
|
|
// HTTP accepts dotted keys; JNI getSetting must use the same grammar
|
|
// (ActivityWatch/aw-server-rust#653 Greptile: don't reject '.').
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
let key = "nested.like.key";
|
|
let value = json!("dotted_value");
|
|
assert_eq!(
|
|
set_setting_request(&client, key, &value),
|
|
rocket::http::Status::Created
|
|
);
|
|
|
|
let res = client
|
|
.get(format!("/api/0/settings/{}", key))
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
let deserialized: Value = serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
assert_eq!(deserialized, value);
|
|
}
|
|
|
|
#[test]
|
|
fn test_get_setting_list() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
// Test array
|
|
let key = "test_key_array";
|
|
let value = json!([1, 2, 3]);
|
|
let response_status = set_setting_request(&client, key, &value);
|
|
assert_eq!(response_status, rocket::http::Status::Created);
|
|
|
|
let res = client
|
|
.get(format!("/api/0/settings/{}", key))
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
let deserialized: Value = serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
assert_eq!(deserialized, value);
|
|
}
|
|
|
|
#[test]
|
|
fn test_get_setting_dict() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
// Test dict
|
|
let key = "test_key_dict";
|
|
let value = json!({"key": "value", "another_key": "another value"});
|
|
let response_status = set_setting_request(&client, key, &value);
|
|
assert_eq!(response_status, rocket::http::Status::Created);
|
|
|
|
let res = client
|
|
.get("/api/0/settings/test_key_dict")
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
let deserialized: Value = serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
assert_eq!(deserialized, value);
|
|
}
|
|
|
|
#[test]
|
|
fn test_set_setting() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
let key = "test_key";
|
|
let value1 = json!("test_value");
|
|
let value2 = json!("changed_test_value");
|
|
let post_1_status = set_setting_request(&client, key, &value1);
|
|
assert_eq!(post_1_status, rocket::http::Status::Created);
|
|
|
|
let res = client
|
|
.get(format!("/api/0/settings/{}", key))
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
let deserialized: Value = serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
assert_eq!(deserialized, value1);
|
|
|
|
let post_2_status = set_setting_request(&client, key, &value2);
|
|
assert_eq!(post_2_status, rocket::http::Status::Created);
|
|
|
|
let res = client
|
|
.get("/api/0/settings/test_key")
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
let new_deserialized: Value = serde_json::from_str(&res.into_string().unwrap()).unwrap();
|
|
assert_eq!(new_deserialized, value2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_delete_setting() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
let value = json!("test_value");
|
|
let response_status = set_setting_request(&client, "test_key", &value);
|
|
assert_eq!(response_status, rocket::http::Status::Created);
|
|
|
|
// Test deleting
|
|
let res = client
|
|
.delete("/api/0/settings/test_key")
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
|
|
let res = client
|
|
.get("/api/0/settings/test_key")
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
assert_eq!(res.into_string().unwrap(), "null");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cors_catching() {
|
|
let server = setup_testserver();
|
|
let client = Client::untracked(server).expect("valid instance");
|
|
|
|
let res = client
|
|
.options("/api/0/buckets/")
|
|
.header(ContentType::JSON)
|
|
.header(Header::new("Host", "127.0.0.1:5600"))
|
|
.dispatch();
|
|
assert_eq!(res.status(), rocket::http::Status::Ok);
|
|
}
|
|
}
|