mod mock_error;
use chrono::DateTime;
use mock_error::setup_error_handler;
use octocrab::{
models::{
orgs::secrets::{
CreateOrganizationSecret, CreateOrganizationSecretResponse, OrganizationSecret,
OrganizationSecrets, Visibility,
},
PublicKey,
},
Octocrab,
};
use wiremock::{
matchers::{method, path},
Mock, MockServer, ResponseTemplate,
};
const ORG: &str = "some-org";
async fn setup_get_api(template: ResponseTemplate, secrets_path: &str) -> MockServer {
let mock_server = MockServer::start().await;
Mock::given(method("GET"))
.and(path(format!("/orgs/{ORG}/actions/secrets{secrets_path}")))
.respond_with(template)
.mount(&mock_server)
.await;
setup_error_handler(
&mock_server,
&format!("GET on /orgs/{ORG}/actions/secrets{secrets_path} was not received"),
)
.await;
mock_server
}
async fn setup_put_api(template: ResponseTemplate, secrets_path: &str) -> MockServer {
let mock_server = MockServer::start().await;
Mock::given(method("PUT"))
.and(path(format!("/orgs/{ORG}/actions/secrets{secrets_path}")))
.respond_with(template)
.mount(&mock_server)
.await;
setup_error_handler(
&mock_server,
&format!("PUT on /orgs/{ORG}/actions/secrets{secrets_path} was not received"),
)
.await;
mock_server
}
async fn setup_delete_api(template: ResponseTemplate, secrets_path: &str) -> MockServer {
let mock_server = MockServer::start().await;
Mock::given(method("DELETE"))
.and(path(format!("/orgs/{ORG}/actions/secrets{secrets_path}")))
.respond_with(template)
.mount(&mock_server)
.await;
setup_error_handler(
&mock_server,
&format!("DELETE on /orgs/{ORG}/actions/secrets{secrets_path} was not received"),
)
.await;
mock_server
}
fn setup_octocrab(uri: &str) -> Octocrab {
Octocrab::builder().base_uri(uri).unwrap().build().unwrap()
}
#[tokio::test]
async fn should_return_org_secrets() {
let org_secrets: OrganizationSecrets =
serde_json::from_str(include_str!("resources/org_secrets.json")).unwrap();
let template = ResponseTemplate::new(200).set_body_json(&org_secrets);
let mock_server = setup_get_api(template, "").await;
let result = setup_octocrab(&mock_server.uri())
.orgs(ORG.to_owned())
.secrets()
.get_secrets()
.await;
assert!(
result.is_ok(),
"expected successful result, got error: {:#?}",
result
);
let item = result.unwrap();
assert_eq!(item.total_count, 3);
assert_eq!(
item.secrets,
vec![
OrganizationSecret {
name: String::from("GIST_ID"),
visibility: Visibility::Private,
selected_repositories_url: None,
created_at: DateTime::parse_from_rfc3339("2019-08-10T14:59:22Z")
.unwrap()
.into(),
updated_at: DateTime::parse_from_rfc3339("2020-01-10T14:59:22Z")
.unwrap()
.into(),
},
OrganizationSecret {
name: String::from("DEPLOY_TOKEN"),
visibility: Visibility::All,
selected_repositories_url: None,
created_at: DateTime::parse_from_rfc3339("2019-08-10T14:59:22Z")
.unwrap()
.into(),
updated_at: DateTime::parse_from_rfc3339("2020-01-10T14:59:22Z")
.unwrap()
.into(),
},
OrganizationSecret {
name: String::from("GH_TOKEN"),
visibility: Visibility::Selected,
selected_repositories_url: Some(String::from("https://api.github.com/orgs/octo-org/actions/secrets/SUPER_SECRET/repositories")),
created_at: DateTime::parse_from_rfc3339("2019-08-10T14:59:22Z")
.unwrap()
.into(),
updated_at: DateTime::parse_from_rfc3339("2020-01-10T14:59:22Z")
.unwrap()
.into(),
},
]
);
}
#[tokio::test]
async fn should_return_org_public_key() {
let org_secrets: PublicKey =
serde_json::from_str(include_str!("resources/org_public_key.json")).unwrap();
let template = ResponseTemplate::new(200).set_body_json(&org_secrets);
let mock_server = setup_get_api(template, "/public-key").await;
let result = setup_octocrab(&mock_server.uri())
.orgs(ORG.to_owned())
.secrets()
.get_public_key()
.await;
assert!(
result.is_ok(),
"expected successful result, got error: {:#?}",
result
);
let item = result.unwrap();
assert_eq!(item.key_id, String::from("012345678912345678"));
assert_eq!(
item.key,
String::from("2Sg8iYjAxxmI2LvUXpJjkYrMxURPc8r+dB7TJyvv1234")
);
}
#[tokio::test]
async fn should_return_org_secret() {
let org_secrets: OrganizationSecret =
serde_json::from_str(include_str!("resources/org_secret.json")).unwrap();
let template = ResponseTemplate::new(200).set_body_json(&org_secrets);
let mock_server = setup_get_api(template, "/GH_TOKEN").await;
let result = setup_octocrab(&mock_server.uri())
.orgs(ORG.to_owned())
.secrets()
.get_secret("GH_TOKEN")
.await;
assert!(
result.is_ok(),
"expected successful result, got error: {:#?}",
result
);
let item = result.unwrap();
assert_eq!(
item,
OrganizationSecret {
name: String::from("GH_TOKEN"),
visibility: Visibility::Selected,
selected_repositories_url: Some(String::from(
"https://api.github.com/orgs/octo-org/actions/secrets/SUPER_SECRET/repositories"
)),
created_at: DateTime::parse_from_rfc3339("2019-08-10T14:59:22Z")
.unwrap()
.into(),
updated_at: DateTime::parse_from_rfc3339("2020-01-10T14:59:22Z")
.unwrap()
.into(),
}
);
}
#[tokio::test]
async fn should_add_secret() {
let template = ResponseTemplate::new(201);
let mock_server = setup_put_api(template, "/GH_TOKEN").await;
let result = setup_octocrab(&mock_server.uri())
.orgs(ORG.to_owned())
.secrets()
.create_or_update_secret(
"GH_TOKEN",
&CreateOrganizationSecret {
visibility: Visibility::All,
selected_repository_ids: None,
key_id: "123456",
encrypted_value: "some-b64-string",
},
)
.await;
assert!(
result.is_ok(),
"expected successful result, got error: {:#?}",
result
);
let item = result.unwrap();
assert_eq!(item, CreateOrganizationSecretResponse::Created);
}
#[tokio::test]
async fn should_update_secret_204() {
let template = ResponseTemplate::new(204);
let mock_server = setup_put_api(template, "/GH_TOKEN").await;
let result = setup_octocrab(&mock_server.uri())
.orgs(ORG.to_owned())
.secrets()
.create_or_update_secret(
"GH_TOKEN",
&CreateOrganizationSecret {
visibility: Visibility::All,
selected_repository_ids: None,
key_id: "123456",
encrypted_value: "some-b64-string",
},
)
.await;
assert!(
result.is_ok(),
"expected successful result, got error: {:#?}",
result
);
let item = result.unwrap();
assert_eq!(item, CreateOrganizationSecretResponse::Updated);
}
#[tokio::test]
async fn should_delete_secret() {
let template = ResponseTemplate::new(204);
let mock_server = setup_delete_api(template, "/GH_TOKEN").await;
let result = setup_octocrab(&mock_server.uri())
.orgs(ORG.to_owned())
.secrets()
.delete_secret("GH_TOKEN")
.await;
assert!(
result.is_ok(),
"expected successful result, got error: {:#?}",
result
);
}
#[tokio::test]
async fn should_noop_secret_500() {
let template = ResponseTemplate::new(500);
let mock_server = setup_delete_api(template, "/GH_TOKEN").await;
let result = setup_octocrab(&mock_server.uri())
.orgs(ORG.to_owned())
.secrets()
.delete_secret("GH_TOKEN")
.await;
assert!(
result.is_err(),
"expected error result, got success somehow: {:#?}",
result
);
}