Skip to content
Draft
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
3 changes: 3 additions & 0 deletions .github/workflows/native-bazel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
name: ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 30
environment: production
steps:
- name: Checkout
uses: >- # v4.2.2
Expand Down Expand Up @@ -59,3 +60,5 @@ jobs:
exit 1
fi
shell: bash
env:
NATIVELINK_TEST_MONGO_URL: ${{ secrets.NATIVELINK_TEST_MONGO_URL}}
3 changes: 3 additions & 0 deletions .github/workflows/native-cargo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
name: ${{ matrix.os }} / ${{ matrix.toolchain }}
runs-on: ${{ matrix.os }}
timeout-minutes: 30
environment: production
steps:
- name: Checkout
uses: >- # v4.2.2
Expand All @@ -46,6 +47,8 @@ jobs:

- name: Test on ${{ runner.os }}
run: cargo test --all --profile=smol
env:
NATIVELINK_TEST_MONGO_URL: ${{ secrets.NATIVELINK_TEST_MONGO_URL}}

# Not a default target, but need to make sure we don't actually break it
- name: Test worker_find_logging
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/nix.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ jobs:
name: Cargo Dev / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 45
environment: production
steps:
- name: Checkout
uses: >- # v4.2.2
Expand All @@ -70,6 +71,8 @@ jobs:
run: >
nix develop --impure --command
bash -c "cargo test --all --profile=smol"
env:
NATIVELINK_TEST_MONGO_URL: ${{ secrets.NATIVELINK_TEST_MONGO_URL }}

