Skip to content

Commit 264c31d

Browse files
authored
add test for BlessedVersionExtraLocalSpec (#8)
1 parent 8372d55 commit 264c31d

3 files changed

Lines changed: 161 additions & 46 deletions

File tree

crates/dropshot-api-manager/src/output.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ pub fn display_load_problems(
225225
let mut nerrors = 0;
226226
for e in error_accumulator.iter_errors() {
227227
nerrors += 1;
228-
println!(
228+
eprintln!(
229229
"{:>HEADER_WIDTH$} {:#}",
230230
FAILURE.style(styles.failure_header),
231231
e

crates/integration-tests/src/common/mod.rs

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,10 @@ impl TestEnvironment {
147147
&self,
148148
api_ident: &str,
149149
version: &str,
150-
) -> bool {
151-
self.find_versioned_document(api_ident, version).is_some()
150+
) -> anyhow::Result<bool> {
151+
let maybe_path =
152+
self.find_versioned_document_path(api_ident, version)?;
153+
Ok(maybe_path.is_some())
152154
}
153155

154156
/// Check that a versioned document exists for a versioned API at a specific
@@ -158,7 +160,8 @@ impl TestEnvironment {
158160
api_ident: &str,
159161
version: &str,
160162
) -> anyhow::Result<bool> {
161-
let Some(path) = self.find_versioned_document(api_ident, version)
163+
let Some(path) =
164+
self.find_versioned_document_path(api_ident, version)?
162165
else {
163166
return Ok(false);
164167
};
@@ -172,24 +175,25 @@ impl TestEnvironment {
172175
Ok(output.trim() == path)
173176
}
174177

175-
fn find_versioned_document(
178+
/// Find the path of a versioned API document for a specific version,
179+
/// relative to the workspace root.
180+
pub fn find_versioned_document_path(
176181
&self,
177182
api_ident: &str,
178183
version: &str,
179-
) -> Option<Utf8PathBuf> {
180-
let files = self
181-
.list_document_files()
182-
.expect("reading document files succeeded");
184+
) -> Result<Option<Utf8PathBuf>> {
185+
let files = self.list_document_files()?;
183186

184187
// Versioned documents are stored in subdirectories like:
185188
// documents/api/api-version-hash.json.
186189
let pattern =
187190
format!("documents/{}/{}-{}-", api_ident, api_ident, version);
188191

189-
files.iter().find_map(|f| {
192+
let path = files.iter().find_map(|f| {
190193
let rel_path = rel_path_forward_slashes(f.as_ref());
191194
rel_path.starts_with(&pattern).then(|| Utf8PathBuf::from(rel_path))
192-
})
195+
});
196+
Ok(path)
193197
}
194198

195199
/// Read the content of a versioned API document for a specific version.
@@ -198,25 +202,15 @@ impl TestEnvironment {
198202
api_ident: &str,
199203
version: &str,
200204
) -> Result<String> {
201-
// Find the document file that matches the version pattern.
202-
let files = self.list_document_files()?;
203-
let pattern =
204-
format!("documents/{}/{}-{}-", api_ident, api_ident, version);
205-
206-
let matching_file = files
207-
.iter()
208-
.find(|f| {
209-
rel_path_forward_slashes(f.as_ref()).starts_with(&pattern)
210-
})
211-
.ok_or_else(|| {
212-
anyhow!(
213-
"No versioned document found for {} version {}",
214-
api_ident,
215-
version
205+
let path = self
206+
.find_versioned_document_path(api_ident, version)?
207+
.with_context(|| {
208+
format!(
209+
"did not find versioned document for {} v{}",
210+
api_ident, version
216211
)
217212
})?;
218-
219-
self.read_file(matching_file)
213+
self.read_file(&path)
220214
}
221215

222216
/// List all versioned documents for a specific API.

crates/integration-tests/tests/integration/versioned.rs

Lines changed: 139 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//! OpenAPI document. These are "blessed" documents that are checked into git
77
//! and must remain stable across changes.
88
9-
use anyhow::Result;
9+
use anyhow::{Context, Result};
1010
use dropshot_api_manager::test_util::{CheckResult, check_apis_up_to_date};
1111
use integration_tests::common::{
1212
create_versioned_health_test_apis_incompatible,
@@ -21,18 +21,36 @@ fn test_versioned_generate_basic() -> Result<()> {
2121
let apis = create_versioned_health_test_apis()?;
2222

2323
// Initially, no documents should exist.
24-
assert!(!env.versioned_local_document_exists("versioned-health", "1.0.0"));
25-
assert!(!env.versioned_local_document_exists("versioned-health", "2.0.0"));
26-
assert!(!env.versioned_local_document_exists("versioned-health", "3.0.0"));
24+
assert!(
25+
!env.versioned_local_document_exists("versioned-health", "1.0.0")
26+
.unwrap()
27+
);
28+
assert!(
29+
!env.versioned_local_document_exists("versioned-health", "2.0.0")
30+
.unwrap()
31+
);
32+
assert!(
33+
!env.versioned_local_document_exists("versioned-health", "3.0.0")
34+
.unwrap()
35+
);
2736
assert!(!env.versioned_latest_document_exists("versioned-health"));
2837

2938
// Generate the documents.
3039
env.generate_documents(&apis)?;
3140

3241
// Now the version documents should exist.
33-
assert!(env.versioned_local_document_exists("versioned-health", "1.0.0"));
34-
assert!(env.versioned_local_document_exists("versioned-health", "2.0.0"));
35-
assert!(env.versioned_local_document_exists("versioned-health", "3.0.0"));
42+
assert!(
43+
env.versioned_local_document_exists("versioned-health", "1.0.0")
44+
.unwrap()
45+
);
46+
assert!(
47+
env.versioned_local_document_exists("versioned-health", "2.0.0")
48+
.unwrap()
49+
);
50+
assert!(
51+
env.versioned_local_document_exists("versioned-health", "3.0.0")
52+
.unwrap()
53+
);
3654
assert!(env.versioned_latest_document_exists("versioned-health"));
3755

3856
// Read and validate one of the documents is valid JSON.
@@ -135,15 +153,30 @@ fn test_multiple_versioned_apis() -> Result<()> {
135153

136154
// Check that documents exist for both APIs and all their versions.
137155
// Versioned health API (3 versions).
138-
assert!(env.versioned_local_document_exists("versioned-health", "1.0.0"));
139-
assert!(env.versioned_local_document_exists("versioned-health", "2.0.0"));
140-
assert!(env.versioned_local_document_exists("versioned-health", "3.0.0"));
156+
assert!(
157+
env.versioned_local_document_exists("versioned-health", "1.0.0")
158+
.unwrap()
159+
);
160+
assert!(
161+
env.versioned_local_document_exists("versioned-health", "2.0.0")
162+
.unwrap()
163+
);
164+
assert!(
165+
env.versioned_local_document_exists("versioned-health", "3.0.0")
166+
.unwrap()
167+
);
141168
assert!(env.versioned_latest_document_exists("versioned-health"));
142169

143170
// Versioned user API (3 versions).
144-
assert!(env.versioned_local_document_exists("versioned-user", "1.0.0"));
145-
assert!(env.versioned_local_document_exists("versioned-user", "2.0.0"));
146-
assert!(env.versioned_local_document_exists("versioned-user", "3.0.0"));
171+
assert!(
172+
env.versioned_local_document_exists("versioned-user", "1.0.0").unwrap()
173+
);
174+
assert!(
175+
env.versioned_local_document_exists("versioned-user", "2.0.0").unwrap()
176+
);
177+
assert!(
178+
env.versioned_local_document_exists("versioned-user", "3.0.0").unwrap()
179+
);
147180
assert!(env.versioned_latest_document_exists("versioned-user"));
148181

149182
// List all versioned documents for each API.
@@ -171,8 +204,13 @@ fn test_mixed_lockstep_and_versioned_apis() -> Result<()> {
171204
assert!(env.lockstep_document_exists("counter"));
172205

173206
// Check versioned APIs exist as version-specific files.
174-
assert!(env.versioned_local_document_exists("versioned-health", "1.0.0"));
175-
assert!(env.versioned_local_document_exists("versioned-user", "1.0.0"));
207+
assert!(
208+
env.versioned_local_document_exists("versioned-health", "1.0.0")
209+
.unwrap()
210+
);
211+
assert!(
212+
env.versioned_local_document_exists("versioned-user", "1.0.0").unwrap()
213+
);
176214

177215
// List all document files to verify proper structure.
178216
let all_files = env.list_document_files()?;
@@ -328,9 +366,27 @@ fn test_removing_api_version_fails_check() -> Result<()> {
328366
env.commit_documents()?;
329367

330368
// Verify all versions exist.
331-
assert!(env.versioned_local_document_exists("versioned-health", "1.0.0"));
332-
assert!(env.versioned_local_document_exists("versioned-health", "2.0.0"));
333-
assert!(env.versioned_local_document_exists("versioned-health", "3.0.0"));
369+
assert!(
370+
env.versioned_local_and_blessed_document_exists(
371+
"versioned-health",
372+
"1.0.0"
373+
)
374+
.unwrap()
375+
);
376+
assert!(
377+
env.versioned_local_and_blessed_document_exists(
378+
"versioned-health",
379+
"2.0.0"
380+
)
381+
.unwrap()
382+
);
383+
assert!(
384+
env.versioned_local_and_blessed_document_exists(
385+
"versioned-health",
386+
"3.0.0"
387+
)
388+
.unwrap()
389+
);
334390

335391
// Create API with fewer versions (simulating version removal).
336392
let reduced_apis = create_versioned_health_test_apis_reduced_versions()?;
@@ -652,3 +708,68 @@ fn test_incompatible_blessed_api_change() -> Result<()> {
652708

653709
Ok(())
654710
}
711+
712+
/// Test BlessedVersionExtraLocalSpec problems.
713+
///
714+
/// This test:
715+
///
716+
/// * creates blessed versions
717+
/// * in a separate environment, creates another blessed version
718+
/// * copies over this extra version
719+
#[test]
720+
fn test_blessed_version_extra_local_spec() -> Result<()> {
721+
let env = TestEnvironment::new()?;
722+
let apis = create_versioned_health_test_apis()?;
723+
724+
// Generate and commit initial documents to make them blessed.
725+
env.generate_documents(&apis)?;
726+
env.commit_documents()?;
727+
728+
// Verify initial state is up-to-date.
729+
let result = check_apis_up_to_date(env.environment(), &apis)?;
730+
assert_eq!(result, CheckResult::Success);
731+
732+
// Generate with the incompatible APIs.
733+
let env2 = TestEnvironment::new()?;
734+
let incompatible_apis = create_versioned_health_test_apis_incompatible()?;
735+
736+
env2.generate_documents(&incompatible_apis)?;
737+
738+
// Ensure that the v3 documents are actually different between env and env2.
739+
let env_path = env
740+
.find_versioned_document_path("versioned-health", "3.0.0")?
741+
.expect("should find v3.0.0 document");
742+
let env2_path = env2
743+
.find_versioned_document_path("versioned-health", "3.0.0")?
744+
.expect("should find v3.0.0 document");
745+
assert_ne!(
746+
env_path, env2_path,
747+
"incompatible APIs should lead to different hashes"
748+
);
749+
750+
// Copy env2's document into env's documents directory.
751+
let src = env2.workspace_root().join(&env2_path);
752+
let dst = env
753+
.documents_dir()
754+
.join("versioned-health")
755+
.join(env2_path.file_name().unwrap());
756+
757+
std::fs::copy(&src, &dst)
758+
.with_context(|| format!("failed to copy {} to {}", src, dst))?;
759+
assert!(dst.exists(), "destination path {dst} exists");
760+
761+
let result = check_apis_up_to_date(env.environment(), &apis)?;
762+
assert_eq!(result, CheckResult::NeedsUpdate);
763+
764+
// Regenerating documents should remove the file.
765+
env.generate_documents(&apis)?;
766+
767+
// After fix-up, should be up-to-date again.
768+
let result = check_apis_up_to_date(env.environment(), &apis)?;
769+
assert_eq!(result, CheckResult::Success);
770+
771+
// The destination path should be missing now.
772+
assert!(!dst.exists(), "destination path {dst} no longer exists");
773+
774+
Ok(())
775+
}

0 commit comments

Comments
 (0)