use serde::{Deserialize, Serialize};
use super::{InternalVerb, VerbCategory};
pub struct CloudObjectBucketCreate;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct CloudObjectBucketCreateInput {
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub location_hint: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct CloudObjectBucketCreateOutput {
pub endpoint: String,
}
impl InternalVerb for CloudObjectBucketCreate {
type Input = CloudObjectBucketCreateInput;
type Output = CloudObjectBucketCreateOutput;
const ID: &'static str = "cloud.object.bucket.create";
const CATEGORY: VerbCategory = VerbCategory::Cloud;
}
pub struct CloudObjectBucketDelete;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct CloudObjectBucketDeleteInput {
pub name: String,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct CloudObjectBucketDeleteOutput {}
impl InternalVerb for CloudObjectBucketDelete {
type Input = CloudObjectBucketDeleteInput;
type Output = CloudObjectBucketDeleteOutput;
const ID: &'static str = "cloud.object.bucket.delete";
const CATEGORY: VerbCategory = VerbCategory::Cloud;
}
pub struct CloudObjectBucketExists;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct CloudObjectBucketExistsInput {
pub name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct CloudObjectBucketExistsOutput {
pub exists: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub endpoint: Option<String>,
}
impl InternalVerb for CloudObjectBucketExists {
type Input = CloudObjectBucketExistsInput;
type Output = CloudObjectBucketExistsOutput;
const ID: &'static str = "cloud.object.bucket.exists";
const CATEGORY: VerbCategory = VerbCategory::Cloud;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verb_ids_match_canonical_namespace() {
assert_eq!(CloudObjectBucketCreate::ID, "cloud.object.bucket.create");
assert_eq!(CloudObjectBucketDelete::ID, "cloud.object.bucket.delete");
assert_eq!(CloudObjectBucketExists::ID, "cloud.object.bucket.exists");
for id in [
CloudObjectBucketCreate::ID,
CloudObjectBucketDelete::ID,
CloudObjectBucketExists::ID,
] {
assert!(id.starts_with("cloud."), "{id}");
}
}
#[test]
fn verbs_are_under_cloud_category() {
assert_eq!(CloudObjectBucketCreate::CATEGORY, VerbCategory::Cloud);
assert_eq!(CloudObjectBucketDelete::CATEGORY, VerbCategory::Cloud);
assert_eq!(CloudObjectBucketExists::CATEGORY, VerbCategory::Cloud);
}
#[test]
fn create_input_location_hint_is_optional() {
let with_hint = CloudObjectBucketCreateInput {
name: "my-bucket".into(),
location_hint: Some("WEUR".into()),
};
let wire = serde_json::to_string(&with_hint).unwrap();
let back: CloudObjectBucketCreateInput = serde_json::from_str(&wire).unwrap();
assert_eq!(back.location_hint.as_deref(), Some("WEUR"));
let no_hint = r#"{"name":"my-bucket"}"#;
let parsed: CloudObjectBucketCreateInput = serde_json::from_str(no_hint).unwrap();
assert!(parsed.location_hint.is_none());
}
#[test]
fn create_input_omits_hint_when_absent() {
let input = CloudObjectBucketCreateInput {
name: "b".into(),
location_hint: None,
};
let wire = serde_json::to_value(&input).unwrap();
assert!(!wire.as_object().unwrap().contains_key("location_hint"));
}
#[test]
fn delete_output_serializes_to_empty_object() {
let wire = serde_json::to_value(CloudObjectBucketDeleteOutput::default()).unwrap();
assert_eq!(wire, serde_json::json!({}));
}
#[test]
fn exists_output_omits_endpoint_when_absent() {
let out = CloudObjectBucketExistsOutput {
exists: false,
endpoint: None,
};
let wire = serde_json::to_value(&out).unwrap();
assert_eq!(wire, serde_json::json!({ "exists": false }));
}
#[test]
fn exists_output_includes_endpoint_when_present() {
let out = CloudObjectBucketExistsOutput {
exists: true,
endpoint: Some("https://acct.r2.cloudflarestorage.com".into()),
};
let wire = serde_json::to_value(&out).unwrap();
assert_eq!(wire["exists"], true);
assert!(wire["endpoint"].as_str().is_some());
}
#[cfg(feature = "json-schema")]
#[test]
fn verbs_emit_schemas_via_for_verb() {
use super::super::VerbDescriptor;
let create = VerbDescriptor::for_verb::<CloudObjectBucketCreate>();
assert_eq!(create.id, "cloud.object.bucket.create");
assert!(create.input_schema.to_string().contains("name"));
let delete = VerbDescriptor::for_verb::<CloudObjectBucketDelete>();
assert_eq!(delete.id, "cloud.object.bucket.delete");
let exists = VerbDescriptor::for_verb::<CloudObjectBucketExists>();
assert_eq!(exists.id, "cloud.object.bucket.exists");
assert!(exists.output_schema.to_string().contains("exists"));
}
}