Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for TestClock operations #579

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ required-features = ["async"]
name = "subscriptions"
required-features = ["async"]

[[example]]
name = "test-clocks"
required-features = ["async"]

[[example]]
name = "webhook-axum"
required-features = ["async"]
Expand Down
82 changes: 82 additions & 0 deletions examples/test-clocks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use std::time::{Duration, SystemTime, UNIX_EPOCH};

use futures_util::TryStreamExt;
use stripe::{
AdvanceTestClock, Client, CreateTestClock, ListTestClocks, TestHelpersTestClockStatus,
};
use tokio::time::sleep;

#[tokio::main]
async fn main() {
let secret_key = std::env::var("STRIPE_SECRET_KEY").expect("Missing STRIPE_SECRET_KEY in env");
let client = Client::new(secret_key);

let now = SystemTime::now();
let timestamp = now.duration_since(UNIX_EPOCH).unwrap().as_secs();

let test_clock_1 = stripe::TestHelpersTestClock::create(
&client,
&CreateTestClock { frozen_time: timestamp as i64, name: "Example test clock 1" },
)
.await
.unwrap();

assert_eq!(test_clock_1.status, Some(TestHelpersTestClockStatus::Ready));
println!("created a test clock at https://dashboard.stripe.com/test/billing/subscriptions/test-clocks/{}", test_clock_1.id);

let test_clock_2 = stripe::TestHelpersTestClock::create(
&client,
&CreateTestClock { frozen_time: timestamp as i64, name: "Example test clock 2" },
)
.await
.unwrap();

assert_eq!(test_clock_2.status, Some(TestHelpersTestClockStatus::Ready));
println!("created a test clock at https://dashboard.stripe.com/test/billing/subscriptions/test-clocks/{}", test_clock_2.id);

let mut all_test_clocks_params = ListTestClocks::default();
all_test_clocks_params.limit = Some(1); // Force pagination to happen
let all_test_clocks = stripe::TestHelpersTestClock::list(&client, &ListTestClocks::default())
.await
.unwrap()
.paginate(ListTestClocks::default())
.stream(&client)
.try_collect::<Vec<_>>()
.await
.unwrap();
assert_eq!(all_test_clocks.len(), 2);
println!(
"all test clocks: {:?}",
all_test_clocks.into_iter().map(|test_clock| test_clock.id).collect::<Vec<_>>()
);

let new_timestamp = timestamp + (60 * 60 * 60);
let mut test_clock_1 = stripe::TestHelpersTestClock::advance(
&client,
&test_clock_1.id,
&AdvanceTestClock { frozen_time: new_timestamp as i64 },
)
.await
.unwrap();
assert_eq!(test_clock_1.status, Some(TestHelpersTestClockStatus::Advancing));
println!("advancing test clock {} to {}", test_clock_1.id, new_timestamp);

while test_clock_1.status == Some(TestHelpersTestClockStatus::Advancing) {
println!("test clock {} is still advancing...", test_clock_1.id);
sleep(Duration::from_secs(1)).await;

test_clock_1 =
stripe::TestHelpersTestClock::retrieve(&client, &test_clock_1.id).await.unwrap();
}
println!("test clock {} is now on status {}", test_clock_1.id, test_clock_1.status.unwrap());

let deleted_test_clock_1 =
stripe::TestHelpersTestClock::delete(&client, &test_clock_1.id).await.unwrap();
assert!(deleted_test_clock_1.deleted);
println!("delete test clock {}", deleted_test_clock_1.id);

let deleted_test_clock_2 =
stripe::TestHelpersTestClock::delete(&client, &test_clock_2.id).await.unwrap();
assert!(deleted_test_clock_2.deleted);
println!("delete test clock {}", deleted_test_clock_2.id);
}
2 changes: 2 additions & 0 deletions src/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod core {
pub mod payout_ext;
pub mod placeholders;
pub mod setup_intent_ext;
pub mod test_clock_ext;
pub mod token_ext;
pub mod transfer_reversal_ext;
}
Expand Down Expand Up @@ -112,6 +113,7 @@ pub use {
payment_source::*,
placeholders::*,
payout_ext::*,
test_clock_ext::*,
token_ext::*,
setup_intent_ext::*,
},
Expand Down
118 changes: 118 additions & 0 deletions src/resources/test_clock_ext.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// pub struct TestClockRetrieve {}