installation:
strategy:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/sanitizers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
name: ${{ matrix.sanitizer }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 30
environment: production
steps:
- name: Checkout
uses: >- # v4.2.2
Expand All @@ -44,3 +45,5 @@ jobs:
- name: Run Bazel tests
run: bazel test --config=${{ matrix.sanitizer }} --verbose_failures //...
shell: bash
env:
NATIVELINK_TEST_MONGO_URL: ${{ secrets.NATIVELINK_TEST_MONGO_URL}}
5 changes: 5 additions & 0 deletions nativelink-store/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ rust_test_suite(
"tests/size_partitioning_store_test.rs",
"tests/verify_store_test.rs",
],
env_inherit = [
"NATIVELINK_TEST_MONGO_URL",
"CI",
"GITHUB_ACTIONS",
],
proc_macro_deps = [
"//nativelink-macro",
"@crates//:async-trait",
Expand Down
163 changes: 128 additions & 35 deletions nativelink-store/tests/mongo_store_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,13 @@ pub struct TestMongoHelper {
pub database_name: String,
}

fn in_ci() -> bool {
std::env::var("CI").is_ok() || std::env::var("GITHUB_ACTIONS").is_ok()
}

fn non_ci_test_store_access() {
// Check if this is a local development environment without credentials
let is_ci = std::env::var("CI").is_ok() || std::env::var("GITHUB_ACTIONS").is_ok();

if !is_ci {
if !in_ci() {
eprintln!("\n🔒 MongoDB tests require access to the NativeLink test database.");
eprintln!(" For local development access, please email: [email protected]");
eprintln!(" ");
Expand Down Expand Up @@ -177,18 +179,64 @@ async fn create_test_store() -> Result<Arc<ExperimentalMongoStore>, Error> {
ExperimentalMongoStore::new(spec).await
}

enum MongoDBState {
Ok(TestMongoHelper),
Broken(Error),
Skipping,
}

/// Utility to check if `MongoDB` is available for testing.
/// Returns an error that can be used to skip tests when `MongoDB` is not available.
async fn check_mongodb_available() -> Result<(), Error> {
TestMongoHelper::new_or_skip().await.map(|_| ())
async fn check_mongodb_available() -> MongoDBState {
match TestMongoHelper::new_or_skip().await {
Ok(helper) => MongoDBState::Ok(helper),
Err(err) if err.code == Code::Unavailable && !in_ci() => {
eprintln!("Skipping MongoDB test - MongoDB not available");
MongoDBState::Skipping
}
Err(err) => {
eprintln!("Mongo test error: {err}");
MongoDBState::Broken(err)
}
}
}

#[nativelink_test]
async fn connect_with_username_and_password() -> Result<(), Error> {
match check_mongodb_available().await {
MongoDBState::Ok(_helper) => {}
MongoDBState::Broken(err) => {
return Err(err);
}
MongoDBState::Skipping => {
return Ok(());
}
}

let spec = create_test_spec();
let store = ExperimentalMongoStore::new(spec)
.await
.expect("Working store");
let digest = DigestInfo::try_new(VALID_HASH1, 2)?;
let result = store.has(digest).await?;
assert!(
result.is_some(),
"Expected mongo store to have hash: {VALID_HASH1}",
);
Ok(())
}

#[nativelink_test]
async fn upload_and_get_data() -> Result<(), Error> {
// Create test helper with automatic cleanup
let Ok(helper) = TestMongoHelper::new_or_skip().await else {
eprintln!("Skipping MongoDB test - MongoDB not available");
return Ok(());
let helper = match check_mongodb_available().await {
MongoDBState::Ok(helper) => helper,
MongoDBState::Broken(err) => {
return Err(err);
}
MongoDBState::Skipping => {
return Ok(());
}
};

// Construct the data we want to send.
Expand Down Expand Up @@ -252,9 +300,14 @@ async fn upload_and_get_data_without_prefix() -> Result<(), Error> {
#[nativelink_test]
async fn upload_empty_data() -> Result<(), Error> {
// Skip test if MongoDB is not available
if check_mongodb_available().await.is_err() {
eprintln!("Skipping MongoDB test - MongoDB not available");
return Ok(());
match check_mongodb_available().await {
MongoDBState::Ok(_helper) => {}
MongoDBState::Broken(err) => {
return Err(err);
}
MongoDBState::Skipping => {
return Ok(());
}
}

let data = Bytes::from_static(b"");
Expand All @@ -277,9 +330,14 @@ async fn upload_empty_data() -> Result<(), Error> {
#[allow(clippy::items_after_statements)]
async fn test_large_downloads_are_chunked() -> Result<(), Error> {
// Skip test if MongoDB is not available
if check_mongodb_available().await.is_err() {
eprintln!("Skipping MongoDB test - MongoDB not available");
return Ok(());
match check_mongodb_available().await {
MongoDBState::Ok(_helper) => {}
MongoDBState::Broken(err) => {
return Err(err);
}
MongoDBState::Skipping => {
return Ok(());
}
}

const READ_CHUNK_SIZE: usize = 1024;
Expand Down Expand Up @@ -316,9 +374,14 @@ async fn test_large_downloads_are_chunked() -> Result<(), Error> {
#[allow(clippy::items_after_statements)]
async fn yield_between_sending_packets_in_update() -> Result<(), Error> {
// Skip test if MongoDB is not available
if check_mongodb_available().await.is_err() {
eprintln!("Skipping MongoDB test - MongoDB not available");
return Ok(());
match check_mongodb_available().await {
MongoDBState::Ok(_helper) => {}
MongoDBState::Broken(err) => {
return Err(err);
}
MongoDBState::Skipping => {
return Ok(());
}
}

const READ_CHUNK_SIZE: usize = 1024;
Expand Down Expand Up @@ -372,9 +435,14 @@ async fn yield_between_sending_packets_in_update() -> Result<(), Error> {
#[nativelink_test]
async fn zero_len_items_exist_check() -> Result<(), Error> {
// Skip test if MongoDB is not available
if check_mongodb_available().await.is_err() {
eprintln!("Skipping MongoDB test - MongoDB not available");
return Ok(());
match check_mongodb_available().await {
MongoDBState::Ok(_helper) => {}
MongoDBState::Broken(err) => {
return Err(err);
}
MongoDBState::Skipping => {
return Ok(());
}
}

let digest = DigestInfo::try_new(VALID_HASH1, 0)?;
Expand Down Expand Up @@ -427,9 +495,14 @@ async fn test_empty_connection_string() -> Result<(), Error> {
#[nativelink_test]
async fn test_default_values() -> Result<(), Error> {
// Skip test if MongoDB is not available
if check_mongodb_available().await.is_err() {
eprintln!("Skipping MongoDB test - MongoDB not available");
return Ok(());
match check_mongodb_available().await {
MongoDBState::Ok(_helper) => {}
MongoDBState::Broken(err) => {
return Err(err);
}
MongoDBState::Skipping => {
return Ok(());
}
}

let mut spec = create_test_spec();
Expand Down Expand Up @@ -464,9 +537,14 @@ async fn test_default_values() -> Result<(), Error> {
#[nativelink_test]
async fn dont_loop_forever_on_empty() -> Result<(), Error> {
// Skip test if MongoDB is not available
if check_mongodb_available().await.is_err() {
eprintln!("Skipping MongoDB test - MongoDB not available");
return Ok(());
match check_mongodb_available().await {
MongoDBState::Ok(_helper) => {}
MongoDBState::Broken(err) => {
return Err(err);
}
MongoDBState::Skipping => {
return Ok(());
}
}

let store = create_test_store().await?;
Expand Down Expand Up @@ -502,9 +580,14 @@ async fn dont_loop_forever_on_empty() -> Result<(), Error> {
#[nativelink_test]
async fn test_partial_reads() -> Result<(), Error> {
// Create test helper with automatic cleanup
let Ok(helper) = TestMongoHelper::new_or_skip().await else {
eprintln!("Skipping MongoDB test - MongoDB not available");
return Ok(());
let helper = match check_mongodb_available().await {
MongoDBState::Ok(helper) => helper,
MongoDBState::Broken(err) => {
return Err(err);
}
MongoDBState::Skipping => {
return Ok(());
}
};

let data = Bytes::from_static(b"Hello, MongoDB World!");
Expand Down Expand Up @@ -620,9 +703,14 @@ async fn test_database_lifecycle() -> Result<(), Error> {
#[allow(clippy::use_debug)]
async fn create_ten_cas_entries() -> Result<(), Error> {
// Create test helper with automatic cleanup
let Ok(helper) = TestMongoHelper::new_or_skip().await else {
eprintln!("Skipping MongoDB test - MongoDB not available");
return Ok(());
let helper = match check_mongodb_available().await {
MongoDBState::Ok(helper) => helper,
MongoDBState::Broken(err) => {
return Err(err);
}
MongoDBState::Skipping => {
return Ok(());
}
};

eprintln!(
Expand Down Expand Up @@ -848,9 +936,14 @@ impl SchedulerStoreDecodeTo for TestSchedulerKey {
#[nativelink_test]
async fn test_scheduler_store_operations() -> Result<(), Error> {
// Create test helper
let Ok(helper) = TestMongoHelper::new_or_skip().await else {
eprintln!("Skipping MongoDB test - MongoDB not available");
return Ok(());
let helper = match check_mongodb_available().await {
MongoDBState::Ok(helper) => helper,
MongoDBState::Broken(err) => {
return Err(err);
}
MongoDBState::Skipping => {
return Ok(());
}
};

eprintln!(
Expand Down
Loading