Skip to main content

cloud_sdk_testkit/
metadata.rs

1//! Provider-neutral response metadata fixtures.
2
3/// Fixture metadata validation error.
4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5pub enum FixtureMetadataError {
6    /// Pagination page and page-size values must be nonzero.
7    PaginationZero,
8    /// Current page must not exceed the last page.
9    PageAfterLast,
10    /// Last page does not match total entries and page size.
11    InvalidLastPage,
12    /// Remaining requests must not exceed the rate limit.
13    RemainingExceedsLimit,
14    /// Rate limits must be nonzero.
15    RateLimitZero,
16    /// Action progress must be in `0..=100`.
17    InvalidProgress,
18}
19
20/// Pagination metadata for a deterministic response.
21#[derive(Clone, Copy, Debug, Eq, PartialEq)]
22pub struct PaginationFixture {
23    page: u64,
24    per_page: u64,
25    total_entries: u64,
26    last_page: u64,
27}
28
29impl PaginationFixture {
30    /// Creates coherent pagination metadata.
31    pub const fn new(
32        page: u64,
33        per_page: u64,
34        total_entries: u64,
35        last_page: u64,
36    ) -> Result<Self, FixtureMetadataError> {
37        if page == 0 || per_page == 0 || last_page == 0 {
38            return Err(FixtureMetadataError::PaginationZero);
39        }
40        if page > last_page {
41            return Err(FixtureMetadataError::PageAfterLast);
42        }
43        let mut expected_last = match total_entries.checked_div(per_page) {
44            Some(value) => value,
45            None => return Err(FixtureMetadataError::PaginationZero),
46        };
47        let remainder = match total_entries.checked_rem(per_page) {
48            Some(value) => value,
49            None => return Err(FixtureMetadataError::PaginationZero),
50        };
51        if remainder != 0 {
52            expected_last = match expected_last.checked_add(1) {
53                Some(value) => value,
54                None => return Err(FixtureMetadataError::InvalidLastPage),
55            };
56        }
57        if expected_last == 0 {
58            expected_last = 1;
59        }
60        if last_page != expected_last {
61            return Err(FixtureMetadataError::InvalidLastPage);
62        }
63        Ok(Self {
64            page,
65            per_page,
66            total_entries,
67            last_page,
68        })
69    }
70
71    /// Returns the current page.
72    #[must_use]
73    pub const fn page(self) -> u64 {
74        self.page
75    }
76
77    /// Returns the requested page size.
78    #[must_use]
79    pub const fn per_page(self) -> u64 {
80        self.per_page
81    }
82
83    /// Returns the total entry count.
84    #[must_use]
85    pub const fn total_entries(self) -> u64 {
86        self.total_entries
87    }
88
89    /// Returns the last page number.
90    #[must_use]
91    pub const fn last_page(self) -> u64 {
92        self.last_page
93    }
94}
95
96/// Provider-neutral action lifecycle fixture.
97#[derive(Clone, Copy, Debug, Eq, PartialEq)]
98pub enum ActionState {
99    /// Action remains in progress.
100    Running,
101    /// Action completed successfully.
102    Success,
103    /// Action completed with an error.
104    Error,
105}
106
107/// Action metadata for polling tests.
108#[derive(Clone, Copy, Debug, Eq, PartialEq)]
109pub struct ActionFixture {
110    state: ActionState,
111    progress: u8,
112}
113
114impl ActionFixture {
115    /// Creates bounded action metadata.
116    pub const fn new(state: ActionState, progress: u8) -> Result<Self, FixtureMetadataError> {
117        if progress > 100 {
118            return Err(FixtureMetadataError::InvalidProgress);
119        }
120        Ok(Self { state, progress })
121    }
122
123    /// Returns the lifecycle state.
124    #[must_use]
125    pub const fn state(self) -> ActionState {
126        self.state
127    }
128
129    /// Returns progress in `0..=100`.
130    #[must_use]
131    pub const fn progress(self) -> u8 {
132        self.progress
133    }
134}
135
136/// Rate-limit metadata fixture.
137#[derive(Clone, Copy, Debug, Eq, PartialEq)]
138pub struct RateLimitFixture {
139    limit: u64,
140    remaining: u64,
141    reset_at: Option<u64>,
142}
143
144impl RateLimitFixture {
145    /// Creates coherent rate-limit metadata.
146    pub const fn new(
147        limit: u64,
148        remaining: u64,
149        reset_at: Option<u64>,
150    ) -> Result<Self, FixtureMetadataError> {
151        if limit == 0 {
152            return Err(FixtureMetadataError::RateLimitZero);
153        }
154        if remaining > limit {
155            return Err(FixtureMetadataError::RemainingExceedsLimit);
156        }
157        Ok(Self {
158            limit,
159            remaining,
160            reset_at,
161        })
162    }
163
164    /// Returns the request limit.
165    #[must_use]
166    pub const fn limit(self) -> u64 {
167        self.limit
168    }
169
170    /// Returns the remaining request count.
171    #[must_use]
172    pub const fn remaining(self) -> u64 {
173        self.remaining
174    }
175
176    /// Returns an optional provider-specific reset timestamp.
177    #[must_use]
178    pub const fn reset_at(self) -> Option<u64> {
179        self.reset_at
180    }
181}