From 85942e987da4222c6e51f80069cf8ed47aeb6e4b Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sat, 15 Jun 2019 17:33:16 +0100 Subject: [PATCH 1/2] Removed dependency on `dbms_utility.name_resolve`. Fixed issue with utPLSQL failing to run when schema contains package named the same as schema owning it. It is now possible to have utPLSQL test package like this: ``` create or replace package some_schema.some_schema as --%suite --%test procedure sample_test; end; / create or replace package body some_schema.some_schema as procedure sample_test is begin ut.expect(1).to_equal(1); end; end; / ``` The tests from the package can be invoked by calling: `exec ut.run('some_schema.some_schema');` If only schema is provided, all test packages in schema are executed. `exec ut.run('some_schema');` Resolves #569 Resolves #885 --- source/core/types/ut_executable.tpb | 15 ++-- source/core/types/ut_executable.tps | 2 +- source/core/ut_metadata.pkb | 74 +++++-------------- source/core/ut_metadata.pks | 12 --- .../test_before_after_annotations.pkb | 3 +- test/ut3_user/api/test_ut_run.pkb | 38 +++++++++- test/ut3_user/api/test_ut_run.pks | 11 +++ 7 files changed, 76 insertions(+), 79 deletions(-) diff --git a/source/core/types/ut_executable.tpb b/source/core/types/ut_executable.tpb index b41e75388..2fc1e3a7e 100644 --- a/source/core/types/ut_executable.tpb +++ b/source/core/types/ut_executable.tpb @@ -29,9 +29,13 @@ create or replace type body ut_executable is return; end; - member function form_name return varchar2 is + member function form_name(a_skip_current_user_schema boolean := false) return varchar2 is + l_owner_name varchar2(250) := owner_name; begin - return ut_metadata.form_name(owner_name, object_name, procedure_name); + if a_skip_current_user_schema and sys_context('userenv', 'current_schema') = owner_name then + l_owner_name := null; + end if; + return ut_metadata.form_name(l_owner_name, object_name, procedure_name); end; member procedure do_execute(self in out nocopy ut_executable, a_item in out nocopy ut_suite_item) is @@ -71,10 +75,9 @@ create or replace type body ut_executable is begin if not ut_metadata.package_valid(self.owner_name, self.object_name) then - self.error_stack := l_message_part || 'package does not exist or is invalid: ' ||upper(self.owner_name||'.'||self.object_name); + self.error_stack := l_message_part || 'package '||upper(self.owner_name||'.'||self.object_name)||' does not exist or is invalid.'; elsif not ut_metadata.procedure_exists(self.owner_name, self.object_name, self.procedure_name) then - self.error_stack := l_message_part || 'procedure does not exist ' - || upper(self.owner_name || '.' || self.object_name || '.' ||self.procedure_name); + self.error_stack := l_message_part || 'procedure '||upper(self.owner_name || '.' || self.object_name || '.' ||self.procedure_name)||' does not exist.'; else l_result := false; end if; @@ -115,7 +118,7 @@ create or replace type body ut_executable is ' l_error_backtrace varchar2(32767);' || chr(10) || 'begin' || chr(10) || ' begin' || chr(10) || - ' ' || self.form_name() || ';' || chr(10) || + ' ' || self.form_name( a_skip_current_user_schema => true ) || ';' || chr(10) || ' exception' || chr(10) || ' when others then ' || chr(10) || ' l_error_stack := dbms_utility.format_error_stack;' || chr(10) || diff --git a/source/core/types/ut_executable.tps b/source/core/types/ut_executable.tps index 8186e4bae..9154881f2 100644 --- a/source/core/types/ut_executable.tps +++ b/source/core/types/ut_executable.tps @@ -30,7 +30,7 @@ create or replace type ut_executable under ut_event_item( */ seq_no integer, constructor function ut_executable( self in out nocopy ut_executable, a_owner varchar2, a_package varchar2, a_procedure_name varchar2, a_executable_type varchar2) return self as result, - member function form_name return varchar2, + member function form_name(a_skip_current_user_schema boolean := false) return varchar2, member procedure do_execute(self in out nocopy ut_executable, a_item in out nocopy ut_suite_item), /** * executes the defines executable diff --git a/source/core/ut_metadata.pkb b/source/core/ut_metadata.pkb index 43a57afa9..30262533a 100644 --- a/source/core/ut_metadata.pkb +++ b/source/core/ut_metadata.pkb @@ -21,31 +21,6 @@ create or replace package body ut_metadata as g_cached_object varchar2(500); ------------------------------ --public definitions - - procedure do_resolve(a_owner in out nocopy varchar2, a_object in out nocopy varchar2, a_procedure_name in out nocopy varchar2) is - l_name varchar2(200); - l_context integer := 1; --plsql - begin - l_name := form_name(a_owner, a_object, a_procedure_name); - do_resolve(l_name,l_context,a_owner,a_object, a_procedure_name); - end do_resolve; - - procedure do_resolve(a_fully_qualified_name in varchar2,a_context in integer,a_owner out nocopy varchar2, a_object out nocopy varchar2, - a_procedure_name out nocopy varchar2) is - l_dblink varchar2(200); - l_part1_type number; - l_object_number number; - begin - dbms_utility.name_resolve(name => a_fully_qualified_name - ,context => a_context - ,schema => a_owner - ,part1 => a_object - ,part2 => a_procedure_name - ,dblink => l_dblink - ,part1_type => l_part1_type - ,object_number => l_object_number); - end; - function form_name(a_owner_name varchar2, a_object varchar2, a_subprogram varchar2 default null) return varchar2 is l_name varchar2(200); begin @@ -61,25 +36,16 @@ create or replace package body ut_metadata as function package_valid(a_owner_name varchar2, a_package_name in varchar2) return boolean as l_cnt number; - l_schema varchar2(200); - l_package_name varchar2(200); - l_procedure_name varchar2(200); l_view_name varchar2(200) := get_objects_view_name; begin - l_schema := a_owner_name; - l_package_name := a_package_name; - - do_resolve(l_schema, l_package_name, l_procedure_name); - - execute immediate q'[select count(decode(status, 'VALID', 1, null)) / count(*) + execute immediate q'[select count(*) from ]'||l_view_name||q'[ - where owner = :l_schema - and object_name = :l_package_name - and object_type in ('PACKAGE')]' - into l_cnt using l_schema, l_package_name; - - -- expect both package and body to be valid + where owner = :a_owner_name + and object_name = :a_package_name + and object_type = 'PACKAGE' + and status = 'VALID']' + into l_cnt using upper(a_owner_name), upper(a_package_name); return l_cnt = 1; exception when others then @@ -89,22 +55,12 @@ create or replace package body ut_metadata as function procedure_exists(a_owner_name varchar2, a_package_name in varchar2, a_procedure_name in varchar2) return boolean as l_cnt number; - l_schema varchar2(200); - l_package_name varchar2(200); - l_procedure_name varchar2(200); l_view_name varchar2(200) := get_dba_view('dba_procedures'); begin - - l_schema := a_owner_name; - l_package_name := a_package_name; - l_procedure_name := a_procedure_name; - - do_resolve(l_schema, l_package_name, l_procedure_name); - execute immediate 'select count(*) from '||l_view_name - ||' where owner = :l_schema and object_name = :l_package_name and procedure_name = :l_procedure_name' - into l_cnt using l_schema, l_package_name, l_procedure_name; + ||' where owner = :l_schema and object_name = :l_package_name and procedure_name = :l_procedure_name and rownum = 1' + into l_cnt using a_owner_name, a_package_name, a_procedure_name; --expect one method only for the package with that name. return l_cnt = 1; @@ -327,12 +283,16 @@ create or replace package body ut_metadata as end; function get_object_name(a_full_object_name in varchar2) return varchar2 is - l_schema varchar2(250); - l_object varchar2(250); - l_procedure_name varchar2(250); + l_result varchar2(250); begin - ut_metadata.do_resolve(a_full_object_name,7,l_schema,l_object, l_procedure_name); - return l_object; + l_result := regexp_substr( + a_full_object_name, + '^([A-Za-z0-9$#_]+|".*?")\.([A-Za-z0-9$#_]+|".*?")', subexpression => 2 + ); + if not l_result like '"%"' then + l_result := upper(l_result); + end if; + return l_result; end; function get_anydata_compound_type(a_data_value anydata) return varchar2 is diff --git a/source/core/ut_metadata.pks b/source/core/ut_metadata.pks index 184943f2a..fdd984813 100644 --- a/source/core/ut_metadata.pks +++ b/source/core/ut_metadata.pks @@ -64,18 +64,6 @@ create or replace package ut_metadata authid current_user as function procedure_exists(a_owner_name varchar2, a_package_name in varchar2, a_procedure_name in varchar2) return boolean; - /** - * Resolves [owner.]object[.procedure] using dbms_utility.name_resolve and returns resolved parts - * - */ - procedure do_resolve(a_owner in out nocopy varchar2, a_object in out nocopy varchar2, a_procedure_name in out nocopy varchar2); - - /** - * Resolves single string [owner.]object[.procedure] using dbms_utility.name_resolve and returns parts [owner] [object] [procedure] - */ - procedure do_resolve(a_fully_qualified_name in varchar2,a_context in integer,a_owner out nocopy varchar2, - a_object out nocopy varchar2, a_procedure_name out nocopy varchar2); - /** * Return the text of the source line for a given object (body). It excludes package spec and type spec */ diff --git a/test/ut3_tester/core/annotations/test_before_after_annotations.pkb b/test/ut3_tester/core/annotations/test_before_after_annotations.pkb index 9ee917d84..e2f34e847 100644 --- a/test/ut3_tester/core/annotations/test_before_after_annotations.pkb +++ b/test/ut3_tester/core/annotations/test_before_after_annotations.pkb @@ -282,8 +282,7 @@ create or replace package body test_before_after_annotations is ); ut.expect(g_tests_results).to_match( '1\) beforetest_missing_procedure\s+' || - 'Call params for beforetest are not valid: procedure does not exist ' || - 'UT3_TESTER.DUMMY_BEFORE_AFTER_TEST.NON_EXISTENT_PROCEDURE' + 'Call params for beforetest are not valid: procedure UT3_TESTER\.DUMMY_BEFORE_AFTER_TEST\.NON_EXISTENT_PROCEDURE does not exist\.' ,'m' ); end; diff --git a/test/ut3_user/api/test_ut_run.pkb b/test/ut3_user/api/test_ut_run.pkb index e59571723..3fb2fbfec 100644 --- a/test/ut3_user/api/test_ut_run.pkb +++ b/test/ut3_user/api/test_ut_run.pkb @@ -1,5 +1,7 @@ create or replace package body test_ut_run is + g_owner varchar2(250) := sys_context('userenv', 'current_schema'); + procedure clear_expectations is begin ut3_tester_helper.main_helper.clear_expectations(); @@ -576,7 +578,7 @@ Failures:% select * bulk collect into l_results from table(ut3.ut.run('failing_invalid_spec')); l_actual := ut3_tester_helper.main_helper.table_to_clob(l_results); - ut.expect(l_actual).to_be_like('%Call params for % are not valid: package does not exist or is invalid: %FAILING_INVALID_SPEC%'); + ut.expect(l_actual).to_be_like('%Call params for % are not valid: package %FAILING_INVALID_SPEC% does not exist or is invalid.%'); end; @@ -739,6 +741,40 @@ Failures:% end loop; end; + procedure run_schema_name_test is + l_results ut3.ut_varchar2_list; + l_expected clob; + begin + select * bulk collect into l_results + from table ( ut3.ut.run( g_owner||'.'||g_owner ) ); + l_expected := '%1 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'; + ut.expect(ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( l_expected ); + end; + + procedure create_schema_name_package is + pragma autonomous_transaction; + begin + execute immediate ' + create or replace package '||g_owner||'.'||g_owner||' as + --%suite + + --%test + procedure sample_test; + end;'; + + execute immediate ' + create or replace package body '||g_owner||'.'||g_owner||' as + procedure sample_test is begin ut.expect(1).to_equal(1); end; + end;'; + + end; + + procedure drop_schema_name_package is + pragma autonomous_transaction; + begin + execute immediate 'drop package '||g_owner||'.'||g_owner; + end; + procedure run_with_random_order is l_random_results ut3.ut_varchar2_list; l_results ut3.ut_varchar2_list; diff --git a/test/ut3_user/api/test_ut_run.pks b/test/ut3_user/api/test_ut_run.pks index 4616763d0..406c70b09 100644 --- a/test/ut3_user/api/test_ut_run.pks +++ b/test/ut3_user/api/test_ut_run.pks @@ -85,6 +85,7 @@ create or replace package test_ut_run is --%context(ut_run_function) + --%displayname(ut.run() function options) --%beforeall(create_ut3$user#_tests) --%afterall(drop_ut3$user#_tests) @@ -145,9 +146,18 @@ create or replace package test_ut_run is procedure run_and_report_warnings; procedure create_bad_annot; procedure drop_bad_annot; + + --%test(Can run test package that is named the same as schema name) + --%beforetest(create_schema_name_package) + --%aftertest(drop_schema_name_package) + procedure run_schema_name_test; + procedure create_schema_name_package; + procedure drop_schema_name_package; + --%endcontext --%context(random_order) + --%displayname(Random test execution order) --%beforeall(create_ut3$user#_tests) --%afterall(drop_ut3$user#_tests) @@ -164,6 +174,7 @@ create or replace package test_ut_run is --%endcontext --%context(run with tags) + --%displayname(Call ut.run with #tags) --%beforeall(create_ut3$user#_tests) --%afterall(drop_ut3$user#_tests) From 4014b1fc10dc009d0f02f4d93559dbf92577cae6 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 16 Jun 2019 19:52:07 +0100 Subject: [PATCH 2/2] Adressed review comment. --- source/core/ut_metadata.pkb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/core/ut_metadata.pkb b/source/core/ut_metadata.pkb index 30262533a..0e8a8b79b 100644 --- a/source/core/ut_metadata.pkb +++ b/source/core/ut_metadata.pkb @@ -292,7 +292,7 @@ create or replace package body ut_metadata as if not l_result like '"%"' then l_result := upper(l_result); end if; - return l_result; + return sys.dbms_assert.qualified_sql_name(l_result); end; function get_anydata_compound_type(a_data_value anydata) return varchar2 is