use assert_cmd::Command; use mockito::{mock, Matcher}; use serde_json::json; #[test] fn it_output_version() { let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap(); let assert = cmd.args(&["-V"]).assert(); assert.success().stdout("svanill-vault-cli 0.1.0\n"); } #[test] fn it_exit_with_error_if_the_user_does_not_exist() { let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap(); let m = mock("GET", "/auth/request-challenge?username=test_user") .with_status(401) .with_header("content-type", "application/json") .with_body( r#" { "error": {"code":1005,"message":"The user does not exist"}, "links":{ "create_user":{ "href":"https://api.svanill.com/users/", "rel":"user" } }, "status":401 } "#, ) .create(); let base_url = &mockito::server_url(); let assert = cmd .args(&["-u", "test_user", "-h", base_url, "ls"]) .assert(); m.assert(); assert .failure() .code(1) .stdout("") .stderr("Error: Status: 401, Code: 1005, Message: \"The user does not exist\"\n"); } #[test] fn it_list_remote_files() { let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap(); let username = "test_user"; let base_url = &mockito::server_url(); let (m1, m2) = mock_successful_authentication_requests(&base_url); let m3 = mock_list_files_happy_path(&base_url, &username); let assert = cmd .args(&[ "-h", base_url, "-u", username, "--answer", "test answer", "ls", ]) .assert(); m1.assert(); m2.assert(); m3.assert(); assert.success().stdout( r#" Bytes | Filename 123 | this-is-a-test-file "#, ); } #[test] fn it_delete_files() { let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap(); let base_url = &mockito::server_url(); let (m1, m2) = mock_successful_authentication_requests(&base_url); let m3 = mock("DELETE", "/files/?filename=some-file-to-delete") .with_status(200) .with_header("content-type", "application/json") .with_body(r#"{"status":200}"#) .create(); let assert = cmd .args(&[ "-h", base_url, "-u", "test_user", "--answer", "test answer", "rm", "some-file-to-delete", ]) .assert(); m1.assert(); m2.assert(); m3.assert(); assert .success() .stdout("Success: deleted file \"some-file-to-delete\"\n"); } #[test] fn it_pull_remote_file_output_to_stdout() { let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap(); let username = "test_user"; let base_url = &mockito::server_url(); let (m1, m2) = mock_successful_authentication_requests(&base_url); let m3 = mock_list_files_happy_path(&base_url, &username); let m4 = mock("GET", "/imaginary/url/this-is-a-test-file") .with_status(200) .with_header("content-type", "text/plain") .with_body("imaginary content") .create(); let assert = cmd .args(&[ "-h", base_url, "-u", username, "--answer", "test answer", "pull", "this-is-a-test-file", "-s", ]) .assert(); m1.assert(); m2.assert(); m3.assert(); m4.assert(); assert.success().stdout("imaginary content"); } #[test] fn it_push_content_from_stdin_to_remote_file() { let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap(); let base_url = &mockito::server_url(); let (m1, m2) = mock_successful_authentication_requests(&base_url); let m3 = mock("POST", "/files/request-upload-url") .match_body(r#"{"filename":"some-remote-filename"}"#) .with_status(200) .with_header("content-type", "application/json") .with_body(json!({ "links":{ "retrieve_url":{ "href":format!("{}/some/imaginary/retrieve/url", base_url), "rel":"file" }, "upload_url":{ "form_data":{ "bucket":"some-bucket", "key":"users/test_user/some-remote-filename", "policy":"xxx", "x-amz-algorithm":"AWS4-HMAC-SHA256", "x-amz-credential":"AMIAIT3W6RZTLLGAZEXQ/10230679/us-west-2/s3/aws4_request", "x-amz-date":"20200629T014946Z", "x-amz-signature":"50cf7a0fa5ec900de9a6d7b05f7ecdd8e3c082bb144b7604d71118852e386c2d" }, "href":format!("{}/some/imaginary/upload/url", base_url), "rel":"file" } }, "status":200 }) .to_string()) .create(); let m4 = mock("POST", "/some/imaginary/upload/url") .match_header( "Content-Type", Matcher::Regex("^multipart/form-data(;.*)?".to_string()), ) .match_body(Matcher::Regex("Content-Disposition".to_string())) .with_status(204) .with_header("ETag", "2e01e17dd92be3c7fab5e08505ed64c9") .create(); let assert = cmd .args(&[ "-h", base_url, "-u", "test_user", "--answer", "test answer", "push", "-r", "some-remote-filename", "-", ]) .write_stdin("blob of data") .assert(); m1.assert(); m2.assert(); m3.assert(); m4.assert(); assert .success() .stdout("Successfully pushed file, using as remote name \"some-remote-filename\"\n"); } fn mock_successful_authentication_requests(base_url: &str) -> (mockito::Mock, mockito::Mock) { let m1 = mock("GET", "/auth/request-challenge?username=test_user") .with_status(200) .with_header("content-type", "application/json") .with_body( json!({ "content": {"challenge":"somechallenge"}, "links": { "answer_auth_challenge":{ "href": format!("{}/auth/answer-challenge", base_url), "rel":"auth" }, "create_user":{ "href": format!("{}/users/", base_url), "rel":"user" } }, "status":200 }) .to_string(), ) .create(); let m2 = mock("POST", "/auth/answer-challenge") .with_status(200) .with_header("content-type", "application/json") .with_body( json!({ "content":{"token":"a-secure-token"}, "links":{ "files_list":{ "href":format!("{}/files/", base_url), "rel":"file" }, "request_upload_url":{ "href":format!("{}/files/request-upload-url/", base_url), "rel":"file" } }, "status":200 } ) .to_string(), ) .create(); (m1, m2) } fn mock_list_files_happy_path(base_url: &str, username: &str) -> mockito::Mock { mock("GET", "/files/") .with_status(200) .with_header("content-type", "application/json") .with_body( json!({ "content":[ { "content":{ "checksum":"a9a1bdddeacc612db8b5c01a830af1c3", "filename": format!("users/{}/this-is-a-test-file", username), "size":123, "url":format!("{}/imaginary/url/this-is-a-test-file", base_url), }, "links":{ "delete":{ "href":format!("{}/files/", base_url), "rel":"file" }, "read":{ "href":format!("{}/imaginary/url/this-is-a-test-file", base_url), "rel":"file" } } } ], "status":200 } ) .to_string(), ) .create() }