diff --git a/.travis/install.sh b/.travis/install.sh index 4806105b1..2e96ebfb2 100755 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -74,10 +74,6 @@ PROMPT Creating $UT3_TESTER - Power-user for testing internal framework code create user $UT3_TESTER identified by "$UT3_TESTER_PASSWORD" default tablespace $UT3_TABLESPACE quota unlimited on $UT3_TABLESPACE; grant create session, create procedure, create type, create table to $UT3_TESTER; -PROMPT Additional grants for disabling DDL trigger and testing parser without trigger enabled/present - -grant alter any trigger to $UT3_TESTER; -grant administer database trigger to $UT3_TESTER; grant execute on dbms_lock to $UT3_TESTER; PROMPT Granting $UT3_OWNER code to $UT3_TESTER @@ -98,7 +94,7 @@ end; PROMPT Granting $UT3_OWNER tables to $UT3_TESTER begin - for i in ( select table_name from all_tables t where owner = 'UT3' and nested = 'NO' and IOT_NAME is NULL) + for i in ( select table_name from all_tables t where owner = 'UT3' and nested = 'NO' and iot_name is null) loop execute immediate 'grant select on UT3.'||i.table_name||' to UT3_TESTER'; end loop; @@ -124,8 +120,33 @@ grant create public database link to $UT3_TESTER_HELPER; grant drop public database link to $UT3_TESTER_HELPER; PROMPT Grants for testing coverage outside of main UT3 schema. -grant create any procedure, drop any procedure, execute any procedure, create any type, drop any type, execute any type, under any type, select any table, update any table, insert any table, delete any table, create any table, drop any table, alter any table, select any dictionary, create any synonym, drop any synonym to $UT3_TESTER_HELPER; +grant create any procedure, drop any procedure, execute any procedure, create any type, drop any type, execute any type, under any type, + select any table, update any table, insert any table, delete any table, create any table, drop any table, alter any table, + select any dictionary, create any synonym, drop any synonym, + grant any object privilege, grant any privilege + to $UT3_TESTER_HELPER; + grant create job to $UT3_TESTER_HELPER; +PROMPT Additional grants for disabling DDL trigger and testing parser without trigger enabled/present + +grant alter any trigger to $UT3_TESTER_HELPER; +grant administer database trigger to $UT3_TESTER_HELPER; +grant execute on dbms_lock to $UT3_TESTER_HELPER; + +create user ut3_cache_test_owner identified by ut3; +grant create session, create procedure to ut3_cache_test_owner; + +create user ut3_no_extra_priv_user identified by ut3; +grant create session, create procedure to ut3_no_extra_priv_user; + +create user ut3_select_catalog_user identified by ut3; +grant create session, create procedure, select_catalog_role to ut3_select_catalog_user; + +create user ut3_select_any_table_user identified by ut3; +grant create session, create procedure, select any table to ut3_select_any_table_user; + +create user ut3_execute_any_proc_user identified by ut3; +grant create session, create procedure, execute any procedure to ut3_execute_any_proc_user; exit SQL diff --git a/development/cleanup.sh b/development/cleanup.sh index 313e382ca..4df1e43f5 100755 --- a/development/cleanup.sh +++ b/development/cleanup.sh @@ -23,6 +23,11 @@ drop user ${UT3_RELEASE_VERSION_SCHEMA} cascade; drop user ${UT3_TESTER} cascade; drop user ${UT3_TESTER_HELPER} cascade; drop user ${UT3_USER} cascade; +drop user ut3_cache_test_owner cascade; +drop user ut3_no_extra_priv_user cascade; +drop user ut3_select_catalog_user cascade; +drop user ut3_select_any_table_user cascade; +drop user ut3_execute_any_proc_user cascade; begin for i in ( diff --git a/docs/userguide/install.md b/docs/userguide/install.md index 0a7a04b35..dd80f98ee 100644 --- a/docs/userguide/install.md +++ b/docs/userguide/install.md @@ -138,13 +138,6 @@ cd source sqlplus sys/sys_pass@db as sysdba @install_headless_with_trigger.sql utp3 my_verySecret_password utp3_tablespace ``` -**Note:** ->When installing utPLSQL into database with existing unit test packages, utPLSQL will not be able to already-existing unit test packages. When utPSLQL was installed with DDL trigger, you have to do one of: ->- Recompile existing Unit Test packages to make utPLSQL aware of their existence ->- Invoke `exec ut_runner.rebuild_annotation_cache(a_object_owner=> ... );` for every schema containing unit tests in your database -> -> Steps above are required to assure annotation cache is populated properly from existing objects. Rebuilding annotation cache might be faster than code recompilation. - # Recommended Schema It is highly recommended to install utPLSQL in it's own schema. You are free to choose any name for this schema. Installing uPLSQL into shared schema is really not recommended as you loose isolation of framework. diff --git a/source/core/annotations/ut_annotation_cache_info.sql b/source/core/annotations/ut_annotation_cache_info.sql index e8dc2bfdb..7bbf99e00 100644 --- a/source/core/annotations/ut_annotation_cache_info.sql +++ b/source/core/annotations/ut_annotation_cache_info.sql @@ -17,7 +17,8 @@ create table ut_annotation_cache_info ( object_name varchar2(250) not null, object_type varchar2(250) not null, parse_time timestamp not null, - constraint ut_annotation_cache_info_pk primary key(cache_id), - constraint ut_annotation_cache_info_uk unique (object_owner, object_type, object_name) + constraint ut_annotation_cache_info_pk primary key(cache_id) using index, + constraint ut_annotation_cache_info_uk unique (object_owner, object_type, object_name) using index, + constraint ut_annotation_cache_info_fk foreign key(object_owner, object_type) references ut_annotation_cache_schema(object_owner, object_type) on delete cascade ) organization index; diff --git a/source/core/annotations/ut_annotation_cache_manager.pkb b/source/core/annotations/ut_annotation_cache_manager.pkb index eb60ac3dd..4882108fc 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pkb +++ b/source/core/annotations/ut_annotation_cache_manager.pkb @@ -17,15 +17,25 @@ create or replace package body ut_annotation_cache_manager as */ procedure update_cache(a_object ut_annotated_object) is - l_cache_id integer; - l_new_objects_count integer := 0; + l_cache_id integer; + l_timestamp timestamp := systimestamp; pragma autonomous_transaction; begin + update ut_annotation_cache_schema s + set s.max_parse_time = l_timestamp + where s.object_type = a_object.object_type and s.object_owner = a_object.object_owner; + + if sql%rowcount = 0 then + insert into ut_annotation_cache_schema s + (object_owner, object_type, max_parse_time) + values (a_object.object_owner, a_object.object_type, l_timestamp); + end if; + -- if not in trigger, or object has annotations if ora_sysevent is null or a_object.annotations is not null and a_object.annotations.count > 0 then update ut_annotation_cache_info i - set i.parse_time = systimestamp + set i.parse_time = l_timestamp where (i.object_owner, i.object_name, i.object_type) in ((a_object.object_owner, a_object.object_name, a_object.object_type)) returning cache_id into l_cache_id; @@ -34,23 +44,12 @@ create or replace package body ut_annotation_cache_manager as insert into ut_annotation_cache_info (cache_id, object_owner, object_name, object_type, parse_time) - values (ut_annotation_cache_seq.nextval, a_object.object_owner, a_object.object_name, a_object.object_type, systimestamp) + values (ut_annotation_cache_seq.nextval, a_object.object_owner, a_object.object_name, a_object.object_type, l_timestamp) returning cache_id into l_cache_id; - l_new_objects_count := 1; end if; end if; - update ut_annotation_cache_schema s - set s.object_count = s.object_count + l_new_objects_count, s.max_parse_time = systimestamp - where s.object_type = a_object.object_type and s.object_owner = a_object.object_owner; - - if sql%rowcount = 0 then - insert into ut_annotation_cache_schema s - (object_owner, object_type, object_count, max_parse_time) - values (a_object.object_owner, a_object.object_type, l_new_objects_count, systimestamp); - end if; - delete from ut_annotation_cache c where cache_id = l_cache_id; if a_object.annotations is not null and a_object.annotations.count > 0 then @@ -63,7 +62,8 @@ create or replace package body ut_annotation_cache_manager as end; - procedure cleanup_cache(a_objects ut_annotation_objs_cache_info) is + procedure reset_objects_cache(a_objects ut_annotation_objs_cache_info) is + l_timestamp timestamp := systimestamp; pragma autonomous_transaction; begin @@ -75,23 +75,45 @@ create or replace package body ut_annotation_cache_manager as on o.object_name = i.object_name and o.object_type = i.object_type and o.object_owner = i.object_owner + and o.needs_refresh = 'Y' ); + update ut_annotation_cache_schema s + set s.max_parse_time = l_timestamp + where (s.object_owner, s.object_type) + in ( + select o.object_owner, o.object_type + from table(a_objects) o + where o.needs_refresh = 'Y' + ); + + if sql%rowcount = 0 then + insert into ut_annotation_cache_schema s + (object_owner, object_type, max_parse_time) + select distinct o.object_owner, o.object_type, l_timestamp + from table(a_objects) o + where o.needs_refresh = 'Y'; + end if; + merge into ut_annotation_cache_info i using (select o.object_name, o.object_type, o.object_owner - from table(a_objects) o ) o + from table(a_objects) o + where o.needs_refresh = 'Y' + ) o on (o.object_name = i.object_name and o.object_type = i.object_type and o.object_owner = i.object_owner) - when matched then update set parse_time = systimestamp + when matched then + update + set parse_time = l_timestamp when not matched then insert - (cache_id, object_owner, object_name, object_type, parse_time) - values (ut_annotation_cache_seq.nextval, o.object_owner, o.object_name, o.object_type, systimestamp); + (cache_id, object_owner, object_name, object_type, parse_time) + values (ut_annotation_cache_seq.nextval, o.object_owner, o.object_name, o.object_type, l_timestamp); commit; end; - function get_annotations_objects_info(a_object_owner varchar2, a_object_type varchar2) return ut_annotation_objs_cache_info is + function get_cached_objects_list(a_object_owner varchar2, a_object_type varchar2, a_parsed_after timestamp := null) return ut_annotation_objs_cache_info is l_result ut_annotation_objs_cache_info; begin select ut_annotation_obj_cache_info( @@ -104,7 +126,8 @@ create or replace package body ut_annotation_cache_manager as bulk collect into l_result from ut_annotation_cache_info i where i.object_owner = a_object_owner - and i.object_type = a_object_type; + and i.object_type = a_object_type + and (i.parse_time > a_parsed_after or a_parsed_after is null); return l_result; end; @@ -123,6 +146,16 @@ create or replace package body ut_annotation_cache_manager as return l_result; end; + procedure set_fully_refreshed(a_object_owner varchar2, a_object_type varchar2) is + pragma autonomous_transaction; + begin + update ut_annotation_cache_schema s + set s.full_refresh_time = s.max_parse_time + where s.object_owner = a_object_owner + and s.object_type = a_object_type; + commit; + end; + procedure remove_from_cache(a_objects ut_annotation_objs_cache_info) is pragma autonomous_transaction; begin @@ -138,10 +171,10 @@ create or replace package body ut_annotation_cache_manager as commit; end; - function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info, a_parse_time timestamp) return sys_refcursor is - l_results sys_refcursor; + function get_annotations_parsed_since(a_object_owner varchar2, a_object_type varchar2, a_parsed_after timestamp) return sys_refcursor is + l_results sys_refcursor; begin - open l_results for q'[ + open l_results for select ut_annotated_object( i.object_owner, i.object_name, i.object_type, i.parse_time, cast( @@ -151,14 +184,12 @@ create or replace package body ut_annotation_cache_manager as ) order by c.annotation_position ) as ut_annotations ) - ) - from table(:a_cached_objects) o - join ut_annotation_cache_info i - on o.object_owner = i.object_owner and o.object_name = i.object_name and o.object_type = i.object_type + ) as annotated_object + from ut_annotation_cache_info i join ut_annotation_cache c on i.cache_id = c.cache_id - where ]'|| case when a_parse_time is null then ':a_parse_date is null' else 'i.parse_time > :a_parse_time' end ||q'[ - group by i.object_owner, i.object_name, i.object_type, i.parse_time]' - using a_cached_objects, a_parse_time; + where i.object_owner = a_object_owner and i.object_type = a_object_type + and (i.parse_time > a_parsed_after or a_parsed_after is null) + group by i.object_owner, i.object_type, i.object_name, i.parse_time; return l_results; end; @@ -168,35 +199,24 @@ create or replace package body ut_annotation_cache_manager as pragma autonomous_transaction; begin if a_object_owner is null and a_object_type is null then - l_cache_filter := ':a_object_owner is null and :a_object_type is null'; - l_filter := l_cache_filter; + l_filter := ':a_object_owner is null and :a_object_type is null'; + l_cache_filter := l_filter; else - l_filter := - case when a_object_owner is null then ':a_object_owner is null' else 'object_owner = :a_object_owner' end || ' - and '||case when a_object_type is null then ':a_object_type is null' else 'object_type = :a_object_type' end; - l_cache_filter := ' c.cache_id - in (select i.cache_id - from ut_annotation_cache_info i - where '|| l_filter || ' - )'; + l_filter := case when a_object_owner is null then ':a_object_owner is null' else 'object_owner = :a_object_owner' end; + l_filter := l_filter || ' and ' || case when a_object_type is null then ':a_object_type is null' else 'object_type = :a_object_type' end; + l_cache_filter := ' c.cache_id in (select i.cache_id from ut_annotation_cache_info i where ' || l_filter || ' )'; end if; - execute immediate ' - delete from ut_annotation_cache c - where '||l_cache_filter + execute immediate 'delete from ut_annotation_cache c where ' || l_cache_filter using a_object_owner, a_object_type; - execute immediate ' - delete from ut_annotation_cache_info i - where ' || l_filter + execute immediate ' delete from ut_annotation_cache_info i where ' || l_filter using a_object_owner, a_object_type; - execute immediate ' - delete from ut_annotation_cache_schema s - where ' || l_filter + execute immediate ' delete from ut_annotation_cache_schema s where ' || l_filter using a_object_owner, a_object_type; commit; end; -end ut_annotation_cache_manager; +end; / diff --git a/source/core/annotations/ut_annotation_cache_manager.pks b/source/core/annotations/ut_annotation_cache_manager.pks index 2a1d60f1e..e4ba6dd7a 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pks +++ b/source/core/annotations/ut_annotation_cache_manager.pks @@ -16,6 +16,7 @@ create or replace package ut_annotation_cache_manager authid definer as limitations under the License. */ subtype t_cache_schema_info is ut_annotation_cache_schema%rowtype; + /** * Populates cache with information about object and it's annotations * Cache information for individual object is modified by this code @@ -30,21 +31,27 @@ create or replace package ut_annotation_cache_manager authid definer as * Returns a ref_cursor containing `ut_annotated_object` as result * Range of data returned is limited by the input collection o cache object info * - * @param a_cached_objects a `ut_annotation_objs_cache_info` list with information about objects to get from cache + * @param a_cached_objects - list of `ut_annotation_objs_cache_info` containing objects to get from cache + * @param a_min_parse_time - limit results to annotations parsed after specified time only, + * if null - all cached annotations for given objects are returned */ - function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info, a_parse_time timestamp) return sys_refcursor; - + function get_annotations_parsed_since(a_object_owner varchar2, a_object_type varchar2, a_parsed_after timestamp) return sys_refcursor; - function get_annotations_objects_info(a_object_owner varchar2, a_object_type varchar2) return ut_annotation_objs_cache_info; + procedure set_fully_refreshed(a_object_owner varchar2, a_object_type varchar2); function get_cache_schema_info(a_object_owner varchar2, a_object_type varchar2) return t_cache_schema_info; /** - * Removes cached information about annotations for objects on the list and updates parse_time in cache info table. + * Returns information about all objects stored in annotation cache + */ + function get_cached_objects_list(a_object_owner varchar2, a_object_type varchar2, a_parsed_after timestamp := null) return ut_annotation_objs_cache_info; + + /** + * Resets cached information about annotations for objects on the list and updates parse_time in cache info table. * * @param a_objects a `ut_annotation_objs_cache_info` list with information about objects to remove annotations for */ - procedure cleanup_cache(a_objects ut_annotation_objs_cache_info); + procedure reset_objects_cache(a_objects ut_annotation_objs_cache_info); /** * Removes information about objects on the list diff --git a/source/core/annotations/ut_annotation_cache_schema.sql b/source/core/annotations/ut_annotation_cache_schema.sql index abab7385e..b8f908e84 100644 --- a/source/core/annotations/ut_annotation_cache_schema.sql +++ b/source/core/annotations/ut_annotation_cache_schema.sql @@ -12,10 +12,10 @@ create table ut_annotation_cache_schema ( See the License for the specific language governing permissions and limitations under the License. */ - object_owner varchar2(250) not null, - object_type varchar2(250) not null, - object_count integer not null, - max_parse_time date not null, + object_owner varchar2(250) not null, + object_type varchar2(250) not null, + max_parse_time date not null, + full_refresh_time timestamp, constraint ut_annotation_cache_schema_pk primary key(object_owner, object_type) ) organization index; diff --git a/source/core/annotations/ut_annotation_manager.pkb b/source/core/annotations/ut_annotation_manager.pkb index fd2997632..a37391d37 100644 --- a/source/core/annotations/ut_annotation_manager.pkb +++ b/source/core/annotations/ut_annotation_manager.pkb @@ -19,86 +19,85 @@ create or replace package body ut_annotation_manager as ------------------------------ --private definitions - function get_missing_objects(a_object_owner varchar2, a_object_type varchar2) return ut_annotation_objs_cache_info is - l_rows sys_refcursor; - l_ut_owner varchar2(250) := ut_utils.ut_owner; - l_objects_view varchar2(200) := ut_metadata.get_objects_view_name(); - l_cursor_text varchar2(32767); - l_data ut_annotation_objs_cache_info; - l_result ut_annotation_objs_cache_info; - l_card natural; + function user_can_see_whole_schema( a_schema_name varchar2 ) return boolean is begin - l_data := ut_annotation_cache_manager.get_annotations_objects_info(a_object_owner, a_object_type); - l_card := ut_utils.scale_cardinality(cardinality(l_data)); - - l_cursor_text := - 'select /*+ cardinality(i '||l_card||') */ - value(i) - from table( cast( :l_data as '||l_ut_owner||'.ut_annotation_objs_cache_info ) ) i - where - not exists ( - select 1 from '||l_objects_view||q'[ o - where o.owner = i.object_owner - and o.object_name = i.object_name - and o.object_type = i.object_type - and o.owner = ']'||ut_utils.qualified_sql_name(a_object_owner)||q'[' - and o.object_type = ']'||ut_utils.qualified_sql_name(a_object_type)||q'[' - )]'; - open l_rows for l_cursor_text using l_data; - fetch l_rows bulk collect into l_result limit ut_utils.gc_max_objects_fetch_limit; - close l_rows; - return l_result; + return sys_context('userenv','current_schema') = a_schema_name + or ut_metadata.user_has_execute_any_proc() + or ut_metadata.is_object_visible('dba_objects'); end; - function get_annotation_objs_info( - a_object_owner varchar2, - a_object_type varchar2, - a_parse_date timestamp := null, - a_full_scan boolean := true - ) return ut_annotation_objs_cache_info is - l_rows sys_refcursor; - l_ut_owner varchar2(250) := ut_utils.ut_owner; - l_objects_view varchar2(200) := ut_metadata.get_objects_view_name(); - l_cursor_text varchar2(32767); - l_data ut_annotation_objs_cache_info; - l_result ut_annotation_objs_cache_info; + function get_non_existing_objects( a_object_owner varchar2, a_object_type varchar2 ) return ut_annotation_objs_cache_info is + l_objects_view varchar2(200) := ut_metadata.get_objects_view_name(); + l_object_to_delete ut_annotation_objs_cache_info := ut_annotation_objs_cache_info(); + l_cached_objects ut_annotation_objs_cache_info; begin - ut_event_manager.trigger_event( - 'get_annotation_objs_info - start ( a_full_scan = ' || ut_utils.to_string(a_full_scan) || ' )' - ); + l_cached_objects := ut_annotation_cache_manager.get_cached_objects_list( a_object_owner, a_object_type ); + + if l_cached_objects is not empty then + execute immediate 'select /*+ cardinality(i '||ut_utils.scale_cardinality(cardinality(l_cached_objects))||') */ + value(i) + from table( :l_data ) i + where + not exists ( + select 1 from '||l_objects_view||q'[ o + where o.owner = i.object_owner + and o.object_name = i.object_name + and o.object_type = i.object_type + and o.owner = ']'||ut_utils.qualified_sql_name(a_object_owner)||q'[' + and o.object_type = ']'||ut_utils.qualified_sql_name(a_object_type)||q'[' + )]' + bulk collect into l_object_to_delete + using l_cached_objects; + end if; + return l_object_to_delete; + end; - l_data := ut_annotation_cache_manager.get_annotations_objects_info(a_object_owner, a_object_type); + function get_objects_to_refresh( + a_object_owner varchar2, + a_object_type varchar2, + a_modified_after timestamp + ) return ut_annotation_objs_cache_info is + l_ut_owner varchar2(250) := ut_utils.ut_owner; + l_refresh_needed boolean; + l_objects_view varchar2(200) := ut_metadata.get_objects_view_name(); + l_cached_objects ut_annotation_objs_cache_info; + l_result ut_annotation_objs_cache_info; + begin + ut_event_manager.trigger_event( 'get_objects_to_refresh - start' ); - if not a_full_scan then - l_result := l_data; - else - l_cursor_text := - 'select /*+ cardinality(i '||ut_utils.scale_cardinality(cardinality(l_data))||') */ - '||l_ut_owner||q'[.ut_annotation_obj_cache_info( - object_owner => o.owner, - object_name => o.object_name, - object_type => o.object_type, - needs_refresh => case when o.last_ddl_time < cast(i.parse_time as date) then 'N' else 'Y' end, - parse_time => i.parse_time - ) - from ]'||l_objects_view||' o - left join table( cast(:l_data as '||l_ut_owner||q'[.ut_annotation_objs_cache_info ) ) i - on o.owner = i.object_owner - and o.object_name = i.object_name - and o.object_type = i.object_type - where o.owner = ']'||ut_utils.qualified_sql_name(a_object_owner)||q'[' - and o.object_type = ']'||ut_utils.qualified_sql_name(a_object_type)||q'[' - and ]' + l_refresh_needed := ( ut_trigger_check.is_alive() = false ) or a_modified_after is null; + l_cached_objects := ut_annotation_cache_manager.get_cached_objects_list( a_object_owner, a_object_type, a_modified_after ); + if l_refresh_needed then + --limit the list to objects that exist and are visible to the invoking user + --enrich the list by info about cache validity + execute immediate + 'select /*+ cardinality(i '||ut_utils.scale_cardinality(cardinality(l_cached_objects))||') */ + '||l_ut_owner||q'[.ut_annotation_obj_cache_info( + object_owner => o.owner, + object_name => o.object_name, + object_type => o.object_type, + needs_refresh => 'Y', + parse_time => c.parse_time + ) + from ]'||l_objects_view||' o + left join table( cast(:l_cached_objects as '||l_ut_owner||q'[.ut_annotation_objs_cache_info ) ) c + on o.owner = c.object_owner + and o.object_name = c.object_name + and o.object_type = c.object_type + where o.owner = ']'||ut_utils.qualified_sql_name(a_object_owner)||q'[' + and o.object_type = ']'||ut_utils.qualified_sql_name(a_object_type)||q'[' + and case when o.last_ddl_time < cast(c.parse_time as date) then 'N' else 'Y' end = 'Y' + and ]' || case - when a_parse_date is null - then ':a_parse_date is null' - else 'o.last_ddl_time >= cast(:a_parse_date as date)' - end; - open l_rows for l_cursor_text using l_data, a_parse_date; - fetch l_rows bulk collect into l_result limit ut_utils.gc_max_objects_fetch_limit; - close l_rows; + when a_modified_after is null + then ':a_modified_after is null' + else 'o.last_ddl_time >= cast(:a_modified_after as date)' + end + bulk collect into l_result using l_cached_objects, a_modified_after; + else + l_result := l_cached_objects; end if; - ut_event_manager.trigger_event('get_annotation_objs_info - end (count='||l_result.count||')'); + ut_event_manager.trigger_event('get_objects_to_refresh - end (count='||l_result.count||')'); return l_result; end; @@ -109,24 +108,24 @@ create or replace package body ut_annotation_manager as begin l_card := ut_utils.scale_cardinality(cardinality(a_objects_to_refresh)); open l_result for - q'[select s.name, s.text + q'[select x.name, x.text from (select /*+ cardinality( r ]'||l_card||q'[ )*/ s.name, s.text, s.line, max(case when s.text like '%--%\%%' escape '\' - and regexp_like(s.text,'--\s*%') + and regexp_like(s.text,'^\s*--\s*%') then 'Y' else 'N' end ) over(partition by s.name) is_annotated from table(:a_objects_to_refresh) r join ]'||l_sources_view||q'[ s - on s.name = r.object_name + on s.name = r.object_name and s.owner = r.object_owner - and s.type = r.object_type - where s.owner = ']'||ut_utils.qualified_sql_name(a_object_owner)||q'[' - and s.type = ']'||ut_utils.qualified_sql_name(a_object_type)||q'[' - ) s - where s.is_annotated = 'Y' - order by s.name, s.line]' + and s.type = r.object_type + where s.owner = ']'||ut_utils.qualified_sql_name(a_object_owner)||q'[' + and s.type = ']'||ut_utils.qualified_sql_name(a_object_type)||q'[' + ) x + where x.is_annotated = 'Y' + order by x.name, x.line]' using a_objects_to_refresh; return l_result; @@ -174,47 +173,57 @@ create or replace package body ut_annotation_manager as end; - procedure refresh_annotation_cache( - a_object_owner varchar2, - a_object_type varchar2, - a_info_rows ut_annotation_objs_cache_info + procedure validate_annotation_cache( + a_object_owner varchar2, + a_object_type varchar2, + a_modified_after timestamp := null ) is - l_objects_to_parse ut_annotation_objs_cache_info; + l_objects_to_refresh ut_annotation_objs_cache_info; + l_modified_after timestamp := a_modified_after; begin - select value(x) - bulk collect into l_objects_to_parse - from table(a_info_rows) x where x.needs_refresh = 'Y'; + if ut_annotation_cache_manager.get_cache_schema_info(a_object_owner, a_object_type).full_refresh_time is null then + l_modified_after := null; + end if; - ut_event_manager.trigger_event('rebuild_annotation_cache - start (l_objects_to_parse.count = '||l_objects_to_parse.count||')'); - ut_annotation_cache_manager.cleanup_cache(l_objects_to_parse); + l_objects_to_refresh := get_objects_to_refresh(a_object_owner, a_object_type, l_modified_after); - if sys_context('userenv','current_schema') = a_object_owner - or ut_metadata.user_has_execute_any_proc() - or ut_metadata.is_object_visible('dba_objects') - then - ut_annotation_cache_manager.remove_from_cache( - get_missing_objects(a_object_owner, a_object_type) - ); + ut_event_manager.trigger_event('validate_annotation_cache - start (l_objects_to_refresh.count = '||l_objects_to_refresh.count||')'); + + + if user_can_see_whole_schema( a_object_owner ) then + --Remove non existing objects from cache only when user can see whole schema + ut_annotation_cache_manager.remove_from_cache( get_non_existing_objects( a_object_owner, a_object_type ) ); end if; --if some source needs parsing and putting into cache - if l_objects_to_parse.count > 0 then + if l_objects_to_refresh.count > 0 then + --Delete annotations for objects that are to be refreshed + ut_annotation_cache_manager.reset_objects_cache(l_objects_to_refresh); + --Rebuild cache from objects source build_annot_cache_for_sources( a_object_owner, a_object_type, - get_sources_to_annotate(a_object_owner, a_object_type, l_objects_to_parse) + get_sources_to_annotate(a_object_owner, a_object_type, l_objects_to_refresh) ); end if; - ut_event_manager.trigger_event('rebuild_annotation_cache - end'); + + if l_modified_after is null then + if user_can_see_whole_schema( a_object_owner ) then + ut_annotation_cache_manager.set_fully_refreshed( a_object_owner, a_object_type ); + else + -- if user cannot see full schema - we dont mark it as fully refreshed + -- it will get refreshed each time until someone with proper privs will refresh it + null; + end if; + end if; + ut_event_manager.trigger_event('validate_annotation_cache - end'); end; ------------------------------------------------------------ --public definitions ------------------------------------------------------------ procedure rebuild_annotation_cache(a_object_owner varchar2, a_object_type varchar2) is - l_annotation_objs_info ut_annotation_objs_cache_info; begin - l_annotation_objs_info := get_annotation_objs_info(a_object_owner, a_object_type, null, true); - refresh_annotation_cache( a_object_owner, a_object_type, l_annotation_objs_info ); + validate_annotation_cache( a_object_owner, a_object_type ); end; procedure trigger_obj_annotation_rebuild is @@ -295,17 +304,14 @@ create or replace package body ut_annotation_manager as end if; end; - function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2, a_parse_date timestamp := null) return sys_refcursor is - l_annotation_objs_info ut_annotation_objs_cache_info; + function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2, a_modified_after timestamp) return sys_refcursor is l_cursor sys_refcursor; - l_full_scan_needed boolean := not ut_trigger_check.is_alive(); begin - ut_event_manager.trigger_event('get_annotated_objects - start'); - l_annotation_objs_info := get_annotation_objs_info(a_object_owner, a_object_type, a_parse_date, l_full_scan_needed); - refresh_annotation_cache(a_object_owner, a_object_type, l_annotation_objs_info); + ut_event_manager.trigger_event('get_annotated_objects - start: a_modified_after='||ut_utils.to_string(a_modified_after)); + validate_annotation_cache(a_object_owner, a_object_type, a_modified_after); --pipe annotations from cache - l_cursor := ut_annotation_cache_manager.get_annotations_for_objects(l_annotation_objs_info, a_parse_date); + l_cursor := ut_annotation_cache_manager.get_annotations_parsed_since(a_object_owner, a_object_type, a_modified_after); ut_event_manager.trigger_event('get_annotated_objects - end'); return l_cursor; end; @@ -315,5 +321,5 @@ create or replace package body ut_annotation_manager as ut_annotation_cache_manager.purge_cache(a_object_owner, a_object_type); end; -end ut_annotation_manager; +end; / diff --git a/source/core/annotations/ut_annotation_manager.pks b/source/core/annotations/ut_annotation_manager.pks index 1d6bd3d71..70257afac 100644 --- a/source/core/annotations/ut_annotation_manager.pks +++ b/source/core/annotations/ut_annotation_manager.pks @@ -23,18 +23,17 @@ create or replace package ut_annotation_manager authid current_user as /** * Gets annotations for all objects of a specified type for database schema. * Annotations that are stale or missing are parsed and placed in persistent cache. - * After placing in cache, annotation data is returned as pipelined table data. + * After placing in cache, annotation data is returned as ref_cursor. * - * @param a_object_owner owner of objects to get annotations for - * @param a_object_type type of objects to get annotations for - * @param a_parse_date date when object was last parsed - * @return array containing annotated objects along with annotations for each object (nested) + * @param a_object_owner owner of objects to get annotations for + * @param a_object_type type of objects to get annotations for + * @param a_modified_after return only objects modified after thr timestamp + * @return cursor containing annotated objects along with annotations for each object (nested) */ - function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2, a_parse_date timestamp := null) return sys_refcursor; + function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2, a_modified_after timestamp) return sys_refcursor; /** * Rebuilds annotation cache for a specified schema and object type. - * The procedure is called internally by `get_annotated_objects` function. * It can be used to speedup initial execution of utPLSQL on a given schema * if it is executed before any call is made to `ut.run` or `ut_runner.run` procedure. * @@ -57,5 +56,5 @@ create or replace package ut_annotation_manager authid current_user as procedure purge_cache(a_object_owner varchar2, a_object_type varchar2); -end ut_annotation_manager; +end; / diff --git a/source/core/annotations/ut_annotation_parser.pkb b/source/core/annotations/ut_annotation_parser.pkb index bbe58a667..6248f36b9 100644 --- a/source/core/annotations/ut_annotation_parser.pkb +++ b/source/core/annotations/ut_annotation_parser.pkb @@ -212,14 +212,6 @@ create or replace package body ut_annotation_parser as select value(x) bulk collect into l_result from table(l_annotations) x order by x.position; - -- printing out parsed structure for debugging - $if $$ut_trace $then - print_parse_results(l_result); - dbms_output.put_line('Annotations count: ' || l_result.count); - for i in 1 .. l_result.count loop - dbms_output.put_line(xmltype(l_result(i)).getclobval()); - end loop; - $end return l_result; end parse_object_annotations; @@ -229,7 +221,8 @@ create or replace package body ut_annotation_parser as l_annotations ut_annotations := ut_annotations(); ex_package_is_wrapped exception; pragma exception_init(ex_package_is_wrapped, -24241); - + source_text_is_empty exception; + pragma exception_init(source_text_is_empty, -24236); begin if a_source_lines.count > 0 then --convert to post-processed source clob @@ -248,12 +241,12 @@ create or replace package body ut_annotation_parser as l_annotations := parse_object_annotations(l_source); dbms_lob.freetemporary(l_source); exception - when ex_package_is_wrapped then + when ex_package_is_wrapped or source_text_is_empty then null; end; end if; return l_annotations; end; -end ut_annotation_parser; +end; / diff --git a/source/core/annotations/ut_annotation_parser.pks b/source/core/annotations/ut_annotation_parser.pks index b0a61e576..0368811db 100644 --- a/source/core/annotations/ut_annotation_parser.pks +++ b/source/core/annotations/ut_annotation_parser.pks @@ -40,5 +40,5 @@ create or replace package ut_annotation_parser authid current_user as */ function parse_object_annotations(a_source clob) return ut_annotations; -end ut_annotation_parser; +end; / diff --git a/source/core/annotations/ut_trigger_check.pkb b/source/core/annotations/ut_trigger_check.pkb index e07acd3b2..76d3aa11c 100644 --- a/source/core/annotations/ut_trigger_check.pkb +++ b/source/core/annotations/ut_trigger_check.pkb @@ -22,9 +22,7 @@ create or replace package body ut_trigger_check is function is_alive return boolean is pragma autonomous_transaction; begin - if not g_is_trigger_live then - execute immediate 'create or replace synonym '||ut_utils.ut_owner||'.'||gc_check_object_name||' for no_object'; - end if; + execute immediate 'create or replace synonym '||ut_utils.ut_owner||'.'||gc_check_object_name||' for no_object'; return g_is_trigger_live; end; diff --git a/source/core/types/ut_executable_test.tpb b/source/core/types/ut_executable_test.tpb index 89ab16dab..6f25ea1c8 100644 --- a/source/core/types/ut_executable_test.tpb +++ b/source/core/types/ut_executable_test.tpb @@ -160,7 +160,7 @@ create or replace type body ut_executable_test as l_fail_message := 'Expected one of exceptions ('||l_expected_error_codes||') but nothing was raised.'; else l_actual_error_no := regexp_substr(self.error_stack, '^[a-zA-Z]{3}(-[0-9]+)', subexpression=>1); - if not l_actual_error_no member of a_expected_error_codes then + if not l_actual_error_no member of a_expected_error_codes or l_actual_error_no is null then l_fail_message := 'Actual: '||l_actual_error_no||' was expected to '; if cardinality(a_expected_error_codes) > 1 then l_fail_message := l_fail_message || 'be one of: ('||l_expected_error_codes||')'; diff --git a/source/core/types/ut_suite_cache_row.tps b/source/core/types/ut_suite_cache_row.tps index fb4a8bb9f..d9f542de3 100644 --- a/source/core/types/ut_suite_cache_row.tps +++ b/source/core/types/ut_suite_cache_row.tps @@ -15,26 +15,26 @@ create type ut_suite_cache_row as object ( See the License for the specific language governing permissions and limitations under the License. */ - id number(22,0), - self_type varchar2(250 byte), - path varchar2(1000 byte), - object_owner varchar2(250 byte), - object_name varchar2(250 byte), - name varchar2(250 byte), - line_no number, - parse_time timestamp (6), - description varchar2(4000 byte), - rollback_type number, - disabled_flag number, - warnings ut_varchar2_rows, - before_all_list ut_executables, - after_all_list ut_executables, - before_each_list ut_executables, - before_test_list ut_executables, - after_each_list ut_executables, - after_test_list ut_executables, + id number(22,0), + self_type varchar2(250 byte), + path varchar2(1000 byte), + object_owner varchar2(250 byte), + object_name varchar2(250 byte), + name varchar2(250 byte), + line_no number, + parse_time timestamp (6), + description varchar2(4000 byte), + rollback_type number, + disabled_flag number, + warnings ut_varchar2_rows, + before_all_list ut_executables, + after_all_list ut_executables, + before_each_list ut_executables, + before_test_list ut_executables, + after_each_list ut_executables, + after_test_list ut_executables, expected_error_codes ut_varchar2_rows, - tags ut_varchar2_rows, - item ut_executable_test + tags ut_varchar2_rows, + item ut_executable_test ) / \ No newline at end of file diff --git a/source/core/ut_metadata.pkb b/source/core/ut_metadata.pkb index 7859d6b3f..5448f1b5f 100644 --- a/source/core/ut_metadata.pkb +++ b/source/core/ut_metadata.pkb @@ -123,7 +123,7 @@ create or replace package body ut_metadata as function user_has_execute_any_proc return boolean is l_ut_owner varchar2(250) := ut_utils.ut_owner; begin - return is_object_visible(l_ut_owner||'.ut_utils'); + return is_object_visible(l_ut_owner||'.ut_utils') and sys_context('userenv','current_schema') != l_ut_owner; end; function is_object_visible(a_object_name varchar2) return boolean is diff --git a/source/core/ut_suite_cache_manager.pkb b/source/core/ut_suite_cache_manager.pkb index 05984da3f..7c4b1ee93 100644 --- a/source/core/ut_suite_cache_manager.pkb +++ b/source/core/ut_suite_cache_manager.pkb @@ -23,7 +23,7 @@ create or replace package body ut_suite_cache_manager is gc_get_cache_suite_sql constant varchar2(32767) := q'[with suite_items as ( - select /*+ cardinality(c 100) */ value(c) as obj + select /*+ cardinality(c 500) */ value(c) as obj from ut_suite_cache c where 1 = 1 and c.object_owner = :l_object_owner @@ -87,7 +87,7 @@ create or replace package body ut_suite_cache_manager is l_result ut_varchar2_rows; l_data ut_annotation_objs_cache_info; begin - l_data := ut_annotation_cache_manager.get_annotations_objects_info(a_object_owner, 'PACKAGE'); + l_data := ut_annotation_cache_manager.get_cached_objects_list(a_object_owner, 'PACKAGE'); select i.object_name bulk collect into l_result @@ -258,7 +258,7 @@ create or replace package body ut_suite_cache_manager is select min(t.parse_time) into l_cache_parse_time from ut_suite_cache_schema t - where object_owner = a_schema_name; + where object_owner = upper(a_schema_name); return l_cache_parse_time; end; @@ -380,13 +380,16 @@ create or replace package body ut_suite_cache_manager is pragma autonomous_transaction; begin l_objects := get_missing_cache_objects(a_schema_name); - delete from ut_suite_cache i - where i.object_owner = a_schema_name - and i.object_name in ( select column_value from table (l_objects) ); - delete from ut_suite_cache_package i - where i.object_owner = a_schema_name - and i.object_name in ( select column_value from table (l_objects) ); + if l_objects is not empty then + delete from ut_suite_cache i + where i.object_owner = a_schema_name + and i.object_name in ( select column_value from table (l_objects) ); + + delete from ut_suite_cache_package i + where i.object_owner = a_schema_name + and i.object_name in ( select column_value from table (l_objects) ); + end if; commit; end; @@ -459,5 +462,5 @@ create or replace package body ut_suite_cache_manager is return l_count > 0; end; -end ut_suite_cache_manager; +end; / diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index e71a51dc8..ee5063105 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -363,7 +363,8 @@ create or replace package body ut_suite_manager is 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; @@ -373,7 +374,7 @@ create or replace package body ut_suite_manager is a_owner_name varchar2 ) return boolean is begin - return sys_context( 'userenv', 'current_schema' ) = a_owner_name or ut_metadata.user_has_execute_any_proc() or ut_trigger_check.is_alive(); + return sys_context( 'userenv', 'current_schema' ) = a_owner_name or ut_metadata.user_has_execute_any_proc(); end; procedure build_and_cache_suites( @@ -608,6 +609,7 @@ create or replace package body ut_suite_manager is 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; @@ -627,7 +629,7 @@ create or replace package body ut_suite_manager is refresh_cache(l_owner_name); l_item_exists := ut_suite_cache_manager.suite_item_exists( l_owner_name, l_package_name, l_procedure_name ); - if not can_skip_all_objects_scan( l_owner_name ) then + if not can_skip_all_objects_scan( l_owner_name ) and l_package_name is not null then select count(1) into l_count from dual c diff --git a/source/core/ut_utils.pkb b/source/core/ut_utils.pkb index 13f64d1bd..26de41e0e 100644 --- a/source/core/ut_utils.pkb +++ b/source/core/ut_utils.pkb @@ -512,9 +512,11 @@ create or replace package body ut_utils is procedure flush_lines(a_lines ut_varchar2_rows, a_offset integer) is begin - insert into ut_dbms_output_cache (seq_no,text) - select rownum+a_offset, column_value - from table(a_lines); + if a_lines is not empty then + insert into ut_dbms_output_cache (seq_no,text) + select rownum+a_offset, column_value + from table(a_lines); + end if; end; begin loop @@ -534,7 +536,7 @@ create or replace package body ut_utils is procedure read_cache_to_dbms_output is l_lines_data sys_refcursor; l_lines ut_varchar2_rows; - c_lines_limit constant integer := 1000; + c_lines_limit constant integer := 10000; pragma autonomous_transaction; begin open l_lines_data for select text from ut_dbms_output_cache order by seq_no; diff --git a/test/install_ut3_tester_helper.sql b/test/install_ut3_tester_helper.sql index c6244fd39..c0c20634e 100644 --- a/test/install_ut3_tester_helper.sql +++ b/test/install_ut3_tester_helper.sql @@ -26,6 +26,10 @@ alter session set plsql_optimize_level=0; @@ut3_tester_helper/expectations_helper.pkb @@ut3_tester_helper/ut_example_tests.pkb +@@ut3_tester_helper/annotation_cache_helper.pks +@@ut3_tester_helper/annotation_cache_helper.pkb +create or replace synonym ut3_tester.annotation_cache_helper for ut3_tester_helper.annotation_cache_helper; + set linesize 200 set define on set verify off diff --git a/test/install_ut3_tester_tests.sql b/test/install_ut3_tester_tests.sql index 6b3a5356c..9548d5148 100644 --- a/test/install_ut3_tester_tests.sql +++ b/test/install_ut3_tester_tests.sql @@ -13,6 +13,7 @@ alter session set plsql_optimize_level=0; @@ut3_tester/core/annotations/test_annotation_parser.pks @@ut3_tester/core/annotations/test_annot_throws_exception.pks @@ut3_tester/core/annotations/test_annotation_manager.pks +@@ut3_tester/core/annotations/test_annotation_cache.pks @@ut3_tester/core/expectations/test_expectation_processor.pks @@ut3_tester/core/test_ut_utils.pks @@ut3_tester/core/test_ut_test.pks @@ -27,9 +28,10 @@ alter session set plsql_optimize_level=0; @@ut3_tester/core.pkb @@ut3_tester/core/annotations/test_before_after_annotations.pkb @@ut3_tester/core/annotations/test_annotation_parser.pkb -@@ut3_tester/core/expectations/test_expectation_processor.pkb @@ut3_tester/core/annotations/test_annotation_manager.pkb @@ut3_tester/core/annotations/test_annot_throws_exception.pkb +@@ut3_tester/core/annotations/test_annotation_cache.pkb +@@ut3_tester/core/expectations/test_expectation_processor.pkb @@ut3_tester/core/test_ut_utils.pkb @@ut3_tester/core/test_ut_test.pkb @@ut3_tester/core/test_ut_suite.pkb diff --git a/test/ut3_tester/core/annotations/test_annotation_cache.pkb b/test/ut3_tester/core/annotations/test_annotation_cache.pkb new file mode 100644 index 000000000..372fec890 --- /dev/null +++ b/test/ut3_tester/core/annotations/test_annotation_cache.pkb @@ -0,0 +1,503 @@ +create or replace package body test_annotation_cache is + + procedure cache_populated_for_packages(a_packages ut_varchar2_rows) is + l_actual_cache_info sys_refcursor; + l_expected_cache_info sys_refcursor; + begin + open l_actual_cache_info for + select * + from ut3.ut_annotation_cache_info + where object_owner = 'UT3_CACHE_TEST_OWNER'; + open l_expected_cache_info for + select 'UT3_CACHE_TEST_OWNER' as object_owner, upper( column_value ) as object_name + from table (a_packages) x; + ut.expect( l_actual_cache_info ).to_equal( l_expected_cache_info ).exclude( 'CACHE_ID,PARSE_TIME,OBJECT_TYPE' ).JOIN_BY('OBJECT_NAME'); + end; + + procedure can_run_one_package(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + + --Assert - only granted_test_suite is invoked + ut.expect( l_actual ).to_be_like( 'granted_test_suite%2 tests, 0 failed%' ); + rollback; + end; + + procedure can_run_new_package(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Arrange + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.add_new_suite( ); + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + --Assert -Both granted_test_suite and new_suite are invoked + ut.expect( l_actual ).to_be_like( 'granted_test_suite%new_suite%4 tests, 0 failed%' ); + rollback; + end ; + + procedure cant_run_revoked_package(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Arrange + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.add_new_suite( ); + annotation_cache_helper.revoke_granted_suite( ); + + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + --Assert -Only new_suite gets invoked + ut.expect( l_actual ).to_be_like( 'new_suite%2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%' ); + ut.expect( l_actual ).not_to_be_like( '%granted_test_suite%' ); + rollback; + end; + + procedure cant_run_dropped_package(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Arrange + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.add_new_suite( ); + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.revoke_granted_suite( ); + annotation_cache_helper.cleanup_new_suite( ); + + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + --Assert - no test suites are invoked + ut.expect( l_actual ).to_be_like( '%0 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%' ); + ut.expect( l_actual ).not_to_be_like( '%new_suite%' ); + ut.expect( l_actual ).not_to_be_like( '%granted_test_suite%' ); + rollback; + end; + + procedure can_run_all_packages(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + + --Assert - only granted_test_suite is invoked + ut.expect( l_actual ).to_be_like( 'granted_test_suite%not_granted_test_suite%4 tests, 0 failed%' ); + rollback; + end; + + procedure can_run_all_new_packages(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Arrange + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.add_new_suite( ); + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + + --Assert - only granted_test_suite is invoked + ut.expect( l_actual ).to_be_like( 'granted_test_suite%new_suite%not_granted_test_suite% tests, 0 failed%' ); + rollback; + end; + + procedure can_run_revoked_packages(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Arrange + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.add_new_suite( ); + annotation_cache_helper.revoke_granted_suite( ); + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + + --Assert - only granted_test_suite is invoked + ut.expect( l_actual ).to_be_like( 'granted_test_suite%new_suite%not_granted_test_suite% tests, 0 failed%' ); + rollback; + end; + + procedure can_run_all_but_dropped(a_user varchar2) is + l_actual clob; + l_current_time date := sysdate; + pragma autonomous_transaction; + begin + --Arrange + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.add_new_suite( ); + l_actual := annotation_cache_helper.run_tests_as( a_user ); + annotation_cache_helper.revoke_granted_suite( ); + annotation_cache_helper.cleanup_new_suite( ); + + --Act + l_actual := annotation_cache_helper.run_tests_as( a_user ); + --Assert - no test suites are invoked + ut.expect( l_actual ).to_be_like( 'granted_test_suite%not_granted_test_suite%4 tests, 0 failed%' ); + ut.expect( l_actual ).not_to_be_like( '%new_suite%' ); + rollback; + end; + + + procedure user_can_run_one_package is + begin + can_run_one_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure user_can_run_new_package is + begin + can_run_new_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure user_cant_run_revoked_package is + begin + cant_run_revoked_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure user_cant_run_dropped_package is + begin + cant_run_dropped_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure sel_cat_user_can_run_one is + begin + can_run_one_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure sel_cat_user_can_run_new is + begin + can_run_new_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure sel_cat_user_cant_run_revoked is + begin + cant_run_revoked_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure sel_cat_user_cant_run_dropped is + begin + cant_run_dropped_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure sel_any_user_can_run_one is + begin + can_run_one_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure sel_any_user_can_run_new is + begin + can_run_new_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure sel_any_user_cant_run_revoked is + begin + cant_run_revoked_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure sel_any_user_cant_run_dropped is + begin + cant_run_dropped_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure exe_any_user_can_run_all is + begin + can_run_all_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure exe_any_user_can_run_new is + begin + can_run_all_new_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure exe_any_user_can_run_revoked is + begin + can_run_revoked_packages('ut3_execute_any_proc_user'); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure exe_any_user_cant_run_dropped is + begin + can_run_all_but_dropped('ut3_execute_any_proc_user'); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure owner_user_can_run_all is + begin + can_run_all_packages( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + + procedure owner_user_can_run_new is + begin + can_run_all_new_packages( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure owner_user_cant_run_dropped is + begin + can_run_all_but_dropped('ut3_cache_test_owner'); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + + procedure t_user_can_run_one_package is + begin + can_run_one_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_user_can_run_new_package is + begin + can_run_new_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_user_cant_run_revoked_pkg is + begin + cant_run_revoked_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_user_cant_run_dropped_pkg is + begin + cant_run_dropped_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_cat_user_can_run_one is + begin + can_run_one_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_cat_user_can_run_new is + begin + can_run_new_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_cat_user_cant_run_revokd is + begin + cant_run_revoked_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_cat_user_cant_run_dropd is + begin + cant_run_dropped_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + + procedure t_sel_any_user_can_run_one is + begin + can_run_one_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_any_user_can_run_new is + begin + can_run_new_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_any_user_cant_run_revokd is + begin + cant_run_revoked_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_sel_any_user_cant_run_dropd is + begin + cant_run_dropped_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + + procedure t_exe_any_user_can_run_all is + begin + can_run_all_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_exe_any_user_can_run_new is + begin + can_run_all_new_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_exe_any_user_can_run_revokd is + begin + can_run_revoked_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_exe_any_user_cant_run_dropd is + begin + can_run_all_but_dropped( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_owner_user_can_run_all is + begin + can_run_all_packages( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_owner_user_can_run_new is + begin + can_run_all_new_packages( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure t_owner_user_cant_run_dropd is + begin + can_run_all_but_dropped( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + + + + procedure p_user_can_run_one_package is + begin + can_run_one_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure p_user_can_run_new_package is + begin + can_run_new_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure p_user_cant_run_revoked_pack is + begin + cant_run_revoked_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure p_user_cant_run_dropped_pack is + begin + cant_run_dropped_package( 'ut3_no_extra_priv_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + + + procedure p_sel_cat_user_can_run_one is + begin + can_run_one_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure p_sel_cat_user_can_run_new is + begin + can_run_new_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure p_sel_cat_user_cant_run_revokd is + begin + cant_run_revoked_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure p_sel_cat_user_cant_run_dropd is + begin + cant_run_dropped_package( 'ut3_select_catalog_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure p_sel_any_user_can_run_one is + begin + can_run_one_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure p_sel_any_user_can_run_new is + begin + can_run_new_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure p_sel_any_user_cant_run_revokd is + begin + cant_run_revoked_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE' ) ); + end; + + procedure p_sel_any_user_cant_run_dropd is + begin + cant_run_dropped_package( 'ut3_select_any_table_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE' ) ); + end; + + procedure p_exe_any_user_can_run_all is + begin + can_run_all_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure p_exe_any_user_can_run_new is + begin + can_run_all_new_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure p_exe_any_user_can_run_revokd is + begin + can_run_revoked_packages( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure p_exe_any_user_cant_run_dropd is + begin + can_run_all_but_dropped( 'ut3_execute_any_proc_user' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure p_owner_user_can_run_all is + begin + can_run_all_packages( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure p_owner_user_can_run_new is + begin + can_run_all_new_packages( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NEW_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + + procedure p_owner_user_cant_run_dropped is + begin + can_run_all_but_dropped( 'ut3_cache_test_owner' ); + cache_populated_for_packages( ut_varchar2_rows( 'GRANTED_TEST_SUITE', 'NOT_GRANTED_TEST_SUITE' ) ); + end; + +end; +/ diff --git a/test/ut3_tester/core/annotations/test_annotation_cache.pks b/test/ut3_tester/core/annotations/test_annotation_cache.pks new file mode 100644 index 000000000..f44b816e1 --- /dev/null +++ b/test/ut3_tester/core/annotations/test_annotation_cache.pks @@ -0,0 +1,273 @@ +create or replace package test_annotation_cache is + + --%suite(annotation cache) + --%suitepath(utplsql.ut3_tester.core.annotations) + --%beforeall(annotation_cache_helper.create_run_function_for_users) + --%afterall(annotation_cache_helper.drop_run_function_for_users) + + --%context(With DDL trigger enabled) + + --%beforeall(annotation_cache_helper.enable_ddl_trigger) + --%beforeeach(annotation_cache_helper.setup_two_suites) + --%aftereach(annotation_cache_helper.cleanup_new_suite) + --%afterall(annotation_cache_helper.cleanup_two_suites) + + --%context(User without elevated privileges) + + --%test(Can only execute granted packages) + procedure t_user_can_run_one_package; + + --%test(Can see newly created packages as they are added) + procedure t_user_can_run_new_package; + + --%test(Cannot execute revoked packages) + procedure t_user_cant_run_revoked_pkg; + + --%test(Cannot execute dropped unit test packages) + procedure t_user_cant_run_dropped_pkg; + + --%endcontext + + --%context(User with select_catalog_role) + + --%test(Can only execute granted packages) + procedure t_sel_cat_user_can_run_one; + + --%test(Can see newly created packages as they are added) + procedure t_sel_cat_user_can_run_new; + + --%test(Cannot execute revoked packages) + procedure t_sel_cat_user_cant_run_revokd; + + --%test(Cannot execute dropped unit test packages) + procedure t_sel_cat_user_cant_run_dropd; + + --%endcontext + + --%context(User with select any table privilege) + + --%test(Can only execute granted packages) + procedure t_sel_any_user_can_run_one; + + --%test(Can see newly created packages as they are added) + procedure t_sel_any_user_can_run_new; + + --%test(Cannot execute revoked packages) + procedure t_sel_any_user_cant_run_revokd; + + --%test(Cannot execute dropped unit test packages) + procedure t_sel_any_user_cant_run_dropd; + + --%endcontext + + --%context(User with execute any procedure) + + --%test(Can execute and see all unit test packages) + procedure t_exe_any_user_can_run_all; + + --%test(Can see newly created packages as they are added) + procedure t_exe_any_user_can_run_new; + + --%test(Can execute revoked packages) + procedure t_exe_any_user_can_run_revokd; + + --%test(Cannot execute dropped unit test packages) + procedure t_exe_any_user_cant_run_dropd; + + --%endcontext + + --%context(User owning test packages) + + --%test(Can execute and see all unit test packages) + procedure t_owner_user_can_run_all; + + --%test(Can see newly created packages as they are added) + procedure t_owner_user_can_run_new; + + --%test(Cannot execute dropped unit test packages) + procedure t_owner_user_cant_run_dropd; + + --%endcontext + + --%endcontext + + --%context(With DDL trigger disabled) + + --%beforeall(annotation_cache_helper.disable_ddl_trigger) + --%beforeeach(annotation_cache_helper.setup_two_suites) + --%beforeeach(annotation_cache_helper.purge_annotation_cache) + --%aftereach(annotation_cache_helper.cleanup_new_suite) + --%afterall(annotation_cache_helper.enable_ddl_trigger) + --%afterall(annotation_cache_helper.cleanup_two_suites) + + --%context(User without elevated privileges) + + --%test(Can only execute granted packages) + procedure user_can_run_one_package; + + --%test(Can see newly created packages as they are added) + procedure user_can_run_new_package; + + --%test(Cannot execute revoked packages) + procedure user_cant_run_revoked_package; + + --%test(Cannot execute dropped unit test packages) + procedure user_cant_run_dropped_package; + + --%endcontext + + --%context(User with select_catalog_role) + + --%test(Can only execute granted packages) + procedure sel_cat_user_can_run_one; + + --%test(Can see newly created packages as they are added) + procedure sel_cat_user_can_run_new; + + --%test(Cannot execute revoked packages) + procedure sel_cat_user_cant_run_revoked; + + --%test(Cannot execute dropped unit test packages) + procedure sel_cat_user_cant_run_dropped; + + --%endcontext + + --%context(User with select any table privilege) + + --%test(Can only execute granted packages) + procedure sel_any_user_can_run_one; + + --%test(Can see newly created packages as they are added) + procedure sel_any_user_can_run_new; + + --%test(Cannot execute revoked packages) + procedure sel_any_user_cant_run_revoked; + + --%test(Cannot execute dropped unit test packages) + procedure sel_any_user_cant_run_dropped; + + --%endcontext + + --%context(User with execute any procedure) + + --%test(Can execute and see all unit test packages) + procedure exe_any_user_can_run_all; + + --%test(Can see newly created packages as they are added) + procedure exe_any_user_can_run_new; + + --%test(Can execute revoked packages) + procedure exe_any_user_can_run_revoked; + + --%test(Cannot execute dropped unit test packages) + procedure exe_any_user_cant_run_dropped; + + --%endcontext + + --%context(User owning test packages) + + --%test(Can execute and see all unit test packages) + procedure owner_user_can_run_all; + + --%test(Can see newly created packages as they are added) + procedure owner_user_can_run_new; + + --%test(Cannot execute dropped unit test packages) + procedure owner_user_cant_run_dropped; + + --%endcontext + + --%endcontext + + --%context(With DDL trigger enabled and cache purged) + + --%beforeall(annotation_cache_helper.enable_ddl_trigger) + + --%beforeeach(annotation_cache_helper.setup_two_suites) + --%beforeeach(annotation_cache_helper.purge_annotation_cache) + + --%aftereach(annotation_cache_helper.cleanup_new_suite) + --%aftereach(annotation_cache_helper.cleanup_two_suites) + + --%context(User without elevated privileges) + + --%test(Can only execute granted packages) + procedure p_user_can_run_one_package; + + --%test(Can see newly created packages as they are added) + procedure p_user_can_run_new_package; + + --%test(Cannot execute revoked packages) + procedure p_user_cant_run_revoked_pack; + + --%test(Cannot execute dropped unit test packages) + procedure p_user_cant_run_dropped_pack; + + --%endcontext + + --%context(User with select_catalog_role) + + --%test(Can only execute granted packages) + procedure p_sel_cat_user_can_run_one; + + --%test(Can see newly created packages as they are added) + procedure p_sel_cat_user_can_run_new; + + --%test(Cannot execute revoked packages) + procedure p_sel_cat_user_cant_run_revokd; + + --%test(Cannot execute dropped unit test packages) + procedure p_sel_cat_user_cant_run_dropd; + + --%endcontext + + --%context(User with select any table privilege) + + --%test(Can only execute granted packages) + procedure p_sel_any_user_can_run_one; + + --%test(Can see newly created packages as they are added) + procedure p_sel_any_user_can_run_new; + + --%test(Cannot execute revoked packages) + procedure p_sel_any_user_cant_run_revokd; + + --%test(Cannot execute dropped unit test packages) + procedure p_sel_any_user_cant_run_dropd; + + --%endcontext + + --%context(User with execute any procedure) + + --%test(Can execute and see all unit test packages) + procedure p_exe_any_user_can_run_all; + + --%test(Can see newly created packages as they are added) + procedure p_exe_any_user_can_run_new; + + --%test(Can execute revoked packages) + procedure p_exe_any_user_can_run_revokd; + + --%test(Cannot execute dropped unit test packages) + procedure p_exe_any_user_cant_run_dropd; + + --%endcontext + + --%context(User owning test packages) + + --%test(Can execute and see all unit test packages) + procedure p_owner_user_can_run_all; + + --%test(Can see newly created packages as they are added) + procedure p_owner_user_can_run_new; + + --%test(Cannot execute dropped unit test packages) + procedure p_owner_user_cant_run_dropped; + + --%endcontext + + + --%endcontext + +end; +/ diff --git a/test/ut3_tester/core/annotations/test_annotation_manager.pkb b/test/ut3_tester/core/annotations/test_annotation_manager.pkb index d564e5d57..8a3efc508 100644 --- a/test/ut3_tester/core/annotations/test_annotation_manager.pkb +++ b/test/ut3_tester/core/annotations/test_annotation_manager.pkb @@ -1,45 +1,34 @@ create or replace package body test_annotation_manager is - procedure disable_ddl_trigger is + procedure exec_autonomous(a_sql varchar2) is pragma autonomous_transaction; begin - execute immediate 'alter trigger ut3.ut_trigger_annotation_parsing disable'; - execute immediate 'begin ut3.ut_trigger_check.is_alive(); end;'; - end; - - procedure enable_ddl_trigger is - pragma autonomous_transaction; - begin - execute immediate 'alter trigger ut3.ut_trigger_annotation_parsing enable'; + execute immediate a_sql; end; procedure create_dummy_package is - pragma autonomous_transaction; begin - execute immediate q'[create or replace package dummy_package as + exec_autonomous(q'[create or replace package dummy_package as procedure some_dummy_procedure; - end;]'; + end;]'); end; procedure drop_dummy_package is - pragma autonomous_transaction; begin - execute immediate q'[drop package dummy_package]'; + exec_autonomous(q'[drop package dummy_package]'); exception when others then null; end; procedure recompile_dummy_package is - pragma autonomous_transaction; begin - execute immediate q'[alter package dummy_package compile]'; + exec_autonomous(q'[alter package dummy_package compile]'); end; procedure create_dummy_test_package is - pragma autonomous_transaction; begin - execute immediate q'[ + exec_autonomous(q'[ /* * Some multiline comments before package spec create or replace package dummy_test_package dummy comment to prove that we pick the right piece of code @@ -55,34 +44,31 @@ create or replace package body test_annotation_manager is --%test(dummy_test) --%beforetest(some_procedure) procedure some_dummy_test_procedure; - end;]'; - execute immediate q'[grant execute on dummy_test_package to public]'; + end;]'); + exec_autonomous(q'[grant execute on dummy_test_package to public]'); end; procedure modify_dummy_test_package is - pragma autonomous_transaction; begin - execute immediate q'[create or replace package dummy_test_package as + exec_autonomous(q'[create or replace package dummy_test_package as --%suite(dummy_test_suite) --%test(dummy_test) procedure some_dummy_test_procedure; - end;]'; + end;]'); end; procedure drop_dummy_test_package is - pragma autonomous_transaction; begin - execute immediate q'[drop package dummy_test_package]'; + exec_autonomous(q'[drop package dummy_test_package]'); exception when others then null; end; procedure recompile_dummy_test_package is - pragma autonomous_transaction; begin - execute immediate q'[alter package dummy_test_package compile]'; + exec_autonomous(q'[alter package dummy_test_package compile]'); end; procedure create_parse_proc_as_ut3$user# is @@ -128,35 +114,31 @@ create or replace package body test_annotation_manager is ut.expect(l_actual).to_be_empty(); end; - procedure assert_dummy_test_package(a_start_date date) is + procedure assert_dummy_test_package(a_start_time timestamp) is l_actual_cache_id integer; + l_data ut3.ut_annotated_objects; + l_result sys_refcursor; l_actual sys_refcursor; l_expected sys_refcursor; begin - select max(cache_id) - into l_actual_cache_id - from ut3.ut_annotation_cache_info - where object_owner = sys_context('USERENV', 'CURRENT_USER') and object_type = 'PACKAGE' and object_name = 'DUMMY_TEST_PACKAGE' - and parse_time >= a_start_date; - ut.expect(l_actual_cache_id).to_be_not_null; - - open l_actual for - select annotation_position, annotation_name, annotation_text, subobject_name - from ut3.ut_annotation_cache where cache_id = l_actual_cache_id - order by annotation_position; - open l_expected for - select 2 as annotation_position, 'suite' as annotation_name, - 'dummy_test_suite' as annotation_text, '' as subobject_name - from dual union all - select 3, 'rollback' , 'manual', '' as subobject_name - from dual union all - select 7, 'test' , 'dummy_test', 'some_dummy_test_procedure' as subobject_name - from dual union all - select 8, 'beforetest' , 'some_procedure', 'some_dummy_test_procedure' as subobject_name - from dual; - - ut.expect(l_actual).to_equal(l_expected); + select + ut3.ut_annotated_object( + sys_context('USERENV', 'CURRENT_USER'), + 'DUMMY_TEST_PACKAGE', 'PACKAGE', a_start_time, + ut3.ut_annotations( + ut3.ut_annotation( 2, 'suite', 'dummy_test_suite', null ), + ut3.ut_annotation( 3, 'rollback', 'manual', null ), + ut3.ut_annotation( 7, 'test', 'dummy_test', 'some_dummy_test_procedure' ), + ut3.ut_annotation( 8, 'beforetest', 'some_procedure', 'some_dummy_test_procedure' ) + ) + ) annotated_object + from dual; + + l_result := ut3.ut_annotation_manager.get_annotated_objects(sys_context('USERENV', 'CURRENT_USER'), 'PACKAGE', a_start_time); + fetch l_result bulk collect into l_data; + open l_actual for select value(x) as annotated_object from table(l_data) x where object_name = 'DUMMY_TEST_PACKAGE'; + ut.expect(l_actual).to_equal(l_expected).exclude('ANNOTATED_OBJECT/PARSE_TIME').join_by('ANNOTATED_OBJECT/OBJECT_NAME'); end; @@ -164,10 +146,10 @@ create or replace package body test_annotation_manager is l_actual_cache_id integer; begin --Arrange - disable_ddl_trigger(); + annotation_cache_helper.disable_ddl_trigger(); create_dummy_test_package(); --Act - enable_ddl_trigger(); + annotation_cache_helper.enable_ddl_trigger(); --Assert select max(cache_id) into l_actual_cache_id @@ -182,10 +164,10 @@ create or replace package body test_annotation_manager is l_start_date date; begin --Arrange - disable_ddl_trigger(); + annotation_cache_helper.disable_ddl_trigger(); create_dummy_test_package(); --Act - enable_ddl_trigger(); + annotation_cache_helper.enable_ddl_trigger(); l_start_date := sysdate; recompile_dummy_test_package(); --Assert @@ -197,11 +179,11 @@ create or replace package body test_annotation_manager is l_start_date date; begin --Arrange - disable_ddl_trigger(); + annotation_cache_helper.disable_ddl_trigger(); create_dummy_test_package(); create_dummy_package(); --Act - enable_ddl_trigger(); + annotation_cache_helper.enable_ddl_trigger(); l_start_date := sysdate; ut3.ut_annotation_manager.rebuild_annotation_cache(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); --Assert @@ -259,74 +241,123 @@ create or replace package body test_annotation_manager is end; - --%test(Updates annotation cache when package recompiled) - procedure trg_update_modified_package is + procedure trg_populate_cache_after_purge is + l_start_date date; begin - null; + --Arrange + create_dummy_test_package(); + l_start_date := sysdate; + ut3.ut_annotation_manager.purge_cache(sys_context('USERENV', 'CURRENT_USER'), 'PACKAGE'); + --Act & Assert + assert_dummy_test_package(l_start_date); end; - procedure add_new_package is - l_actual_cache_id integer; - l_actual sys_refcursor; - l_start_date date; + procedure add_annotated_package is + l_start_time timestamp := systimestamp; + begin + --Arrange + create_dummy_test_package(); + --Act & Assert + assert_dummy_test_package( l_start_time ); + end; + + procedure remove_annotated_package is + l_start_time timestamp := systimestamp; begin + --Arrange + create_dummy_test_package(); + assert_dummy_test_package( l_start_time ); + --Act - l_start_date := sysdate; - ut3.ut_annotation_manager.rebuild_annotation_cache(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); + drop_dummy_test_package(); + --Assert - select max(cache_id) - into l_actual_cache_id - from ut3.ut_annotation_cache_info - where object_owner = sys_context('USERENV', 'CURRENT_USER') and object_type = 'PACKAGE' and object_name = 'DUMMY_PACKAGE' - and parse_time >= l_start_date; + ut.expect( + ut3.ut_annotation_manager.get_annotated_objects( + sys_context( 'USERENV', 'CURRENT_USER' ), 'PACKAGE', l_start_time + ), + 'Annotations are empty after package was dropped' + ).to_be_empty(); + end; - ut.expect(l_actual_cache_id).to_be_not_null; + procedure add_not_annotated_package is + l_start_time timestamp := systimestamp; + begin + --Arrange + create_dummy_package(); + --Act & Assert + ut.expect( + ut3.ut_annotation_manager.get_annotated_objects( + sys_context( 'USERENV', 'CURRENT_USER' ), 'PACKAGE', l_start_time + ), + 'Annotations are empty for not annotated package' + ).to_be_empty(); + end; - open l_actual for - select * - from ut3.ut_annotation_cache - where cache_id = l_actual_cache_id; + procedure remove_not_annotated_package is + l_start_time timestamp := systimestamp; + begin + --Arrange + create_dummy_package(); + ut.expect( + ut3.ut_annotation_manager.get_annotated_objects( + sys_context( 'USERENV', 'CURRENT_USER' ), 'PACKAGE', l_start_time + ), + 'Annotations are empty for non annotated package' + ).to_be_empty(); - ut.expect(l_actual).to_be_empty(); + --Act + drop_dummy_package(); + --Assert + ut.expect( + ut3.ut_annotation_manager.get_annotated_objects( + sys_context( 'USERENV', 'CURRENT_USER' ), 'PACKAGE', l_start_time + ), + 'Annotations are empty after non annoteted package was dropped' + ).to_be_empty(); end; - procedure update_modified_package is - l_actual integer; - l_start_date date; + procedure remove_annotations_from_pkg is + l_start_time timestamp := systimestamp; begin --Arrange - l_start_date := sysdate; - ut3.ut_annotation_manager.rebuild_annotation_cache(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); - recompile_dummy_package(); - l_start_date := sysdate; - $if dbms_db_version.version >= 18 $then - dbms_session.sleep(1); - $else - dbms_lock.sleep(1); - $end + create_dummy_test_package(); + assert_dummy_test_package( l_start_time ); --Act - ut3.ut_annotation_manager.rebuild_annotation_cache(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); + exec_autonomous(q'[create or replace package dummy_test_package as + procedure some_dummy_test_procedure; + end;]'); + --Assert - assert_dummy_package(l_start_date); + ut.expect( + ut3.ut_annotation_manager.get_annotated_objects( + sys_context( 'USERENV', 'CURRENT_USER' ), 'PACKAGE', l_start_time + ) + ).to_be_empty(); end; - - procedure add_new_test_package is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_start_date date; + procedure add_annotations_to_package is + l_start_time timestamp := systimestamp; begin --Arrange - l_start_date := sysdate; + exec_autonomous(q'[create or replace package dummy_test_package as + procedure some_dummy_test_procedure; + end;]'); + ut.expect( + ut3.ut_annotation_manager.get_annotated_objects( + sys_context( 'USERENV', 'CURRENT_USER' ), 'PACKAGE', l_start_time + ) + ).to_be_empty(); + --Act - ut3.ut_annotation_manager.rebuild_annotation_cache(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); + create_dummy_test_package(); + --Assert - assert_dummy_test_package(l_start_date); + assert_dummy_test_package( l_start_time ); end; - procedure update_modified_test_package is l_actual_cache_id integer; l_actual sys_refcursor; @@ -365,29 +396,35 @@ create or replace package body test_annotation_manager is procedure keep_dropped_data_in_cache is - l_actual sys_refcursor; - l_expected sys_refcursor; - l_start_date date; + l_cache_count integer; + l_start_date date; begin - parse_dummy_test_as_ut3$user#(); l_start_date := sysdate; + parse_dummy_test_as_ut3$user#(); drop_dummy_test_package(); --Act parse_dummy_test_as_ut3$user#(); --Assert - assert_dummy_test_package(l_start_date); + select count(1) + into l_cache_count + from ut3.ut_annotation_cache_info + where object_owner = sys_context('USERENV', 'CURRENT_USER') + and object_type = 'PACKAGE' + and object_name = 'DUMMY_TEST_PACKAGE' + and parse_time > l_start_date; + ut.expect( l_cache_count ).to_equal(1); end; procedure no_data_for_dropped_object is - l_result sys_refcursor; - l_data ut3.ut_annotated_objects; - l_actual sys_refcursor; + l_result sys_refcursor; + l_data ut3.ut_annotated_objects; + l_actual sys_refcursor; + l_start_time timestamp := systimestamp; begin --Arrange - ut3.ut_annotation_manager.rebuild_annotation_cache(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); drop_dummy_test_package(); --Act - l_result := ut3.ut_annotation_manager.get_annotated_objects(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); + l_result := ut3.ut_annotation_manager.get_annotated_objects( sys_context('USERENV', 'CURRENT_USER'),'PACKAGE', l_start_time ); fetch l_result bulk collect into l_data; open l_actual for select object_name from table(l_data) where object_name = 'DUMMY_TEST_PACKAGE'; --Assert @@ -396,13 +433,9 @@ create or replace package body test_annotation_manager is procedure cleanup_dropped_data_in_cache is l_cache_count integer; - l_actual sys_refcursor; - l_expected sys_refcursor; - l_start_date date; begin --Arrange ut3.ut_annotation_manager.rebuild_annotation_cache(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); - l_start_date := sysdate; drop_dummy_test_package(); --Act ut3.ut_annotation_manager.rebuild_annotation_cache(sys_context('USERENV', 'CURRENT_USER'),'PACKAGE'); @@ -418,5 +451,16 @@ create or replace package body test_annotation_manager is end; + procedure populate_cache_after_purge is + l_start_date date; + begin + --Arrange + create_dummy_test_package(); + l_start_date := sysdate; + ut3.ut_annotation_manager.purge_cache(sys_context('USERENV', 'CURRENT_USER'), 'PACKAGE'); + --Act & Assert + assert_dummy_test_package(l_start_date); + end; + end test_annotation_manager; / diff --git a/test/ut3_tester/core/annotations/test_annotation_manager.pks b/test/ut3_tester/core/annotations/test_annotation_manager.pks index fd5bc3410..5d7464fd2 100644 --- a/test/ut3_tester/core/annotations/test_annotation_manager.pks +++ b/test/ut3_tester/core/annotations/test_annotation_manager.pks @@ -3,13 +3,11 @@ create or replace package test_annotation_manager is --%suite(ut_annotation_manager) --%suitepath(utplsql.ut3_tester.core.annotations) + --%afterall(drop_dummy_test_package) + --%aftereach procedure cleanup_annotation_cache; - procedure disable_ddl_trigger; - - procedure enable_ddl_trigger; - procedure create_dummy_package; procedure drop_dummy_package; @@ -45,30 +43,43 @@ create or replace package test_annotation_manager is --%beforetest(create_dummy_test_package) procedure trg_no_data_for_dropped_object; - --%test(Updates annotation cache when package recompiled) - procedure trg_update_modified_package; + --%test(Objects are populated on scan after cache was purged) + --%beforetest(annotation_cache_helper.disable_ddl_trigger) + --%aftertest(annotation_cache_helper.enable_ddl_trigger) + procedure trg_populate_cache_after_purge; --%endcontext - --%context(Without DDL trigger enabled) + --%context(Without DDL trigger) - --%beforeall(disable_ddl_trigger) + --%beforeall(annotation_cache_helper.disable_ddl_trigger) - --%afterall(enable_ddl_trigger) + --%afterall(annotation_cache_helper.enable_ddl_trigger) --%beforeeach(create_dummy_package) --%aftereach(drop_dummy_package) - --%test(Adds new package to annotation cache info when it is not unit test package) - procedure add_new_package; + --%test(Returns annotations when annotated package was created) + --%aftertest(drop_dummy_test_package) + procedure add_annotated_package; - --%test(Updates annotation cache info for modified package) - procedure update_modified_package; + --%test(Doesn't return annotations when annotated package was removed) + --%aftertest(drop_dummy_test_package) + procedure remove_annotated_package; - --%test(Adds annotations to cache for unit test package) - --%beforetest(create_dummy_test_package) + --%test(Doesn't return annotations when package doesn't contain annotations) + procedure add_not_annotated_package; + + --%test(Doesn't return annotations when package without annotations was dropped) + procedure remove_not_annotated_package; + + --%test(Doesn't return annotations when annotations removed from package) --%aftertest(drop_dummy_test_package) - procedure add_new_test_package; + procedure remove_annotations_from_pkg; + + --%test(Returns annotations when annotations were added to package) + --%aftertest(drop_dummy_test_package) + procedure add_annotations_to_package; --%test(Updates annotations in cache for modified test package) procedure update_modified_test_package; @@ -84,6 +95,9 @@ create or replace package test_annotation_manager is --%test(Remove object from cache when object dropped and user can see whole schema) procedure cleanup_dropped_data_in_cache; + --%test(Objects are populated on scan after cache was purged) + procedure populate_cache_after_purge; + --%endcontext end test_annotation_manager; diff --git a/test/ut3_tester/core/test_suite_manager.pkb b/test/ut3_tester/core/test_suite_manager.pkb index e693771b4..fd35adc70 100644 --- a/test/ut3_tester/core/test_suite_manager.pkb +++ b/test/ut3_tester/core/test_suite_manager.pkb @@ -1437,7 +1437,7 @@ end;]'; l_expected := ut3.ut_object_names( ut3.ut_object_name('UT3','SOME_TEST_PACKAGE') ); - l_actual := ut3_tester_helper.run_helper.get_object_name('UT3'); + l_actual := ut3_tester_helper.run_helper.get_schema_ut_packages('UT3'); ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected)); end; @@ -1458,7 +1458,7 @@ end;]'; l_expected_message varchar2(500); begin l_expected_message := q'[ORA-20217: 'Suitepath exceeds 1000 CHAR on: UT3.DUMMY_LONG_TEST_PACKAGE,UT3.DUMMY_LONG_TEST_PACKAGE1'%]'; - l_actual := ut3_tester_helper.run_helper.get_object_name('UT3'); + l_actual := ut3_tester_helper.run_helper.get_schema_ut_packages('UT3'); ut.fail('Expected exception for suitpaths over 1k for two packages'); exception when others then diff --git a/test/ut3_tester_helper/annotation_cache_helper.pkb b/test/ut3_tester_helper/annotation_cache_helper.pkb new file mode 100644 index 000000000..0d56823df --- /dev/null +++ b/test/ut3_tester_helper/annotation_cache_helper.pkb @@ -0,0 +1,167 @@ +create or replace package body annotation_cache_helper as + + procedure setup_two_suites is + pragma autonomous_transaction; + begin + execute immediate + 'create or replace package ut3_cache_test_owner.granted_test_suite is + --%suite + + --%test + procedure test1; + --%test + procedure test2; + end;'; + + execute immediate + 'create or replace package body ut3_cache_test_owner.granted_test_suite is + procedure test1 is begin ut3.ut.expect( 1 ).to_equal( 1 ); end; + procedure test2 is begin ut3.ut.expect( 1 ).to_equal( 1 ); end; + end;'; + execute immediate + 'create or replace package ut3_cache_test_owner.not_granted_test_suite is + --%suite + + --%test + procedure test1; + --%test + procedure test2; + end;'; + execute immediate + 'create or replace package body ut3_cache_test_owner.not_granted_test_suite is + procedure test1 is begin ut3.ut.expect( 1 ).to_equal( 1 ); end; + procedure test2 is begin ut3.ut.expect( 1 ).to_equal( 1 ); end; + end;'; + + execute immediate + 'grant execute on ut3_cache_test_owner.granted_test_suite to + ut3_execute_any_proc_user, ut3_select_any_table_user, ut3_select_catalog_user, ut3_no_extra_priv_user'; + end; + + procedure revoke_granted_suite is + pragma autonomous_transaction; + begin + execute immediate + 'revoke execute on ut3_cache_test_owner.granted_test_suite from + ut3_execute_any_proc_user, ut3_select_any_table_user, ut3_select_catalog_user, ut3_no_extra_priv_user'; + exception + when others then + null; + end; + + + procedure add_new_suite is + pragma autonomous_transaction; + begin + execute immediate + 'create or replace package ut3_cache_test_owner.new_suite is + --%suite + + --%test + procedure test1; + --%test + procedure test2; + end;'; + + execute immediate + 'create or replace package body ut3_cache_test_owner.new_suite is + procedure test1 is begin ut3.ut.expect( 1 ).to_equal( 1 ); end; + procedure test2 is begin ut3.ut.expect( 1 ).to_equal( 1 ); end; + end;'; + execute immediate + 'grant execute on ut3_cache_test_owner.new_suite to + ut3_execute_any_proc_user, ut3_select_any_table_user, ut3_select_catalog_user, ut3_no_extra_priv_user'; + end; + + procedure cleanup_two_suites is + pragma autonomous_transaction; + begin + begin + execute immediate 'drop package ut3_cache_test_owner.not_granted_test_suite'; + exception + when others then + null; + end; + begin + execute immediate 'drop package ut3_cache_test_owner.granted_test_suite'; + exception + when others then + null; + end; + end; + + procedure cleanup_new_suite is + pragma autonomous_transaction; + begin + execute immediate 'drop package ut3_cache_test_owner.new_suite'; + exception + when others then + null; + end; + + procedure purge_annotation_cache is + begin + ut3.ut_runner.purge_cache( 'UT3_CACHE_TEST_OWNER' ); + end; + + + procedure disable_ddl_trigger is + pragma autonomous_transaction; + begin + execute immediate 'alter trigger ut3.ut_trigger_annotation_parsing disable'; + execute immediate 'begin ut3.ut_trigger_check.is_alive( ); end;'; + end; + + procedure enable_ddl_trigger is + pragma autonomous_transaction; + begin + execute immediate 'alter trigger ut3.ut_trigger_annotation_parsing enable'; + end; + + procedure create_run_function_for_user(a_user varchar2) is + pragma autonomous_transaction; + begin + execute immediate + 'create or replace function ' || a_user || '.ut_run return clob is + l_data ut3.ut_varchar2_list; + l_results clob; + begin + select * bulk collect into l_data from table (ut3.ut.run( ''ut3_cache_test_owner'' )); + return ut3_tester_helper.main_helper.table_to_clob( l_data ); + end; + '; + execute immediate 'grant execute on ' || a_user || '.ut_run to public '; + end; + + procedure drop_run_function_for_user(a_user varchar2) is + pragma autonomous_transaction; + begin + execute immediate 'drop function ' || a_user || '.ut_run'; + end; + + procedure create_run_function_for_users is + begin + create_run_function_for_user( 'ut3_no_extra_priv_user' ); + create_run_function_for_user( 'ut3_select_catalog_user' ); + create_run_function_for_user( 'ut3_select_any_table_user' ); + create_run_function_for_user( 'ut3_execute_any_proc_user' ); + create_run_function_for_user( 'ut3_cache_test_owner' ); + end; + + procedure drop_run_function_for_users is + begin + drop_run_function_for_user( 'ut3_no_extra_priv_user' ); + drop_run_function_for_user( 'ut3_select_catalog_user' ); + drop_run_function_for_user( 'ut3_select_any_table_user' ); + drop_run_function_for_user( 'ut3_execute_any_proc_user' ); + drop_run_function_for_user( 'ut3_cache_test_owner' ); + end; + + function run_tests_as(a_user varchar2) return clob is + l_results clob; + begin + execute immediate 'begin :x := '||a_user||'.ut_run; end;' using out l_results; + return l_results; + end; +end; +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/annotation_cache_helper.pks b/test/ut3_tester_helper/annotation_cache_helper.pks new file mode 100644 index 000000000..d6ab1f8e2 --- /dev/null +++ b/test/ut3_tester_helper/annotation_cache_helper.pks @@ -0,0 +1,21 @@ +create or replace package annotation_cache_helper as + + procedure setup_two_suites; + procedure add_new_suite; + procedure revoke_granted_suite; + + procedure cleanup_two_suites; + procedure cleanup_new_suite; + + procedure purge_annotation_cache; + + procedure disable_ddl_trigger; + procedure enable_ddl_trigger; + + procedure create_run_function_for_users; + procedure drop_run_function_for_users; + + function run_tests_as(a_user varchar2) return clob; + +end; +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/run_helper.pkb b/test/ut3_tester_helper/run_helper.pkb index 9a9c8587f..70695977b 100644 --- a/test/ut3_tester_helper/run_helper.pkb +++ b/test/ut3_tester_helper/run_helper.pkb @@ -614,7 +614,7 @@ create or replace package body run_helper is execute immediate q'[drop package ut3.some_test_package]'; end; - function get_object_name(a_owner in varchar2) return ut3.ut_object_names is + function get_schema_ut_packages(a_owner in varchar2) return ut3.ut_object_names is begin return ut3.ut_suite_manager.get_schema_ut_packages(ut3.ut_varchar2_rows(a_owner)); end; diff --git a/test/ut3_tester_helper/run_helper.pks b/test/ut3_tester_helper/run_helper.pks index 0f5e5a925..03eb314a7 100644 --- a/test/ut3_tester_helper/run_helper.pks +++ b/test/ut3_tester_helper/run_helper.pks @@ -59,7 +59,7 @@ create or replace package run_helper is procedure drop_dummy_long_test_package; procedure create_ut3_suite; procedure drop_ut3_suite; - function get_object_name(a_owner in varchar2) return ut3.ut_object_names; + function get_schema_ut_packages(a_owner in varchar2) return ut3.ut_object_names; function ut_output_buffer_tmp return t_out_buff_tab pipelined; procedure delete_buffer;