use serde::Serialize;

use crate::{
params::Paginable, Client, List, Response, TestHelpersTestClock, TestHelpersTestClockId,
Timestamp,
};

#[derive(Clone, Debug, Serialize, Default)]
pub struct CreateTestClock<'a> {
/// The initial frozen time for this test clock.
pub frozen_time: Timestamp,

/// The name for this test clock.
pub name: &'a str,
}

impl<'a> CreateTestClock<'a> {
pub fn new() -> Self {
Self { frozen_time: Default::default(), name: Default::default() }
}
}

#[derive(Clone, Debug, Serialize, Default)]
pub struct AdvanceTestClock {
/// The time to advance the test clock. Must be after the test clock’s current frozen time.
/// Cannot be more than two intervals in the future from the shortest subscription in this test clock.
/// If there are no subscriptions in this test clock, it cannot be more than two years in the future.
pub frozen_time: Timestamp,
}

#[derive(Clone, Debug, Serialize, Default)]
pub struct ListTestClocks {
/// A cursor for use in pagination.
///
/// `ending_before` is an object ID that defines your place in the list. For instance,
/// if you make a list request and receive 100 objects, starting with `obj_bar`,
/// your subsequent call can include `ending_before=obj_bar` in order to fetch the previous
/// page of the list.
#[serde(skip_serializing_if = "Option::is_none")]
pub ending_before: Option<TestHelpersTestClockId>,

/// A cursor for use in pagination.
///
/// `starting_after` is an object ID that defines your place in the list. For instance,
/// if you make a list request and receive 100 objects, ending with `obj_foo`, your subsequent
/// call can include `starting_after=obj_foo` in order to fetch the next page of the list.
#[serde(skip_serializing_if = "Option::is_none")]
pub starting_after: Option<TestHelpersTestClockId>,

/// A limit on the number of objects to be returned. Limit can range between 1 and 100,
/// and the default is 10.
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
}

impl ListTestClocks {
pub fn new() -> Self {
Self {
ending_before: Default::default(),
starting_after: Default::default(),
limit: Default::default(),
}
}
}

impl Paginable for ListTestClocks {
type O = TestHelpersTestClock;

fn set_last(&mut self, item: Self::O) {
self.starting_after = Some(item.id);
}
}

impl TestHelpersTestClock {
/// Creates a new test clock that can be attached to new customers and quotes.
///
/// For more details see <https://docs.stripe.com/api/test_clocks/create>
pub fn create(client: &Client, params: &CreateTestClock<'_>) -> Response<TestHelpersTestClock> {
client.post_form("/test_helpers/test_clocks", params)
}

/// Retrieves a test clock.
///
/// For more details see <https://docs.stripe.com/api/test_clocks/retrieve>
pub fn retrieve(
client: &Client,
id: &TestHelpersTestClockId,
) -> Response<TestHelpersTestClock> {
client.get(&format!("/test_helpers/test_clocks/{}", id))
}

/// Returns a list of your test clocks.
///
/// For more details see <https://docs.stripe.com/api/test_clocks/list>
pub fn list(client: &Client, params: &ListTestClocks) -> Response<List<TestHelpersTestClock>> {
client.get_query("/test_helpers/test_clocks", params)
}

/// Deletes a test clock.
///
/// For more details see <https://docs.stripe.com/api/test_clocks/delete>
pub fn delete(client: &Client, id: &TestHelpersTestClockId) -> Response<TestHelpersTestClock> {
client.delete(&format!("/test_helpers/test_clocks/{}", id))
}

/// Starts advancing a test clock to a specified time in the future. Advancement is done when status changes to `Ready`.
///
/// For more details see <https://docs.stripe.com/api/test_clocks/advance>
pub fn advance(
client: &Client,
test_clock_id: &TestHelpersTestClockId,
params: &AdvanceTestClock,
) -> Response<TestHelpersTestClock> {
client.post_form(&format!("test_helpers/test_clocks/{}/advance", test_clock_id), params)
}
}
Loading