diff --git a/influxdb_iox/tests/end_to_end_cases/management_api.rs b/influxdb_iox/tests/end_to_end_cases/management_api.rs index 6b75efba97..12874d8ec3 100644 --- a/influxdb_iox/tests/end_to_end_cases/management_api.rs +++ b/influxdb_iox/tests/end_to_end_cases/management_api.rs @@ -1,5 +1,3 @@ -use std::{fs::set_permissions, os::unix::fs::PermissionsExt}; - use arrow_util::assert_batches_sorted_eq; use data_types::chunk_metadata::ChunkId; use generated_types::{ @@ -12,7 +10,7 @@ use influxdb_iox_client::{ management::{Client, CreateDatabaseError}, write::WriteError, }; - +use std::{fs::set_permissions, os::unix::fs::PermissionsExt}; use test_helpers::assert_contains; use super::scenario::{ @@ -28,6 +26,7 @@ use chrono::{DateTime, Utc}; use std::convert::TryInto; use std::time::Instant; use tonic::Code; +use uuid::Uuid; #[tokio::test] async fn test_serving_readiness() { @@ -1155,7 +1154,7 @@ async fn test_get_server_status_db_error() { let server_fixture = ServerFixture::create_single_use().await; let mut client = server_fixture.management_client(); - // All databases are owned by server 42 + // Valid content of the owner.pb file let owner_info = OwnerInfo { id: 42, location: "arbitrary".to_string(), @@ -1165,11 +1164,11 @@ async fn test_get_server_status_db_error() { .expect("owner info serialization should be valid"); let owner_info_bytes = owner_info_bytes.freeze(); - // create valid owner info but malformed DB rules + // create valid owner info but malformed DB rules that will put DB in an error state + let my_db_uuid = Uuid::new_v4(); let mut path = server_fixture.dir().to_path_buf(); path.push("42"); - path.push("my_db"); - path.push("0"); + path.push(my_db_uuid.to_string()); std::fs::create_dir_all(path.clone()).unwrap(); let mut owner_info_path = path.clone(); owner_info_path.push("owner.pb"); @@ -1177,57 +1176,15 @@ async fn test_get_server_status_db_error() { path.push("rules.pb"); std::fs::write(path, "foo").unwrap(); - // create soft-deleted database - let mut path = server_fixture.dir().to_path_buf(); - path.push("42"); - path.push("soft_deleted"); - path.push("0"); - std::fs::create_dir_all(path.clone()).unwrap(); - let mut owner_info_path = path.clone(); - owner_info_path.push("owner.pb"); - std::fs::write(owner_info_path, &owner_info_bytes).unwrap(); - path.push("DELETED"); - std::fs::write(path, "foo").unwrap(); - - // create DB dir containing multiple active databases - let mut path = server_fixture.dir().to_path_buf(); - path.push("42"); - path.push("multiple_active"); - let mut other_gen_path = path.clone(); - path.push("0"); - std::fs::create_dir_all(path.clone()).unwrap(); - let mut owner_info_path = path.clone(); - owner_info_path.push("owner.pb"); - std::fs::write(owner_info_path, &owner_info_bytes).unwrap(); - path.push("rules.pb"); - std::fs::write(path, "foo").unwrap(); - other_gen_path.push("1"); - std::fs::create_dir_all(other_gen_path.clone()).unwrap(); - let mut owner_info_path = other_gen_path.clone(); - owner_info_path.push("owner.pb"); - std::fs::write(owner_info_path, &owner_info_bytes).unwrap(); - other_gen_path.push("rules.pb"); - std::fs::write(other_gen_path, "foo").unwrap(); - - // create the server config listing the ownership of these three databases + // create the server config listing the ownership of this database let mut path = server_fixture.dir().to_path_buf(); path.push("42"); path.push("config.pb"); let data = ServerConfig { - databases: vec![ - (String::from("my_db"), String::from("42/my_db")), - ( - String::from("soft_deleted"), - String::from("42/soft_deleted"), - ), - ( - String::from("multiple_active"), - String::from("42/multiple_active"), - ), - ] - .into_iter() - .collect(), + databases: vec![(String::from("my_db"), format!("42/{}", my_db_uuid))] + .into_iter() + .collect(), }; let mut encoded = bytes::BytesMut::new(); @@ -1244,24 +1201,11 @@ async fn test_get_server_status_db_error() { let status = client.get_server_status().await.unwrap(); assert!(status.initialized); assert_eq!(status.error, None); - assert_eq!(status.database_statuses.len(), 3); + assert_eq!(status.database_statuses.len(), 1); dbg!(&status.database_statuses); - // databases should be alphabetical by name: multiple_active, my_db, soft_deleted let db_status = &status.database_statuses[0]; dbg!(&db_status); - assert_eq!(db_status.db_name, "multiple_active"); - assert!(dbg!(&db_status.error.as_ref().unwrap().message).contains( - "error finding active generation directory in object storage: Multiple active \ - databases found in object storage" - )); - assert_eq!( - DatabaseState::from_i32(db_status.state).unwrap(), - DatabaseState::DatabaseObjectStoreLookupError, - ); - - let db_status = &status.database_statuses[1]; - dbg!(&db_status); assert_eq!(db_status.db_name, "my_db"); assert!(dbg!(&db_status.error.as_ref().unwrap().message) .contains("error deserializing database rules")); @@ -1269,16 +1213,6 @@ async fn test_get_server_status_db_error() { DatabaseState::from_i32(db_status.state).unwrap(), DatabaseState::RulesLoadError ); - - let db_status = &status.database_statuses[2]; - dbg!(&db_status); - assert_eq!(db_status.db_name, "soft_deleted"); - assert!(dbg!(&db_status.error.as_ref().unwrap().message) - .contains("no active generation directory found, not loading")); - assert_eq!( - DatabaseState::from_i32(db_status.state).unwrap(), - DatabaseState::NoActiveDatabase, - ); } #[tokio::test] diff --git a/server/src/lib.rs b/server/src/lib.rs index d2ea43652d..1ea24c4ced 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -1369,14 +1369,10 @@ mod tests { }, }; use entry::test_helpers::lp_to_entry; - use futures::TryStreamExt; use influxdb_line_protocol::parse_lines; use iox_object_store::IoxObjectStore; use metric::{Attributes, Metric, U64Counter}; - use object_store::{ - path::{parsed::DirsAndFileName, ObjectStorePath}, - ObjectStore, ObjectStoreApi, - }; + use object_store::ObjectStore; use parquet_catalog::{ core::{PreservedCatalog, PreservedCatalogConfig}, test_helpers::{load_ok, new_empty}, @@ -1489,6 +1485,7 @@ mod tests { let read_rules = ProvidedDatabaseRules::load(&iox_object_store) .await .unwrap(); + let bananas_uuid = read_rules.uuid(); // Same rules that were provided are read assert_eq!(provided_rules.original(), read_rules.original()); @@ -1506,24 +1503,28 @@ mod tests { // assert server config file exists and has 1 entry let config = server_config(application.object_store(), server_id).await; - assert_config_contents(&config, &[(&name, String::from("1/bananas/"))]); + assert_config_contents( + &config, + &[(&name, format!("{}/{}/", server_id, bananas_uuid))], + ); let db2 = DatabaseName::new("db_awesome").unwrap(); let rules2 = DatabaseRules::new(db2.clone()); let provided_rules2 = make_provided_rules(rules2); - server + let awesome = server .create_database(provided_rules2) .await .expect("failed to create 2nd db"); + let awesome_uuid = awesome.provided_rules().unwrap().uuid(); // assert server config file exists and has 2 entries let config = server_config(application.object_store(), server_id).await; assert_config_contents( &config, &[ - (&name, String::from("1/bananas/")), - (&db2, String::from("1/db_awesome/")), + (&name, format!("{}/{}/", server_id, bananas_uuid)), + (&db2, format!("{}/{}/", server_id, awesome_uuid)), ], ); @@ -1545,8 +1546,8 @@ mod tests { assert_config_contents( &config, &[ - (&name, String::from("1/bananas/")), - (&db2, String::from("1/db_awesome/")), + (&name, format!("{}/{}/", server_id, bananas_uuid)), + (&db2, format!("{}/{}/", server_id, awesome_uuid)), ], ); } @@ -1613,6 +1614,7 @@ mod tests { let bananas = create_simple_database(&server, "bananas") .await .expect("failed to create database"); + let bananas_uuid = bananas.provided_rules().unwrap().uuid(); std::mem::drop(server); @@ -1623,6 +1625,7 @@ mod tests { let apples = create_simple_database(&server, "apples") .await .expect("failed to create database"); + let apples_uuid = apples.provided_rules().unwrap().uuid(); assert_eq!(server.db_names_sorted(), vec!["apples", "bananas"]); @@ -1647,8 +1650,14 @@ mod tests { assert_config_contents( &config, &[ - (&apples.config().name, String::from("1/apples/")), - (&bananas.config().name, String::from("1/bananas/")), + ( + &apples.config().name, + format!("{}/{}/", server_id, apples_uuid), + ), + ( + &bananas.config().name, + format!("{}/{}/", server_id, bananas_uuid), + ), ], ); @@ -1659,10 +1668,10 @@ mod tests { let bananas_database = server.database(&bananas_name).unwrap(); apples_database.wait_for_init().await.unwrap(); - let err = bananas_database.wait_for_init().await.unwrap_err(); - assert!(apples_database.init_error().is_none()); - assert_contains!(err.to_string(), "error fetching rules"); + + let err = bananas_database.wait_for_init().await.unwrap_err(); + assert_contains!(err.to_string(), "No rules found to load"); assert!(Arc::ptr_eq(&err, &bananas_database.init_error().unwrap())); } @@ -2193,9 +2202,10 @@ mod tests { server.wait_for_init().await.unwrap(); // create database - create_simple_database(&server, &foo_db_name) + let foo = create_simple_database(&server, &foo_db_name) .await .expect("failed to create database"); + let foo_uuid = foo.provided_rules().unwrap().uuid(); // delete database server @@ -2214,35 +2224,23 @@ mod tests { // server is initialized assert!(server.initialized()); - // DB names contains foo - assert_eq!(server.db_names_sorted().len(), 1); - assert!(server.db_names_sorted().contains(&String::from("foo"))); - - // server config contains foo - let config = server_config(application.object_store(), server_id).await; - assert_config_contents(&config, &[(&foo_db_name, String::from("1/foo/"))]); + // DB names is empty + assert!(server.db_names_sorted().is_empty()); // can't delete an inactive database let err = server.delete_database(&foo_db_name).await; assert!( - matches!(&err, Err(Error::CannotMarkDatabaseDeleted { .. })), + matches!(&err, Err(Error::DatabaseNotFound { .. })), "got {:?}", err ); - let foo_database = server.database(&foo_db_name).unwrap(); - let err = foo_database.wait_for_init().await.unwrap_err(); - assert!( - matches!(err.as_ref(), database::InitError::NoActiveDatabase), - "got {:?}", - err - ); - assert!(Arc::ptr_eq(&err, &foo_database.init_error().unwrap())); - // creating a new DB with the deleted db's name works - create_simple_database(&server, &foo_db_name) + let new_foo = create_simple_database(&server, &foo_db_name) .await .expect("failed to create database"); + let new_foo_uuid = new_foo.provided_rules().unwrap().uuid(); + assert_ne!(foo_uuid, new_foo_uuid); // DB names contains foo assert_eq!(server.db_names_sorted().len(), 1); @@ -2250,103 +2248,13 @@ mod tests { // server config contains foo let config = server_config(application.object_store(), server_id).await; - assert_config_contents(&config, &[(&foo_db_name, String::from("1/foo/"))]); + assert_config_contents( + &config, + &[(&foo_db_name, format!("{}/{}/", server_id, new_foo_uuid))], + ); // calling delete database works server.delete_database(&foo_db_name).await.unwrap(); - - // DB names still contains foo - assert_eq!(server.db_names_sorted().len(), 1); - assert!(server.db_names_sorted().contains(&String::from("foo"))); - - // creating another new DB with the deleted db's name works - create_simple_database(&server, &foo_db_name) - .await - .expect("failed to create database"); - - // DB names still contains foo - assert_eq!(server.db_names_sorted().len(), 1); - assert!(server.db_names_sorted().contains(&String::from("foo"))); - } - - #[tokio::test] - async fn init_too_many_active_generation_directories() { - let application = make_application(); - let server_id = ServerId::try_from(1).unwrap(); - - let server = make_server(Arc::clone(&application)); - server.set_id(server_id).unwrap(); - server.wait_for_init().await.unwrap(); - - let foo_db_name = DatabaseName::new("foo").unwrap(); - - // Create database - create_simple_database(&server, &foo_db_name) - .await - .expect("failed to create database"); - - // Delete it - server.delete_database(&foo_db_name).await.unwrap(); - - // Create it again - create_simple_database(&server, &foo_db_name) - .await - .expect("failed to create database"); - - // Delete it again - server.delete_database(&foo_db_name).await.unwrap(); - - std::mem::drop(server); - - // Remove the tombstone files from both database generation directories - let mut db_path = application.object_store().new_path(); - db_path.push_all_dirs(&[server_id.to_string().as_str(), foo_db_name.as_str()]); - let database_files: Vec<_> = application - .object_store() - .list(Some(&db_path)) - .await - .unwrap() - .try_collect::>() - .await - .unwrap() - .into_iter() - .flatten() - .collect(); - - // Delete all tombstone files - let mut deleted_something = false; - for file in database_files { - let parsed: DirsAndFileName = file.clone().into(); - if parsed.file_name.unwrap().to_string() == "DELETED" { - application.object_store().delete(&file).await.unwrap(); - deleted_something = true; - } - } - assert!(deleted_something); - - // Restart the server - let server = make_server(Arc::clone(&application)); - server.set_id(server_id).unwrap(); - server.wait_for_init().await.unwrap(); - // generic error MUST NOT be set - assert!(server.server_init_error().is_none()); - // server is initialized - assert!(server.initialized()); - - // The database should be in an error state - let foo_database = server.database(&foo_db_name).unwrap(); - let err = foo_database.wait_for_init().await.unwrap_err(); - assert!( - matches!( - err.as_ref(), - database::InitError::DatabaseObjectStoreLookup { - source: iox_object_store::IoxObjectStoreError::MultipleActiveDatabasesFound - } - ), - "got {:?}", - err - ); - assert!(Arc::ptr_eq(&err, &foo_database.init_error().unwrap())); } #[tokio::test] @@ -2620,41 +2528,6 @@ mod tests { ); } - #[tokio::test] - async fn cannot_create_db_when_catalog_is_present() { - let application = make_application(); - let server_id = ServerId::try_from(1).unwrap(); - let db_name = DatabaseName::new("my_db").unwrap(); - - // setup server - let server = make_server(Arc::clone(&application)); - server.set_id(server_id).unwrap(); - server.wait_for_init().await.unwrap(); - - let iox_object_store = Arc::new( - IoxObjectStore::create(Arc::clone(application.object_store()), server_id, &db_name) - .await - .unwrap(), - ); - - let config = PreservedCatalogConfig::new( - iox_object_store, - db_name.to_string(), - Arc::clone(application.time_provider()), - ); - - // create catalog - new_empty(config).await; - - // creating database will now result in an error - let err = create_simple_database(&server, db_name).await.unwrap_err(); - assert!( - matches!(err, Error::DatabaseAlreadyExists { .. }), - "got: {:?}", - err - ); - } - #[tokio::test] async fn write_buffer_errors_propagate() { let application = make_application();