diff --git a/.luacheckrc b/.luacheckrc index 4b6a658166f8f2177872e75cc64915860b6923e8..5e9dee0c890e3e061b7566ae4d87a36a736b7d90 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -29,8 +29,7 @@ include_files = { exclude_files = { "build/**/*.lua", - ".rocks/**/*.lua", + "**/.rocks/**/*.lua", ".git/**/*.lua", "http/mime_types.lua", - "test_app/.rocks/**/*.lua" } diff --git a/Makefile b/Makefile index f39cbd186579f828f3f03a2980e2de24249d73c8..977b3c2f1ca7580f1b5963596bd811a6cb709746 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ lint: cargo clippy -- -Dclippy::all -Wclippy::pedantic cargo audit -f audit.toml ./deps.sh - ./.rocks/bin/luacheck . --exclude-files ./sbroad-cartridge/test_app/.rocks/* + ./.rocks/bin/luacheck . test: cargo test --features mock -vv diff --git a/sbroad-cartridge/Makefile b/sbroad-cartridge/Makefile index 355c3762016dbee476b86ae63112014faf0eecc9..3d0fc04a8b7152bfbbe1d24719459a919813c92a 100644 --- a/sbroad-cartridge/Makefile +++ b/sbroad-cartridge/Makefile @@ -23,7 +23,7 @@ build_integration: cartridge build $(TEST_APP) run_integration: - cd $(TEST_APP) && rm -rf tmp/tarantool.log && TARANTOOL_LOG_LEVEL=7 TARANTOOL_LOG=tmp/tarantool.log ./.rocks/bin/luatest --coverage -v test/ && cd .. + cd $(TEST_APP) && rm -rf tmp/tarantool.log && TARANTOOL_LOG_LEVEL=5 TARANTOOL_LOG=tmp/tarantool.log ./.rocks/bin/luatest --coverage -v test/ && cd .. install_debug: mkdir -p $(LUADIR)/$(PROJECT_NAME) diff --git a/sbroad-cartridge/cartridge/roles/sbroad-router.lua b/sbroad-cartridge/cartridge/roles/sbroad-router.lua index 6f9956a34c3a9df0691567f3557b8f74e97e90e7..517f26d26b914e9e37150d7ed372e3922b4f6faf 100644 --- a/sbroad-cartridge/cartridge/roles/sbroad-router.lua +++ b/sbroad-cartridge/cartridge/roles/sbroad-router.lua @@ -11,6 +11,7 @@ local function init(opts) -- luacheck: no unused args _G.sbroad.trace = sbroad_router.trace sbroad_router.init() + sbroad_router.init_statistics() return true end diff --git a/sbroad-cartridge/cartridge/roles/sbroad-storage.lua b/sbroad-cartridge/cartridge/roles/sbroad-storage.lua index 02e4a8ce6f1ebef122c7baa8024381493cf5044c..2bc8aa3ffdd6de0719a25ff5252cf29ce5dd4c8a 100644 --- a/sbroad-cartridge/cartridge/roles/sbroad-storage.lua +++ b/sbroad-cartridge/cartridge/roles/sbroad-storage.lua @@ -2,6 +2,7 @@ local sbroad_storage = require('sbroad.storage') local function init(opts) -- luacheck: no unused args sbroad_storage.init() + sbroad_storage.init_statistics() return true end diff --git a/sbroad-cartridge/src/api/helper.rs b/sbroad-cartridge/src/api/helper.rs index c5b8adc8d94bcd0173b19bea3892fe01503ba0b7..befe12f9caa7b639bc16cd6bc6a68730430fe207 100644 --- a/sbroad-cartridge/src/api/helper.rs +++ b/sbroad-cartridge/src/api/helper.rs @@ -1,3 +1,4 @@ +use sbroad::error; use sbroad::executor::engine::Configuration; use sbroad::log::tarantool_error; use std::cell::RefCell; @@ -11,7 +12,7 @@ where // Tarantool can yield in the middle of a current closure, // so we can hold only an immutable reference to the engine. let mut config: Option<_> = None; - (*engine).with(|engine| { + let mut code = (*engine).with(|engine| { let runtime = match engine.try_borrow() { Ok(runtime) => runtime, Err(e) => { @@ -26,14 +27,21 @@ where config = conf; 0 } - Err(e) => tarantool_error(&format!("Failed to get configuration: {}", e)), + Err(e) => { + error!(Option::from("get config"), &format!("{:?}", e)); + tarantool_error(&format!("Failed to get configuration: {}", e)) + } } }); + if code != 0 { + return code; + } + // Tarantool never yields here, so it is possible to hold // a mutable reference to the engine. if let Some(config) = config { - (*engine).with(|runtime| { + code = (*engine).with(|runtime| { let mut runtime = match runtime.try_borrow_mut() { Ok(runtime) => runtime, Err(e) => { @@ -48,5 +56,5 @@ where }); } - 0 + code } diff --git a/sbroad-cartridge/src/cartridge/config.rs b/sbroad-cartridge/src/cartridge/config.rs index 1ab0746b4d4f22fe1831beaa004c6ca15c9318b7..cdfb078896c4c934e5db1e5b4fd2325fbffb7da3 100644 --- a/sbroad-cartridge/src/cartridge/config.rs +++ b/sbroad-cartridge/src/cartridge/config.rs @@ -99,7 +99,12 @@ impl RouterConfiguration { }; let t = match val["type"].as_str() { Some(t) => Type::new(t)?, - None => return Err(QueryPlannerError::TypeNotImplemented), + None => { + return Err(QueryPlannerError::CustomError(format!( + "Type not found for columns {}", + name + ))) + } }; let qualified_name = normalize_name_from_schema(name); debug!( diff --git a/sbroad-cartridge/src/cartridge/config/tests.rs b/sbroad-cartridge/src/cartridge/config/tests.rs index b3a288cf10fc06f792ef4cd49fc357d9f172716c..84abf36ad6d5789ad5442cc610ce33bc65fe9088 100644 --- a/sbroad-cartridge/src/cartridge/config/tests.rs +++ b/sbroad-cartridge/src/cartridge/config/tests.rs @@ -166,3 +166,76 @@ fn test_waiting_timeout() { assert_eq!(s.get_exec_waiting_timeout(), 200); } +#[test] +fn test_invalid_schema() { + let test_schema = r#"spaces: + TEST_SPACE: + engine: vinyl + is_local: false + temporary: false + format: + - name: bucket_id + type: unsigned + is_nullable: false + - name: FID + type: integer + is_nullable: false + - name: DATE_START + type: integer + is_nullable: false + - name: DATE_END + type: integer + is_nullable: false + - name: COMMON_ID + type: string + is_nullable: false + - name: EXCLUDE_ID + type: string + is_nullable: true + - name: COMMON_TEXT + type: string + is_nullable: false + - name: COMMON_DETAIL + type: array + is_nullable: false + - name: TYPOLOGY_TYPE + type: integer + is_nullable: true + - name: TYPOLOGY_ID + type: string + is_nullable: true + indexes: + - type: TREE + name: primary + unique: true + parts: + - path: FID + type: integer + is_nullable: false + - path: COMMON_ID + type: string + is_nullable: false + - path: DATE_START + type: integer + is_nullable: false + - type: TREE + name: bucket_id + unique: false + parts: + - path: bucket_id + type: unsigned + is_nullable: false + sharding_key: + - FID + - COMMON_ID + - DATE_START +"#; + + let mut s = RouterConfiguration::new(); + s.set_sharding_column("\"bucket_id\"".into()); + + assert_eq!( + s.load_schema(test_schema).unwrap_err(), + QueryPlannerError::CustomError("type `array` not implemented".into()) + ); +} diff --git a/sbroad-cartridge/src/router.lua b/sbroad-cartridge/src/router.lua index be99180ca8850009338b9883ae3a87a25f6d6fc2..25375da36cb6a485c665ba4b36b7827bbc790109 100644 --- a/sbroad-cartridge/src/router.lua +++ b/sbroad-cartridge/src/router.lua @@ -223,7 +223,6 @@ local function init() { if_not_exists = true, language = 'C' } ) - box.func["libsbroad.init_statistics"]:call({}) end local function calculate_bucket_id(values, space_name) -- luacheck: no unused args @@ -258,6 +257,10 @@ local function invalidate_cache () box.func["libsbroad.invalidate_coordinator_cache"]:call({}) end +local function init_statistics () + box.func["libsbroad.init_statistics"]:call({}) +end + local function trace(query, params, context, id) local has_err, parser_res = pcall( function() @@ -281,5 +284,6 @@ return { invalidate_cache = invalidate_cache, execute = execute, trace = trace, - calculate_bucket_id = calculate_bucket_id + calculate_bucket_id = calculate_bucket_id, + init_statistics = init_statistics } diff --git a/sbroad-cartridge/src/storage.lua b/sbroad-cartridge/src/storage.lua index 3eeca2a99bc2bb00ac0d71f617bac56042cc306a..648d8d0513a530c708752c78d12257440ad736c2 100644 --- a/sbroad-cartridge/src/storage.lua +++ b/sbroad-cartridge/src/storage.lua @@ -92,15 +92,18 @@ local function init() 'libsbroad.init_statistics', { if_not_exists = true, language = 'C' } ) - - box.func["libsbroad.init_statistics"]:call({}) end local function invalidate_cache() box.func["libsbroad.invalidate_segment_cache"]:call({}) end +local function init_statistics() + box.func["libsbroad.init_statistics"]:call({}) +end + return { init = init, - invalidate_cache = invalidate_cache + invalidate_cache = invalidate_cache, + init_statistics = init_statistics } diff --git a/sbroad-cartridge/test_app/test/helper.lua b/sbroad-cartridge/test_app/test/helper.lua index a75804a774941547c540ab1b419badacd33769e5..7092105059b1619206a748c7d26db362a394f070 100644 --- a/sbroad-cartridge/test_app/test/helper.lua +++ b/sbroad-cartridge/test_app/test/helper.lua @@ -5,44 +5,16 @@ local fio = require('fio') local t = require('luatest') local cartridge_helpers = require('cartridge.test-helpers') -local helper = {} +local helper = { + cluster = nil +} -- luacheck: ignore package helper.root = fio.dirname(fio.abspath(package.search('init'))) helper.datadir = fio.pathjoin(helper.root, 'tmp', 'db_test') helper.server_command = fio.pathjoin(helper.root, 'init.lua') -helper.cluster = cartridge_helpers.Cluster:new({ - server_command = helper.server_command, - datadir = helper.datadir, - use_vshard = true, - replicasets = { - { - alias = "api", - uuid = cartridge_helpers.uuid('a'), - roles = {'app.roles.api'}, - servers = { - { instance_uuid = cartridge_helpers.uuid('a', 1) } - }, - }, - { - alias = "storage-1", - uuid = cartridge_helpers.uuid("b"), - roles = { "app.roles.storage" }, - servers = { - { instance_uuid = cartridge_helpers.uuid("b", 1) } - }, - }, - { - alias = "storage-2", - uuid = cartridge_helpers.uuid("c"), - roles = { "app.roles.storage" }, - servers = { - { instance_uuid = cartridge_helpers.uuid("c", 1) } - }, - } - } -}) +-- helper.cluster = nil local config = { ["executor_waiting_timeout"] = 200, @@ -1356,15 +1328,56 @@ local config = { helper.cluster_config = config -t.before_suite(function() +helper.start_test_cluster = function (cfg) fio.rmtree(helper.datadir) fio.mktree(helper.datadir) + + helper.cluster = cartridge_helpers.Cluster:new({ + server_command = helper.server_command, + datadir = helper.datadir, + use_vshard = true, + replicasets = { + { + alias = "api", + uuid = cartridge_helpers.uuid('a'), + roles = {'app.roles.api'}, + servers = { + { instance_uuid = cartridge_helpers.uuid('a', 1) } + }, + }, + { + alias = "storage-1", + uuid = cartridge_helpers.uuid("b"), + roles = { "app.roles.storage" }, + servers = { + { instance_uuid = cartridge_helpers.uuid("b", 1) } + }, + }, + { + alias = "storage-2", + uuid = cartridge_helpers.uuid("c"), + roles = { "app.roles.storage" }, + servers = { + { instance_uuid = cartridge_helpers.uuid("c", 1) } + }, + } + } + }) + helper.cluster:start() - helper.cluster:upload_config(config) + helper.cluster:upload_config(cfg) +end + +helper.stop_test_cluster = function () + helper.cluster:stop() +end + +t.before_suite(function() + helper.start_test_cluster(config) end) t.after_suite(function() - helper.cluster:stop() + helper.stop_test_cluster() end) return helper diff --git a/sbroad-cartridge/test_app/test/integration/api_test.lua b/sbroad-cartridge/test_app/test/integration/api_test.lua index 5e724b2623ce3890fc39a0b87e7ae0b382706cfd..e6502c9c228e28fc0aae48a23821fa8db3b07597 100644 --- a/sbroad-cartridge/test_app/test/integration/api_test.lua +++ b/sbroad-cartridge/test_app/test/integration/api_test.lua @@ -2,7 +2,13 @@ local t = require('luatest') local g = t.group('integration_api') local helper = require('test.helper') -local cluster = helper.cluster +local cluster = nil + +g.before_all( + function() + cluster = helper.cluster + end +) g.before_each( function() diff --git a/sbroad-cartridge/test_app/test/integration/ddl_test.lua b/sbroad-cartridge/test_app/test/integration/ddl_test.lua index 6c93a5cb9effb57e1dc9ad1e0cc7c5af8fe4e64b..3f7a2110464441bc1d79a1a59a74399eb9c73010 100644 --- a/sbroad-cartridge/test_app/test/integration/ddl_test.lua +++ b/sbroad-cartridge/test_app/test/integration/ddl_test.lua @@ -2,10 +2,12 @@ local t = require('luatest') local g = t.group('sbroad_with_ddl') local helper = require('test.helper') -local cluster = helper.cluster +local cluster = nil g.before_all( function() + cluster = helper.cluster + local storage1 = cluster:server("storage-1-1").net_box storage1:call("box.execute", { [[truncate table "broken_hot"]] }) storage1:call("box.execute", { [[truncate table "BROKEN"]] }) diff --git a/sbroad-cartridge/test_app/test/integration/target_queries_test.lua b/sbroad-cartridge/test_app/test/integration/target_queries_test.lua index c257262d5ddbf8e03617851c59ba0d9df9192239..fdf088ffcd22e754c13d2a2572432e146c14cffa 100644 --- a/sbroad-cartridge/test_app/test/integration/target_queries_test.lua +++ b/sbroad-cartridge/test_app/test/integration/target_queries_test.lua @@ -2,10 +2,12 @@ local t = require('luatest') local target_queries = t.group('target_queries') local helper = require('test.helper') -local cluster = helper.cluster +local cluster = nil target_queries.before_all( function() + cluster = helper.cluster + local api = cluster:server("api-1").net_box local r, err = api:call("sbroad.execute", { diff --git a/sbroad-cartridge/test_app/test/integration/validate_schema_test.lua b/sbroad-cartridge/test_app/test/integration/validate_schema_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..ed577a1b6d8cf4cf78681003b76260e79736599b --- /dev/null +++ b/sbroad-cartridge/test_app/test/integration/validate_schema_test.lua @@ -0,0 +1,83 @@ +local t = require('luatest') +local g = t.group('schema_validate') +local helper = require('test.helper') + +g.before_all( + function() + helper.stop_test_cluster() + + local cfg = { + schema = { + spaces = { + t = { + format = { + { + name = "id", + type = "integer", + is_nullable = false, + }, + { + name = "a", + type = "array", + is_nullable = false, + }, + { + name = "bucket_id", + type = "unsigned", + is_nullable = true, + }, + }, + temporary = false, + engine = "memtx", + indexes = { + { + unique = true, + parts = { + { + path = "id", + type = "integer", + is_nullable = false, + }, + }, + type = "TREE", + name = "id", + }, + { + unique = false, + parts = { + { + path = "bucket_id", + type = "unsigned", + is_nullable = true, + }, + }, + type = "TREE", + name = "bucket_id", + }, + }, + is_local = false, + sharding_key = { "id" }, + }, + } + } + } + + + helper.start_test_cluster(cfg) + end +) + +g.after_all( + function() + helper.stop_test_cluster() + + helper.start_test_cluster(helper.cluster_config) + end +) + +g.test_schema_invalid = function () + local api = helper.cluster:server("api-1").net_box + + local _, err = api:call("sbroad.execute", { [[select * from "t"]], {}}) + t.assert_str_contains(tostring(err), "Failed to get configuration: type `array` not implemented") +end diff --git a/sbroad-core/src/errors.rs b/sbroad-core/src/errors.rs index 06a73258191a37d83a35e644d09cb66c47057916..275b27df33136569db20f35d625d706f8689ff94 100644 --- a/sbroad-core/src/errors.rs +++ b/sbroad-core/src/errors.rs @@ -42,7 +42,6 @@ const SPACE_FORMAT_NOT_FOUND: &str = "space format not found"; const UNINITIALIZED_DISTRIBUTION: &str = "uninitialized distribution"; const UNSUPPORTED_TYPE_IR_VALUE: &str = "unsupported type ir value"; const VALUE_OUT_OF_RANGE_ERROR: &str = "value out of range"; -const TYPE_NOT_IMPLEMENTED: &str = "type is not implemented"; #[derive(Clone, Debug, PartialEq, Eq, Serialize)] pub enum QueryPlannerError { @@ -87,7 +86,6 @@ pub enum QueryPlannerError { SpaceNotFound, UninitializedDistribution, ValueOutOfRange, - TypeNotImplemented, UnsupportedValueType, } @@ -135,7 +133,6 @@ impl fmt::Display for QueryPlannerError { QueryPlannerError::SpaceNotFound => SPACE_NOT_FOUND, QueryPlannerError::UninitializedDistribution => UNINITIALIZED_DISTRIBUTION, QueryPlannerError::ValueOutOfRange => VALUE_OUT_OF_RANGE_ERROR, - QueryPlannerError::TypeNotImplemented => TYPE_NOT_IMPLEMENTED, QueryPlannerError::UnsupportedValueType => UNSUPPORTED_TYPE_IR_VALUE, }; write!(f, "{}", p) diff --git a/sbroad-core/src/ir/relation.rs b/sbroad-core/src/ir/relation.rs index f658b707c7c22ad05337a3518e884d0369d40db5..0ec2678eb4d2f91655ebe8de1fbb82e1e36a0d90 100644 --- a/sbroad-core/src/ir/relation.rs +++ b/sbroad-core/src/ir/relation.rs @@ -44,7 +44,10 @@ impl Type { "scalar" => Ok(Type::Scalar), "string" => Ok(Type::String), "unsigned" => Ok(Type::Unsigned), - _ => Err(QueryPlannerError::TypeNotImplemented), + v => Err(QueryPlannerError::CustomError(format!( + "type `{}` not implemented", + v + ))), } } }