diff --git a/docs/userguide/querying_suites.md b/docs/userguide/querying_suites.md index 976630ae9..0cfd513f3 100644 --- a/docs/userguide/querying_suites.md +++ b/docs/userguide/querying_suites.md @@ -39,6 +39,16 @@ To get a full information about suite `TEST_STUFF` including suite description, select * from table(ut_runner.get_suites_info(USER, 'TEST_STUFF')) where item_type = 'UT_TEST'; ``` +To get a full information about suites that have a path like `ut3:tests.test_package_*` including suite description, all contexts and tests in a suite +```sql +select * from table(ut_runner.get_suites_info('ut3:tests.test_package_*') where item_type = 'UT_TEST'; +``` + +To get a full information about suites that have object name like `test_package_*` including suite description, all contexts and tests in a suite +```sql +select * from table(ut_runner.get_suites_info('test_package_*')); +``` + ## Checking if schema contains tests Function `ut_runner.has_suites(a_owner)` returns boolean value indicating if given schema contains test suites. diff --git a/docs/userguide/running-unit-tests.md b/docs/userguide/running-unit-tests.md index e2f308c47..2288bf3f1 100644 --- a/docs/userguide/running-unit-tests.md +++ b/docs/userguide/running-unit-tests.md @@ -45,6 +45,9 @@ The **functions** can only be used in SELECT statements. They execute the specif ## ut.run procedures The examples below illustrate different ways and options to invoke `ut.run` procedures. +You can use a wildcard character `*` to call tests by part of their name or to call tests that are located on paths matched by part of path string. +Wildcard character can be placed anywhere on the path and can occur mutliple times. +Schema name cannot contain a wildcard character whether is in a suitepath call or call by object name. ```sql alter session set current_schema=hr; @@ -75,6 +78,23 @@ end; Executes all tests from all packages that are on the _com.my_org.my_project_ suitepath. Check the [annotations documentation](annotations.md) to find out about suitepaths and how they can be used to organize test packages for your project. +```sql +set serveroutput on +begin + ut.run('hr:com*'); +end; +``` + +Executes all tests in schema `hr` from all packages that are on suitepath starting with `com`. + +```sql +set serveroutput on +begin + ut.run('hr:co*.my_*.my_*'); +end; +``` + +Executes all tests in schema `hr` from all packages that starting with `my_` and all tests starting with `my_*` that are on suitepath starting with `co` . ```sql set serveroutput on @@ -124,6 +144,22 @@ Using a list of items to execute allows you to execute a fine-grained set of tes List can be passed as a comma separated list or a list of *ut_varchar2_list objects* or as a list within ut_varchar2_list. +```sql +set serveroutput on +begin + ut.run('hr.test*'); +end; +``` +Executes all tests in schema `hr` located in packages starting with name `test`. + +```sql +set serveroutput on +begin + ut.run('hr.test_apply_bonus.bonus_*'); +end; +``` +Executes test procedures with names starting with `bonus` in package `hr.test_apply_bonus` . + **Note:** diff --git a/source/api/ut_runner.pkb b/source/api/ut_runner.pkb index cbf1971e7..b69a51a04 100644 --- a/source/api/ut_runner.pkb +++ b/source/api/ut_runner.pkb @@ -172,12 +172,14 @@ create or replace package body ut_runner is ut_annotation_manager.purge_cache(a_object_owner, a_object_type); end; - function get_suites_info(a_owner varchar2 := null, a_package_name varchar2 := null) return ut_suite_items_info pipelined is + function get_suites_info(a_owner varchar2, a_package_name varchar2) return ut_suite_items_info pipelined is l_cursor sys_refcursor; l_results ut_suite_items_info; c_bulk_limit constant integer := 100; + l_path varchar2(4000) := nvl(a_owner,sys_context('userenv', 'current_schema'))||'.'||nvl(a_package_name,'*'); begin - l_cursor := ut_suite_manager.get_suites_info( nvl(a_owner,sys_context('userenv', 'current_schema')), a_package_name ); + + l_cursor := ut_suite_manager.get_suites_info(ut_varchar2_list(l_path)); loop fetch l_cursor bulk collect into l_results limit c_bulk_limit; for i in 1 .. l_results.count loop @@ -189,6 +191,26 @@ create or replace package body ut_runner is return; end; + function get_suites_info(a_path varchar2 := null) return ut_suite_items_info pipelined is + l_cursor sys_refcursor; + l_results ut_suite_items_info; + c_bulk_limit constant integer := 100; + i pls_integer; + begin + l_cursor := ut_suite_manager.get_suites_info(ut_varchar2_list(nvl(a_path,sys_context('userenv', 'current_schema')))); + loop + fetch l_cursor bulk collect into l_results limit c_bulk_limit; + i := l_results.first; + while (i is not null) loop + pipe row (l_results(i)); + i := l_results.next(i); + end loop; + exit when l_cursor%notfound; + end loop; + close l_cursor; + return; + end; + function is_test(a_owner varchar2, a_package_name varchar2, a_procedure_name varchar2) return boolean is l_result boolean := false; begin @@ -243,37 +265,6 @@ create or replace package body ut_runner is end loop; end; - function hash_suite_path(a_path varchar2, a_random_seed positiven) return varchar2 is - l_start_pos pls_integer := 1; - l_end_pos pls_integer := 1; - l_result varchar2(4000); - l_item varchar2(4000); - l_at_end boolean := false; - begin - if a_random_seed is null then - l_result := a_path; - end if; - if a_path is not null then - loop - l_end_pos := instr(a_path,'.',l_start_pos); - if l_end_pos = 0 then - l_end_pos := length(a_path)+1; - l_at_end := true; - end if; - l_item := substr(a_path,l_start_pos,l_end_pos-l_start_pos); - if l_item is not null then - l_result := - l_result || - ut_utils.get_hash( to_char( dbms_utility.get_hash_value( l_item, 1, a_random_seed ) ) ); - end if; - exit when l_at_end; - l_result := l_result || chr(0); - l_start_pos := l_end_pos + 1; - end loop; - end if; - return l_result; - end; - procedure coverage_start(a_coverage_run_id raw) is begin ut_coverage.coverage_start(a_coverage_run_id); diff --git a/source/api/ut_runner.pks b/source/api/ut_runner.pks index 3170dedee..85eff1c93 100644 --- a/source/api/ut_runner.pks +++ b/source/api/ut_runner.pks @@ -104,7 +104,14 @@ create or replace package ut_runner authid current_user is * @param a_package_name name of unit test package to retrieve (optional), if NULL all unit test packages are returned * @return ut_suite_items_info table of objects */ - function get_suites_info(a_owner varchar2 := null, a_package_name varchar2 := null) return ut_suite_items_info pipelined; + function get_suites_info(a_owner varchar2, a_package_name varchar2) return ut_suite_items_info pipelined; + + /** + * Returns a pipelined collection containing information about unit test suites and the tests contained in them + * + * @param a_path a path from which we lookg for object or suite + */ + function get_suites_info(a_path varchar2 := null) return ut_suite_items_info pipelined; /** @@ -144,11 +151,6 @@ create or replace package ut_runner authid current_user is */ function get_reporters_list return tt_reporters_info pipelined; - /* - * Returns a hash value of suitepath based on input path and random seed - */ - function hash_suite_path(a_path varchar2, a_random_seed positiven) return varchar2; - procedure coverage_start(a_coverage_run_id raw); procedure coverage_stop; diff --git a/source/core/types/ut_path_item.tpb b/source/core/types/ut_path_item.tpb new file mode 100644 index 000000000..6cdb2b8ad --- /dev/null +++ b/source/core/types/ut_path_item.tpb @@ -0,0 +1,42 @@ +create or replace type body ut_path_item as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + constructor function ut_path_item(self in out nocopy ut_path_item, schema_name varchar2, object_name varchar2,procedure_name varchar2) return self as result is + begin + self.schema_name := schema_name; + self.object_name := object_name; + self.procedure_name := procedure_name; + return; + end; + + constructor function ut_path_item(self in out nocopy ut_path_item, schema_name varchar2,suite_path varchar2) return self as result is + begin + self.schema_name := schema_name; + self.suite_path := suite_path; + return; + end; + + constructor function ut_path_item(self in out nocopy ut_path_item, schema_name varchar2, object_name varchar2,procedure_name varchar2,suite_path varchar2) return self as result is + begin + self.schema_name := schema_name; + self.object_name := object_name; + self.procedure_name := procedure_name; + self.suite_path := suite_path; + return; + end; +end; +/ diff --git a/source/core/types/ut_path_item.tps b/source/core/types/ut_path_item.tps new file mode 100644 index 000000000..c8ec81be5 --- /dev/null +++ b/source/core/types/ut_path_item.tps @@ -0,0 +1,26 @@ +create or replace type ut_path_item as object ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + schema_name varchar2(4000), + object_name varchar2(250), + procedure_name varchar2(250), + suite_path varchar2(4000), + constructor function ut_path_item(self in out nocopy ut_path_item, schema_name varchar2, object_name varchar2,procedure_name varchar2) return self as result, + constructor function ut_path_item(self in out nocopy ut_path_item, schema_name varchar2, suite_path varchar2) return self as result, + constructor function ut_path_item(self in out nocopy ut_path_item, schema_name varchar2, object_name varchar2,procedure_name varchar2,suite_path varchar2) return self as result +) +/ diff --git a/source/core/types/ut_path_items.tps b/source/core/types/ut_path_items.tps new file mode 100644 index 000000000..0c87cf28c --- /dev/null +++ b/source/core/types/ut_path_items.tps @@ -0,0 +1,19 @@ +create or replace type ut_path_items as + /* + utPLSQL - Version 3 + Copyright 2016 - 2021 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + table of ut_path_item +/ diff --git a/source/core/ut_suite_cache_manager.pkb b/source/core/ut_suite_cache_manager.pkb index 1023a515b..d3e832a9b 100644 --- a/source/core/ut_suite_cache_manager.pkb +++ b/source/core/ut_suite_cache_manager.pkb @@ -19,26 +19,16 @@ create or replace package body ut_suite_cache_manager is /* * Private code */ - - gc_get_cache_suite_sql constant varchar2(32767) := - q'[with + cursor c_get_bulk_cache_suite(cp_suite_items in ut_suite_cache_rows) is + with suite_items as ( select /*+ cardinality(c 500) */ value(c) as obj - from ut_suite_cache c - where 1 = 1 - and c.object_owner = :l_object_owner - and ( {:path:} - and {:object_name:} - and {:procedure_name:} - ) - ) - ), - {:tags:} + from table(cp_suite_items) c), suitepaths as ( select distinct substr(c.obj.path,1,instr(c.obj.path,'.',-1)-1) as suitepath, c.obj.path as path, c.obj.object_owner as object_owner - from {:suite_item_name:} c + from suite_items c where c.obj.self_type = 'UT_SUITE' ), gen as ( @@ -73,15 +63,10 @@ create or replace package body ut_suite_cache_manager is s.y, null, s.z ) as obj from logical_suite_data s - ), - items as ( - select obj from {:suite_item_name:} - union all - select obj from logical_suites ) - select /*+ no_parallel */ c.obj - from items c - order by c.obj.object_owner,{:random_seed:}]'; + select /*+ no_parallel */ obj from suite_items + union all + select /*+ no_parallel */ obj from logical_suites; function get_missing_cache_objects(a_object_owner varchar2) return ut_varchar2_rows is l_result ut_varchar2_rows; @@ -102,158 +87,264 @@ create or replace package body ut_suite_cache_manager is return l_result; end; - - function get_path_sql(a_path in varchar2) return varchar2 is + function group_paths_by_schema(a_paths ut_varchar2_list) return ut_path_items is + c_package_path_regex constant varchar2(100) := '^([A-Za-z0-9$#_]+)(\.([A-Za-z0-9$#_\*]+))?(\.([A-Za-z0-9$#_\*]+))?$'; + l_results ut_path_items := ut_path_items(); + l_path_item ut_path_item; + i pls_integer; begin - return case when a_path is not null then q'[ - :l_path||'.' like c.path || '.%' /*all parents and self*/ - or ( c.path||'.' like :l_path || '.%' /*all children and self*/ - ]' - else ' :l_path is null and ( :l_path is null ' end; + i := a_paths.first; + while (i is not null) loop + l_results.extend; + if a_paths(i) like '%:%' then + l_path_item := ut_path_item(schema_name => upper(regexp_substr(a_paths(i),'^[^.:]+')), + suite_path => ltrim(regexp_substr(a_paths(i),'[.:].*$'),':')); + l_results(l_results.last) := l_path_item; + else + l_path_item := ut_path_item(schema_name => regexp_substr(a_paths(i), c_package_path_regex, subexpression => 1), + object_name => regexp_substr(a_paths(i), c_package_path_regex, subexpression => 3), + procedure_name => regexp_substr(a_paths(i), c_package_path_regex, subexpression => 5)); + l_results(l_results.last) := l_path_item; + end if; + i := a_paths.next(i); + end loop; + + return l_results; end; - - function get_object_name_sql(a_object_name in varchar2) return varchar2 is - begin - return case when a_object_name is not null - then ' c.object_name = :a_object_name ' - else ' :a_object_name is null' end; + + /* + First SQL queries for objects where procedure is null or its only wildcard. + We split that due to fact that we can use func min to combine rows. + + Second union is responsible expanding paths where the procedure filter is given + We cannot select min here as filter can cover only half of tests within + package. Even if the filter doesnt return anything we still capture a proc filter + name for error reporting later on. + + Third SQL cover scenario where a suitapath only is populated and wildcard is given + + Fourth SQL cover scenario where suitepath is populated with no filters + */ + function expand_paths(a_schema_paths ut_path_items) return ut_path_items is + l_schema_paths ut_path_items:= ut_path_items(); + begin + with + schema_paths as ( + select * from table(a_schema_paths) + ), + paths_for_object as ( + select /*+ no_parallel */ min(path) as suite_path,sp.schema_name as schema_name,nvl(c.object_name,sp.object_name) as object_name, + null as procedure_name + from schema_paths sp left outer join ut_suite_cache c + on ( c.object_owner = upper(sp.schema_name) + and c.object_name like replace(upper(sp.object_name),'*','%')) + where sp.suite_path is null and sp.object_name is not null + and ( sp.procedure_name is null or sp.procedure_name = '*') + group by sp.schema_name,nvl(c.object_name,sp.object_name) + ), + paths_for_procedures as ( + select /*+ no_parallel */ path as suite_path,sp.schema_name as schema_name,nvl(c.object_name,sp.object_name) as object_name, + nvl(c.name,sp.procedure_name) as procedure_name + from schema_paths sp left outer join ut_suite_cache c + on ( c.object_owner = upper(sp.schema_name) + and c.object_name like replace(upper(sp.object_name),'*','%') + and c.name like nvl(replace(upper(sp.procedure_name),'*','%'), c.name)) + where sp.suite_path is null and sp.object_name is not null + and (sp.procedure_name is not null and sp.procedure_name != '*') + ), + paths_for_suite_path_with_ast as ( + select /*+ no_parallel */ nvl(c.path,sp.suite_path) as suite_path,sp.schema_name,sp.object_name,sp.procedure_name as procedure_name + from schema_paths sp left outer join ut_suite_cache c on + ( c.object_owner = upper(sp.schema_name) + --and c.path like replace(sp.suite_path,'*','%')) + and regexp_like(c.path,'^'||replace(sp.suite_path,'*','[A-Za-z0-9$#_]*'))) + where sp.suite_path is not null and instr(sp.suite_path,'*') > 0 + ), + straigth_suite_paths as ( + select /*+ no_parallel */ sp.suite_path as suite_path,sp.schema_name,sp.object_name,sp.procedure_name as procedure_name + from schema_paths sp + where + (sp.suite_path is not null and instr(sp.suite_path,'*') = 0) + or + (sp.suite_path is null and sp.object_name is null) + ), + all_suitepaths_together as ( + select * from paths_for_object + union all + select * from paths_for_procedures + union all + select * from paths_for_suite_path_with_ast + union all + select * from straigth_suite_paths + ) + select ut_path_item(schema_name,object_name,procedure_name,suite_path) + bulk collect into l_schema_paths + from + (select schema_name,object_name,procedure_name,suite_path, + row_number() over ( partition by schema_name,object_name,procedure_name,suite_path order by 1) as r_num + from all_suitepaths_together) + where r_num = 1 ; + return l_schema_paths; end; - - function get_procedure_name_sql(a_procedure_name in varchar2) return varchar2 is + + /* + Get a suite items rows that matching our criteria like + path,object_name etc. + We need to consider also an wildcard character on our procedures and object + names. + Were the path is populated we need to make sure we dont return duplicates + as the wildcard can produce multiple results from same path and + parents and child for each can be same resulting in duplicates + */ + function get_suite_items ( + a_schema_paths ut_path_items + ) return ut_suite_cache_rows is + l_suite_items ut_suite_cache_rows := ut_suite_cache_rows(); begin - return case when a_procedure_name is not null - then ' c.name = :a_procedure_name' - else ' :a_procedure_name is null' end; + select obj bulk collect into l_suite_items + from ( + select /*+ cardinality(c 500) */ value(c) as obj,row_number() over ( partition by path,object_owner order by path,object_owner asc) as r_num + from ut_suite_cache c, + table(a_schema_paths) sp + where c.object_owner = upper(sp.schema_name) + and ((sp.suite_path is not null and sp.suite_path||'.' like c.path||'.%' /*all parents and self*/ + or + ( + c.path||'.' like sp.suite_path||'.%' /*all children and self*/ + and c.object_name like nvl(upper(sp.object_name),c.object_name) + and c.name like nvl(upper(sp.procedure_name),c.name) + )) + or + ( sp.suite_path is null + and c.object_name = nvl(upper(sp.object_name),c.object_name) + and c.name = nvl(upper(sp.procedure_name),c.name)))) where r_num =1; + return l_suite_items; end; - - function get_tags_sql(a_tags_count in integer) return varchar2 is + + /* + Having a base set of suites we will do a further filter down if there are + any tags defined. + */ + function get_tags_suites ( + a_suite_items ut_suite_cache_rows, + a_tags ut_varchar2_rows + ) return ut_suite_cache_rows is + l_suite_tags ut_suite_cache_rows := ut_suite_cache_rows(); + l_include_tags ut_varchar2_rows; + l_exclude_tags ut_varchar2_rows; begin - return case when a_tags_count > 0 then - q'[included_tags as ( - select c.obj.path as path - from suite_items c - where c.obj.tags multiset intersect :a_include_tag_list is not empty or :a_include_tag_list is empty + + select /*+ no_parallel */ column_value + bulk collect into l_include_tags + from table(a_tags) + where column_value not like '-%'; + + select /*+ no_parallel */ ltrim(column_value,'-') + bulk collect into l_exclude_tags + from table(a_tags) + where column_value like '-%'; + + with included_tags as ( + select c.path as path + from table(a_suite_items) c + where c.tags multiset intersect l_include_tags is not empty or l_include_tags is empty ), excluded_tags as ( - select c.obj.path as path - from suite_items c - where c.obj.tags multiset intersect :a_exclude_tag_list is not empty - ), - suite_items_tags as ( - select c.* - from suite_items c + select c.path as path + from table(a_suite_items) c + where c.tags multiset intersect l_exclude_tags is not empty + ) + select value(c) as obj + bulk collect into l_suite_tags + from table(a_suite_items) c where exists ( select 1 from included_tags t - where t.path||'.' like c.obj.path || '.%' /*all parents and self*/ - or c.obj.path||'.' like t.path || '.%' /*all children and self*/ + where t.path||'.' like c.path || '.%' /*all ancestors and self*/ + or c.path||'.' like t.path || '.%' /*all descendants and self*/ ) and not exists ( select 1 from excluded_tags t - where c.obj.path||'.' like t.path || '.%' /*all children and self*/ - ) - ),]' - else - q'[dummy as (select 'x' from dual where :a_include_tag_list is null and :a_include_tag_list is null and :a_exclude_tag_list is null),]' - end; + where c.path||'.' like t.path || '.%' /*all descendants and self*/ + ); + return l_suite_tags; end; - - function get_random_seed_sql(a_random_seed positive) return varchar2 is + + /* + We will sort a suites in hierarchical structure. + Sorting from bottom to top so when we consolidate + we will go in proper order. + For random seed we will add an extra sort that can be null. + The object owner is irrelevant on joing via path as we already + resolved a list of test we want to use so as long they share a suitepath + they are correct. + */ + procedure sort_and_randomize_tests( + a_suite_rows in out ut_suite_cache_rows, + a_random_seed positive := null) + is + l_suite_rows ut_suite_cache_rows; begin - return case - when a_random_seed is null then q'[ - nlssort( - replace( - /*suite path until objects name (excluding contexts and test path) with trailing dot (full stop)*/ - substr( c.obj.path, 1, instr( c.obj.path, lower(c.obj.object_name), -1 ) + length(c.obj.object_name) ), - '.', - /*'.' replaced with chr(0) to assure that child elements come before parent when sorting in descending order*/ - chr(0) - ), - 'nls_sort=binary' - )desc nulls last, - case when c.obj.self_type = 'UT_SUITE_CONTEXT' then - ( select /*+ no_parallel */ max( x.line_no ) + 1 - from ut_suite_cache x - where c.obj.object_owner = x.object_owner - and c.obj.object_name = x.object_name - and x.path like c.obj.path || '.%' - ) - else - c.obj.line_no - end, - /*assures that child contexts come before parent contexts*/ - regexp_count(c.obj.path,'\.') desc, - :a_random_seed]' - else - ' ut_runner.hash_suite_path( - c.obj.path, :a_random_seed - ) desc nulls last' - end; + with + extract_parent_child as ( + select s.path, substr(s.path,1,instr(s.path,'.',-1,1)-1) as parent_path,s.object_owner, + case when a_random_seed is null then s.line_no end line_no, + case when a_random_seed is not null then ut_utils.hash_suite_path(s.path, a_random_seed) end random_seed + from table(a_suite_rows) s), + t1(path,parent_path,object_owner,line_no,random_seed) as ( + --Anchor member + select s.path, parent_path,s.object_owner,s.line_no,random_seed + from extract_parent_child s + where parent_path is null + union all + --Recursive member + select t2.path, t2.parent_path,t2.object_owner,t2.line_no,t2.random_seed + from t1,extract_parent_child t2 + where t2.parent_path = t1.path + and t2.object_owner = t1.object_owner) + search depth first by line_no desc,random_seed desc nulls last set order1 + select value(i) as obj + bulk collect into l_suite_rows + from t1 c + join table(a_suite_rows) i on i.object_owner = c.object_owner and i.path = c.path + order by order1 desc; + + a_suite_rows := l_suite_rows; end; - - - + /* * Public code */ + + function get_schema_paths(a_paths in ut_varchar2_list) return ut_path_items is + begin + return expand_paths(group_paths_by_schema(a_paths)); + end; + function get_cached_suite_rows( - a_object_owner varchar2, - a_path varchar2 := null, - a_object_name varchar2 := null, - a_procedure_name varchar2 := null, + a_schema_paths ut_path_items, a_random_seed positive := null, a_tags ut_varchar2_rows := null ) return ut_suite_cache_rows is - l_path varchar2(4000); l_results ut_suite_cache_rows := ut_suite_cache_rows(); - l_sql varchar2(32767); - l_suite_item_name varchar2(20); + l_suite_items ut_suite_cache_rows := ut_suite_cache_rows(); + l_schema_paths ut_path_items; l_tags ut_varchar2_rows := coalesce(a_tags,ut_varchar2_rows()); - l_include_tags ut_varchar2_rows; - l_exclude_tags ut_varchar2_rows; - l_object_owner varchar2(250) := ut_utils.qualified_sql_name(a_object_owner); - l_object_name varchar2(250) := ut_utils.qualified_sql_name(a_object_name); - l_procedure_name varchar2(250) := ut_utils.qualified_sql_name(a_procedure_name); - begin - - select /*+ no_parallel */ column_value - bulk collect into l_include_tags - from table(l_tags) - where column_value not like '-%'; - - select /*+ no_parallel */ ltrim(column_value,'-') - bulk collect into l_exclude_tags - from table(l_tags) - where column_value like '-%'; - - if a_path is null and a_object_name is not null then - select /*+ no_parallel */ min(c.path) - into l_path - from ut_suite_cache c - where c.object_owner = upper(l_object_owner) - and c.object_name = upper(l_object_name) - and c.name = nvl(upper(l_procedure_name), c.name); - else - l_path := lower(ut_utils.qualified_sql_name(a_path)); - end if; - l_suite_item_name := case when l_tags.count > 0 then 'suite_items_tags' else 'suite_items' end; - - l_sql := gc_get_cache_suite_sql; - l_sql := replace(l_sql,'{:suite_item_name:}',l_suite_item_name); - l_sql := replace(l_sql,'{:object_owner:}',upper(l_object_owner)); - l_sql := replace(l_sql,'{:path:}',get_path_sql(l_path)); - l_sql := replace(l_sql,'{:object_name:}',get_object_name_sql(l_object_name)); - l_sql := replace(l_sql,'{:procedure_name:}',get_procedure_name_sql(l_procedure_name)); - l_sql := replace(l_sql,'{:tags:}',get_tags_sql(l_tags.count)); - l_sql := replace(l_sql,'{:random_seed:}',get_random_seed_sql(a_random_seed)); - - ut_event_manager.trigger_event(ut_event_manager.gc_debug, ut_key_anyvalues().put('l_sql',l_sql) ); + begin - execute immediate l_sql - bulk collect into l_results - using upper(l_object_owner), l_path, l_path, upper(a_object_name), upper(a_procedure_name), l_include_tags, l_include_tags, l_exclude_tags, a_random_seed; + l_schema_paths := a_schema_paths; + l_suite_items := get_suite_items(a_schema_paths); + if l_tags.count > 0 then + l_suite_items := get_tags_suites(l_suite_items,l_tags); + end if; + + open c_get_bulk_cache_suite(l_suite_items); + fetch c_get_bulk_cache_suite bulk collect into l_results; + close c_get_bulk_cache_suite; + return l_results; end; + + function get_schema_parse_time(a_schema_name varchar2) return timestamp result_cache is l_cache_parse_time timestamp; @@ -398,22 +489,25 @@ create or replace package body ut_suite_cache_manager is end; function get_cached_suite_info( - a_object_owner varchar2, - a_object_name varchar2 + a_schema_paths ut_path_items + ) return ut_suite_cache_rows is + begin + return get_cached_suite_rows( a_schema_paths ); + end; + + function get_suite_items_info( + a_suite_cache_items ut_suite_cache_rows ) return ut_suite_items_info is - l_cache_rows ut_suite_cache_rows; l_results ut_suite_items_info; begin - l_cache_rows := get_cached_suite_rows( a_object_owner => a_object_owner, a_object_name =>a_object_name ); select /*+ no_parallel */ ut_suite_item_info( c.object_owner, c.object_name, c.name, c.description, c.self_type, c.line_no, c.path, c.disabled_flag, c.disabled_reason, c.tags ) bulk collect into l_results - from table(l_cache_rows) c; - - return l_results; + from table(a_suite_cache_items) c; + return l_results; end; function get_cached_packages( diff --git a/source/core/ut_suite_cache_manager.pks b/source/core/ut_suite_cache_manager.pks index 0a38851fe..974babca5 100644 --- a/source/core/ut_suite_cache_manager.pks +++ b/source/core/ut_suite_cache_manager.pks @@ -40,30 +40,41 @@ create or replace package ut_suite_cache_manager authid definer is */ procedure remove_missing_objs_from_cache(a_schema_name varchar2); + /* + * We will sort a suites in hierarchical structure. + * Sorting from bottom to top so when we consolidate + * we will go in proper order. + */ + procedure sort_and_randomize_tests( + a_suite_rows in out ut_suite_cache_rows, + a_random_seed positive := null); + /* * Retrieves suite items data from cache. * Returned data is not filtered by user access rights. * Not to be used publicly. Used internally for building suites at runtime. */ function get_cached_suite_rows( - a_object_owner varchar2, - a_path varchar2 := null, - a_object_name varchar2 := null, - a_procedure_name varchar2 := null, + a_schema_paths ut_path_items, a_random_seed positive := null, a_tags ut_varchar2_rows := null ) return ut_suite_cache_rows; - + + function get_schema_paths(a_paths in ut_varchar2_list) return ut_path_items; + /* * Retrieves suite item info rows from cache. * Returned data is not filtered by user access rights. * Not to be used publicly. Used internally for building suites info. */ function get_cached_suite_info( - a_object_owner varchar2, - a_object_name varchar2 + a_schema_paths ut_path_items + ) return ut_suite_cache_rows; + + function get_suite_items_info( + a_suite_cache_items ut_suite_cache_rows ) return ut_suite_items_info; - + /* * Retrieves list of cached suite packages. * Returned data is not filtered by user access rights. diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index a11b0249c..805fd608b 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -17,19 +17,9 @@ create or replace package body ut_suite_manager is */ gc_suitpath_error_message constant varchar2(100) := 'Suitepath exceeds 1000 CHAR on: '; - - type t_path_item is record ( - object_name varchar2(250), - procedure_name varchar2(250), - suite_path varchar2(4000) - ); - type t_path_items is table of t_path_item; - type t_schema_paths is table of t_path_items index by varchar2(250 char); - cursor c_cached_suites_cursor is select * from table(ut_suite_cache_rows()); type tt_cached_suites is table of c_cached_suites_cursor%rowtype; type t_cached_suites_cursor is ref cursor return c_cached_suites_cursor%rowtype; - type t_item_levels is table of ut_suite_items index by binary_integer; ------------------ @@ -41,7 +31,8 @@ create or replace package body ut_suite_manager is else for i in 1 .. a_paths.count loop l_path := a_paths(i); - if l_path is null or not (regexp_like(l_path, '^[A-Za-z0-9$#_]+(\.[A-Za-z0-9$#_]+){0,2}$') or regexp_like(l_path, '^([A-Za-z0-9$#_]+)?:[A-Za-z0-9$#_]+(\.[A-Za-z0-9$#_]+)*$')) then + if l_path is null or not ( + regexp_like(l_path, '^[A-Za-z0-9$#_\*]+(\.[A-Za-z0-9$#_\*]+){0,2}$') or regexp_like(l_path, '^([A-Za-z0-9$#_]+)?:[A-Za-z0-9$#_\*]+(\.[A-Za-z0-9$#_\*]+)*$')) then raise_application_error(ut_utils.gc_invalid_path_format, 'Invalid path format: ' || nvl(l_path, 'NULL')); end if; end loop; @@ -84,12 +75,14 @@ create or replace package body ut_suite_manager is -- get schema name / object.[procedure] name -- When path is one of: schema or schema.package[.object] or package[.object] -- transform it back to schema[.package[.object]] + -- Object name or procedure is allowed to have filter char + -- However this is not allowed on schema begin - l_object := regexp_substr(a_paths(i), '^[A-Za-z0-9$#_]+'); + l_object := regexp_substr(a_paths(i), '^[A-Za-z0-9$#_\*]+'); l_schema := sys.dbms_assert.schema_name(upper(l_object)); exception when sys.dbms_assert.invalid_schema_name then - if ut_metadata.package_exists_in_cur_schema(upper(l_object)) then + if l_object like '%*%' or ut_metadata.package_exists_in_cur_schema(upper(l_object)) then a_paths(i) := c_current_schema || '.' || a_paths(i); l_schema := c_current_schema; else @@ -110,34 +103,6 @@ create or replace package body ut_suite_manager is l_schema_names := resolve_schema_names(a_paths); end; - function group_paths_by_schema(a_paths ut_varchar2_list) return t_schema_paths is - c_package_path_regex constant varchar2(100) := '^([A-Za-z0-9$#_]+)(\.([A-Za-z0-9$#_]+))?(\.([A-Za-z0-9$#_]+))?$'; - l_schema varchar2(4000); - l_empty_result t_path_item; - l_result t_path_item; - l_results t_schema_paths; - begin - for i in 1 .. a_paths.count loop - l_result := l_empty_result; - if a_paths(i) like '%:%' then - l_schema := upper(regexp_substr(a_paths(i),'^[^.:]+')); - l_result.suite_path := ltrim(regexp_substr(a_paths(i),'[.:].*$'),':'); - else - l_schema := regexp_substr(a_paths(i), c_package_path_regex, subexpression => 1); - l_result.object_name := regexp_substr(a_paths(i), c_package_path_regex, subexpression => 3); - l_result.procedure_name := regexp_substr(a_paths(i), c_package_path_regex, subexpression => 5); - end if; - if l_results.exists(l_schema) then - l_results(l_schema).extend; - l_results(l_schema)(l_results(l_schema).last) := l_result; - else - l_results(l_schema) := t_path_items(l_result); - end if; - end loop; - return l_results; - end; - - function sort_by_seq_no( a_list ut_executables ) return ut_executables is @@ -331,42 +296,82 @@ create or replace package body ut_suite_manager is close a_suite_data_cursor; end reconstruct_from_cache; + function get_filtered_cursor( + a_unfiltered_rows in ut_suite_cache_rows, + a_skip_all_objects boolean := false + ) + return ut_suite_cache_rows is + l_result ut_suite_cache_rows := ut_suite_cache_rows(); + begin + if ut_metadata.user_has_execute_any_proc() or a_skip_all_objects then + l_result := a_unfiltered_rows; + else + select obj bulk collect into l_result + from ( + select /*+ no_parallel */ value(c) as obj from table(a_unfiltered_rows) c + where sys_context( 'userenv', 'current_user' ) = upper(c.object_owner) + union all + select /*+ no_parallel */ value(c) as obj from table(a_unfiltered_rows) c + where sys_context( 'userenv', 'current_user' ) != upper(c.object_owner) + and ( exists + ( select 1 + from all_objects a + where a.object_name = c.object_name + and a.owner = c.object_owner + and a.object_type = 'PACKAGE' + ) + or c.self_type = 'UT_LOGICAL_SUITE')); + end if; + return l_result; + end; + + procedure reconcile_paths_and_suites( + a_schema_paths ut_path_items, + a_filtered_rows ut_suite_cache_rows + ) is + begin + for i in ( select /*+ no_parallel */ sp.schema_name,sp.object_name,sp.procedure_name, + sp.suite_path,sc.path + from table(a_schema_paths) sp left outer join + table(a_filtered_rows) sc on + (( upper(sp.schema_name) = upper(sc.object_owner) and upper(sp.object_name) = upper(sc.object_name) + and nvl(upper(sp.procedure_name),sc.name) = sc.name ) + or (sc.path = sp.suite_path)) + where sc.path is null) + loop + if i.suite_path is not null then + raise_application_error(ut_utils.gc_suite_package_not_found,'No suite packages found for path '||i.schema_name||':'||i.suite_path|| '.'); + elsif i.procedure_name is not null then + raise_application_error(ut_utils.gc_suite_package_not_found,'Suite test '||i.schema_name||'.'||i.object_name|| '.'||i.procedure_name||' does not exist'); + elsif i.object_name is not null then + raise_application_error(ut_utils.gc_suite_package_not_found,'Suite package '||i.schema_name||'.'||i.object_name|| ' does not exist'); + end if; + end loop; + end; + function get_cached_suite_data( - a_object_owner varchar2, - a_path varchar2 := null, - a_object_name varchar2 := null, - a_procedure_name varchar2 := null, - a_skip_all_objects boolean := false, + a_schema_paths ut_path_items, a_random_seed positive, - a_tags ut_varchar2_rows := null + a_tags ut_varchar2_rows := null, + a_skip_all_objects boolean := false ) return t_cached_suites_cursor is l_unfiltered_rows ut_suite_cache_rows; + l_filtered_rows ut_suite_cache_rows; l_result t_cached_suites_cursor; begin l_unfiltered_rows := ut_suite_cache_manager.get_cached_suite_rows( - a_object_owner, - a_path, - a_object_name, - a_procedure_name, + a_schema_paths, a_random_seed, a_tags ); - if a_skip_all_objects then - open l_result for - select /*+ no_parallel */ c.* from table(l_unfiltered_rows) c; - else - open l_result for - select /*+ no_parallel */ c.* from table(l_unfiltered_rows) c - where exists - ( select 1 - from all_objects a - where a.object_name = c.object_name - and a.owner = c.object_owner - and a.object_type = 'PACKAGE' - ) - or c.self_type = 'UT_LOGICAL_SUITE'; - end if; + l_filtered_rows := get_filtered_cursor(l_unfiltered_rows,a_skip_all_objects); + reconcile_paths_and_suites(a_schema_paths,l_filtered_rows); + + ut_suite_cache_manager.sort_and_randomize_tests(l_filtered_rows,a_random_seed); + + open l_result for + select * from table(l_filtered_rows); return l_result; end; @@ -442,31 +447,21 @@ create or replace package body ut_suite_manager is ut_event_manager.trigger_event('refresh_cache - end'); end; - procedure add_suites_for_path( - a_owner_name varchar2, - a_path varchar2 := null, - a_object_name varchar2 := null, - a_procedure_name varchar2 := null, + procedure add_suites_for_paths( + a_schema_paths ut_path_items, a_suites in out nocopy ut_suite_items, a_random_seed positive, a_tags ut_varchar2_rows := null ) is begin - refresh_cache(a_owner_name); - reconstruct_from_cache( a_suites, get_cached_suite_data( - a_owner_name, - a_path, - a_object_name, - a_procedure_name, - can_skip_all_objects_scan(a_owner_name), + a_schema_paths, a_random_seed, a_tags ) ); - end; ----------------------------------------------- @@ -482,19 +477,17 @@ create or replace package body ut_suite_manager is a_skip_all_objects boolean := false ) return ut_suite_items is l_suites ut_suite_items := ut_suite_items(); + l_schema_paths ut_path_items; begin build_and_cache_suites(a_owner_name, a_annotated_objects); - + l_schema_paths := ut_path_items(ut_path_item(a_owner_name,a_object_name,a_procedure_name,a_path)); reconstruct_from_cache( l_suites, get_cached_suite_data( - a_owner_name, - a_path, - a_object_name, - a_procedure_name, - a_skip_all_objects, + l_schema_paths, null, - null + null, + a_skip_all_objects ) ); return l_suites; @@ -530,49 +523,32 @@ create or replace package body ut_suite_manager is a_tags ut_varchar2_rows := ut_varchar2_rows() ) is l_paths ut_varchar2_list := a_paths; - l_path_items t_path_items; - l_path_item t_path_item; + l_schema_names ut_varchar2_rows; + l_schema_paths ut_path_items; l_schema varchar2(4000); - l_suites_count pls_integer := 0; - l_index varchar2(4000 char); - l_schema_paths t_schema_paths; begin ut_event_manager.trigger_event('configure_execution_by_path - start'); a_suites := ut_suite_items(); --resolve schema names from paths and group paths by schema name - resolve_schema_names(l_paths); - - l_schema_paths := group_paths_by_schema(l_paths); + l_schema_names := resolve_schema_names(l_paths); - l_schema := l_schema_paths.first; + --refresh cache + l_schema := l_schema_names.first; while l_schema is not null loop - l_path_items := l_schema_paths(l_schema); - for i in 1 .. l_path_items.count loop - l_path_item := l_path_items(i); - add_suites_for_path( - upper(l_schema), - l_path_item.suite_path, - l_path_item.object_name, - l_path_item.procedure_name, - a_suites, - a_random_seed, - a_tags - ); - if a_suites.count = l_suites_count then - if l_path_item.suite_path is not null then - raise_application_error(ut_utils.gc_suite_package_not_found,'No suite packages found for path '||l_schema||':'||l_path_item.suite_path|| '.'); - elsif l_path_item.procedure_name is not null then - raise_application_error(ut_utils.gc_suite_package_not_found,'Suite test '||l_schema||'.'||l_path_item.object_name|| '.'||l_path_item.procedure_name||' does not exist'); - elsif l_path_item.object_name is not null then - raise_application_error(ut_utils.gc_suite_package_not_found,'Suite package '||l_schema||'.'||l_path_item.object_name|| ' does not exist'); - end if; - end if; - l_index := a_suites.first; - l_suites_count := a_suites.count; - end loop; - l_schema := l_schema_paths.next(l_schema); + refresh_cache(upper(l_schema_names(l_schema))); + l_schema := l_schema_names.next(l_schema); end loop; + l_schema_paths := ut_suite_cache_manager.get_schema_paths(l_paths); + + --We will get a single list of paths rather than loop by loop. + add_suites_for_paths( + l_schema_paths, + a_suites, + a_random_seed, + a_tags + ); + --propagate rollback type to suite items after organizing suites into hierarchy for i in 1 .. a_suites.count loop a_suites(i).set_rollback_type( a_suites(i).get_rollback_type() ); @@ -582,37 +558,34 @@ create or replace package body ut_suite_manager is end configure_execution_by_path; function get_suites_info( - a_owner_name varchar2, - a_package_name varchar2 := null + a_paths ut_varchar2_list ) return sys_refcursor is - l_result sys_refcursor; - l_all_suite_info ut_suite_items_info; - l_owner_name varchar2(250) := ut_utils.qualified_sql_name(a_owner_name); - l_package_name varchar2(250) := ut_utils.qualified_sql_name(a_package_name); - begin + l_result sys_refcursor; + l_all_suite_info ut_suite_items_info; + l_schema_names ut_varchar2_rows; + l_schema_paths ut_path_items; + l_paths ut_varchar2_list := a_paths; + l_schema varchar2(4000); + l_unfiltered_rows ut_suite_cache_rows; + l_filtered_rows ut_suite_cache_rows; - refresh_cache(l_owner_name); + begin + l_schema_names := resolve_schema_names(l_paths); + --refresh cache + l_schema := l_schema_names.first; + while l_schema is not null loop + refresh_cache(upper(l_schema_names(l_schema))); + l_schema := l_schema_names.next(l_schema); + end loop; + l_schema_paths := ut_suite_cache_manager.get_schema_paths(l_paths); + l_unfiltered_rows := ut_suite_cache_manager.get_cached_suite_info(l_schema_paths); + l_filtered_rows := get_filtered_cursor(l_unfiltered_rows); + l_all_suite_info := ut_suite_cache_manager.get_suite_items_info(l_filtered_rows); + open l_result for + select /*+ no_parallel */ value(c) + from table(l_all_suite_info) c + order by c.object_owner, c.object_name, c.item_line_no; - l_all_suite_info := ut_suite_cache_manager.get_cached_suite_info( l_owner_name, l_package_name ); - if can_skip_all_objects_scan( l_owner_name ) then - open l_result for - select /*+ no_parallel */ value(c) - from table(l_all_suite_info) c - order by c.object_owner, c.object_name, c.item_line_no; - else - open l_result for - select /*+ no_parallel */ value(c) - from table(l_all_suite_info) c - where exists - ( select 1 - from all_objects a - where a.object_name = c.object_name - and a.owner = c.object_owner - and a.object_type = 'PACKAGE' - ) - or c.item_type = 'UT_LOGICAL_SUITE' - order by c.object_owner, c.object_name, c.item_line_no; - end if; return l_result; end; diff --git a/source/core/ut_suite_manager.pks b/source/core/ut_suite_manager.pks index 5ae98d72a..170b83f05 100644 --- a/source/core/ut_suite_manager.pks +++ b/source/core/ut_suite_manager.pks @@ -39,6 +39,7 @@ create or replace package ut_suite_manager authid current_user is * @return array containing root suites-ready to be executed * */ + --TODO:Zerknij czy mozna wywalic function configure_execution_by_path(a_paths ut_varchar2_list, a_random_seed positive := null) return ut_suite_items; /** @@ -79,15 +80,11 @@ create or replace package ut_suite_manager authid current_user is /** * Returns a ref cursor containing information about unit test suites and the tests contained in them * - * @param a_owner owner of unit tests to retrieve - * @param a_package_name name of test package (optional) - * @param a_procedure_name name of test procedure (optional) - * @return ut_suite_items_info table of objects + * @param a_paths list of paths to be resolved and return a suites. */ function get_suites_info( - a_owner_name varchar2, - a_package_name varchar2 := null - ) return sys_refcursor; + a_paths ut_varchar2_list + ) return sys_refcursor; /** * Returns true if given suite item exists diff --git a/source/core/ut_utils.pkb b/source/core/ut_utils.pkb index 3675e834d..162e50f8f 100644 --- a/source/core/ut_utils.pkb +++ b/source/core/ut_utils.pkb @@ -892,6 +892,37 @@ create or replace package body ut_utils is return case when a_data is null then null else dbms_crypto.hash(a_data, a_hash_type) end; end; + function hash_suite_path(a_path varchar2, a_random_seed positiven) return varchar2 is + l_start_pos pls_integer := 1; + l_end_pos pls_integer := 1; + l_result varchar2(4000); + l_item varchar2(4000); + l_at_end boolean := false; + begin + if a_random_seed is null then + l_result := a_path; + end if; + if a_path is not null then + loop + l_end_pos := instr(a_path,'.',l_start_pos); + if l_end_pos = 0 then + l_end_pos := length(a_path)+1; + l_at_end := true; + end if; + l_item := substr(a_path,l_start_pos,l_end_pos-l_start_pos); + if l_item is not null then + l_result := + l_result || + ut_utils.get_hash( to_char( dbms_utility.get_hash_value( l_item, 1, a_random_seed ) ) ); + end if; + exit when l_at_end; + l_result := l_result || chr(0); + l_start_pos := l_end_pos + 1; + end loop; + end if; + return l_result; + end; + function qualified_sql_name(a_name varchar2) return varchar2 is begin return diff --git a/source/core/ut_utils.pks b/source/core/ut_utils.pks index 3635bccad..995d83c10 100644 --- a/source/core/ut_utils.pks +++ b/source/core/ut_utils.pks @@ -452,6 +452,11 @@ create or replace package ut_utils authid definer is */ function get_hash(a_data clob, a_hash_type binary_integer := dbms_crypto.hash_sh1) return t_hash; + /* + * Returns a hash value of suitepath based on input path and random seed + */ + function hash_suite_path(a_path varchar2, a_random_seed positiven) return varchar2; + /* * Verifies that the input string is a qualified SQL name using sys.dbms_assert.qualified_sql_name * If null value passed returns null diff --git a/source/create_grants.sql b/source/create_grants.sql index 6401b1522..8a44ab371 100644 --- a/source/create_grants.sql +++ b/source/create_grants.sql @@ -60,6 +60,7 @@ grant execute on &&ut3_owner..ut_file_mapping to &ut3_user; grant execute on &&ut3_owner..ut_file_mapper to &ut3_user; grant execute on &&ut3_owner..ut_suite_items_info to &ut3_user; grant execute on &&ut3_owner..ut_suite_item_info to &ut3_user; +grant execute on &&ut3_owner..ut_suite_cache_rows to &ut3_user; grant execute on &&ut3_owner..ut_run_info to &ut3_user; grant execute on &&ut3_owner..ut_coverage_options to &ut3_user; diff --git a/source/install.sql b/source/install.sql index cda057bdf..6f3c16801 100644 --- a/source/install.sql +++ b/source/install.sql @@ -89,7 +89,8 @@ create or replace context &&ut3_owner._info using &&ut3_owner..ut_session_contex @@install_component.sql 'core/types/ut_run.tps' @@install_component.sql 'core/types/ut_reporter_base.tps' @@install_component.sql 'core/types/ut_reporters.tps' - +@@install_component.sql 'core/types/ut_path_item.tps' +@@install_component.sql 'core/types/ut_path_items.tps' @@install_component.sql 'expectations/json_objects_specs.sql' @@install_component.sql 'expectations/matchers/ut_matcher_options_items.tps' @@ -207,6 +208,7 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@install_component.sql 'core/types/ut_executable_test.tpb' @@install_component.sql 'core/types/ut_console_reporter_base.tps' @@install_component.sql 'core/types/ut_console_reporter_base.tpb' +@@install_component.sql 'core/types/ut_path_item.tpb' --expectations and matchers @@install_component.sql 'expectations/data_values/ut_compound_data_tmp.sql' diff --git a/source/uninstall_objects.sql b/source/uninstall_objects.sql index 4d77d9993..ab4069497 100644 --- a/source/uninstall_objects.sql +++ b/source/uninstall_objects.sql @@ -88,6 +88,10 @@ drop type ut_suite_items_info force; drop type ut_suite_item_info force; +drop type ut_path_items force; + +drop type ut_path_item force; + drop package ut_suite_manager; drop package ut_suite_builder; diff --git a/test/ut3_tester/core/test_suite_manager.pkb b/test/ut3_tester/core/test_suite_manager.pkb index c8b4a9453..fbac0f3f5 100644 --- a/test/ut3_tester/core/test_suite_manager.pkb +++ b/test/ut3_tester/core/test_suite_manager.pkb @@ -278,8 +278,167 @@ end test_package_with_ctx;]'; end; end test_package_with_ctx;]'; + + execute immediate q'[create or replace package test1_frontwildcard is + + --%suite + --%displayname(test1_frontwildcard) + --%suitepath(front_wildcard) + --%rollback(manual) + + --%test + --%displayname(Test1 from test test1_frontwildcard) + procedure first_test; + + --%test + --%displayname(Test2 from test test1_frontwildcard) + procedure second_test; + +end test1_frontwildcard;]'; + + execute immediate q'[create or replace package body test1_frontwildcard is + + procedure first_test is + begin + ut.expect(1).to_equal(1); + end; + + procedure second_test is + begin + ut.expect(1).to_equal(2); + end; + +end test1_frontwildcard;]'; + + execute immediate q'[create or replace package test2_frontwildcard is + + --%suite + --%displayname(test2_frontwildcard) + --%suitepath(front_wildcard) + --%rollback(manual) + + --%test + --%displayname(Test1 from test package test2_frontwildcard) + procedure first_test; + +end test2_frontwildcard;]'; + + execute immediate q'[create or replace package body test2_frontwildcard is + + procedure first_test is + begin + ut.expect(1).to_equal(1); + end; + +end test2_frontwildcard;]'; + + execute immediate q'[create or replace package middle_test1_wildcard is + + --%suite + --%displayname(middle_test1_wildcard) + --%suitepath(wild_middle_card) + --%rollback(manual) + + --%test + --%displayname(Test1 from test middle_test1_wildcard) + procedure middle_first_test; + + --%test + --%displayname(Test2 from test middle_test1_wildcard) + procedure middle_second_test; + +end middle_test1_wildcard;]'; + + execute immediate q'[create or replace package body middle_test1_wildcard is + + procedure middle_first_test is + begin + ut.expect(1).to_equal(1); + end; + + procedure middle_second_test is + begin + ut.expect(1).to_equal(2); + end; + +end middle_test1_wildcard;]'; + + execute immediate q'[create or replace package middle_test2_wildcard is + + --%suite + --%displayname(middle_test2_wildcard) + --%suitepath(wild_middle_card) + --%rollback(manual) + + --%test + --%displayname(Test1 from test package middle_test2_wildcard) + procedure middle_first_test; + +end middle_test2_wildcard;]'; + + execute immediate q'[create or replace package body middle_test2_wildcard is + + procedure middle_first_test is + begin + ut.expect(1).to_equal(1); + end; + +end middle_test2_wildcard;]'; + + execute immediate q'[create or replace package test1_multi_wildcard is + + --%suite + --%displayname(test1_multi_wildcard) + --%suitepath(wildcard_multi_asterisks) + --%rollback(manual) + + --%test + --%displayname(Test1 from test test1_multi_wildcard) + procedure first_multi_test1; + + --%test + --%displayname(Test2 from test test1_multi_wildcard) + procedure second_multi_test2; + +end test1_multi_wildcard;]'; + + execute immediate q'[create or replace package body test1_multi_wildcard is + + procedure first_multi_test1 is + begin + ut.expect(1).to_equal(1); end; + procedure second_multi_test2 is + begin + ut.expect(1).to_equal(2); + end; + +end test1_multi_wildcard;]'; + + execute immediate q'[create or replace package test2_multi_wildcard is + + --%suite + --%displayname(test2_multi_wildcard) + --%suitepath(wildcard_multi_asterisks) + --%rollback(manual) + + --%test + --%displayname(Test1 from test package test2_multi_wildcard) + procedure first_multi_test1; + +end test2_multi_wildcard;]'; + + execute immediate q'[create or replace package body test2_multi_wildcard is + + procedure first_multi_test1 is + begin + ut.expect(1).to_equal(1); + end; + +end test2_multi_wildcard;]'; + + end; procedure drop_dummy_packages is pragma autonomous_transaction; @@ -288,6 +447,12 @@ end test_package_with_ctx;]'; execute immediate 'drop package test_package_2'; execute immediate 'drop package test_package_3'; execute immediate 'drop package test_package_with_ctx'; + execute immediate 'drop package test1_frontwildcard'; + execute immediate 'drop package test2_frontwildcard'; + execute immediate 'drop package middle_test1_wildcard'; + execute immediate 'drop package middle_test2_wildcard'; + execute immediate 'drop package test1_multi_wildcard'; + execute immediate 'drop package test2_multi_wildcard'; end; procedure test_schema_run is @@ -945,6 +1110,36 @@ end;]'; ut.expect(sqlerrm).to_be_like('%failing_non_existing%'); end; + procedure test_search_nonex_pck_wild is + l_objects_to_run ut3_develop.ut_suite_items; + begin + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('ut3_develop.failing_non_*')); + ut.fail('Non existing package did not raise exception'); + exception + when others then + ut.expect(sqlerrm).to_be_like('%failing_non_*%'); + end; + + procedure test_search_nonex_prc_wild is + l_objects_to_run ut3_develop.ut_suite_items; + begin + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('ut3_tester.test_package_1.nonexist*')); + ut.fail('Non existing package did not raise exception'); + exception + when others then + ut.expect(sqlerrm).to_be_like('%nonexist*%'); + end; + + procedure test_search_nonex_path_wild is + l_objects_to_run ut3_develop.ut_suite_items; + begin + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list('ut3_develop:failing_non_*')); + ut.fail('Non existing path did not raise exception'); + exception + when others then + ut.expect(sqlerrm).to_be_like('%:failing_non_*%'); + end; + procedure test_search_nonexist_sch_pck is l_objects_to_run ut3_develop.ut_suite_items; begin @@ -1560,5 +1755,467 @@ end;]'; end; + procedure test_wild_card_obj_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.test_package_*'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + l_ctx_suite ut3_develop.ut_logical_suite; + l_test_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(3); + + + for i in 1 .. 3 loop + l_test_suite := treat(l_objects_to_run(i) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name in ('test_package_with_ctx','tests', 'tests2')).to_be_true; + + case l_test_suite.name + when 'test_package_with_ctx' then + ut.expect(l_test_suite.items.count).to_equal(1); + l_ctx_suite:= treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_ctx_suite.name).to_equal('some_context'); + ut.expect(l_ctx_suite.description).to_equal('Some context description'); + ut.expect(l_ctx_suite.items.count).to_equal(1); + l_test_proc := treat(l_ctx_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test_proc.name).to_equal('test1'); + when 'tests' then + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(3); + ut.expect(l_test1_suite.rollback_type).to_equal(ut3_develop.ut_utils.gc_rollback_manual); + l_test2_suite := treat(l_test1_suite.items(1) as ut3_develop.ut_logical_suite); + + ut.expect(l_test2_suite.name).to_equal('test_package_2'); + ut.expect(l_test2_suite.items.count).to_equal(3); + ut.expect(l_test2_suite.rollback_type).to_equal(ut3_develop.ut_utils.gc_rollback_manual); + when 'tests2' then + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('test_package_3'); + ut.expect(l_test1_suite.items.count).to_equal(3); + end case; + + end loop; + + end; + + procedure test_wild_card_prc_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.test_package_1.test*'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('tests'); + + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(2); + + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('test1'); + + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('test2'); + end; + + procedure test_wild_card_path_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':tests*'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test2_suite ut3_develop.ut_logical_suite; + l_ctx_suite ut3_develop.ut_logical_suite; + l_test_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(2); + + + for i in 1 .. 2 loop + l_test_suite := treat(l_objects_to_run(i) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name in ('tests', 'tests2')).to_be_true; + + case l_test_suite.name + when 'tests' then + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('test_package_1'); + ut.expect(l_test1_suite.items.count).to_equal(3); + + for i in 1 ..3 loop + case l_test1_suite.items(i).self_type + when 'UT_SUITE' then + l_test2_suite := treat(l_test1_suite.items(i) as ut3_develop.ut_logical_suite); + ut.expect(l_test2_suite.name).to_equal('test_package_2'); + ut.expect(l_test2_suite.items.count).to_equal(3); + + l_test_proc := treat(l_test2_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test_proc.name in ('test1', 'test2','context_test')).to_be_true; + + l_test_proc := treat(l_test2_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test_proc.name in ('test1', 'test2','context_test')).to_be_true; + + l_test_proc := treat(l_test2_suite.items(3) as ut3_develop.ut_test); + ut.expect(l_test_proc.name in ('test1', 'test2','context_test')).to_be_true; + + when 'UT_TEST' then + l_test_proc := treat(l_test1_suite.items(i) as ut3_develop.ut_test); + ut.expect(l_test_proc.name in ('test1', 'test2')).to_be_true; + end case; + end loop; + when 'tests2' then + ut.expect(l_test_suite.items.count).to_equal(1); + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('test_package_3'); + ut.expect(l_test1_suite.items.count).to_equal(3); + for i in 1 .. 3 loop + l_test_proc := treat(l_test1_suite.items(i) as ut3_develop.ut_test); + ut.expect(l_test_proc.name in ('test1', 'test2','disabled_test')).to_be_true; + end loop; + end case; + + end loop; + + end; + + procedure test_wild_card_front_obj_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.*_frontwildcard'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('front_wildcard'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'test1_frontwildcard' then + ut.expect(l_test1_suite.items.count).to_equal(2); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_test'); + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('second_test'); + when 'test2_frontwildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_test'); + end case; + + end loop; + end; + + procedure test_wild_card_front_prc_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.test1_frontwildcard.*_test'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('front_wildcard'); + + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('test1_frontwildcard'); + ut.expect(l_test1_suite.items.count).to_equal(2); + + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_test'); + + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('second_test'); + end; + + procedure test_wild_card_front_path_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':*_wildcard'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('front_wildcard'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'test1_frontwildcard' then + ut.expect(l_test1_suite.items.count).to_equal(2); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_test'); + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('second_test'); + when 'test2_frontwildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_test'); + end case; + + end loop; + end; + + procedure test_wild_card_mid_obj_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.middle_*_wildcard'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wild_middle_card'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'middle_test1_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(2); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('middle_first_test'); + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('middle_second_test'); + when 'middle_test2_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('middle_first_test'); + end case; + + end loop; + end; + + procedure test_wild_card_mid_prc_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.middle_test1_wildcard.middle_*_test'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wild_middle_card'); + + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('middle_test1_wildcard'); + ut.expect(l_test1_suite.items.count).to_equal(2); + + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('middle_first_test'); + + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('middle_second_test'); + end; + + procedure test_wild_card_mid_path_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':wild_*card'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wild_middle_card'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'middle_test1_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(2); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('middle_first_test'); + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('middle_second_test'); + when 'middle_test2_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('middle_first_test'); + end case; + + end loop; + end; + + procedure test_wild_card_mul_obj_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.*_multi_*card'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wildcard_multi_asterisks'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'test1_multi_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(2); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('second_multi_test2'); + when 'test2_multi_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + end case; + + end loop; + end; + + procedure test_wild_card_mul_prc_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||'.test1_multi_wildcard.*_multi_*'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wildcard_multi_asterisks'); + + l_test1_suite := treat(l_test_suite.items(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test1_suite.name).to_equal('test1_multi_wildcard'); + ut.expect(l_test1_suite.items.count).to_equal(2); + + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('second_multi_test2'); + end; + + procedure test_wild_card_mul_path_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':wild*_multi_*risks'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wildcard_multi_asterisks'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'test1_multi_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(2); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + l_test2_proc := treat(l_test1_suite.items(2) as ut3_develop.ut_test); + ut.expect(l_test2_proc.name).to_equal('second_multi_test2'); + when 'test2_multi_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + end case; + + end loop; + end; + + procedure tst_wild_card_mul_lv_path_name is + c_path varchar2(100) := sys_context('USERENV', 'CURRENT_USER')||':wild*_multi_*risks.*_multi_wildcard.*_multi_test1'; + l_objects_to_run ut3_develop.ut_suite_items; + l_test_suite ut3_develop.ut_logical_suite; + l_test1_suite ut3_develop.ut_logical_suite; + l_test1_proc ut3_develop.ut_test; + l_test2_proc ut3_develop.ut_test; + begin + --Act + l_objects_to_run := ut3_develop.ut_suite_manager.configure_execution_by_path(ut3_develop.ut_varchar2_list(c_path)); + + --Assert + ut.expect(l_objects_to_run.count).to_equal(1); + l_test_suite := treat(l_objects_to_run(1) as ut3_develop.ut_logical_suite); + ut.expect(l_test_suite.name).to_equal('wildcard_multi_asterisks'); + ut.expect(l_test_suite.items.count).to_equal(2); + + for i in 1 .. 2 loop + l_test1_suite := treat(l_test_suite.items(i) as ut3_develop.ut_logical_suite); + case l_test1_suite.name + when 'test1_multi_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + when 'test2_multi_wildcard' then + ut.expect(l_test1_suite.items.count).to_equal(1); + l_test1_proc := treat(l_test1_suite.items(1) as ut3_develop.ut_test); + ut.expect(l_test1_proc.name).to_equal('first_multi_test1'); + end case; + + end loop; + end; + end test_suite_manager; / diff --git a/test/ut3_tester/core/test_suite_manager.pks b/test/ut3_tester/core/test_suite_manager.pks index 154df9ca6..d9d4efc09 100644 --- a/test/ut3_tester/core/test_suite_manager.pks +++ b/test/ut3_tester/core/test_suite_manager.pks @@ -75,8 +75,17 @@ create or replace package test_suite_manager is --%test(Prepare runner for nonexisting package with schema) procedure test_search_nonexisting_pck; - - --%test(Prepare runner for nonexisting package without schema) + + --%test(Prepare runner for nonexisting package using wildcard filter) + procedure test_search_nonex_pck_wild; + + --%test(Prepare runner for nonexisting procedure using wildcard filter) + procedure test_search_nonex_prc_wild; + + --%test(Prepare runner for nonexisting path using wildcard filter) + procedure test_search_nonex_path_wild; + + --%test(Prepare runner for nonexisting package without schema) procedure test_search_nonexist_sch_pck; --%test(Test description with comma) @@ -185,6 +194,48 @@ create or replace package test_suite_manager is --%aftertest(clean_remove_annot_test) procedure test_rem_cache_on_crt_anno; + --%context(wildcard_filters) + + --%test(Execute test_packages using a object_name with wildcard at the end ) + procedure test_wild_card_obj_name; + + --%test(Execute test_packages using a procedure name with wildcard at the end) + procedure test_wild_card_prc_name; + + --%test(Execute test_packages using a path name with wildcard at the end) + procedure test_wild_card_path_name; + + --%test(Execute test_packages using a object_name with wildcard in the front) + procedure test_wild_card_front_obj_name; + + --%test(Execute test_packages using a procedure name with wildcard in the front) + procedure test_wild_card_front_prc_name; + + -- %test(Execute test_packages using a path name with wildcard in the front) + procedure test_wild_card_front_path_name; + + --%test(Execute test_packages using a object_name with wildcard in the middle) + procedure test_wild_card_mid_obj_name; + + --%test(Execute test_packages using a procedure name with wildcard in the middle) + procedure test_wild_card_mid_prc_name; + + -- %test(Execute test_packages using a path name with wildcard in the middle) + procedure test_wild_card_mid_path_name; + + --%test(Execute test_packages using a object_name with multiple wildcards) + procedure test_wild_card_mul_obj_name; + + --%test(Execute test_packages using a procedure name with multiple wildcards) + procedure test_wild_card_mul_prc_name; + + -- %test(Execute test_packages using a path name with multiple wildcards) + procedure test_wild_card_mul_path_name; + + -- %test(Execute test_packages using a path name with multiple wildcards on different level) + procedure tst_wild_card_mul_lv_path_name; + + --%endcontext end test_suite_manager; / diff --git a/test/ut3_user/api/test_ut_run.pkb b/test/ut3_user/api/test_ut_run.pkb index 492efcba2..41b969359 100644 --- a/test/ut3_user/api/test_ut_run.pkb +++ b/test/ut3_user/api/test_ut_run.pkb @@ -854,7 +854,7 @@ Failures:% l_results ut3_develop.ut_varchar2_list; begin select * bulk collect into l_random_results - from table ( ut3_develop.ut.run( 'ut3_tester_helper.test_package_1', a_random_test_order_seed => 3 ) ) + from table ( ut3_develop.ut.run( 'ut3_tester_helper.test_package_1', a_random_test_order_seed => 6 ) ) where trim(column_value) is not null and column_value not like 'Finished in %' and column_value not like '%Tests were executed with random order %'; diff --git a/test/ut3_user/api/test_ut_runner.pkb b/test/ut3_user/api/test_ut_runner.pkb index 80b1cd60b..b6b7c67e7 100644 --- a/test/ut3_user/api/test_ut_runner.pkb +++ b/test/ut3_user/api/test_ut_runner.pkb @@ -344,6 +344,38 @@ end;'; ut.expect(l_actual).to_equal(l_expected); end; + procedure test_get_suites_info_by_path is + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for + select + 'UT3_USER' object_owner, 'DUMMY_TEST_PACKAGE' object_name, 'DUMMY_TEST_PACKAGE' item_name, + 'dummy_test_suite' item_description, 'UT_SUITE' item_type, 2 item_line_no, + 'some.path.dummy_test_package' path, 0 disabled_flag, null disabled_reason,null tags + from dual union all + select + 'UT3_USER' object_owner, 'DUMMY_TEST_PACKAGE' object_name, 'SOME_DUMMY_TEST_PROCEDURE' item_name, + 'dummy_test' item_description, 'UT_TEST' item_type, 6 item_line_no, + 'some.path.dummy_test_package.some_dummy_test_procedure' path, 0 disabled_flag, null disabled_reason,null tags + from dual union all + select + 'UT3_USER' object_owner, 'PATH' object_name, 'PATH' item_name, + null item_description, 'UT_LOGICAL_SUITE' item_type, null item_line_no, + 'some.path' path, 0 disabled_flag, null disabled_reason, null tags + from dual union all + select + 'UT3_USER' object_owner, 'SOME' object_name, 'SOME' item_name, + null item_description, 'UT_LOGICAL_SUITE' item_type, null item_line_no, + 'some' path, 0 disabled_flag, null disabled_reason, null tags + from dual; + --Act + open l_actual for select * from table(ut3_develop.ut_runner.get_suites_info('ut3_user:some.path.dummy_test_package')); + --Assert + ut.expect(l_actual).to_equal(l_expected); + end; + procedure test_get_reporters_list is l_expected sys_refcursor; l_actual sys_refcursor; diff --git a/test/ut3_user/api/test_ut_runner.pks b/test/ut3_user/api/test_ut_runner.pks index 08282e997..e003ba852 100644 --- a/test/ut3_user/api/test_ut_runner.pks +++ b/test/ut3_user/api/test_ut_runner.pks @@ -65,6 +65,11 @@ create or replace package test_ut_runner is --%aftertest(cleanup_cache) procedure test_get_suites_info_twotag; + --%test(get_suites_info returns a cursor containing records for a newly created test with passed path) + --%beforetest(setup_cache_objects) + --%aftertest(cleanup_cache) + procedure test_get_suites_info_by_path; + --%test(get_reporters_list returns a cursor containing all built-in reporters and information about output-reporter) --%beforetest(setup_cache_objects) --%aftertest(cleanup_cache)