From e41d6f9471ffa99e609e7c4f05a1e163e4948cfe Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Tue, 30 Oct 2018 23:47:28 +0000 Subject: [PATCH 01/33] Interim commit with lots of dirty code - got to a place where I get the infamous ORA-00600 `ORA-00600: internal error code, arguments: [pfrobj.c: invalid RTTI for Object], [], [], [], [], [], [], [], [], [], [], []`` --- .../core/annotations/ut_annotated_object.tps | 1 + .../ut_annotation_cache_manager.pkb | 19 +- .../ut_annotation_cache_manager.pks | 2 +- .../annotations/ut_annotation_manager.pkb | 54 +- .../annotations/ut_annotation_manager.pks | 3 +- source/core/types/ut_logical_suite.tpb | 2 +- source/core/types/ut_logical_suites.tps | 19 + source/core/types/ut_suite.tpb | 4 +- source/core/types/ut_suite.tps | 2 +- source/core/types/ut_suite_context.tpb | 4 +- source/core/types/ut_suite_context.tps | 2 +- source/core/types/ut_suite_item.tpb | 12 +- source/core/types/ut_suite_item.tps | 19 +- source/core/types/ut_test.tpb | 8 +- source/core/types/ut_test.tps | 2 +- source/core/ut_expectation_processor.pkb | 4 +- source/core/ut_expectation_processor.pks | 2 +- source/core/ut_suite_builder.pkb | 619 ++++++++++++++---- source/core/ut_suite_builder.pks | 32 +- source/core/ut_suite_cache.sql | 89 +++ source/core/ut_suite_cache_manager.pkb | 284 ++++++++ source/core/ut_suite_cache_manager.pks | 32 + source/core/ut_suite_cache_schema.sql | 20 + source/core/ut_suite_manager.pkb | 147 ++++- source/install.sql | 5 + source/uninstall_objects.sql | 4 + .../expectations/test_expectations_cursor.pkb | 25 +- test/core/test_suite_builder.pkb | 57 +- test/core/test_suite_builder.pks | 14 +- test/core/test_ut_executable.pkb | 12 +- test/core/test_ut_suite.pkb | 28 +- test/core/test_ut_test.pkb | 30 +- 32 files changed, 1270 insertions(+), 287 deletions(-) create mode 100644 source/core/types/ut_logical_suites.tps create mode 100644 source/core/ut_suite_cache.sql create mode 100644 source/core/ut_suite_cache_manager.pkb create mode 100644 source/core/ut_suite_cache_manager.pks create mode 100644 source/core/ut_suite_cache_schema.sql diff --git a/source/core/annotations/ut_annotated_object.tps b/source/core/annotations/ut_annotated_object.tps index 4bf141a3f..e78a2a282 100644 --- a/source/core/annotations/ut_annotated_object.tps +++ b/source/core/annotations/ut_annotated_object.tps @@ -18,6 +18,7 @@ create type ut_annotated_object as object( object_owner varchar2(250), object_name varchar2(250), object_type varchar2(50), + parse_time date, annotations ut_annotations ) / diff --git a/source/core/annotations/ut_annotation_cache_manager.pkb b/source/core/annotations/ut_annotation_cache_manager.pkb index a05914e37..e9d60730b 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pkb +++ b/source/core/annotations/ut_annotation_cache_manager.pkb @@ -37,17 +37,10 @@ create or replace package body ut_annotation_cache_manager as where cache_id = l_cache_id; if a_object.annotations is not null and a_object.annotations.count > 0 then --- begin insert into ut_annotation_cache (cache_id, annotation_position, annotation_name, annotation_text, subobject_name) select l_cache_id, a.position, a.name, a.text, a.subobject_name from table(a_object.annotations) a; - --TODO - duplicate annotations found?? - should not happen, getting standalone annotations need to happen after procedure annotations were parsed --- exception --- when others then --- dbms_output.put_line(xmltype(anydata.convertCollection(a_object.annotations)).getclobval); --- raise; --- end; end if; commit; end; @@ -81,12 +74,12 @@ 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) return sys_refcursor is + function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info, a_parse_date date) return sys_refcursor is l_results sys_refcursor; begin - open l_results for + open l_results for q'[ select ut_annotated_object( - o.object_owner, o.object_name, o.object_type, + i.object_owner, i.object_name, i.object_type, i.parse_time, cast( collect( ut_annotation( @@ -95,11 +88,13 @@ create or replace package body ut_annotation_cache_manager as ) as ut_annotations ) ) - from table(a_cached_objects) o + 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 join ut_annotation_cache c on i.cache_id = c.cache_id - group by o.object_owner, o.object_name, o.object_type; + where ]'|| case when a_parse_date is null then ':a_parse_date is null' else 'i.parse_time > :a_parse_date' end ||q'[ + group by i.object_owner, i.object_name, i.object_type, i.parse_time]' + using a_cached_objects, a_parse_date; return l_results; end; diff --git a/source/core/annotations/ut_annotation_cache_manager.pks b/source/core/annotations/ut_annotation_cache_manager.pks index d37212d69..7663fdc33 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pks +++ b/source/core/annotations/ut_annotation_cache_manager.pks @@ -32,7 +32,7 @@ create or replace package ut_annotation_cache_manager authid definer as * * @param a_cached_objects a `ut_annotation_objs_cache_info` list with information about objects to get from cache */ - function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info) return sys_refcursor; + function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info, a_parse_date date) return sys_refcursor; /** * Removes cached information about annotations for objects on the list and updates parse_time in cache info table. diff --git a/source/core/annotations/ut_annotation_manager.pkb b/source/core/annotations/ut_annotation_manager.pkb index e44e5dd10..7c299b766 100644 --- a/source/core/annotations/ut_annotation_manager.pkb +++ b/source/core/annotations/ut_annotation_manager.pkb @@ -19,11 +19,12 @@ create or replace package body ut_annotation_manager as ------------------------------ --private definitions - function get_annotation_objs_info_cur(a_object_owner varchar2, a_object_type varchar2) return sys_refcursor is - l_result sys_refcursor; + function get_annotation_objs_info(a_object_owner varchar2, a_object_type varchar2, a_parse_date date := null) 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_dba_view('dba_objects'); - l_cursor_text long; + l_cursor_text varchar2(32767); + l_result ut_annotation_objs_cache_info; begin l_cursor_text := q'[select ]'||l_ut_owner||q'[.ut_annotation_obj_cache_info( @@ -34,10 +35,20 @@ create or replace package body ut_annotation_manager as ) from ]'||l_objects_view||q'[ o left join ]'||l_ut_owner||q'[.ut_annotation_cache_info i - on o.owner = i.object_owner and o.object_name = i.object_name and o.object_type = i.object_type + on o.owner = i.object_owner + and o.object_name = i.object_name + and o.object_type = i.object_type where o.owner = :a_object_owner - and o.object_type = :a_object_type]'; - open l_result for l_cursor_text using a_object_owner, a_object_type; + and o.object_type = :a_object_type + and ]' + || case + when a_parse_date is null + then ':a_parse_date is null' + else 'o.last_ddl_time > :a_parse_date' + end; + open l_rows for l_cursor_text using a_object_owner, a_object_type, a_parse_date; + fetch l_rows bulk collect into l_result limit 1000000; + close l_rows; return l_result; end; @@ -103,6 +114,7 @@ create or replace package body ut_annotation_manager as l_names dbms_preprocessor.source_lines_t; l_name varchar2(250); l_object_lines dbms_preprocessor.source_lines_t; + l_parse_time date := sysdate; pragma autonomous_transaction; begin ut_annotation_cache_manager.cleanup_cache(a_schema_objects); @@ -112,7 +124,7 @@ create or replace package body ut_annotation_manager as if l_names(i) != l_name then l_annotations := ut_annotation_parser.parse_object_annotations(l_object_lines); ut_annotation_cache_manager.update_cache( - ut_annotated_object(a_object_owner, l_name, a_object_type, l_annotations) + ut_annotated_object(a_object_owner, l_name, a_object_type, l_parse_time, l_annotations) ); l_object_lines.delete; end if; @@ -126,7 +138,7 @@ create or replace package body ut_annotation_manager as if a_sources_cursor%rowcount > 0 then l_annotations := ut_annotation_parser.parse_object_annotations(l_object_lines); ut_annotation_cache_manager.update_cache( - ut_annotated_object(a_object_owner, l_name, a_object_type, l_annotations) + ut_annotated_object(a_object_owner, l_name, a_object_type, l_parse_time, l_annotations) ); l_object_lines.delete; end if; @@ -140,7 +152,8 @@ create or replace package body ut_annotation_manager as l_objects_to_parse ut_annotation_objs_cache_info := ut_annotation_objs_cache_info(); begin --get list of objects in cache - select count( 1)into l_objects_in_cache_count from table(a_info_rows) x where x.needs_refresh = 'N'; + select count(1) into l_objects_in_cache_count + from table(a_info_rows) x where x.needs_refresh = 'N'; --if cache is empty and there are objects to parse if l_objects_in_cache_count = 0 and a_info_rows.count > 0 then @@ -173,30 +186,26 @@ create or replace package body ut_annotation_manager as --public definitions ------------------------------------------------------------ procedure rebuild_annotation_cache(a_object_owner varchar2, a_object_type varchar2) is - l_info_cursor sys_refcursor; - l_info_rows ut_annotation_objs_cache_info; begin - l_info_cursor := get_annotation_objs_info_cur(a_object_owner, a_object_type); - fetch l_info_cursor bulk collect into l_info_rows; - close l_info_cursor; - rebuild_annotation_cache(a_object_owner, a_object_type, l_info_rows); + rebuild_annotation_cache( + a_object_owner, + a_object_type, + get_annotation_objs_info(a_object_owner, a_object_type, null) + ); end; - function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2) return ut_annotated_objects pipelined is - l_info_cursor sys_refcursor; + function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2, a_parse_date date := null) return ut_annotated_objects pipelined is l_info_rows ut_annotation_objs_cache_info; l_cursor sys_refcursor; l_results ut_annotated_objects; c_object_fetch_limit constant integer := 10; begin - - l_info_cursor := get_annotation_objs_info_cur(a_object_owner, a_object_type); - fetch l_info_cursor bulk collect into l_info_rows; - close l_info_cursor; + + l_info_rows := get_annotation_objs_info(a_object_owner, a_object_type, a_parse_date); rebuild_annotation_cache(a_object_owner, a_object_type, l_info_rows); --pipe annotations from cache - l_cursor := ut_annotation_cache_manager.get_annotations_for_objects(l_info_rows); + l_cursor := ut_annotation_cache_manager.get_annotations_for_objects(l_info_rows, a_parse_date); loop fetch l_cursor bulk collect into l_results limit c_object_fetch_limit; for i in 1 .. l_results.count loop @@ -205,7 +214,6 @@ create or replace package body ut_annotation_manager as exit when l_cursor%notfound; end loop; close l_cursor; - end; procedure purge_cache(a_object_owner varchar2, a_object_type varchar2) is diff --git a/source/core/annotations/ut_annotation_manager.pks b/source/core/annotations/ut_annotation_manager.pks index a2925c388..f0468ccd5 100644 --- a/source/core/annotations/ut_annotation_manager.pks +++ b/source/core/annotations/ut_annotation_manager.pks @@ -27,9 +27,10 @@ create or replace package ut_annotation_manager authid current_user as * * @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) */ - function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2) return ut_annotated_objects pipelined; + function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2, a_parse_date date := null) return ut_annotated_objects pipelined; /** * Rebuilds annotation cache for a specified schema and object type. diff --git a/source/core/types/ut_logical_suite.tpb b/source/core/types/ut_logical_suite.tpb index 0443bf105..1acfc776c 100644 --- a/source/core/types/ut_logical_suite.tpb +++ b/source/core/types/ut_logical_suite.tpb @@ -21,7 +21,7 @@ create or replace type body ut_logical_suite as ) return self as result is begin self.self_type := $$plsql_unit; - self.init(a_object_owner, a_object_name, a_name); + self.init(a_object_owner, a_object_name, a_name, 0); self.path := a_path; self.disabled_flag := ut_utils.boolean_to_int(false); self.items := ut_suite_items(); diff --git a/source/core/types/ut_logical_suites.tps b/source/core/types/ut_logical_suites.tps new file mode 100644 index 000000000..560f245d0 --- /dev/null +++ b/source/core/types/ut_logical_suites.tps @@ -0,0 +1,19 @@ +create or replace type ut_logical_suites as + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + table of ut_logical_suite +/ diff --git a/source/core/types/ut_suite.tpb b/source/core/types/ut_suite.tpb index 9d9a60e8d..b92804fb0 100644 --- a/source/core/types/ut_suite.tpb +++ b/source/core/types/ut_suite.tpb @@ -17,11 +17,11 @@ create or replace type body ut_suite as */ constructor function ut_suite ( - self in out nocopy ut_suite, a_object_owner varchar2, a_object_name varchar2 + self in out nocopy ut_suite, a_object_owner varchar2, a_object_name varchar2, a_line_no integer ) return self as result is begin self.self_type := $$plsql_unit; - self.init(a_object_owner, a_object_name, a_object_name); + self.init(a_object_owner, a_object_name, a_object_name, a_line_no); self.items := ut_suite_items(); before_all_list := ut_executables(); after_all_list := ut_executables(); diff --git a/source/core/types/ut_suite.tps b/source/core/types/ut_suite.tps index f56d95c08..7057e4911 100644 --- a/source/core/types/ut_suite.tps +++ b/source/core/types/ut_suite.tps @@ -27,7 +27,7 @@ create or replace type ut_suite under ut_logical_suite ( */ after_all_list ut_executables, constructor function ut_suite ( - self in out nocopy ut_suite, a_object_owner varchar2, a_object_name varchar2 + self in out nocopy ut_suite, a_object_owner varchar2, a_object_name varchar2, a_line_no integer ) return self as result, overriding member function do_execute(self in out nocopy ut_suite) return boolean, overriding member function get_error_stack_traces(self ut_suite) return ut_varchar2_list, diff --git a/source/core/types/ut_suite_context.tpb b/source/core/types/ut_suite_context.tpb index a4add114b..c8255f374 100644 --- a/source/core/types/ut_suite_context.tpb +++ b/source/core/types/ut_suite_context.tpb @@ -17,11 +17,11 @@ create or replace type body ut_suite_context as */ constructor function ut_suite_context ( - self in out nocopy ut_suite_context, a_object_owner varchar2, a_object_name varchar2, a_context_name varchar2 := null + self in out nocopy ut_suite_context, a_object_owner varchar2, a_object_name varchar2, a_context_name varchar2 := null, a_line_no integer ) return self as result is begin self.self_type := $$plsql_unit; - self.init(a_object_owner, a_object_name, a_context_name); + self.init(a_object_owner, a_object_name, a_context_name, a_line_no); self.items := ut_suite_items(); before_all_list := ut_executables(); after_all_list := ut_executables(); diff --git a/source/core/types/ut_suite_context.tps b/source/core/types/ut_suite_context.tps index 345c12a65..ce4510c39 100644 --- a/source/core/types/ut_suite_context.tps +++ b/source/core/types/ut_suite_context.tps @@ -16,7 +16,7 @@ create or replace type ut_suite_context under ut_suite ( limitations under the License. */ constructor function ut_suite_context ( - self in out nocopy ut_suite_context, a_object_owner varchar2, a_object_name varchar2, a_context_name varchar2 := null + self in out nocopy ut_suite_context, a_object_owner varchar2, a_object_name varchar2, a_context_name varchar2 := null, a_line_no integer ) return self as result ) / diff --git a/source/core/types/ut_suite_item.tpb b/source/core/types/ut_suite_item.tpb index a3319a4d8..4788a9a3c 100644 --- a/source/core/types/ut_suite_item.tpb +++ b/source/core/types/ut_suite_item.tpb @@ -16,22 +16,18 @@ create or replace type body ut_suite_item as limitations under the License. */ - member procedure init(self in out nocopy ut_suite_item, a_object_owner varchar2, a_object_name varchar2, a_name varchar2) is + member procedure init(self in out nocopy ut_suite_item, a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_line_no integer) is begin self.object_owner := a_object_owner; self.object_name := lower(trim(a_object_name)); self.name := lower(trim(a_name)); self.results_count := ut_results_counter(); - self.warnings := ut_varchar2_list(); + self.warnings := ut_varchar2_rows(); + self.line_no := a_line_no; self.transaction_invalidators := ut_varchar2_list(); self.disabled_flag := ut_utils.boolean_to_int(false); end; - member procedure set_disabled_flag(self in out nocopy ut_suite_item, a_disabled_flag boolean) is - begin - self.disabled_flag := ut_utils.boolean_to_int(a_disabled_flag); - end; - member function get_disabled_flag return boolean is begin return ut_utils.int_to_boolean(self.disabled_flag); @@ -47,7 +43,7 @@ create or replace type body ut_suite_item as return nvl(self.rollback_type, ut_utils.gc_rollback_default); end; -final member procedure do_execute(self in out nocopy ut_suite_item) is + final member procedure do_execute(self in out nocopy ut_suite_item) is l_completed_without_errors boolean; begin l_completed_without_errors := self.do_execute(); diff --git a/source/core/types/ut_suite_item.tps b/source/core/types/ut_suite_item.tps index 52b6a2a19..0f08263c4 100644 --- a/source/core/types/ut_suite_item.tps +++ b/source/core/types/ut_suite_item.tps @@ -19,15 +19,15 @@ create or replace type ut_suite_item force under ut_event_item ( /** * owner of the database object (package) */ - object_owner varchar2(4000 byte), + object_owner varchar2(250 byte), /** * name of the database object (package) */ - object_name varchar2(4000 byte), + object_name varchar2(250 byte), /** * Name of the object (suite, sub-suite, test) */ - name varchar2(4000 byte), + name varchar2(250 byte), /** * Description fo the suite item (as given by the annotation) */ @@ -45,15 +45,22 @@ create or replace type ut_suite_item force under ut_event_item ( * Indicates if the test is to be disabled by execution */ disabled_flag integer(1), + /** + * Line no where annotation identifying this item is placed in package + */ + line_no integer, + /** + * Time when the suite item was last parsed from package source + */ + parse_time date, --execution result fields start_time timestamp with time zone, end_time timestamp with time zone, result integer(1), - warnings ut_varchar2_list, + warnings ut_varchar2_rows, results_count ut_results_counter, transaction_invalidators ut_varchar2_list, - member procedure init(self in out nocopy ut_suite_item, a_object_owner varchar2, a_object_name varchar2, a_name varchar2), - member procedure set_disabled_flag(self in out nocopy ut_suite_item, a_disabled_flag boolean), + member procedure init(self in out nocopy ut_suite_item, a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_line_no integer), member function get_disabled_flag return boolean, not instantiable member procedure mark_as_skipped(self in out nocopy ut_suite_item), member procedure set_rollback_type(self in out nocopy ut_suite_item, a_rollback_type integer), diff --git a/source/core/types/ut_test.tpb b/source/core/types/ut_test.tpb index f6495ecd6..ed9692e14 100644 --- a/source/core/types/ut_test.tpb +++ b/source/core/types/ut_test.tpb @@ -18,11 +18,11 @@ create or replace type body ut_test as constructor function ut_test( self in out nocopy ut_test, a_object_owner varchar2 := null, a_object_name varchar2, a_name varchar2, - a_expected_error_codes ut_integer_list := null + a_line_no integer, a_expected_error_codes ut_integer_list := null ) return self as result is begin self.self_type := $$plsql_unit; - self.init(a_object_owner, a_object_name, a_name); + self.init(a_object_owner, a_object_name, a_name, a_line_no); self.item := ut_executable_test(a_object_owner, a_object_name, a_name, ut_utils.gc_test_execute); self.before_each_list := ut_executables(); self.before_test_list := ut_executables(); @@ -97,7 +97,7 @@ create or replace type body ut_test as end; overriding member procedure calc_execution_result(self in out nocopy ut_test) is - l_warnings ut_varchar2_list; + l_warnings ut_varchar2_rows; begin if self.get_error_stack_traces().count = 0 then self.result := ut_expectation_processor.get_status(); @@ -107,7 +107,7 @@ create or replace type body ut_test as --expectation results need to be part of test results self.all_expectations := ut_expectation_processor.get_all_expectations(); self.failed_expectations := ut_expectation_processor.get_failed_expectations(); - l_warnings := coalesce( ut_expectation_processor.get_warnings(), ut_varchar2_list() ); + l_warnings := coalesce( ut_expectation_processor.get_warnings(), ut_varchar2_rows() ); self.warnings := self.warnings multiset union all l_warnings; self.results_count.increase_warning_count( cardinality(l_warnings) ); self.results_count.set_counter_values(self.result); diff --git a/source/core/types/ut_test.tps b/source/core/types/ut_test.tps index d26e220b9..752ef3ef7 100644 --- a/source/core/types/ut_test.tps +++ b/source/core/types/ut_test.tps @@ -57,7 +57,7 @@ create or replace type ut_test under ut_suite_item ( expected_error_codes ut_integer_list, constructor function ut_test( self in out nocopy ut_test, a_object_owner varchar2 := null, a_object_name varchar2, a_name varchar2, - a_expected_error_codes ut_integer_list := null + a_line_no integer, a_expected_error_codes ut_integer_list := null ) return self as result, overriding member procedure mark_as_skipped(self in out nocopy ut_test), overriding member function do_execute(self in out nocopy ut_test) return boolean, diff --git a/source/core/ut_expectation_processor.pkb b/source/core/ut_expectation_processor.pkb index 45dfb7dee..170846125 100644 --- a/source/core/ut_expectation_processor.pkb +++ b/source/core/ut_expectation_processor.pkb @@ -22,7 +22,7 @@ create or replace package body ut_expectation_processor as g_expectations_called ut_expectation_results := ut_expectation_results(); - g_warnings ut_varchar2_list := ut_varchar2_list(); + g_warnings ut_varchar2_rows := ut_varchar2_rows(); g_nulls_are_equal boolean_not_null := gc_default_nulls_are_equal; @@ -176,7 +176,7 @@ create or replace package body ut_expectation_processor as ); end; - function get_warnings return ut_varchar2_list is + function get_warnings return ut_varchar2_rows is begin return g_warnings; end; diff --git a/source/core/ut_expectation_processor.pks b/source/core/ut_expectation_processor.pks index f5d13ccb6..f58de2441 100644 --- a/source/core/ut_expectation_processor.pks +++ b/source/core/ut_expectation_processor.pks @@ -52,7 +52,7 @@ create or replace package ut_expectation_processor authid current_user as procedure add_depreciation_warning(a_deprecated_syntax varchar2, a_new_syntax varchar2); - function get_warnings return ut_varchar2_list; + function get_warnings return ut_varchar2_rows; function invalidation_exception_found return boolean; procedure set_invalidation_exception; diff --git a/source/core/ut_suite_builder.pkb b/source/core/ut_suite_builder.pkb index 8558b4331..ce269280a 100644 --- a/source/core/ut_suite_builder.pkb +++ b/source/core/ut_suite_builder.pkb @@ -59,7 +59,7 @@ create or replace package body ut_suite_builder is ); gc_placeholder constant varchar2(3) := '\\%'; - + gc_integer_exception constant varchar2(1) := 'I'; gc_named_exception constant varchar2(1) := 'N'; @@ -73,7 +73,7 @@ create or replace package body ut_suite_builder is text t_annotation_text, procedure_name t_object_name ); - + type tt_annotations_by_line is table of t_annotation index by t_annotation_position; --list of annotation texts for a given annotation indexed by annotation position: @@ -84,17 +84,18 @@ create or replace package body ut_suite_builder is -- procedure some_test ... -- when you'd like to have two beforetest procedures executed in a single test type tt_annotation_texts is table of t_annotation_text index by t_annotation_position; - + type tt_annotations_by_name is table of tt_annotation_texts index by t_annotation_name; type tt_annotations_by_proc is table of tt_annotations_by_name index by t_object_name; type t_annotations_info is record ( - owner t_object_name, - name t_object_name, - by_line tt_annotations_by_line, - by_proc tt_annotations_by_proc, - by_name tt_annotations_by_name + owner t_object_name, + name t_object_name, + parse_time date, + by_line tt_annotations_by_line, + by_proc tt_annotations_by_proc, + by_name tt_annotations_by_name ); procedure delete_annotations_range( @@ -430,37 +431,39 @@ create or replace package body ut_suite_builder is a_suite in out nocopy ut_suite, a_tests in out nocopy tt_tests, a_procedure_name t_object_name, - a_proc_annotations tt_annotations_by_name + a_annotations t_annotations_info ) is l_test ut_test; l_annotation_texts tt_annotation_texts; l_annotation_pos binary_integer; + l_proc_annotations tt_annotations_by_name := a_annotations.by_proc(a_procedure_name); begin - if not a_proc_annotations.exists(gc_test) then + if not l_proc_annotations.exists(gc_test) then return; end if; - warning_on_duplicate_annot(a_suite, a_proc_annotations, gc_test, a_procedure_name); - warning_on_duplicate_annot(a_suite, a_proc_annotations, gc_displayname, a_procedure_name); - warning_on_duplicate_annot(a_suite, a_proc_annotations, gc_rollback, a_procedure_name); + warning_on_duplicate_annot( a_suite, l_proc_annotations, gc_test, a_procedure_name); + warning_on_duplicate_annot( a_suite, l_proc_annotations, gc_displayname, a_procedure_name); + warning_on_duplicate_annot( a_suite, l_proc_annotations, gc_rollback, a_procedure_name); warning_bad_annot_combination( - a_suite, a_procedure_name, a_proc_annotations, gc_test, + a_suite, a_procedure_name, l_proc_annotations, gc_test, ut_varchar2_list(gc_beforeeach, gc_aftereach, gc_beforeall, gc_afterall) ); - - l_test := ut_test(a_suite.object_owner, a_suite.object_name, a_procedure_name); - if a_proc_annotations.exists(gc_displayname) then - l_annotation_texts := a_proc_annotations(gc_displayname); + l_test := ut_test(a_suite.object_owner, a_suite.object_name, a_procedure_name, l_proc_annotations( gc_test).first); + l_test.parse_time := a_annotations.parse_time; + + if l_proc_annotations.exists( gc_displayname) then + l_annotation_texts := l_proc_annotations( gc_displayname); --take the last definition if more than one was provided l_test.description := l_annotation_texts(l_annotation_texts.first); --TODO if more than one - warning else - l_test.description := a_proc_annotations(gc_test)(a_proc_annotations(gc_test).first); + l_test.description := l_proc_annotations(gc_test)(l_proc_annotations(gc_test).first); end if; l_test.path := a_suite.path ||'.'||a_procedure_name; - if a_proc_annotations.exists(gc_rollback) then - l_annotation_texts := a_proc_annotations(gc_rollback); + if l_proc_annotations.exists(gc_rollback) then + l_annotation_texts := l_proc_annotations(gc_rollback); l_test.rollback_type := get_rollback_type(l_annotation_texts(l_annotation_texts.first)); if l_test.rollback_type is null then add_annotation_ignored_warning( @@ -470,22 +473,22 @@ create or replace package body ut_suite_builder is end if; end if; - if a_proc_annotations.exists(gc_beforetest) then + if l_proc_annotations.exists( gc_beforetest) then l_test.before_test_list := convert_list( - add_executables( l_test.object_owner, l_test.object_name, a_proc_annotations( gc_beforetest ), gc_beforetest ) + add_executables( l_test.object_owner, l_test.object_name, l_proc_annotations( gc_beforetest ), gc_beforetest ) ); end if; - if a_proc_annotations.exists(gc_aftertest) then + if l_proc_annotations.exists( gc_aftertest) then l_test.after_test_list := convert_list( - add_executables( l_test.object_owner, l_test.object_name, a_proc_annotations( gc_aftertest ), gc_aftertest ) + add_executables( l_test.object_owner, l_test.object_name, l_proc_annotations( gc_aftertest ), gc_aftertest ) ); end if; - if a_proc_annotations.exists(gc_throws) then - add_to_throws_numbers_list(a_suite, l_test.expected_error_codes, a_procedure_name, a_proc_annotations(gc_throws)); + if l_proc_annotations.exists( gc_throws) then + add_to_throws_numbers_list(a_suite, l_test.expected_error_codes, a_procedure_name, l_proc_annotations( gc_throws)); end if; - l_test.disabled_flag := ut_utils.boolean_to_int(a_proc_annotations.exists(gc_disabled)); + l_test.disabled_flag := ut_utils.boolean_to_int( l_proc_annotations.exists( gc_disabled)); - a_tests(a_proc_annotations(gc_test).first) := l_test; + a_tests( l_proc_annotations( gc_test).first) := l_test; end; procedure update_before_after_each( @@ -512,13 +515,37 @@ create or replace package body ut_suite_builder is end if; end; + procedure update_before_after_each( + a_suite_items in out nocopy ut_suite_items, + a_before_each_list tt_executables, + a_after_each_list tt_executables + ) is + l_test ut_test; + l_context ut_logical_suite; + begin + if a_suite_items is not null then + for i in 1 .. a_suite_items.count loop + if a_suite_items(i) is of (ut_test) then + l_test := treat( a_suite_items(i) as ut_test); + l_test.before_each_list := coalesce(convert_list(a_before_each_list),ut_executables()) multiset union all l_test.before_each_list; + l_test.after_each_list := l_test.after_each_list multiset union all coalesce(convert_list(a_after_each_list),ut_executables()); + a_suite_items(i) := l_test; + elsif a_suite_items(i) is of (ut_logical_suite) then + l_context := treat(a_suite_items(i) as ut_logical_suite); + update_before_after_each(l_context.items, a_before_each_list, a_after_each_list); + a_suite_items(i) := l_context; + end if; + end loop; + end if; + end; + procedure process_before_after_annot( a_list in out nocopy tt_executables, a_annotation_name t_annotation_name, a_procedure_name t_object_name, a_proc_annotations tt_annotations_by_name, a_suite in out nocopy ut_suite - ) is + ) is begin if a_proc_annotations.exists(a_annotation_name) and not a_proc_annotations.exists(gc_test) then a_list( a_proc_annotations(a_annotation_name).first ) := ut_executables(ut_executable(a_suite.object_owner, a_suite.object_name, a_procedure_name, a_annotation_name)); @@ -528,7 +555,7 @@ create or replace package body ut_suite_builder is end; procedure add_annotated_procedures( - a_proc_annotations tt_annotations_by_proc, + a_proc_annotations t_annotations_info, a_suite in out nocopy ut_suite, a_before_each_list in out nocopy tt_executables, a_after_each_list in out nocopy tt_executables, @@ -538,18 +565,42 @@ create or replace package body ut_suite_builder is l_procedure_name t_object_name; l_tests tt_tests; begin - l_procedure_name := a_proc_annotations.first; + l_procedure_name := a_proc_annotations.by_proc.first; while l_procedure_name is not null loop - add_test( a_suite, l_tests, l_procedure_name, a_proc_annotations(l_procedure_name) ); - process_before_after_annot(a_before_each_list, gc_beforeeach, l_procedure_name, a_proc_annotations(l_procedure_name), a_suite); - process_before_after_annot(a_after_each_list, gc_aftereach, l_procedure_name, a_proc_annotations(l_procedure_name), a_suite); - process_before_after_annot(a_before_all_list, gc_beforeall, l_procedure_name, a_proc_annotations(l_procedure_name), a_suite); - process_before_after_annot(a_after_all_list, gc_afterall, l_procedure_name, a_proc_annotations(l_procedure_name), a_suite); - l_procedure_name := a_proc_annotations.next( l_procedure_name ); + add_test( a_suite, l_tests, l_procedure_name, a_proc_annotations ); + process_before_after_annot(a_before_each_list, gc_beforeeach, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); + process_before_after_annot(a_after_each_list, gc_aftereach, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); + process_before_after_annot(a_before_all_list, gc_beforeall, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); + process_before_after_annot(a_after_all_list, gc_afterall, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); + l_procedure_name := a_proc_annotations.by_proc.next( l_procedure_name ); end loop; a_suite.items := a_suite.items multiset union all convert_list(l_tests); end; + function get_annotated_procedures( + a_proc_annotations t_annotations_info, + a_suite in out nocopy ut_suite, + a_before_each_list in out nocopy tt_executables, + a_after_each_list in out nocopy tt_executables, + a_before_all_list in out nocopy tt_executables, + a_after_all_list in out nocopy tt_executables + ) return ut_suite_items is + l_procedure_name t_object_name; + l_tests tt_tests; + + begin + l_procedure_name := a_proc_annotations.by_proc.first; + while l_procedure_name is not null loop + add_test( a_suite, l_tests, l_procedure_name, a_proc_annotations ); + process_before_after_annot(a_before_each_list, gc_beforeeach, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); + process_before_after_annot(a_after_each_list, gc_aftereach, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); + process_before_after_annot(a_before_all_list, gc_beforeall, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); + process_before_after_annot(a_after_all_list, gc_afterall, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); + l_procedure_name := a_proc_annotations.by_proc.next( l_procedure_name ); + end loop; + return convert_list(l_tests); + end; + procedure build_suitepath( a_suite in out nocopy ut_suite, a_annotations t_annotations_info @@ -630,7 +681,7 @@ create or replace package body ut_suite_builder is a_suite.disabled_flag := ut_utils.boolean_to_int(a_annotations.by_name.exists(gc_disabled)); --process procedure annotations for suite - add_annotated_procedures(a_annotations.by_proc, a_suite, l_before_each_list, l_after_each_list, l_before_all_list, l_after_all_list); + add_annotated_procedures(a_annotations, a_suite, l_before_each_list, l_after_each_list, l_before_all_list, l_after_all_list); a_suite.set_rollback_type(l_rollback_type); update_before_after_each(a_suite, l_before_each_list, l_after_each_list); @@ -638,6 +689,112 @@ create or replace package body ut_suite_builder is a_suite.after_all_list := convert_list(l_after_all_list); end; + function get_suite_items( + a_suite in out nocopy ut_suite, + a_annotations t_annotations_info + ) return ut_suite_items is + l_before_each_list tt_executables; + l_after_each_list tt_executables; + l_before_all_list tt_executables; + l_after_all_list tt_executables; + l_rollback_type ut_utils.t_rollback_type; + l_annotation_text t_annotation_text; + l_results ut_suite_items := ut_suite_items(); + begin + if a_annotations.by_name.exists(gc_displayname) then + l_annotation_text := trim(a_annotations.by_name(gc_displayname)(a_annotations.by_name(gc_displayname).first)); + if l_annotation_text is not null then + a_suite.description := l_annotation_text; + else + add_annotation_ignored_warning( + a_suite, gc_displayname, '%%% annotation requires a non-empty parameter value.', + a_annotations.by_name(gc_displayname).first + ); + end if; + warning_on_duplicate_annot(a_suite, a_annotations.by_name, gc_displayname); + end if; + + if a_annotations.by_name.exists(gc_rollback) then + l_rollback_type := get_rollback_type(a_annotations.by_name(gc_rollback)(a_annotations.by_name(gc_rollback).first)); + if l_rollback_type is null then + add_annotation_ignored_warning( + a_suite, gc_rollback, '%%% annotation requires one of values as parameter: "auto" or "manual".', + a_annotations.by_name(gc_rollback).first + ); + end if; + warning_on_duplicate_annot(a_suite, a_annotations.by_name, gc_rollback); + end if; + if a_annotations.by_name.exists(gc_beforeall) then + l_before_all_list := add_executables( a_suite.object_owner, a_suite.object_name, a_annotations.by_name(gc_beforeall), gc_beforeall ); + end if; + if a_annotations.by_name.exists(gc_afterall) then + l_after_all_list := add_executables( a_suite.object_owner, a_suite.object_name, a_annotations.by_name(gc_afterall), gc_afterall ); + end if; + + if a_annotations.by_name.exists(gc_beforeeach) then + l_before_each_list := add_executables( a_suite.object_owner, a_suite.object_name, a_annotations.by_name(gc_beforeeach), gc_beforeeach ); + end if; + if a_annotations.by_name.exists(gc_aftereach) then + l_after_each_list := add_executables( a_suite.object_owner, a_suite.object_name, a_annotations.by_name(gc_aftereach), gc_aftereach ); + end if; + + a_suite.disabled_flag := ut_utils.boolean_to_int(a_annotations.by_name.exists(gc_disabled)); + + --process procedure annotations for suite + l_results := get_annotated_procedures(a_annotations, a_suite, l_before_each_list, l_after_each_list, l_before_all_list, l_after_all_list); + + a_suite.set_rollback_type(l_rollback_type); + update_before_after_each(l_results, l_before_each_list, l_after_each_list); + a_suite.before_all_list := convert_list(l_before_all_list); + a_suite.after_all_list := convert_list(l_after_all_list); + return l_results; + end; + + function get_endcontext_position( + a_context_ann_pos t_annotation_position, + a_package_annotations in out nocopy tt_annotations_by_name + ) return t_annotation_position is + l_result t_annotation_position; + begin + if a_package_annotations.exists(gc_endcontext) then + l_result := a_package_annotations(gc_endcontext).first; + while l_result <= a_context_ann_pos loop + l_result := a_package_annotations(gc_endcontext).next(l_result); + end loop; + end if; + return l_result; + end; + + function get_annotations_in_context( + a_annotations t_annotations_info, + a_context_pos t_annotation_position, + a_end_context_pos t_annotation_position + ) return t_annotations_info is + l_result t_annotations_info; + l_position t_annotation_position; + l_procedure_name t_object_name; + l_annotation_name t_annotation_name; + l_annotation_text t_annotation_text; + begin + l_position := a_context_pos; + l_result.owner := a_annotations.owner; + l_result.name := a_annotations.name; + l_result.parse_time := a_annotations.parse_time; + while l_position is not null and l_position <= a_end_context_pos loop + l_result.by_line(l_position) := a_annotations.by_line(l_position); + l_procedure_name := l_result.by_line(l_position).procedure_name; + l_annotation_name := l_result.by_line(l_position).name; + l_annotation_text := l_result.by_line(l_position).text; + if l_procedure_name is not null then + l_result.by_proc(l_procedure_name)(l_annotation_name)(l_position) := l_annotation_text; + else + l_result.by_name(l_annotation_name)(l_position) := l_annotation_text; + end if; + l_position := a_annotations.by_line.next(l_position); + end loop; + return l_result; + end; + procedure add_suite_contexts( a_suite in out nocopy ut_suite, @@ -649,54 +806,70 @@ create or replace package body ut_suite_builder is l_ctx_annotations t_annotations_info; l_context ut_suite_context; l_context_no binary_integer := 1; + type tt_context_names is table of boolean index by t_object_name; + l_context_names tt_context_names; + begin + if not a_annotations.by_name.exists(gc_context) then + return; + end if; - function get_endcontext_position( - a_context_ann_pos t_annotation_position, - a_package_annotations in out nocopy tt_annotations_by_name - ) return t_annotation_position is - l_result t_annotation_position; - begin - if a_package_annotations.exists(gc_endcontext) then - l_result := a_package_annotations(gc_endcontext).first; - while l_result <= a_context_ann_pos loop - l_result := a_package_annotations(gc_endcontext).next(l_result); - end loop; + l_context_pos := a_annotations.by_name( gc_context).first; + + while l_context_pos is not null loop + l_end_context_pos := get_endcontext_position(l_context_pos, a_annotations.by_name ); + if l_end_context_pos is null then + exit; end if; - return l_result; - end; - function get_annotations_in_context( - a_annotations t_annotations_info, - a_context_pos t_annotation_position, - a_end_context_pos t_annotation_position - ) return t_annotations_info is - l_result t_annotations_info; - l_position t_annotation_position; - l_procedure_name t_object_name; - l_annotation_name t_annotation_name; - l_annotation_text t_annotation_text; - begin - l_position := a_context_pos; - l_result.owner := a_annotations.owner; - l_result.name := a_annotations.name; - while l_position is not null and l_position <= a_end_context_pos loop - l_result.by_line(l_position) := a_annotations.by_line(l_position); - l_procedure_name := l_result.by_line(l_position).procedure_name; - l_annotation_name := l_result.by_line(l_position).name; - l_annotation_text := l_result.by_line(l_position).text; - if l_procedure_name is not null then - l_result.by_proc(l_procedure_name)(l_annotation_name)(l_position) := l_annotation_text; - else - l_result.by_name(l_annotation_name)(l_position) := l_annotation_text; - end if; - l_position := a_annotations.by_line.next(l_position); - end loop; - return l_result; - end; + --create a sub-set of annotations to process as sub-suite (context) + l_ctx_annotations := get_annotations_in_context( a_annotations, l_context_pos, l_end_context_pos); + + l_context_name := coalesce( + l_ctx_annotations.by_line( l_context_pos ).text + , gc_context||'_'||l_context_no + ); + if l_context_names.exists(l_context_name) then + add_annotation_ignored_warning( a_suite, 'context', 'Context name must be unique in a suite. Context and all of it''s content ignored.', l_context_pos ); + else + l_context_names(l_context_name) := true; + l_context := ut_suite_context(a_suite.object_owner, a_suite.object_name, l_context_name, l_context_pos ); + + l_context.path := a_suite.path||'.'||l_context_name; + l_context.description := l_ctx_annotations.by_line( l_context_pos ).text; + + warning_on_duplicate_annot( l_context, l_ctx_annotations.by_name, gc_context ); + + populate_suite_contents( l_context, l_ctx_annotations ); + + a_suite.add_item(l_context); + end if; + -- remove annotations within context after processing them + delete_annotations_range(a_annotations, l_context_pos, l_end_context_pos); + + exit when not a_annotations.by_name.exists( gc_context); + + l_context_pos := a_annotations.by_name( gc_context).next( l_context_pos); + l_context_no := l_context_no + 1; + end loop; + end; + + function get_suite_contexts_items( + a_suite in out nocopy ut_suite, + a_annotations in out nocopy t_annotations_info + ) return ut_suite_items is + l_context_pos t_annotation_position; + l_end_context_pos t_annotation_position; + l_context_name t_object_name; + l_ctx_annotations t_annotations_info; + l_context ut_suite_context; + l_context_no binary_integer := 1; + type tt_context_names is table of boolean index by t_object_name; + l_context_names tt_context_names; + l_results ut_suite_items := ut_suite_items(); begin if not a_annotations.by_name.exists(gc_context) then - return; + return l_results; end if; l_context_pos := a_annotations.by_name( gc_context).first; @@ -714,18 +887,23 @@ create or replace package body ut_suite_builder is l_ctx_annotations.by_line( l_context_pos ).text , gc_context||'_'||l_context_no ); + if l_context_names.exists(l_context_name) then + add_annotation_ignored_warning( a_suite, 'context', 'Context name must be unique in a suite. Context and all of it''s content ignored.', l_context_pos ); + else + l_context_names(l_context_name) := true; - l_context := ut_suite_context(a_suite.object_owner, a_suite.object_name, l_context_name ); - - l_context.path := a_suite.path||'.'||l_context_name; - l_context.description := l_ctx_annotations.by_line( l_context_pos ).text; - - warning_on_duplicate_annot( l_context, l_ctx_annotations.by_name, gc_context ); + l_context := ut_suite_context(a_suite.object_owner, a_suite.object_name, l_context_name, l_context_pos ); - populate_suite_contents( l_context, l_ctx_annotations ); + l_context.path := a_suite.path||'.'||l_context_name; + l_context.description := l_ctx_annotations.by_line( l_context_pos ).text; + l_context.parse_time := a_annotations.parse_time; - a_suite.add_item(l_context); + warning_on_duplicate_annot( l_context, l_ctx_annotations.by_name, gc_context ); + l_results := l_results multiset union all get_suite_items( l_context, l_ctx_annotations ); + l_results.extend; + l_results(l_results.last) := l_context; + end if; -- remove annotations within context after processing them delete_annotations_range(a_annotations, l_context_pos, l_end_context_pos); @@ -734,6 +912,7 @@ create or replace package body ut_suite_builder is l_context_pos := a_annotations.by_name( gc_context).next( l_context_pos); l_context_no := l_context_no + 1; end loop; + return l_results; end; procedure warning_on_incomplete_context( @@ -794,9 +973,9 @@ create or replace package body ut_suite_builder is if l_annotations.by_name.exists( gc_suite) then --create an incomplete suite - l_suite := ut_suite(l_annotations.owner, l_annotations.name); - l_annotation_pos := l_annotations.by_name( gc_suite).first; - l_suite.description := l_annotations.by_name( gc_suite)( l_annotation_pos); + l_annotation_pos := l_annotations.by_name(gc_suite).first; + l_suite := ut_suite(l_annotations.owner, l_annotations.name, l_annotation_pos); + l_suite.description := l_annotations.by_name(gc_suite)(l_annotation_pos); warning_on_unknown_annotations(l_suite, l_annotations.by_line); warning_on_duplicate_annot( l_suite, l_annotations.by_name, gc_suite ); @@ -813,7 +992,54 @@ create or replace package body ut_suite_builder is return l_suite; end; - function build_suites_hierarchy(a_suites_by_path tt_schema_suites) return tt_schema_suites is + function build_parent_suites_for_path(a_suite ut_suite) return ut_suite_items is + l_results ut_suite_items := ut_suite_items(); + l_path varchar2(200); + l_name varchar2(200); + begin + l_path := a_suite.path; + loop + l_path := substr( l_path, 1, instr(l_path,'.',-1)-1); + exit when l_path is null; + l_name := substr( l_path, instr(l_path,'.',-1)+1); + l_results.extend; + l_results(l_results.last) := + ut_logical_suite( + a_object_owner => a_suite.object_owner, + a_object_name => l_name, a_name => l_name, a_path => l_path + ); + l_results(l_results.last).parse_time := a_suite.parse_time; + end loop; + return l_results; + end; + function create_suite_items( a_annotations t_annotations_info ) return ut_suite_items is + l_annotations t_annotations_info := a_annotations; + l_annotation_pos t_annotation_position; + l_suite ut_suite; + l_results ut_suite_items; + begin + if l_annotations.by_name.exists(gc_suite) then + l_annotation_pos := l_annotations.by_name(gc_suite).first; + l_suite := ut_suite(l_annotations.owner, l_annotations.name, l_annotation_pos); + l_suite.description := l_annotations.by_name( gc_suite)( l_annotation_pos); + l_suite.parse_time := l_annotations.parse_time; + warning_on_unknown_annotations(l_suite, l_annotations.by_line); + + warning_on_duplicate_annot( l_suite, l_annotations.by_name, gc_suite ); + + build_suitepath( l_suite, l_annotations ); + l_results := get_suite_contexts_items( l_suite, l_annotations ) multiset union all get_suite_items( l_suite, l_annotations ); + + --by this time all contexts were consumed and l_annotations should not have any context/endcontext annotation in it. + warning_on_incomplete_context( l_suite, l_annotations.by_name ); + l_results.extend; + l_results(l_results.last) := l_suite; + l_results := l_results multiset union all build_parent_suites_for_path(l_suite); + end if; + return l_results; + end; + + function build_suites_hierarchy( a_suites_by_path tt_schema_suites ) return tt_schema_suites is l_result tt_schema_suites; l_suite_path varchar2(4000 char); l_parent_path varchar2(4000 char); @@ -856,49 +1082,53 @@ create or replace package body ut_suite_builder is return l_result; end; + function convert_package_annotations(a_object ut_annotated_object) return t_annotations_info is + l_result t_annotations_info; + l_annotation t_annotation; + l_annotation_no binary_integer; + l_annotation_pos binary_integer; + begin + l_result.owner := a_object.object_owner; + l_result.name := lower(trim(a_object.object_name)); + l_result.parse_time := a_object.parse_time; + l_annotation_no := a_object.annotations.first; + while l_annotation_no is not null loop + l_annotation_pos := a_object.annotations(l_annotation_no).position; + l_annotation.name := a_object.annotations(l_annotation_no).name; + l_annotation.text := a_object.annotations(l_annotation_no).text; + l_annotation.procedure_name := lower(trim(a_object.annotations(l_annotation_no).subobject_name)); + l_result.by_line( l_annotation_pos) := l_annotation; + if l_annotation.procedure_name is null then + l_result.by_name( l_annotation.name)( l_annotation_pos) := l_annotation.text; + else + l_result.by_proc(l_annotation.procedure_name)(l_annotation.name)(l_annotation_pos) := l_annotation.text; + end if; + l_annotation_no := a_object.annotations.next(l_annotation_no); + end loop; + return l_result; + end; + + function build_suites(a_annotated_objects sys_refcursor) return t_schema_suites_info is l_suite ut_logical_suite; l_annotated_objects ut_annotated_objects; l_all_suites tt_schema_suites; l_result t_schema_suites_info; - - function convert_package_annotations(a_object ut_annotated_object) return t_annotations_info is - l_result t_annotations_info; - l_annotation t_annotation; - l_annotation_no binary_integer; - l_annotation_pos binary_integer; - begin - l_result.owner := a_object.object_owner; - l_result.name := lower(trim(a_object.object_name)); - l_annotation_no := a_object.annotations.first; - while l_annotation_no is not null loop - l_annotation_pos := a_object.annotations(l_annotation_no).position; - l_annotation.name := a_object.annotations(l_annotation_no).name; - l_annotation.text := a_object.annotations(l_annotation_no).text; - l_annotation.procedure_name := lower(trim(a_object.annotations(l_annotation_no).subobject_name)); - l_result.by_line( l_annotation_pos) := l_annotation; - if l_annotation.procedure_name is null then - l_result.by_name( l_annotation.name)( l_annotation_pos) := l_annotation.text; - else - l_result.by_proc(l_annotation.procedure_name)(l_annotation.name)(l_annotation_pos) := l_annotation.text; + begin + loop + fetch a_annotated_objects bulk collect into l_annotated_objects limit 10; + + for i in 1 .. l_annotated_objects.count loop + l_suite := create_suite(convert_package_annotations(l_annotated_objects(i))); + ut_suite_cache_manager.save_cache( create_suite_items(convert_package_annotations(l_annotated_objects(i))) ); + if l_suite is not null then + l_all_suites(l_suite.path) := l_suite; + l_result.suite_paths(l_suite.object_name) := l_suite.path; end if; - l_annotation_no := a_object.annotations.next(l_annotation_no); end loop; - return l_result; - end; - - begin - fetch a_annotated_objects bulk collect into l_annotated_objects; - close a_annotated_objects; - - for i in 1 .. l_annotated_objects.count loop - l_suite := create_suite(convert_package_annotations(l_annotated_objects(i))); - if l_suite is not null then - l_all_suites(l_suite.path) := l_suite; - l_result.suite_paths(l_suite.object_name) := l_suite.path; - end if; + exit when a_annotated_objects%notfound; end loop; - + close a_annotated_objects; --build hierarchical structure of the suite -- Restructure single-dimension list into hierarchy of suites by the value of %suitepath attribute value l_result.schema_suites := build_suites_hierarchy(l_all_suites); @@ -906,7 +1136,77 @@ create or replace package body ut_suite_builder is return l_result; end; - function build_schema_suites(a_owner_name varchar2) return t_schema_suites_info is + procedure refresh_suite_cache(a_annotated_objects sys_refcursor) is + l_suite ut_logical_suite; + l_annotated_objects ut_annotated_objects; + l_all_suites tt_schema_suites; + l_result t_schema_suites_info; + begin + loop + fetch a_annotated_objects bulk collect into l_annotated_objects limit 10; + + for i in 1 .. l_annotated_objects.count loop + ut_suite_cache_manager.save_cache( create_suite_items(convert_package_annotations(l_annotated_objects(i))) ); + end loop; + exit when a_annotated_objects%notfound; + end loop; + close a_annotated_objects; + end; + + procedure reconstruct_from_cache( + a_suites in out nocopy ut_suite_items, + a_suite_data_cursor sys_refcursor + ) is + type t_item_levels is table of ut_suite_items index by binary_integer; + l_items_at_level t_item_levels; + l_tests ut_suite_items; + l_logical_suites ut_logical_suites; + l_levels ut_integer_list; + l_cursor_idx integer; + l_prev_level integer; + begin + a_suites := ut_suite_items(); + loop + if l_cursor_idx is null then + fetch a_suite_data_cursor bulk collect into l_tests, l_logical_suites, l_levels limit 1000; + l_cursor_idx := l_levels.first; + end if; + exit when l_cursor_idx is null; + if l_levels(l_cursor_idx) > 1 then + if l_prev_level > l_levels(l_cursor_idx) then + l_logical_suites(l_cursor_idx).items := l_items_at_level(l_prev_level); + l_items_at_level(l_prev_level).delete; + end if; + if not l_items_at_level.exists((l_levels(l_cursor_idx))) then + l_items_at_level(l_levels(l_cursor_idx)) := ut_suite_items(); + end if; + l_items_at_level(l_levels(l_cursor_idx)).extend; + if l_tests(l_cursor_idx) is not null then + l_items_at_level(l_levels(l_cursor_idx))(l_items_at_level(l_levels(l_cursor_idx)).last) + := l_tests(l_cursor_idx); + else + l_items_at_level(l_levels(l_cursor_idx))(l_items_at_level(l_levels(l_cursor_idx)).last) + := l_logical_suites(l_cursor_idx); + end if; + else + if l_prev_level > l_levels(l_cursor_idx) then + l_logical_suites(l_cursor_idx).items := l_items_at_level(l_prev_level); + l_items_at_level(l_prev_level).delete; + end if; + a_suites.extend; + if l_tests(l_cursor_idx) is not null then + a_suites(a_suites.last) := l_tests(l_cursor_idx); + else + a_suites(a_suites.last) := l_logical_suites(l_cursor_idx); + end if; + end if; + l_prev_level := l_levels(l_cursor_idx); + l_cursor_idx := l_levels.next(l_cursor_idx); + end loop; + close a_suite_data_cursor; + end; + + function build_schema_suites_old(a_owner_name varchar2) return t_schema_suites_info is l_annotations_cursor sys_refcursor; begin -- form the single-dimension list of suites constructed from parsed packages @@ -920,5 +1220,66 @@ create or replace package body ut_suite_builder is return build_suites(l_annotations_cursor); end; + function get_build_suites(a_owner_name varchar2) return ut_suite_items is + l_suites t_schema_suites_info; + l_results ut_suite_items := ut_suite_items(); + l_index varchar2(4000); + begin + l_suites := build_schema_suites_old(a_owner_name); + l_index := l_suites.schema_suites.first; + while l_index is not null loop + l_results.extend; + l_results(l_results.last) := l_suites.schema_suites(l_index); + l_index := l_suites.schema_suites.next(l_index); + end loop; + return l_results; + end; + + + procedure refresh_suite_cache(a_owner_name varchar2) is + l_annotations_cursor sys_refcursor; + begin + open l_annotations_cursor for + q'[select value(x) + from table( + ]'||ut_utils.ut_owner||q'[.ut_annotation_manager.get_annotated_objects(:a_owner_name, 'PACKAGE') + )x ]' + using a_owner_name; + refresh_suite_cache(l_annotations_cursor); + end; + + function build_schema_suites(a_owner_name varchar2) return ut_suite_items is + l_suites ut_suite_items; + begin + refresh_suite_cache(a_owner_name); + reconstruct_from_cache(l_suites, ut_suite_cache_manager.cached_suite_by_schema(a_owner_name)); + for i in 1 .. l_suites.count loop + l_suites(i).set_rollback_type(l_suites(i).get_rollback_type); + end loop; + return l_suites; + end; + + function build_schema_suites(a_owner_name varchar2,a_object_name varchar2,a_procedure_name varchar2) return ut_suite_items is + l_suites ut_suite_items; + begin + refresh_suite_cache(a_owner_name); + reconstruct_from_cache(l_suites, ut_suite_cache_manager.cached_suite_by_package(a_owner_name, a_object_name, a_procedure_name)); + for i in 1 .. l_suites.count loop + l_suites(i).set_rollback_type(l_suites(i).get_rollback_type); + end loop; + return l_suites; + end; + + function build_schema_suites(a_owner_name varchar2,a_path varchar2) return ut_suite_items is + l_suites ut_suite_items; + begin + refresh_suite_cache(a_owner_name); + reconstruct_from_cache(l_suites, ut_suite_cache_manager.cached_suite_by_path(a_owner_name, a_path)); + for i in 1 .. l_suites.count loop + l_suites(i).set_rollback_type(l_suites(i).get_rollback_type); + end loop; + return l_suites; + end; + end ut_suite_builder; / diff --git a/source/core/ut_suite_builder.pks b/source/core/ut_suite_builder.pks index 2ae40f4d3..0f4d97c76 100644 --- a/source/core/ut_suite_builder.pks +++ b/source/core/ut_suite_builder.pks @@ -20,10 +20,10 @@ create or replace package ut_suite_builder authid current_user is * Responsible for converting annotations into unit test suites */ - --table of ut_suites indexed by object name ( suite_paths('object_name') = ut_logical_suite + --table of ut_suites indexed by suite path - tt_schema_suites('suite.path') gives ut_logical_suite type tt_schema_suites is table of ut_logical_suite index by varchar2(4000 char); - --table of suite paths indexed by object name ( suite_paths('object_name') = 'suitepath.to.object' + --table of suite paths indexed by object name - t_object_suite_path('object_name') = 'suitepath.to.object' type t_object_suite_path is table of varchar2(4000) index by varchar2(4000 char); type t_schema_suites_info is record ( @@ -34,11 +34,32 @@ create or replace package ut_suite_builder authid current_user is /** * Builds set of hierarchical suites for a given schema * - * @param a_owner_name name of the schema to builds suites for + * @param a_owner_name name of the schema to builds suite for * @return list of suites organized into hierarchy * */ - function build_schema_suites(a_owner_name varchar2) return t_schema_suites_info; + function build_schema_suites(a_owner_name varchar2) return ut_suite_items; + + /** + * Builds set of hierarchical suites for a given schema + * + * @param a_owner_name name of the schema to builds suite for + * @param a_object_name object name to build suite for + * @param a_object_name procedure name to build suite for (can be null) + * @return list of suites organized into hierarchy + * + */ + function build_schema_suites(a_owner_name varchar2, a_object_name varchar2,a_procedure_name varchar2) return ut_suite_items; + + /** + * Builds set of hierarchical suites for a given schema + * + * @param a_owner_name name of the schema to builds suite for + * @param a_path suite path to build suite for + * @return list of suites organized into hierarchy + * + */ + function build_schema_suites(a_owner_name varchar2,a_path varchar2) return ut_suite_items; /** * Builds set of hierarchical suites for given annotations @@ -49,5 +70,8 @@ create or replace package ut_suite_builder authid current_user is */ function build_suites(a_annotated_objects sys_refcursor) return t_schema_suites_info; + function get_build_suites(a_owner_name varchar2) return ut_suite_items; + function build_schema_suites_old(a_owner_name varchar2) return t_schema_suites_info; + end ut_suite_builder; / diff --git a/source/core/ut_suite_cache.sql b/source/core/ut_suite_cache.sql new file mode 100644 index 000000000..183f4cf35 --- /dev/null +++ b/source/core/ut_suite_cache.sql @@ -0,0 +1,89 @@ +create or replace type ut_suite_contexts as table of ut_suite_context +/ +create or replace type ut_tests as table of ut_test +/ + +create table ut_suite_cache ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 utPLSQL Project + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + self_type, + path, + object_owner, + object_name, + name, + line_no, + parse_time, + description, + rollback_type, + disabled_flag, + warnings, + before_all_list, + after_all_list, + before_each_list, + before_test_list, + after_each_list, + after_test_list, + expected_error_codes, + item +) + nested table warnings store as ut_suite_cache_warnings + nested table before_all_list store as ut_suite_cache_before_all + nested table after_all_list store as ut_suite_cache_after_all + nested table before_each_list store as ut_suite_cache_before_each + nested table after_each_list store as ut_suite_cache_after_each + nested table before_test_list store as ut_suite_cache_before_test + nested table after_test_list store as ut_suite_cache_after_test + nested table expected_error_codes store as ut_suite_cache_trhows + as + select + c.self_type, + c.path, + c.object_owner, + c.object_name, + c.name, + c.line_no, + c.parse_time, + c.description, + c.rollback_type, + c.disabled_flag, + c.warnings, + c.before_all_list, + c.after_all_list, + t.before_each_list, + t.before_test_list, + t.after_each_list, + t.after_test_list, + t.expected_error_codes, + t.item + from table(ut_suite_contexts(ut_suite_context(user,'package_name','ctx_name',1))) c + cross join table(ut_tests(ut_test(user,'package_name','test_name',1))) t + where rownum < 0 +/ + +alter table ut_suite_cache modify (object_owner not null, path not null, self_type not null, object_name not null, name not null, parse_time not null) +/ +alter table ut_suite_cache add constraint ut_suite_cache_pk primary key (object_owner, path) +/ +create unique index ut_suite_cache_uk on ut_suite_cache(object_owner, object_name, line_no) +/ +create index ut_suite_cache_nu1 on ut_suite_cache(object_owner, object_name) +/ +alter table ut_suite_cache add constraint ut_suite_cache_schema_fk foreign key (object_owner) references ut_suite_cache_schema(object_owner) +/ + +drop type ut_tests +/ + +drop type ut_suite_contexts +/ diff --git a/source/core/ut_suite_cache_manager.pkb b/source/core/ut_suite_cache_manager.pkb new file mode 100644 index 000000000..a51ee14a7 --- /dev/null +++ b/source/core/ut_suite_cache_manager.pkb @@ -0,0 +1,284 @@ +create or replace package body ut_suite_cache_manager is + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + function get_suite_by(a_schema_name varchar2, a_path varchar2 := null, a_object_name varchar2 := null, a_procedure_name varchar2 := null) return sys_refcursor is + l_result sys_refcursor; + begin + open l_result for + select + case self_type + when 'UT_TEST' + then ut_test( + self_type => self_type, + object_owner => object_owner, object_name => object_name, name => name, + description => description, path => path, rollback_type => rollback_type, + disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, + start_time => null, end_time => null, result => null, warnings => warnings, + results_count => ut_results_counter(), transaction_invalidators => null, + before_each_list => before_each_list, before_test_list => before_test_list, + item => item, after_test_list => after_test_list, after_each_list => after_each_list, + all_expectations => null, failed_expectations => null, + parent_error_stack_trace => null, expected_error_codes => expected_error_codes + ) + end as test_item, + case self_type + when 'UT_SUITE' + then ut_suite( + self_type => self_type, + object_owner => object_owner, object_name => object_name, name => name, + description => description, path => path, rollback_type => rollback_type, + disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, + start_time => null, end_time => null, result => null, warnings => warnings, + results_count => ut_results_counter(), transaction_invalidators => null, + items => ut_suite_items(), + before_all_list => before_all_list, after_all_list => after_all_list + ) + when 'UT_SUITE_CONTEXT' + then ut_suite_context( + self_type => self_type, + object_owner => object_owner, object_name => object_name, name => name, + description => description, path => path, rollback_type => rollback_type, + disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, + start_time => null, end_time => null, result => null, warnings => warnings, + results_count => ut_results_counter(), transaction_invalidators => null, + items => ut_suite_items(), + before_all_list => before_all_list, after_all_list => after_all_list + ) + when 'UT_LOGICAL_SUITE' + then ut_logical_suite( + self_type => self_type, + object_owner => object_owner, object_name => object_name, name => name, + description => description, path => path, rollback_type => rollback_type, + disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, + start_time => null, end_time => null, result => null, warnings => warnings, + results_count => ut_results_counter(), transaction_invalidators => null, + items => ut_suite_items() + ) + end as logical_suite, + length(path) - length( replace(path, '.') )+1 as path_level + from ut_suite_cache x + where ( a_path like path ||'.'||'%' + or ( path like a_path || '%' + and object_name = nvl(lower(a_object_name), object_name) + and name = nvl(lower(a_procedure_name), name) + ) + ) + and object_owner = upper(a_schema_name) + order by path desc, object_name, line_no; + + return l_result; + end; + +-- function get_suite_by(a_schema_name varchar2, a_path varchar2 := null, a_object_name varchar2 := null, a_procedure_name varchar2 := null) return sys_refcursor is +-- l_filter varchar2(1000); +-- l_result sys_refcursor; +-- l_owner varchar2(250) := ut_utils.ut_owner(); +-- begin +-- if a_object_name is not null then +-- l_filter := ' object_name = lower(:a_object_name)'; +-- if a_procedure_name is not null then +-- l_filter := l_filter || ' and name = lower(:a_procedure_name)'; +-- else +-- l_filter := l_filter || ' and :a_procedure_name is null'; +-- end if; +-- else +-- l_filter := ' :a_object_name is null and :a_procedure_name is null'; +-- end if; +-- open l_result for q'[ +-- select +-- case self_type +-- when 'UT_TEST' +-- then ]'||l_owner||q'[.ut_test( +-- self_type => self_type, +-- object_owner => object_owner, object_name => object_name, name => name, +-- description => description, path => path, rollback_type => rollback_type, +-- disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, +-- start_time => null, end_time => null, result => null, warnings => warnings, +-- results_count => ut_results_counter(), transaction_invalidators => null, +-- before_each_list => before_each_list, before_test_list => before_test_list, +-- item => item, after_test_list => after_test_list, after_each_list => after_each_list, +-- all_expectations => null, failed_expectations => null, +-- parent_error_stack_trace => null, expected_error_codes => expected_error_codes +-- ) +-- end as test_item, +-- case self_type +-- when 'UT_SUITE' +-- then ]'||l_owner||q'[.ut_suite( +-- self_type => self_type, +-- object_owner => object_owner, object_name => object_name, name => name, +-- description => description, path => path, rollback_type => rollback_type, +-- disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, +-- start_time => null, end_time => null, result => null, warnings => warnings, +-- results_count => ]'||l_owner||q'[.ut_results_counter(), transaction_invalidators => null, +-- items => ut_suite_items(), +-- before_all_list => before_all_list, after_all_list => after_all_list +-- ) +-- when 'UT_SUITE_CONTEXT' +-- then ]'||l_owner||q'[.ut_suite_context( +-- self_type => self_type, +-- object_owner => object_owner, object_name => object_name, name => name, +-- description => description, path => path, rollback_type => rollback_type, +-- disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, +-- start_time => null, end_time => null, result => null, warnings => warnings, +-- results_count => ]'||l_owner||q'[.ut_results_counter(), transaction_invalidators => null, +-- items => ut_suite_items(), +-- before_all_list => before_all_list, after_all_list => after_all_list +-- ) +-- when 'UT_LOGICAL_SUITE' +-- then ]'||l_owner||q'[.ut_logical_suite( +-- self_type => self_type, +-- object_owner => object_owner, object_name => object_name, name => name, +-- description => description, path => path, rollback_type => rollback_type, +-- disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, +-- start_time => null, end_time => null, result => null, warnings => warnings, +-- results_count => ]'||l_owner||q'[.ut_results_counter(), transaction_invalidators => null, +-- items => ut_suite_items() +-- ) +-- end as logical_suite, +-- length(path) - length( replace(path, '.') )+1 as path_level +-- from ]'||l_owner||q'[.ut_suite_cache x +-- where ( :a_path like path ||'.'||'%' +-- or path like :a_path ||'%' and ]'||l_filter||q'[ ) +-- and object_owner = upper(:a_schema_name) +-- order by path desc, object_name, line_no]' +-- using a_path, a_path, a_object_name, a_procedure_name, a_schema_name; +-- +-- return l_result; +-- end; +-- + function cached_suite_by_path(a_schema_name varchar2, a_path varchar2) return sys_refcursor is + begin + return get_suite_by(a_schema_name, a_path); + end; + + function cached_suite_by_package(a_schema_name varchar2, a_object_name varchar2, a_procedure_name varchar2) return sys_refcursor is + l_path varchar2(4000); + begin + select min(path) into l_path + from ut_suite_cache + where object_owner = upper(a_schema_name) + and object_name = lower(a_object_name) + and name = nvl(lower(a_procedure_name),name); + + return get_suite_by(a_schema_name, l_path, a_object_name, a_procedure_name ); + end; + + function cached_suite_by_schema(a_schema_name varchar2) return sys_refcursor is + begin + return get_suite_by(a_schema_name); + end; + + procedure save_cache(a_suite_items ut_suite_items) is + pragma autonomous_transaction; + l_annotation_parse_time date; + l_suite_parse_time date; + begin + if a_suite_items.count = 0 then + return; + end if; + if a_suite_items(1).self_type != 'UT_LOGICAL_SUITE' then + select min(parse_time) + into l_suite_parse_time from ut_suite_cache t + where t.object_name = a_suite_items(1).object_name + and t.object_owner = a_suite_items(1).object_owner + and rownum = 1; + end if; + + l_annotation_parse_time := a_suite_items(1).parse_time; + + if l_annotation_parse_time > l_suite_parse_time or l_suite_parse_time is null then + + merge into ut_suite_cache_schema t + using(select object_owner, max(parse_time) parse_time from table(a_suite_items) group by object_owner) s + on (s.object_owner = t.object_owner) + when matched then update + set t.parse_time = s.parse_time + where s.parse_time > t.parse_time + when not matched then + insert (object_owner, parse_time) + values (s.object_owner, s.parse_time); + + delete from ut_suite_cache t + where (t.object_name, t.object_owner) + in (select s.object_name, s.object_owner from table(a_suite_items) s where s.self_type != 'UT_LOGICAL_SUITE'); + + merge into ut_suite_cache t + using ( + select self_type, path, object_owner, object_name, name, + line_no, parse_time, description, + rollback_type, disabled_flag, warnings + from table(a_suite_items) x where x.self_type = 'UT_LOGICAL_SUITE' + ) s + on (t.object_name = s.object_name and t.object_owner = s.object_owner) + when not matched then + insert ( + self_type, path, object_owner, object_name, name, + line_no, parse_time, description, + rollback_type, disabled_flag, warnings + ) + values ( + s.self_type, s.path, s.object_owner, s.object_name, s.name, + s.line_no, s.parse_time, s.description, + s.rollback_type, s.disabled_flag, s.warnings + ); + + + insert into ut_suite_cache t + ( + self_type, path, object_owner, object_name, name, + line_no, parse_time, description, + rollback_type, disabled_flag, warnings, + before_all_list, after_all_list, + before_each_list, after_each_list, + before_test_list, after_test_list, + expected_error_codes, item + ) + with + suite_items as ( select value(x) item from table(a_suite_items) x ), + suites as ( + select treat(item as ut_suite) i from suite_items s + where s.item.self_type in ('UT_SUITE','UT_SUITE_CONTEXT') + ), + tests as ( + select treat(item as ut_test) t from suite_items s + where s.item.self_type in ('UT_TEST') + ) + select s.i.self_type as self_type, s.i.path as path, + s.i.object_owner as object_owner, s.i.object_name as object_name, s.i.name as name, + s.i.line_no as line_no, s.i.parse_time as parse_time, s.i.description as description, + s.i.rollback_type as rollback_type, s.i.disabled_flag as disabled_flag, s.i.warnings as warnings, + s.i.before_all_list as before_all_list, s.i.after_all_list as after_all_list, + null before_each_list, null after_each_list, + null before_test_list, null after_test_list, + null expected_error_codes, null item + from suites s + union all + select s.t.self_type as self_type, s.t.path as path, + s.t.object_owner as object_owner, s.t.object_name as object_name, s.t.name as name, + s.t.line_no as line_no, s.t.parse_time as parse_time, s.t.description as description, + s.t.rollback_type as rollback_type, s.t.disabled_flag as disabled_flag, s.t.warnings as warnings, + null before_all_list, null after_all_list, + s.t.before_each_list as before_each_list, s.t.after_each_list as after_each_list, + s.t.before_test_list as before_test_list, s.t.after_test_list as after_test_list, + s.t.expected_error_codes as expected_error_codes, s.t.item as item + from tests s; + end if; + commit; + end; +end ut_suite_cache_manager; +/ diff --git a/source/core/ut_suite_cache_manager.pks b/source/core/ut_suite_cache_manager.pks new file mode 100644 index 000000000..1b2d1f2f6 --- /dev/null +++ b/source/core/ut_suite_cache_manager.pks @@ -0,0 +1,32 @@ +create or replace package ut_suite_cache_manager authid definer is + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + /** + * Responsible for storing and retrieving suite data from cache + */ + + procedure save_cache(a_suite_items ut_suite_items); + + function cached_suite_by_path(a_schema_name varchar2, a_path varchar2) return sys_refcursor; + + function cached_suite_by_package(a_schema_name varchar2, a_object_name varchar2, a_procedure_name varchar2) return sys_refcursor; + + function cached_suite_by_schema(a_schema_name varchar2) return sys_refcursor; + +end ut_suite_cache_manager; +/ diff --git a/source/core/ut_suite_cache_schema.sql b/source/core/ut_suite_cache_schema.sql new file mode 100644 index 000000000..890c72e0b --- /dev/null +++ b/source/core/ut_suite_cache_schema.sql @@ -0,0 +1,20 @@ +create table ut_suite_cache_schema ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 utPLSQL Project + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + object_owner varchar2(250) not null, + parse_time date not null, + constraint ut_suite_cache_schema_pk primary key(object_owner) +) organization index +/ + diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index ca438813d..dd9ffb5de 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -33,7 +33,15 @@ create or replace package body ut_suite_manager is g_schema_suites tt_schema_suites_list; - type t_schema_paths is table of ut_varchar2_list index by varchar2(4000 char); +-- type t_schema_paths is table of ut_varchar2_list index by varchar2(4000 char); + + type t_path_item is record ( + object_name varchar2(250), + procedure_name varchar2(250), + suite_path varchar2(4000) + ); + type t_path_items is table of t_path_item; + type t_schema_paths is table of t_path_items index by varchar2(250 char); ------------------ @@ -88,7 +96,7 @@ create or replace package body ut_suite_manager is l_result.suite_paths := g_schema_suites(a_schema_name).suite_paths; else ut_utils.debug_log('Rescanning schema ' || a_schema_name); - l_result := ut_suite_builder.build_schema_suites(a_schema_name); + l_result := ut_suite_builder.build_schema_suites_old(a_schema_name); update_cache(a_schema_name, l_result, get_schema_info(a_schema_name).obj_cnt ); end if; @@ -144,7 +152,7 @@ create or replace package body ut_suite_manager is end if; end; - function clean_paths(a_paths ut_varchar2_list) return ut_varchar2_list is + function trim_and_lower_paths( a_paths ut_varchar2_list) return ut_varchar2_list is l_paths_temp ut_varchar2_list := ut_varchar2_list(); begin l_paths_temp.extend(a_paths.count); @@ -160,7 +168,7 @@ create or replace package body ut_suite_manager is l_schema_names ut_varchar2_rows := ut_varchar2_rows(); c_current_schema constant all_tables.owner%type := sys_context('USERENV','CURRENT_SCHEMA'); begin - a_paths := set( clean_paths(a_paths) ); + a_paths := set( trim_and_lower_paths( a_paths) ); validate_paths(a_paths); @@ -310,29 +318,104 @@ create or replace package body ut_suite_manager is return l_path; end; +-- function group_paths_by_schema(a_paths ut_varchar2_list) return t_schema_paths is +-- l_result t_schema_paths; +-- l_schema varchar2(4000); +-- begin +-- for i in 1 .. a_paths.count loop +-- l_schema := upper(regexp_substr(a_paths(i),'^[^.:]+')); +-- if l_result.exists(l_schema) then +-- l_result(l_schema).extend; +-- l_result(l_schema)(l_result(l_schema).last) := a_paths(i); +-- else +-- l_result(l_schema) := ut_varchar2_list(a_paths(i)); +-- end if; +-- end loop; +-- return l_result; +-- end; +-- +-- function configure_execution_by_path(a_paths in ut_varchar2_list) return ut_suite_items is +-- l_paths ut_varchar2_list := a_paths; +-- l_path varchar2(32767); +-- l_schema varchar2(4000); +-- l_suites_info t_schema_suites_info; +-- l_index varchar2(4000 char); +-- l_suite ut_logical_suite; +-- l_objects_to_run ut_suite_items; +-- l_schema_paths t_schema_paths; +-- begin +-- --resolve schema names from paths and group paths by schema name +-- resolve_schema_names(l_paths); +-- +-- l_schema_paths := group_paths_by_schema(l_paths); +-- +-- l_objects_to_run := ut_suite_items(); +-- +-- l_schema := l_schema_paths.first; +-- while l_schema is not null loop +-- l_paths := l_schema_paths(l_schema); +-- l_suites_info := get_schema_suites(l_schema); +-- +-- for i in 1 .. l_paths.count loop +-- l_path := l_paths(i); +-- --run whole schema +-- if regexp_like(l_path, '^[A-Za-z0-9$#_]+$') then +-- l_index := l_suites_info.schema_suites.first; +-- while l_index is not null loop +-- l_objects_to_run.extend; +-- l_objects_to_run(l_objects_to_run.count) := l_suites_info.schema_suites(l_index); +-- l_index := l_suites_info.schema_suites.next(l_index); +-- end loop; +-- else +-- l_suite := get_suite_filtered_by_path( convert_to_suite_path( l_path, l_suites_info.suite_paths ), l_suites_info.schema_suites ); +-- l_objects_to_run.extend; +-- l_objects_to_run(l_objects_to_run.count) := l_suite; +-- end if; +-- end loop; +-- l_schema := l_schema_paths.next(l_schema); +-- end loop; +-- +-- --propagate rollback type to suite items after organizing suites into hierarchy +-- for i in 1 .. l_objects_to_run.count loop +-- l_objects_to_run(i).set_rollback_type( l_objects_to_run(i).get_rollback_type() ); +-- end loop; +-- +-- return l_objects_to_run; +-- end configure_execution_by_path; + function group_paths_by_schema(a_paths ut_varchar2_list) return t_schema_paths is - l_result t_schema_paths; - l_schema varchar2(4000); + c_package_path_regex constant varchar2(100) := '^([A-Za-z0-9$#_]+)(\.([A-Za-z0-9$#_]+))?(\.([A-Za-z0-9$#_]+))?$'; + l_schema varchar2(4000); + l_empty_result t_path_item; + l_result t_path_item; + l_results t_schema_paths; begin for i in 1 .. a_paths.count loop - l_schema := upper(regexp_substr(a_paths(i),'^[^.:]+')); - if l_result.exists(l_schema) then - l_result(l_schema).extend; - l_result(l_schema)(l_result(l_schema).last) := a_paths(i); + l_result := l_empty_result; + if a_paths(i) like '%:%' then + l_schema := upper(regexp_substr(a_paths(i),'^[^.:]+')); + l_result.suite_path := ltrim(regexp_substr(a_paths(i),'[.:].*$'),':'); + else + l_schema := regexp_substr(a_paths(i), c_package_path_regex, subexpression => 1); + l_result.object_name := regexp_substr(a_paths(i), c_package_path_regex, subexpression => 3); + l_result.procedure_name := regexp_substr(a_paths(i), c_package_path_regex, subexpression => 5); + end if; + if l_results.exists(l_schema) then + l_results(l_schema).extend; + l_results(l_schema)(l_results(l_schema).last) := l_result; else - l_result(l_schema) := ut_varchar2_list(a_paths(i)); + l_results(l_schema) := t_path_items(l_result); end if; end loop; - return l_result; + return l_results; end; - function configure_execution_by_path(a_paths in ut_varchar2_list) return ut_suite_items is l_paths ut_varchar2_list := a_paths; - l_path varchar2(32767); + l_path_items t_path_items; + l_path_item t_path_item; l_schema varchar2(4000); - l_suites_info t_schema_suites_info; + l_suites ut_suite_items; l_index varchar2(4000 char); - l_suite ut_logical_suite; l_objects_to_run ut_suite_items; l_schema_paths t_schema_paths; begin @@ -345,24 +428,24 @@ create or replace package body ut_suite_manager is l_schema := l_schema_paths.first; while l_schema is not null loop - l_paths := l_schema_paths(l_schema); - l_suites_info := get_schema_suites(l_schema); - - for i in 1 .. l_paths.count loop - l_path := l_paths(i); - --run whole schema - if regexp_like(l_path, '^[A-Za-z0-9$#_]+$') then - l_index := l_suites_info.schema_suites.first; - while l_index is not null loop - l_objects_to_run.extend; - l_objects_to_run(l_objects_to_run.count) := l_suites_info.schema_suites(l_index); - l_index := l_suites_info.schema_suites.next(l_index); - end loop; + l_path_items := l_schema_paths(l_schema); + for i in 1 .. l_path_items.count loop + l_path_item := l_path_items(i); + --whole schema + if l_path_item.object_name is null and l_path_item.suite_path is null then + l_suites := ut_suite_builder.build_schema_suites(upper(l_schema)); + --suite path + elsif l_path_item.suite_path is not null then + l_suites := ut_suite_builder.build_schema_suites(upper(l_schema), l_path_item.suite_path); else - l_suite := get_suite_filtered_by_path( convert_to_suite_path( l_path, l_suites_info.suite_paths ), l_suites_info.schema_suites ); - l_objects_to_run.extend; - l_objects_to_run(l_objects_to_run.count) := l_suite; + l_suites := ut_suite_builder.build_schema_suites(upper(l_schema), l_path_item.object_name, l_path_item.procedure_name); end if; + l_index := l_suites.first; + while l_index is not null loop + l_objects_to_run.extend; + l_objects_to_run(l_objects_to_run.count) := l_suites(l_index); + l_index := l_suites.next(l_index); + end loop; end loop; l_schema := l_schema_paths.next(l_schema); end loop; diff --git a/source/install.sql b/source/install.sql index 902b45aba..d71dcb1d1 100644 --- a/source/install.sql +++ b/source/install.sql @@ -70,6 +70,7 @@ alter session set current_schema = &&ut3_owner; @@install_component.sql 'core/types/ut_executable_test.tps' @@install_component.sql 'core/types/ut_test.tps' @@install_component.sql 'core/types/ut_logical_suite.tps' +@@install_component.sql 'core/types/ut_logical_suites.tps' @@install_component.sql 'core/types/ut_suite.tps' @@install_component.sql 'core/types/ut_suite_context.tps' @@install_component.sql 'core/types/ut_file_mapping.tps' @@ -109,6 +110,10 @@ alter session set current_schema = &&ut3_owner; @@install_component.sql 'core/annotations/ut_annotation_manager.pkb' --suite builder +@@install_component.sql 'core/ut_suite_cache_schema.sql' +@@install_component.sql 'core/ut_suite_cache.sql' +@@install_component.sql 'core/ut_suite_cache_manager.pks' +@@install_component.sql 'core/ut_suite_cache_manager.pkb' @@install_component.sql 'core/ut_suite_builder.pks' @@install_component.sql 'core/ut_suite_builder.pkb' --suite manager diff --git a/source/uninstall_objects.sql b/source/uninstall_objects.sql index cf8b3905f..754a16a34 100644 --- a/source/uninstall_objects.sql +++ b/source/uninstall_objects.sql @@ -55,6 +55,10 @@ drop package ut_suite_manager; drop package ut_suite_builder; +drop table ut_suite_cache; + +drop table ut_suite_cache_schema; + drop package ut; drop table ut_dbms_output_cache; diff --git a/test/core/expectations/test_expectations_cursor.pkb b/test/core/expectations/test_expectations_cursor.pkb index fb75b2da8..ac4fc9acf 100644 --- a/test/core/expectations/test_expectations_cursor.pkb +++ b/test/core/expectations/test_expectations_cursor.pkb @@ -1814,13 +1814,13 @@ Diff:% l_expected_message varchar2(32767); l_actual_message varchar2(32767); begin - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) into l_actual_tab from dual; - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) @@ -1846,13 +1846,13 @@ Diff:% l_expected_message varchar2(32767); l_actual_message varchar2(32767); begin - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) into l_actual_tab from dual; - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) @@ -1878,13 +1878,13 @@ Diff:% l_expected_message varchar2(32767); l_actual_message varchar2(32767); begin - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) into l_actual_tab from dual; - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) @@ -1909,15 +1909,16 @@ Diff:% l_expected_tab ut3.ut_annotated_object; l_expected_message varchar2(32767); l_actual_message varchar2(32767); + l_date date := sysdate; begin - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', l_date, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) into l_actual_tab from dual; - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', l_date, ut3.ut_annotations(ut3.ut_annotation(1,'1test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) @@ -1938,8 +1939,8 @@ Diff:% l_expected_message := q'[%Actual: refcursor [ count = 1 ] was expected to equal: refcursor [ count = 1 ] %Diff: %Rows: [ 1 differences ] -%PK TEST - Actual: TESTTESTTEST1testtesttest2testtesttest% -%PK TEST - Expected: TESTTESTTEST11testtesttest2testtesttest%]'; +%PK TEST - Actual: TESTTESTTEST%1testtesttest2testtesttest% +%PK TEST - Expected: TESTTESTTEST%11testtesttest2testtesttest%]'; l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message; --Assert ut.expect(l_actual_message).to_be_like(l_expected_message); @@ -1954,13 +1955,13 @@ Diff:% l_expected_message varchar2(32767); l_actual_message varchar2(32767); begin - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'1test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) into l_actual_tab from dual; - select ut3.ut_annotated_object('TEST','TEST','TEST', + select ut3.ut_annotated_object('TEST','TEST','TEST', SYSDATE, ut3.ut_annotations(ut3.ut_annotation(1,'test','test','test'), ut3.ut_annotation(2,'test','test','test')) ) diff --git a/test/core/test_suite_builder.pkb b/test/core/test_suite_builder.pkb index 19ea81aa0..3216da333 100644 --- a/test/core/test_suite_builder.pkb +++ b/test/core/test_suite_builder.pkb @@ -11,7 +11,7 @@ create or replace package body test_suite_builder is begin open l_cursor for select value(x) from table( ut3.ut_annotated_objects( - ut3.ut_annotated_object('UT3_TESTER', a_package_name, 'PACKAGE', a_annotations) + ut3.ut_annotated_object('UT3_TESTER', a_package_name, 'PACKAGE', SYSDATE, a_annotations) ) ) x; l_suites := ut3.ut_suite_builder.build_suites(l_cursor).schema_suites; l_suite := l_suites(l_suites.first); @@ -843,6 +843,61 @@ create or replace package body test_suite_builder is ); end; + --%test(Gives warning when two contexts have the same name) + procedure duplicate_context_name is + l_actual clob; + l_annotations ut3.ut_annotations; + begin + --Arrange + l_annotations := ut3.ut_annotations( + ut3.ut_annotation(1, 'suite','Cool', null), + ut3.ut_annotation(2, 'beforeall',null, 'suite_level_beforeall'), + ut3.ut_annotation(3, 'test','In suite', 'suite_level_test'), + ut3.ut_annotation(4, 'context','a_context', null), + ut3.ut_annotation(5, 'displayname','A context', null), + ut3.ut_annotation(6, 'beforeall',null, 'context_setup'), + ut3.ut_annotation(7, 'test', 'In context', 'test_in_a_context'), + ut3.ut_annotation(8, 'endcontext',null, null), + ut3.ut_annotation(9, 'context','a_context', null), + ut3.ut_annotation(10, 'displayname','A context', null), + ut3.ut_annotation(11, 'beforeall',null, 'setup_in_duplicated_context'), + ut3.ut_annotation(12, 'test', 'In duplicated context', 'test_in_duplicated_context'), + ut3.ut_annotation(13, 'endcontext',null, null) + ); + --Act + l_actual := invoke_builder_for_annotations(l_annotations, 'SOME_PACKAGE'); + --Assert + ut.expect(l_actual).to_be_like( + '%Context name must be unique in a suite. Context and all of it's content ignored.%at "UT3_TESTER.SOME_PACKAGE", line 9%' + ,'\' + ); + ut.expect(l_actual).to_be_like( + '' || + '%' || + '' || + '%a_contextA contextsome_package.a_context' || + '%' || + '' || + '%test_in_a_contextIn contextsome_package.a_context.test_in_a_context' || + '%' || + '' || + '' || + '%some_packagecontext_setup' || + '%' || + '' || + '' || + '' || + '%suite_level_testIn suitesome_package.suite_level_test' || + '%' || + '' || + '' || + '%some_packagesuite_level_beforeall' || + '%' || + '' || + '' + ); + end; + procedure throws_value_empty is l_actual clob; l_annotations ut3.ut_annotations; diff --git a/test/core/test_suite_builder.pks b/test/core/test_suite_builder.pks index 36517432b..21ca58206 100644 --- a/test/core/test_suite_builder.pks +++ b/test/core/test_suite_builder.pks @@ -39,6 +39,9 @@ create or replace package test_suite_builder is --%test(Gives warning if more than one --%test annotation used) procedure test_annot_duplicated; + --%test(Is added to suite according to annotation order in package spec) + procedure test_annotation_ordering; + --%endcontext --%context(suitepath) @@ -125,6 +128,9 @@ create or replace package test_suite_builder is --%test(Gives warning if --%endcontext is missing a preceding --%context) procedure endcontext_without_context; + --%test(Gives warning when two contexts have the same name and ignores duplicated context) + procedure duplicate_context_name; + --%endcontext --%context(throws) @@ -155,14 +161,6 @@ create or replace package test_suite_builder is --%endcontext - --%context(test) - --%displayname(--%test annontation) - - --%test(Is added to suite according to annotation order in package spec) - procedure test_annotation_ordering; - - --%endcontext - --%context(unknown_annotation) --%displayname(--%bad_annotation) diff --git a/test/core/test_ut_executable.pkb b/test/core/test_ut_executable.pkb index 2d4cde518..d09a25a6d 100644 --- a/test/core/test_ut_executable.pkb +++ b/test/core/test_ut_executable.pkb @@ -8,7 +8,7 @@ create or replace package body test_ut_executable is l_result boolean; begin --Arrange - l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable'); + l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable', a_line_no=> 1); l_executable := ut3.ut_executable_test( null, 'test_ut_executable', 'passing_proc', ut3.ut_utils.gc_test_execute ); --Act l_result := l_executable.do_execute(l_test); @@ -24,7 +24,7 @@ create or replace package body test_ut_executable is l_result boolean; begin --Arrange - l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable'); + l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable', a_line_no=> 1); l_executable := ut3.ut_executable_test( user, 'test_ut_executable', 'output_proc', ut3.ut_utils.gc_test_execute ); --Act l_result := l_executable.do_execute(l_test); @@ -40,7 +40,7 @@ create or replace package body test_ut_executable is l_result boolean; begin --Arrange - l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable'); + l_test := ut3.ut_test(a_object_name => 'test_ut_executable',a_name => 'test_ut_executable', a_line_no=> 1); l_executable := ut3.ut_executable_test( user, 'test_ut_executable', 'throwing_proc', ut3.ut_utils.gc_test_execute ); --Act l_result := l_executable.do_execute(l_test); @@ -80,10 +80,10 @@ create or replace package body test_ut_executable is procedure form_name is begin - ut.expect(ut3.ut_executable_test( user, 'package', 'proc', null ).form_name()).to_equal(user||'.package.proc'); - ut.expect(ut3.ut_executable_test( null, 'package', 'proc', null ).form_name()).to_equal('package.proc'); + ut.expect(ut3.ut_executable_test( user, ' package ', 'proc', null ).form_name()).to_equal(user||'.package.proc'); + ut.expect(ut3.ut_executable_test( null, 'package', ' proc ', null ).form_name()).to_equal('package.proc'); ut.expect(ut3.ut_executable_test( null, 'proc', null, null ).form_name()).to_equal('proc'); - ut.expect(ut3.ut_executable_test( user, 'proc', null, null ).form_name()).to_equal(user||'.proc'); + ut.expect(ut3.ut_executable_test( ' '||user||' ', 'proc', null, null ).form_name()).to_equal(user||'.proc'); end; procedure passing_proc is diff --git a/test/core/test_ut_suite.pkb b/test/core/test_ut_suite.pkb index c66e25af3..9955aa048 100644 --- a/test/core/test_ut_suite.pkb +++ b/test/core/test_ut_suite.pkb @@ -9,13 +9,13 @@ create or replace package body test_ut_suite is l_suite ut3.ut_suite; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.path := 'ut_example_tests'; l_suite.disabled_flag := ut3.ut_utils.boolean_to_int(true); l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); l_suite.after_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_before_all)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); + l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); --Act l_suite.do_execute(); --Assert @@ -32,10 +32,10 @@ create or replace package body test_ut_suite is l_suite ut3.ut_suite; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.path := 'ut_example_tests'; l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_before_all)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'set_g_number_0')); + l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'set_g_number_0', a_line_no=> 1)); --Act l_suite.do_execute(); --Assert @@ -52,12 +52,12 @@ create or replace package body test_ut_suite is l_suite ut3.ut_suite; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.path := 'ut_example_tests'; l_suite.after_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_after_all)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'set_g_number_0')); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'set_g_number_0', a_line_no=> 1)); + l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); --Act l_suite.do_execute(); --Assert @@ -73,9 +73,9 @@ create or replace package body test_ut_suite is procedure package_without_body is l_suite ut3.ut_suite; begin - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_WITHOUT_BODY'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_WITHOUT_BODY', a_line_no=> 1); l_suite.path := 'UT_WITHOUT_BODY'; - l_suite.add_item(ut3.ut_test(a_object_name => 'ut_without_body',a_name => 'test1'/*, a_rollback_type => ut3.ut_utils.gc_rollback_auto*/)); + l_suite.add_item(ut3.ut_test(a_object_name => 'ut_without_body',a_name => 'test1', a_line_no=> 1)); --Act l_suite.do_execute(); --Assert @@ -85,9 +85,9 @@ create or replace package body test_ut_suite is procedure package_with_invalid_body is l_suite ut3.ut_suite; begin - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_WITH_INVALID_BODY'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_WITH_INVALID_BODY', a_line_no=> 1); l_suite.path := 'UT_WITH_INVALID_BODY'; - l_suite.add_item(ut3.ut_test(a_object_name => 'ut_with_invalid_body',a_name => 'test1'/*, a_rollback_type => ut3.ut_utils.gc_rollback_auto*/)); + l_suite.add_item(ut3.ut_test(a_object_name => 'ut_with_invalid_body',a_name => 'test1', a_line_no=> 1)); --Act l_suite.do_execute(); --Assert @@ -99,10 +99,10 @@ create or replace package body test_ut_suite is begin --Arrange execute immediate 'delete from ut$test_table'; - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_TRANSACTION_CONTROL'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_TRANSACTION_CONTROL', a_line_no=> 1); l_suite.path := 'ut_transaction_control'; l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_TRANSACTION_CONTROL', 'setup', ut3.ut_utils.gc_before_all)); - l_suite.add_item(ut3.ut_test(a_object_owner => USER, a_object_name => 'ut_transaction_control',a_name => a_procedure_name)); + l_suite.add_item(ut3.ut_test(a_object_owner => USER, a_object_name => 'ut_transaction_control',a_name => a_procedure_name, a_line_no=> 1)); l_suite.set_rollback_type(a_rollback_type); --Act diff --git a/test/core/test_ut_test.pkb b/test/core/test_ut_test.pkb index ecce27c3c..857ef5e99 100644 --- a/test/core/test_ut_test.pkb +++ b/test/core/test_ut_test.pkb @@ -10,12 +10,12 @@ create or replace package body test_ut_test is l_test ut3.ut_test; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.path := 'ut_example_tests'; l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); + l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 2)); l_suite.items(l_suite.items.last).disabled_flag := ut3.ut_utils.boolean_to_int(true); --Act l_suite.do_execute(); @@ -34,15 +34,15 @@ create or replace package body test_ut_test is l_test ut3.ut_test; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.path := 'ut_example_tests'; l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); - l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number'); + l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); l_test.before_test_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_before_test)); l_test.after_test_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_after_test)); l_suite.add_item(l_test); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); --Act l_suite.do_execute(); --Assert @@ -60,13 +60,13 @@ create or replace package body test_ut_test is l_test ut3.ut_test; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); - l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number'); + l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); l_test.before_each_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_before_each)); l_test.after_each_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_after_each)); l_suite.add_item(l_test); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); --Act l_suite.do_execute(); --Assert @@ -84,13 +84,13 @@ create or replace package body test_ut_test is l_test ut3.ut_test; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); - l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number'); + l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); l_test.before_test_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_before_test)); l_test.after_test_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_after_test)); l_suite.add_item(l_test); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); --Act l_suite.do_execute(); --Assert @@ -108,13 +108,13 @@ create or replace package body test_ut_test is l_test ut3.ut_test; begin --Arrange - l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS'); + l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); - l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number'); + l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); l_test.before_each_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_before_each)); l_test.after_each_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_after_each)); l_suite.add_item(l_test); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number')); + l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); --Act l_suite.do_execute(); --Assert From f475b7cfea9d7e080b937c31ef88c9c2074ea566 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Fri, 2 Nov 2018 02:18:46 +0000 Subject: [PATCH 02/33] Added `suite_cache`. Refactored lots of code for suite parsing/building. (Acceptance) tests need rework due to changes in test execution ordering. --- .../core/annotations/ut_annotated_object.tps | 2 +- .../annotations/ut_annotation_cache_info.sql | 2 +- .../ut_annotation_cache_manager.pkb | 14 +- .../ut_annotation_cache_manager.pks | 2 +- .../annotations/ut_annotation_manager.pkb | 38 +- .../annotations/ut_annotation_manager.pks | 2 +- source/core/types/ut_logical_suite.tpb | 24 +- source/core/types/ut_logical_suite.tps | 7 +- source/core/types/ut_run.tpb | 10 + source/core/types/ut_run.tps | 6 + source/core/types/ut_suite_item.tps | 8 +- source/core/types/ut_test.tpb | 10 + source/core/types/ut_test.tps | 6 + source/core/ut_suite_builder.pkb | 597 ++++++------------ source/core/ut_suite_builder.pks | 62 +- source/core/ut_suite_cache.sql | 4 +- source/core/ut_suite_cache_manager.pkb | 329 ++++------ source/core/ut_suite_cache_manager.pks | 16 +- source/core/ut_suite_cache_schema.sql | 2 +- source/core/ut_suite_manager.pkb | 286 +-------- test/core/test_suite_builder.pkb | 20 +- 21 files changed, 463 insertions(+), 984 deletions(-) diff --git a/source/core/annotations/ut_annotated_object.tps b/source/core/annotations/ut_annotated_object.tps index e78a2a282..1bfefed69 100644 --- a/source/core/annotations/ut_annotated_object.tps +++ b/source/core/annotations/ut_annotated_object.tps @@ -18,7 +18,7 @@ create type ut_annotated_object as object( object_owner varchar2(250), object_name varchar2(250), object_type varchar2(50), - parse_time date, + parse_time timestamp, annotations ut_annotations ) / diff --git a/source/core/annotations/ut_annotation_cache_info.sql b/source/core/annotations/ut_annotation_cache_info.sql index 48f8a606c..fa7eabeec 100644 --- a/source/core/annotations/ut_annotation_cache_info.sql +++ b/source/core/annotations/ut_annotation_cache_info.sql @@ -16,7 +16,7 @@ create table ut_annotation_cache_info ( object_owner varchar2(250) not null, object_name varchar2(250) not null, object_type varchar2(250) not null, - parse_time date 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_name, object_type) ) organization index; diff --git a/source/core/annotations/ut_annotation_cache_manager.pkb b/source/core/annotations/ut_annotation_cache_manager.pkb index e9d60730b..c54d7eec3 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pkb +++ b/source/core/annotations/ut_annotation_cache_manager.pkb @@ -22,14 +22,14 @@ create or replace package body ut_annotation_cache_manager as pragma autonomous_transaction; begin update ut_annotation_cache_info i - set i.parse_time = sysdate + set i.parse_time = systimestamp 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; if sql%rowcount = 0 then 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, sysdate) + values (ut_annotation_cache_seq.nextval, a_object.object_owner, a_object.object_name, a_object.object_type, systimestamp) returning cache_id into l_cache_id; end if; @@ -66,15 +66,15 @@ 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) - when matched then update set parse_time = sysdate + when matched then update set parse_time = systimestamp 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, sysdate); + values (ut_annotation_cache_seq.nextval, o.object_owner, o.object_name, o.object_type, systimestamp); commit; end; - function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info, a_parse_date date) return sys_refcursor is + 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; begin open l_results for q'[ @@ -92,9 +92,9 @@ create or replace package body ut_annotation_cache_manager as 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 join ut_annotation_cache c on i.cache_id = c.cache_id - where ]'|| case when a_parse_date is null then ':a_parse_date is null' else 'i.parse_time > :a_parse_date' end ||q'[ + 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_date; + using a_cached_objects, a_parse_time; return l_results; end; diff --git a/source/core/annotations/ut_annotation_cache_manager.pks b/source/core/annotations/ut_annotation_cache_manager.pks index 7663fdc33..2ee586d12 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pks +++ b/source/core/annotations/ut_annotation_cache_manager.pks @@ -32,7 +32,7 @@ create or replace package ut_annotation_cache_manager authid definer as * * @param a_cached_objects a `ut_annotation_objs_cache_info` list with information about objects to get from cache */ - function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info, a_parse_date date) return sys_refcursor; + function get_annotations_for_objects(a_cached_objects ut_annotation_objs_cache_info, a_parse_time timestamp) return sys_refcursor; /** * Removes cached information about annotations for objects on the list and updates parse_time in cache info table. diff --git a/source/core/annotations/ut_annotation_manager.pkb b/source/core/annotations/ut_annotation_manager.pkb index 7c299b766..9ad1a9e79 100644 --- a/source/core/annotations/ut_annotation_manager.pkb +++ b/source/core/annotations/ut_annotation_manager.pkb @@ -19,7 +19,7 @@ create or replace package body ut_annotation_manager as ------------------------------ --private definitions - function get_annotation_objs_info(a_object_owner varchar2, a_object_type varchar2, a_parse_date date := null) return ut_annotation_objs_cache_info is + function get_annotation_objs_info(a_object_owner varchar2, a_object_type varchar2, a_parse_date timestamp := null) 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_dba_view('dba_objects'); @@ -31,7 +31,7 @@ create or replace package body ut_annotation_manager as object_owner => o.owner, object_name => o.object_name, object_type => o.object_type, - needs_refresh => case when o.last_ddl_time < i.parse_time then 'N' else 'Y' end + needs_refresh => case when o.last_ddl_time < cast(i.parse_time as date) then 'N' else 'Y' end ) from ]'||l_objects_view||q'[ o left join ]'||l_ut_owner||q'[.ut_annotation_cache_info i @@ -44,7 +44,7 @@ create or replace package body ut_annotation_manager as || case when a_parse_date is null then ':a_parse_date is null' - else 'o.last_ddl_time > :a_parse_date' + else 'o.last_ddl_time > cast(:a_parse_date as date)' end; open l_rows for l_cursor_text using a_object_owner, a_object_type, a_parse_date; fetch l_rows bulk collect into l_result limit 1000000; @@ -148,37 +148,17 @@ create or replace package body ut_annotation_manager as procedure rebuild_annotation_cache( a_object_owner varchar2, a_object_type varchar2, a_info_rows ut_annotation_objs_cache_info) is - l_objects_in_cache_count integer; l_objects_to_parse ut_annotation_objs_cache_info := ut_annotation_objs_cache_info(); begin - --get list of objects in cache - select count(1) into l_objects_in_cache_count - from table(a_info_rows) x where x.needs_refresh = 'N'; - - --if cache is empty and there are objects to parse - if l_objects_in_cache_count = 0 and a_info_rows.count > 0 then + select value(x)bulk collect into l_objects_to_parse from table(a_info_rows) x where x.needs_refresh = 'Y'; + --if some source needs parsing and putting into cache + if l_objects_to_parse.count > 0 then build_annot_cache_for_sources( a_object_owner, a_object_type, - --all schema objects - get_sources_to_annotate(a_object_owner, a_object_type), - a_info_rows + get_sources_to_annotate(a_object_owner, a_object_type, l_objects_to_parse), + l_objects_to_parse ); - - --if not all in cache, get list of objects to rebuild cache for - elsif l_objects_in_cache_count < a_info_rows.count then - - select value(x)bulk collect into l_objects_to_parse from table(a_info_rows) x where x.needs_refresh = 'Y'; - - --if some source needs parsing and putting into cache - if l_objects_to_parse.count > 0 then - 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), - l_objects_to_parse - ); - end if; - end if; end; @@ -194,7 +174,7 @@ create or replace package body ut_annotation_manager as ); end; - function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2, a_parse_date date := null) return ut_annotated_objects pipelined is + function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2, a_parse_date timestamp := null) return ut_annotated_objects pipelined is l_info_rows ut_annotation_objs_cache_info; l_cursor sys_refcursor; l_results ut_annotated_objects; diff --git a/source/core/annotations/ut_annotation_manager.pks b/source/core/annotations/ut_annotation_manager.pks index f0468ccd5..829142bd5 100644 --- a/source/core/annotations/ut_annotation_manager.pks +++ b/source/core/annotations/ut_annotation_manager.pks @@ -30,7 +30,7 @@ create or replace package ut_annotation_manager authid current_user as * @param a_parse_date date when object was last parsed * @return array 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 date := null) return ut_annotated_objects pipelined; + function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2, a_parse_date timestamp := null) return ut_annotated_objects pipelined; /** * Rebuilds annotation cache for a specified schema and object type. diff --git a/source/core/types/ut_logical_suite.tpb b/source/core/types/ut_logical_suite.tpb index 1acfc776c..70e0ca462 100644 --- a/source/core/types/ut_logical_suite.tpb +++ b/source/core/types/ut_logical_suite.tpb @@ -21,7 +21,7 @@ create or replace type body ut_logical_suite as ) return self as result is begin self.self_type := $$plsql_unit; - self.init(a_object_owner, a_object_name, a_name, 0); + self.init(a_object_owner, a_object_name, a_name, null); self.path := a_path; self.disabled_flag := ut_utils.boolean_to_int(false); self.items := ut_suite_items(); @@ -33,10 +33,26 @@ create or replace type body ut_logical_suite as return true; end; - member procedure add_item(self in out nocopy ut_logical_suite, a_item ut_suite_item) is + overriding member procedure add_item( + self in out nocopy ut_logical_suite, + a_item ut_suite_item, + a_expected_level integer := 1, + a_current_level integer :=1 + ) is begin - self.items.extend; - self.items(self.items.last) := a_item; + if a_expected_level > a_current_level then + if self.items.last is not null then + self.items(self.items.last).add_item(a_item, a_expected_level, a_current_level+1); + else + raise_application_error(-20000, 'cannot add suite item to sub suite at level '||a_expected_level||'. suite items at level '||a_current_level||' are empty'); + end if; + else + if self.items is null then + self.items := ut_suite_items(); + end if; + self.items.extend; + self.items(self.items.last) := a_item; + end if; end; overriding member procedure mark_as_skipped(self in out nocopy ut_logical_suite) is diff --git a/source/core/types/ut_logical_suite.tps b/source/core/types/ut_logical_suite.tps index 85bb80870..2672cacd3 100644 --- a/source/core/types/ut_logical_suite.tps +++ b/source/core/types/ut_logical_suite.tps @@ -25,7 +25,12 @@ create or replace type ut_logical_suite under ut_suite_item ( self in out nocopy ut_logical_suite, a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_path varchar2 ) return self as result, member function is_valid(self in out nocopy ut_logical_suite) return boolean, - member procedure add_item(self in out nocopy ut_logical_suite, a_item ut_suite_item), + overriding member procedure add_item( + self in out nocopy ut_logical_suite, + a_item ut_suite_item, + a_expected_level integer := 1, + a_current_level integer :=1 + ), overriding member procedure mark_as_skipped(self in out nocopy ut_logical_suite), overriding member procedure set_rollback_type(self in out nocopy ut_logical_suite, a_rollback_type integer), overriding member function do_execute(self in out nocopy ut_logical_suite) return boolean, diff --git a/source/core/types/ut_run.tpb b/source/core/types/ut_run.tpb index 0db9f38c0..f7756cf37 100644 --- a/source/core/types/ut_run.tpb +++ b/source/core/types/ut_run.tpb @@ -51,6 +51,16 @@ create or replace type body ut_run as null; end; + overriding member procedure add_item( + self in out nocopy ut_run, + a_item ut_suite_item, + a_expected_level integer := 1, + a_current_level integer :=1 + ) is + begin + raise_application_error(-20000, 'Cannot add a suite item to ut_run'); + end; + overriding member function do_execute(self in out nocopy ut_run) return boolean is l_completed_without_errors boolean; begin diff --git a/source/core/types/ut_run.tps b/source/core/types/ut_run.tps index 5dc8e0399..3807a2a75 100644 --- a/source/core/types/ut_run.tps +++ b/source/core/types/ut_run.tps @@ -36,6 +36,12 @@ create or replace type ut_run under ut_suite_item ( a_client_character_set varchar2 := null ) return self as result, overriding member procedure mark_as_skipped(self in out nocopy ut_run), + overriding member procedure add_item( + self in out nocopy ut_run, + a_item ut_suite_item, + a_expected_level integer := 1, + a_current_level integer :=1 + ), overriding member function do_execute(self in out nocopy ut_run) return boolean, overriding member procedure calc_execution_result(self in out nocopy ut_run), overriding member procedure mark_as_errored(self in out nocopy ut_run, a_error_stack_trace varchar2), diff --git a/source/core/types/ut_suite_item.tps b/source/core/types/ut_suite_item.tps index 0f08263c4..927ad3807 100644 --- a/source/core/types/ut_suite_item.tps +++ b/source/core/types/ut_suite_item.tps @@ -52,7 +52,7 @@ create or replace type ut_suite_item force under ut_event_item ( /** * Time when the suite item was last parsed from package source */ - parse_time date, + parse_time timestamp, --execution result fields start_time timestamp with time zone, end_time timestamp with time zone, @@ -63,6 +63,12 @@ create or replace type ut_suite_item force under ut_event_item ( member procedure init(self in out nocopy ut_suite_item, a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_line_no integer), member function get_disabled_flag return boolean, not instantiable member procedure mark_as_skipped(self in out nocopy ut_suite_item), + not instantiable member procedure add_item( + self in out nocopy ut_suite_item, + a_item ut_suite_item, + a_expected_level integer := 1, + a_current_level integer :=1 + ), member procedure set_rollback_type(self in out nocopy ut_suite_item, a_rollback_type integer), member function get_rollback_type return integer, member function create_savepoint_if_needed return varchar2, diff --git a/source/core/types/ut_test.tpb b/source/core/types/ut_test.tpb index ed9692e14..d68b19a87 100644 --- a/source/core/types/ut_test.tpb +++ b/source/core/types/ut_test.tpb @@ -34,6 +34,16 @@ create or replace type body ut_test as return; end; + overriding member procedure add_item( + self in out nocopy ut_test, + a_item ut_suite_item, + a_expected_level integer := 1, + a_current_level integer :=1 + ) is + begin + raise_application_error(-20000, 'Cannot add a suite item to ut_test'); + end; + overriding member procedure mark_as_skipped(self in out nocopy ut_test) is begin ut_event_manager.trigger_event(ut_utils.gc_before_test, self); diff --git a/source/core/types/ut_test.tps b/source/core/types/ut_test.tps index 752ef3ef7..9e26508e4 100644 --- a/source/core/types/ut_test.tps +++ b/source/core/types/ut_test.tps @@ -60,6 +60,12 @@ create or replace type ut_test under ut_suite_item ( a_line_no integer, a_expected_error_codes ut_integer_list := null ) return self as result, overriding member procedure mark_as_skipped(self in out nocopy ut_test), + overriding member procedure add_item( + self in out nocopy ut_test, + a_item ut_suite_item, + a_expected_level integer := 1, + a_current_level integer :=1 + ), overriding member function do_execute(self in out nocopy ut_test) return boolean, overriding member procedure calc_execution_result(self in out nocopy ut_test), overriding member procedure mark_as_errored(self in out nocopy ut_test, a_error_stack_trace varchar2), diff --git a/source/core/ut_suite_builder.pkb b/source/core/ut_suite_builder.pkb index ce269280a..21e784f7e 100644 --- a/source/core/ut_suite_builder.pkb +++ b/source/core/ut_suite_builder.pkb @@ -92,7 +92,7 @@ create or replace package body ut_suite_builder is type t_annotations_info is record ( owner t_object_name, name t_object_name, - parse_time date, + parse_time timestamp, by_line tt_annotations_by_line, by_proc tt_annotations_by_proc, by_name tt_annotations_by_name @@ -121,6 +121,15 @@ create or replace package body ut_suite_builder is a_annotations.by_line.delete(a_start_pos, a_end_pos); end; + + procedure add_items_to_list(a_list in out nocopy ut_suite_items, a_items ut_suite_items) is + begin + for i in 1 .. a_items.count loop + a_list.extend(); + a_list(a_list.last) := a_items(i); + end loop; + end; + ----------------------------------------------- -- Processing annotations ----------------------------------------------- @@ -429,13 +438,12 @@ create or replace package body ut_suite_builder is procedure add_test( a_suite in out nocopy ut_suite, - a_tests in out nocopy tt_tests, + a_suite_items in out nocopy ut_suite_items, a_procedure_name t_object_name, a_annotations t_annotations_info ) is l_test ut_test; l_annotation_texts tt_annotation_texts; - l_annotation_pos binary_integer; l_proc_annotations tt_annotations_by_name := a_annotations.by_proc(a_procedure_name); begin if not l_proc_annotations.exists(gc_test) then @@ -488,10 +496,11 @@ create or replace package body ut_suite_builder is end if; l_test.disabled_flag := ut_utils.boolean_to_int( l_proc_annotations.exists( gc_disabled)); - a_tests( l_proc_annotations( gc_test).first) := l_test; + a_suite_items.extend; + a_suite_items( a_suite_items.last ) := l_test; end; - procedure update_before_after_each( + procedure propagate_before_after_each( a_suite in out nocopy ut_logical_suite, a_before_each_list tt_executables, a_after_each_list tt_executables @@ -508,14 +517,14 @@ create or replace package body ut_suite_builder is a_suite.items(i) := l_test; elsif a_suite.items(i) is of (ut_logical_suite) then l_context := treat(a_suite.items(i) as ut_logical_suite); - update_before_after_each(l_context, a_before_each_list, a_after_each_list); + propagate_before_after_each( l_context, a_before_each_list, a_after_each_list); a_suite.items(i) := l_context; end if; end loop; end if; end; - procedure update_before_after_each( + procedure propagate_before_after_each( a_suite_items in out nocopy ut_suite_items, a_before_each_list tt_executables, a_after_each_list tt_executables @@ -532,7 +541,7 @@ create or replace package body ut_suite_builder is a_suite_items(i) := l_test; elsif a_suite_items(i) is of (ut_logical_suite) then l_context := treat(a_suite_items(i) as ut_logical_suite); - update_before_after_each(l_context.items, a_before_each_list, a_after_each_list); + propagate_before_after_each( l_context.items, a_before_each_list, a_after_each_list); a_suite_items(i) := l_context; end if; end loop; @@ -554,9 +563,10 @@ create or replace package body ut_suite_builder is end if; end; - procedure add_annotated_procedures( + procedure get_annotated_procedures( a_proc_annotations t_annotations_info, a_suite in out nocopy ut_suite, + a_suite_items in out nocopy ut_suite_items, a_before_each_list in out nocopy tt_executables, a_after_each_list in out nocopy tt_executables, a_before_all_list in out nocopy tt_executables, @@ -564,41 +574,17 @@ create or replace package body ut_suite_builder is ) is l_procedure_name t_object_name; l_tests tt_tests; - begin - l_procedure_name := a_proc_annotations.by_proc.first; - while l_procedure_name is not null loop - add_test( a_suite, l_tests, l_procedure_name, a_proc_annotations ); - process_before_after_annot(a_before_each_list, gc_beforeeach, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); - process_before_after_annot(a_after_each_list, gc_aftereach, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); - process_before_after_annot(a_before_all_list, gc_beforeall, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); - process_before_after_annot(a_after_all_list, gc_afterall, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); - l_procedure_name := a_proc_annotations.by_proc.next( l_procedure_name ); - end loop; - a_suite.items := a_suite.items multiset union all convert_list(l_tests); - end; - - function get_annotated_procedures( - a_proc_annotations t_annotations_info, - a_suite in out nocopy ut_suite, - a_before_each_list in out nocopy tt_executables, - a_after_each_list in out nocopy tt_executables, - a_before_all_list in out nocopy tt_executables, - a_after_all_list in out nocopy tt_executables - ) return ut_suite_items is - l_procedure_name t_object_name; - l_tests tt_tests; begin l_procedure_name := a_proc_annotations.by_proc.first; while l_procedure_name is not null loop - add_test( a_suite, l_tests, l_procedure_name, a_proc_annotations ); + add_test( a_suite, a_suite_items, l_procedure_name, a_proc_annotations ); process_before_after_annot(a_before_each_list, gc_beforeeach, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); process_before_after_annot(a_after_each_list, gc_aftereach, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); process_before_after_annot(a_before_all_list, gc_beforeall, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); process_before_after_annot(a_after_all_list, gc_afterall, l_procedure_name, a_proc_annotations.by_proc(l_procedure_name), a_suite); l_procedure_name := a_proc_annotations.by_proc.next( l_procedure_name ); end loop; - return convert_list(l_tests); end; procedure build_suitepath( @@ -629,15 +615,15 @@ create or replace package body ut_suite_builder is a_suite.path := lower(coalesce(a_suite.path, a_suite.object_name)); end; - procedure populate_suite_contents( + procedure add_suite_tests( a_suite in out nocopy ut_suite, - a_annotations t_annotations_info + a_annotations t_annotations_info, + a_suite_items in out nocopy ut_suite_items ) is l_before_each_list tt_executables; l_after_each_list tt_executables; l_before_all_list tt_executables; l_after_all_list tt_executables; - l_executables ut_executables; l_rollback_type ut_utils.t_rollback_type; l_annotation_text t_annotation_text; begin @@ -681,75 +667,14 @@ create or replace package body ut_suite_builder is a_suite.disabled_flag := ut_utils.boolean_to_int(a_annotations.by_name.exists(gc_disabled)); --process procedure annotations for suite - add_annotated_procedures(a_annotations, a_suite, l_before_each_list, l_after_each_list, l_before_all_list, l_after_all_list); + get_annotated_procedures(a_annotations, a_suite, a_suite_items, l_before_each_list, l_after_each_list, l_before_all_list, l_after_all_list); a_suite.set_rollback_type(l_rollback_type); - update_before_after_each(a_suite, l_before_each_list, l_after_each_list); + propagate_before_after_each( a_suite_items, l_before_each_list, l_after_each_list); a_suite.before_all_list := convert_list(l_before_all_list); a_suite.after_all_list := convert_list(l_after_all_list); end; - function get_suite_items( - a_suite in out nocopy ut_suite, - a_annotations t_annotations_info - ) return ut_suite_items is - l_before_each_list tt_executables; - l_after_each_list tt_executables; - l_before_all_list tt_executables; - l_after_all_list tt_executables; - l_rollback_type ut_utils.t_rollback_type; - l_annotation_text t_annotation_text; - l_results ut_suite_items := ut_suite_items(); - begin - if a_annotations.by_name.exists(gc_displayname) then - l_annotation_text := trim(a_annotations.by_name(gc_displayname)(a_annotations.by_name(gc_displayname).first)); - if l_annotation_text is not null then - a_suite.description := l_annotation_text; - else - add_annotation_ignored_warning( - a_suite, gc_displayname, '%%% annotation requires a non-empty parameter value.', - a_annotations.by_name(gc_displayname).first - ); - end if; - warning_on_duplicate_annot(a_suite, a_annotations.by_name, gc_displayname); - end if; - - if a_annotations.by_name.exists(gc_rollback) then - l_rollback_type := get_rollback_type(a_annotations.by_name(gc_rollback)(a_annotations.by_name(gc_rollback).first)); - if l_rollback_type is null then - add_annotation_ignored_warning( - a_suite, gc_rollback, '%%% annotation requires one of values as parameter: "auto" or "manual".', - a_annotations.by_name(gc_rollback).first - ); - end if; - warning_on_duplicate_annot(a_suite, a_annotations.by_name, gc_rollback); - end if; - if a_annotations.by_name.exists(gc_beforeall) then - l_before_all_list := add_executables( a_suite.object_owner, a_suite.object_name, a_annotations.by_name(gc_beforeall), gc_beforeall ); - end if; - if a_annotations.by_name.exists(gc_afterall) then - l_after_all_list := add_executables( a_suite.object_owner, a_suite.object_name, a_annotations.by_name(gc_afterall), gc_afterall ); - end if; - - if a_annotations.by_name.exists(gc_beforeeach) then - l_before_each_list := add_executables( a_suite.object_owner, a_suite.object_name, a_annotations.by_name(gc_beforeeach), gc_beforeeach ); - end if; - if a_annotations.by_name.exists(gc_aftereach) then - l_after_each_list := add_executables( a_suite.object_owner, a_suite.object_name, a_annotations.by_name(gc_aftereach), gc_aftereach ); - end if; - - a_suite.disabled_flag := ut_utils.boolean_to_int(a_annotations.by_name.exists(gc_disabled)); - - --process procedure annotations for suite - l_results := get_annotated_procedures(a_annotations, a_suite, l_before_each_list, l_after_each_list, l_before_all_list, l_after_all_list); - - a_suite.set_rollback_type(l_rollback_type); - update_before_after_each(l_results, l_before_each_list, l_after_each_list); - a_suite.before_all_list := convert_list(l_before_all_list); - a_suite.after_all_list := convert_list(l_after_all_list); - return l_results; - end; - function get_endcontext_position( a_context_ann_pos t_annotation_position, a_package_annotations in out nocopy tt_annotations_by_name @@ -795,10 +720,10 @@ create or replace package body ut_suite_builder is return l_result; end; - - procedure add_suite_contexts( + procedure get_suite_contexts_items( a_suite in out nocopy ut_suite, - a_annotations in out nocopy t_annotations_info + a_annotations in out nocopy t_annotations_info, + a_suite_items out nocopy ut_suite_items ) is l_context_pos t_annotation_position; l_end_context_pos t_annotation_position; @@ -806,9 +731,11 @@ create or replace package body ut_suite_builder is l_ctx_annotations t_annotations_info; l_context ut_suite_context; l_context_no binary_integer := 1; + l_context_items ut_suite_items; type tt_context_names is table of boolean index by t_object_name; l_context_names tt_context_names; begin + a_suite_items := ut_suite_items(); if not a_annotations.by_name.exists(gc_context) then return; end if; @@ -821,65 +748,7 @@ create or replace package body ut_suite_builder is exit; end if; - --create a sub-set of annotations to process as sub-suite (context) - l_ctx_annotations := get_annotations_in_context( a_annotations, l_context_pos, l_end_context_pos); - - l_context_name := coalesce( - l_ctx_annotations.by_line( l_context_pos ).text - , gc_context||'_'||l_context_no - ); - if l_context_names.exists(l_context_name) then - add_annotation_ignored_warning( a_suite, 'context', 'Context name must be unique in a suite. Context and all of it''s content ignored.', l_context_pos ); - else - l_context_names(l_context_name) := true; - l_context := ut_suite_context(a_suite.object_owner, a_suite.object_name, l_context_name, l_context_pos ); - - l_context.path := a_suite.path||'.'||l_context_name; - l_context.description := l_ctx_annotations.by_line( l_context_pos ).text; - - warning_on_duplicate_annot( l_context, l_ctx_annotations.by_name, gc_context ); - - populate_suite_contents( l_context, l_ctx_annotations ); - - a_suite.add_item(l_context); - - end if; - -- remove annotations within context after processing them - delete_annotations_range(a_annotations, l_context_pos, l_end_context_pos); - - exit when not a_annotations.by_name.exists( gc_context); - - l_context_pos := a_annotations.by_name( gc_context).next( l_context_pos); - l_context_no := l_context_no + 1; - end loop; - end; - - function get_suite_contexts_items( - a_suite in out nocopy ut_suite, - a_annotations in out nocopy t_annotations_info - ) return ut_suite_items is - l_context_pos t_annotation_position; - l_end_context_pos t_annotation_position; - l_context_name t_object_name; - l_ctx_annotations t_annotations_info; - l_context ut_suite_context; - l_context_no binary_integer := 1; - type tt_context_names is table of boolean index by t_object_name; - l_context_names tt_context_names; - l_results ut_suite_items := ut_suite_items(); - begin - if not a_annotations.by_name.exists(gc_context) then - return l_results; - end if; - - l_context_pos := a_annotations.by_name( gc_context).first; - - while l_context_pos is not null loop - l_end_context_pos := get_endcontext_position(l_context_pos, a_annotations.by_name ); - if l_end_context_pos is null then - exit; - end if; - + l_context_items := ut_suite_items(); --create a sub-set of annotations to process as sub-suite (context) l_ctx_annotations := get_annotations_in_context( a_annotations, l_context_pos, l_end_context_pos); @@ -900,9 +769,10 @@ create or replace package body ut_suite_builder is warning_on_duplicate_annot( l_context, l_ctx_annotations.by_name, gc_context ); - l_results := l_results multiset union all get_suite_items( l_context, l_ctx_annotations ); - l_results.extend; - l_results(l_results.last) := l_context; + add_suite_tests( l_context, l_ctx_annotations, l_context_items ); + add_items_to_list(a_suite_items, l_context_items); + a_suite_items.extend; + a_suite_items(a_suite_items.last) := l_context; end if; -- remove annotations within context after processing them delete_annotations_range(a_annotations, l_context_pos, l_end_context_pos); @@ -912,7 +782,6 @@ create or replace package body ut_suite_builder is l_context_pos := a_annotations.by_name( gc_context).next( l_context_pos); l_context_no := l_context_no + 1; end loop; - return l_results; end; procedure warning_on_incomplete_context( @@ -963,37 +832,7 @@ create or replace package body ut_suite_builder is end loop; end; - function create_suite( - a_annotations t_annotations_info - ) return ut_logical_suite is - l_annotations t_annotations_info := a_annotations; - l_annotation_pos t_annotation_position; - l_suite ut_suite; - begin - if l_annotations.by_name.exists( gc_suite) then - - --create an incomplete suite - l_annotation_pos := l_annotations.by_name(gc_suite).first; - l_suite := ut_suite(l_annotations.owner, l_annotations.name, l_annotation_pos); - l_suite.description := l_annotations.by_name(gc_suite)(l_annotation_pos); - warning_on_unknown_annotations(l_suite, l_annotations.by_line); - - warning_on_duplicate_annot( l_suite, l_annotations.by_name, gc_suite ); - - build_suitepath( l_suite, l_annotations ); - - add_suite_contexts( l_suite, l_annotations ); - --by this time all contexts were consumed and l_annotations should not have any context/endcontext annotation in it. - warning_on_incomplete_context( l_suite, l_annotations.by_name ); - - populate_suite_contents( l_suite, l_annotations ); - - end if; - return l_suite; - end; - - function build_parent_suites_for_path(a_suite ut_suite) return ut_suite_items is - l_results ut_suite_items := ut_suite_items(); + procedure add_parent_logical_suites( a_suite ut_suite, a_suite_items in out nocopy ut_suite_items) is l_path varchar2(200); l_name varchar2(200); begin @@ -1002,21 +841,20 @@ create or replace package body ut_suite_builder is l_path := substr( l_path, 1, instr(l_path,'.',-1)-1); exit when l_path is null; l_name := substr( l_path, instr(l_path,'.',-1)+1); - l_results.extend; - l_results(l_results.last) := - ut_logical_suite( - a_object_owner => a_suite.object_owner, - a_object_name => l_name, a_name => l_name, a_path => l_path - ); - l_results(l_results.last).parse_time := a_suite.parse_time; + a_suite_items.extend; + a_suite_items( a_suite_items.last) := + ut_logical_suite( + a_object_owner => a_suite.object_owner, + a_object_name => l_name, a_name => l_name, a_path => l_path + ); + a_suite_items( a_suite_items.last).parse_time := a_suite.parse_time; end loop; - return l_results; end; - function create_suite_items( a_annotations t_annotations_info ) return ut_suite_items is - l_annotations t_annotations_info := a_annotations; - l_annotation_pos t_annotation_position; - l_suite ut_suite; - l_results ut_suite_items; + + procedure create_suite_item_list( a_annotations t_annotations_info, a_suite_items out nocopy ut_suite_items ) is + l_annotations t_annotations_info := a_annotations; + l_annotation_pos t_annotation_position; + l_suite ut_suite; begin if l_annotations.by_name.exists(gc_suite) then l_annotation_pos := l_annotations.by_name(gc_suite).first; @@ -1028,58 +866,17 @@ create or replace package body ut_suite_builder is warning_on_duplicate_annot( l_suite, l_annotations.by_name, gc_suite ); build_suitepath( l_suite, l_annotations ); - l_results := get_suite_contexts_items( l_suite, l_annotations ) multiset union all get_suite_items( l_suite, l_annotations ); + get_suite_contexts_items( l_suite, l_annotations, a_suite_items ); + --create suite tests and add + add_suite_tests( l_suite, l_annotations, a_suite_items ); --by this time all contexts were consumed and l_annotations should not have any context/endcontext annotation in it. warning_on_incomplete_context( l_suite, l_annotations.by_name ); - l_results.extend; - l_results(l_results.last) := l_suite; - l_results := l_results multiset union all build_parent_suites_for_path(l_suite); - end if; - return l_results; - end; - function build_suites_hierarchy( a_suites_by_path tt_schema_suites ) return tt_schema_suites is - l_result tt_schema_suites; - l_suite_path varchar2(4000 char); - l_parent_path varchar2(4000 char); - l_name varchar2(4000 char); - l_suites_by_path tt_schema_suites; - begin - l_suites_by_path := a_suites_by_path; - --were iterating in reverse order of the index by path table - -- so the first paths will be the leafs of hierarchy and next will their parents - l_suite_path := l_suites_by_path.last; - ut_utils.debug_log('Input suites to process = '||l_suites_by_path.count); - - while l_suite_path is not null loop - l_parent_path := substr( l_suite_path, 1, instr(l_suite_path,'.',-1)-1); - ut_utils.debug_log('Processing l_suite_path = "'||l_suite_path||'", l_parent_path = "'||l_parent_path||'"'); - --no parent => I'm a root element - if l_parent_path is null then - ut_utils.debug_log(' suite "'||l_suite_path||'" is a root element - adding to return list.'); - l_result(l_suite_path) := l_suites_by_path(l_suite_path); - -- not a root suite - need to add it to a parent suite - else - --parent does not exist and needs to be added - if not l_suites_by_path.exists(l_parent_path) then - l_name := substr( l_parent_path, instr(l_parent_path,'.',-1)+1); - ut_utils.debug_log(' Parent suite "'||l_parent_path||'" not found in the list - Adding suite "'||l_name||'"'); - l_suites_by_path(l_parent_path) := - ut_logical_suite( - a_object_owner => l_suites_by_path(l_suite_path).object_owner, - a_object_name => l_name, a_name => l_name, a_path => l_parent_path - ); - else - ut_utils.debug_log(' Parent suite "'||l_parent_path||'" found in list of suites'); - end if; - ut_utils.debug_log(' adding suite "'||l_suite_path||'" to "'||l_parent_path||'" items'); - l_suites_by_path(l_parent_path).add_item( l_suites_by_path(l_suite_path) ); - end if; - l_suite_path := l_suites_by_path.prior(l_suite_path); - end loop; - ut_utils.debug_log(l_result.count||' root suites created.'); - return l_result; + a_suite_items.extend; + a_suite_items( a_suite_items.last) := l_suite; + add_parent_logical_suites( l_suite, a_suite_items ); + end if; end; function convert_package_annotations(a_object ut_annotated_object) return t_annotations_info is @@ -1108,177 +905,195 @@ create or replace package body ut_suite_builder is return l_result; end; - - function build_suites(a_annotated_objects sys_refcursor) return t_schema_suites_info is - l_suite ut_logical_suite; - l_annotated_objects ut_annotated_objects; - l_all_suites tt_schema_suites; - l_result t_schema_suites_info; - begin - loop - fetch a_annotated_objects bulk collect into l_annotated_objects limit 10; - - for i in 1 .. l_annotated_objects.count loop - l_suite := create_suite(convert_package_annotations(l_annotated_objects(i))); - ut_suite_cache_manager.save_cache( create_suite_items(convert_package_annotations(l_annotated_objects(i))) ); - if l_suite is not null then - l_all_suites(l_suite.path) := l_suite; - l_result.suite_paths(l_suite.object_name) := l_suite.path; - end if; - end loop; - exit when a_annotated_objects%notfound; - end loop; - close a_annotated_objects; - --build hierarchical structure of the suite - -- Restructure single-dimension list into hierarchy of suites by the value of %suitepath attribute value - l_result.schema_suites := build_suites_hierarchy(l_all_suites); - - return l_result; - end; - - procedure refresh_suite_cache(a_annotated_objects sys_refcursor) is - l_suite ut_logical_suite; - l_annotated_objects ut_annotated_objects; - l_all_suites tt_schema_suites; - l_result t_schema_suites_info; - begin - loop - fetch a_annotated_objects bulk collect into l_annotated_objects limit 10; - - for i in 1 .. l_annotated_objects.count loop - ut_suite_cache_manager.save_cache( create_suite_items(convert_package_annotations(l_annotated_objects(i))) ); - end loop; - exit when a_annotated_objects%notfound; - end loop; - close a_annotated_objects; - end; - procedure reconstruct_from_cache( a_suites in out nocopy ut_suite_items, a_suite_data_cursor sys_refcursor ) is type t_item_levels is table of ut_suite_items index by binary_integer; l_items_at_level t_item_levels; - l_tests ut_suite_items; - l_logical_suites ut_logical_suites; - l_levels ut_integer_list; - l_cursor_idx integer; - l_prev_level integer; + l_rows ut_suite_cache_manager.tt_cached_suites; +-- l_items ut_suite_items := ut_suite_items(); + l_tests ut_suite_items := ut_suite_items(); + l_logical_suites ut_logical_suites := ut_logical_suites(); + l_level pls_integer; + l_prev_level pls_integer; + l_idx integer; begin a_suites := ut_suite_items(); loop - if l_cursor_idx is null then - fetch a_suite_data_cursor bulk collect into l_tests, l_logical_suites, l_levels limit 1000; - l_cursor_idx := l_levels.first; + if l_idx is null then + fetch a_suite_data_cursor bulk collect into l_rows limit 1000; +-- l_items.delete; +-- l_items.extend(l_rows.count); + l_tests.delete; + l_tests.extend(l_rows.count); + l_logical_suites.delete; + l_logical_suites.extend(l_rows.count); + for i in 1 .. l_rows.count loop + case l_rows(i).self_type + when 'UT_TEST' then +-- l_items(i) := + l_tests(i) := + ut_test( + self_type => l_rows(i).self_type, + object_owner => l_rows(i).object_owner, object_name => l_rows(i).object_name, + name => l_rows(i).name, description => l_rows(i).description, path => l_rows(i).path, + rollback_type => l_rows(i).rollback_type, disabled_flag => l_rows(i).disabled_flag, + line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + before_each_list => l_rows(i).before_each_list, before_test_list => l_rows(i).before_test_list, + item => l_rows(i).item, + after_test_list => l_rows(i).after_test_list, after_each_list => l_rows(i).after_each_list, + all_expectations => ut_expectation_results(), failed_expectations => ut_expectation_results(), + parent_error_stack_trace => null, expected_error_codes => l_rows(i).expected_error_codes + ); + when 'UT_SUITE' then +-- l_items(i) := + l_logical_suites(i) := + ut_suite( + self_type => l_rows(i).self_type, + object_owner => l_rows(i).object_owner, object_name => l_rows(i).object_name, + name => l_rows(i).name, description => l_rows(i).description, path => l_rows(i).path, + rollback_type => l_rows(i).rollback_type, disabled_flag => l_rows(i).disabled_flag, + line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items(), + before_all_list => l_rows(i).before_all_list, after_all_list => l_rows(i).after_all_list + ); + when 'UT_SUITE_CONTEXT' then +-- l_items(i) := + l_logical_suites(i) := + ut_suite_context( + self_type => l_rows(i).self_type, + object_owner => l_rows(i).object_owner, object_name => l_rows(i).object_name, name => l_rows(i).name, + description => l_rows(i).description, path => l_rows(i).path, rollback_type => l_rows(i).rollback_type, + disabled_flag => l_rows(i).disabled_flag, line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items(), + before_all_list => l_rows(i).before_all_list, after_all_list => l_rows(i).after_all_list + ); + when 'UT_LOGICAL_SUITE' then +-- l_items(i) := + l_logical_suites(i) := + ut_logical_suite( + self_type => l_rows(i).self_type, + object_owner => l_rows(i).object_owner, object_name => l_rows(i).object_name, name => l_rows(i).name, + description => l_rows(i).description, path => l_rows(i).path, rollback_type => l_rows(i).rollback_type, + disabled_flag => l_rows(i).disabled_flag, line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items() + ); + end case; + end loop; + l_idx := l_rows.first; end if; - exit when l_cursor_idx is null; - if l_levels(l_cursor_idx) > 1 then - if l_prev_level > l_levels(l_cursor_idx) then - l_logical_suites(l_cursor_idx).items := l_items_at_level(l_prev_level); + exit when l_idx is null; + l_level := length(l_rows(l_idx).path) - length( replace(l_rows(l_idx).path, '.') ) + 1; + if l_level > 1 then + if l_prev_level > l_level then + l_logical_suites(l_idx).items := l_items_at_level(l_prev_level); l_items_at_level(l_prev_level).delete; end if; - if not l_items_at_level.exists((l_levels(l_cursor_idx))) then - l_items_at_level(l_levels(l_cursor_idx)) := ut_suite_items(); + if not l_items_at_level.exists((l_level)) then + l_items_at_level(l_level) := ut_suite_items(); end if; - l_items_at_level(l_levels(l_cursor_idx)).extend; - if l_tests(l_cursor_idx) is not null then - l_items_at_level(l_levels(l_cursor_idx))(l_items_at_level(l_levels(l_cursor_idx)).last) - := l_tests(l_cursor_idx); + l_items_at_level(l_level).extend; + if l_tests(l_idx) is not null then + l_items_at_level(l_level)(l_items_at_level(l_level).last) := l_tests(l_idx); else - l_items_at_level(l_levels(l_cursor_idx))(l_items_at_level(l_levels(l_cursor_idx)).last) - := l_logical_suites(l_cursor_idx); + l_items_at_level(l_level)(l_items_at_level(l_level).last) := l_logical_suites(l_idx); end if; else - if l_prev_level > l_levels(l_cursor_idx) then - l_logical_suites(l_cursor_idx).items := l_items_at_level(l_prev_level); + if l_prev_level > l_level then + l_logical_suites(l_idx).items := l_items_at_level(l_prev_level); l_items_at_level(l_prev_level).delete; end if; a_suites.extend; - if l_tests(l_cursor_idx) is not null then - a_suites(a_suites.last) := l_tests(l_cursor_idx); + if l_tests(l_idx) is not null then + a_suites(a_suites.last) := l_tests(l_idx); else - a_suites(a_suites.last) := l_logical_suites(l_cursor_idx); + a_suites(a_suites.last) := l_logical_suites(l_idx); end if; end if; - l_prev_level := l_levels(l_cursor_idx); - l_cursor_idx := l_levels.next(l_cursor_idx); +-- if l_level = 0 then +-- a_suites.extend; +-- a_suites(a_suites.last) := l_items(l_idx); +-- else +-- a_suites(a_suites.last).add_item( l_items(l_idx), l_level ); +-- end if; + l_prev_level := l_level; + l_idx := l_rows.next(l_idx); end loop; close a_suite_data_cursor; end; - function build_schema_suites_old(a_owner_name varchar2) return t_schema_suites_info is + function build_suites_from_annotations( + a_owner_name varchar2, + a_annotated_objects sys_refcursor, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null + ) return ut_suite_items is + l_suites ut_suite_items; l_annotations_cursor sys_refcursor; + l_annotated_objects ut_annotated_objects; + l_suite_items ut_suite_items; begin - -- form the single-dimension list of suites constructed from parsed packages - open l_annotations_cursor for - q'[select value(x) - from table( - ]'||ut_utils.ut_owner||q'[.ut_annotation_manager.get_annotated_objects(:a_owner_name, 'PACKAGE') - )x ]' - using a_owner_name; - - return build_suites(l_annotations_cursor); - end; + loop + fetch a_annotated_objects bulk collect into l_annotated_objects limit 10; - function get_build_suites(a_owner_name varchar2) return ut_suite_items is - l_suites t_schema_suites_info; - l_results ut_suite_items := ut_suite_items(); - l_index varchar2(4000); - begin - l_suites := build_schema_suites_old(a_owner_name); - l_index := l_suites.schema_suites.first; - while l_index is not null loop - l_results.extend; - l_results(l_results.last) := l_suites.schema_suites(l_index); - l_index := l_suites.schema_suites.next(l_index); + for i in 1 .. l_annotated_objects.count loop + create_suite_item_list( + convert_package_annotations( l_annotated_objects( i ) ), + l_suite_items + ); + ut_suite_cache_manager.save_cache( a_owner_name, l_suite_items ); + end loop; + exit when a_annotated_objects%notfound; end loop; - return l_results; - end; - - - procedure refresh_suite_cache(a_owner_name varchar2) is - l_annotations_cursor sys_refcursor; - begin - open l_annotations_cursor for - q'[select value(x) - from table( - ]'||ut_utils.ut_owner||q'[.ut_annotation_manager.get_annotated_objects(:a_owner_name, 'PACKAGE') - )x ]' - using a_owner_name; - refresh_suite_cache(l_annotations_cursor); - end; + close a_annotated_objects; - function build_schema_suites(a_owner_name varchar2) return ut_suite_items is - l_suites ut_suite_items; - begin - refresh_suite_cache(a_owner_name); - reconstruct_from_cache(l_suites, ut_suite_cache_manager.cached_suite_by_schema(a_owner_name)); + reconstruct_from_cache( + l_suites, + ut_suite_cache_manager.get_cached_suite_data( + a_owner_name, + a_path, + a_object_name, + a_procedure_name ) + ); for i in 1 .. l_suites.count loop - l_suites(i).set_rollback_type(l_suites(i).get_rollback_type); + l_suites( i ).set_rollback_type( l_suites( i ).get_rollback_type ); end loop; return l_suites; end; - function build_schema_suites(a_owner_name varchar2,a_object_name varchar2,a_procedure_name varchar2) return ut_suite_items is - l_suites ut_suite_items; + function build_schema_suites( + a_owner_name varchar2, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null + ) return ut_suite_items is + l_annotations_cursor sys_refcursor; begin - refresh_suite_cache(a_owner_name); - reconstruct_from_cache(l_suites, ut_suite_cache_manager.cached_suite_by_package(a_owner_name, a_object_name, a_procedure_name)); - for i in 1 .. l_suites.count loop - l_suites(i).set_rollback_type(l_suites(i).get_rollback_type); - end loop; - return l_suites; - end; - function build_schema_suites(a_owner_name varchar2,a_path varchar2) return ut_suite_items is - l_suites ut_suite_items; - begin - refresh_suite_cache(a_owner_name); - reconstruct_from_cache(l_suites, ut_suite_cache_manager.cached_suite_by_path(a_owner_name, a_path)); - for i in 1 .. l_suites.count loop - l_suites(i).set_rollback_type(l_suites(i).get_rollback_type); - end loop; - return l_suites; + open l_annotations_cursor for + q'[select value(x) + from table( + ]' || ut_utils.ut_owner || q'[.ut_annotation_manager.get_annotated_objects(:a_owner_name, 'PACKAGE', :a_suite_cache_parse_time) + )x ]' + using a_owner_name, ut_suite_cache_manager.get_schema_parse_time(a_owner_name); + + return build_suites_from_annotations( + a_owner_name, + l_annotations_cursor, + a_path, + a_object_name, + a_procedure_name + ); end; end ut_suite_builder; diff --git a/source/core/ut_suite_builder.pks b/source/core/ut_suite_builder.pks index 0f4d97c76..b3d07b0a8 100644 --- a/source/core/ut_suite_builder.pks +++ b/source/core/ut_suite_builder.pks @@ -20,58 +20,30 @@ create or replace package ut_suite_builder authid current_user is * Responsible for converting annotations into unit test suites */ - --table of ut_suites indexed by suite path - tt_schema_suites('suite.path') gives ut_logical_suite - type tt_schema_suites is table of ut_logical_suite index by varchar2(4000 char); - - --table of suite paths indexed by object name - t_object_suite_path('object_name') = 'suitepath.to.object' - type t_object_suite_path is table of varchar2(4000) index by varchar2(4000 char); - - type t_schema_suites_info is record ( - schema_suites tt_schema_suites, - suite_paths t_object_suite_path - ); - /** * Builds set of hierarchical suites for a given schema * * @param a_owner_name name of the schema to builds suite for + * @param a_path suite path to build suite for (optional) + * @param a_object_name object name to build suite for (optional) + * @param a_object_name procedure name to build suite for (optional) * @return list of suites organized into hierarchy * */ - function build_schema_suites(a_owner_name varchar2) return ut_suite_items; - - /** - * Builds set of hierarchical suites for a given schema - * - * @param a_owner_name name of the schema to builds suite for - * @param a_object_name object name to build suite for - * @param a_object_name procedure name to build suite for (can be null) - * @return list of suites organized into hierarchy - * - */ - function build_schema_suites(a_owner_name varchar2, a_object_name varchar2,a_procedure_name varchar2) return ut_suite_items; - - /** - * Builds set of hierarchical suites for a given schema - * - * @param a_owner_name name of the schema to builds suite for - * @param a_path suite path to build suite for - * @return list of suites organized into hierarchy - * - */ - function build_schema_suites(a_owner_name varchar2,a_path varchar2) return ut_suite_items; - - /** - * Builds set of hierarchical suites for given annotations - * - * @param a_annotated_objects cursor returning ut_annotated_object type - * @return list of suites organized into hierarchy - * - */ - function build_suites(a_annotated_objects sys_refcursor) return t_schema_suites_info; + function build_schema_suites( + a_owner_name varchar2, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null + ) return ut_suite_items; + + function build_suites_from_annotations( + a_owner_name varchar2, + a_annotated_objects sys_refcursor, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null + ) return ut_suite_items; - function get_build_suites(a_owner_name varchar2) return ut_suite_items; - function build_schema_suites_old(a_owner_name varchar2) return t_schema_suites_info; - end ut_suite_builder; / diff --git a/source/core/ut_suite_cache.sql b/source/core/ut_suite_cache.sql index 183f4cf35..09211722b 100644 --- a/source/core/ut_suite_cache.sql +++ b/source/core/ut_suite_cache.sql @@ -75,9 +75,7 @@ alter table ut_suite_cache modify (object_owner not null, path not null, self_ty / alter table ut_suite_cache add constraint ut_suite_cache_pk primary key (object_owner, path) / -create unique index ut_suite_cache_uk on ut_suite_cache(object_owner, object_name, line_no) -/ -create index ut_suite_cache_nu1 on ut_suite_cache(object_owner, object_name) +create index ut_suite_cache_nu1 on ut_suite_cache(object_owner, object_name, parse_time desc) / alter table ut_suite_cache add constraint ut_suite_cache_schema_fk foreign key (object_owner) references ut_suite_cache_schema(object_owner) / diff --git a/source/core/ut_suite_cache_manager.pkb b/source/core/ut_suite_cache_manager.pkb index a51ee14a7..33712c589 100644 --- a/source/core/ut_suite_cache_manager.pkb +++ b/source/core/ut_suite_cache_manager.pkb @@ -16,227 +16,130 @@ create or replace package body ut_suite_cache_manager is limitations under the License. */ - function get_suite_by(a_schema_name varchar2, a_path varchar2 := null, a_object_name varchar2 := null, a_procedure_name varchar2 := null) return sys_refcursor is + function get_cached_suite_data( + a_schema_name varchar2, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null + ) return t_cached_suites_cursor is + l_path varchar2( 4000 ); l_result sys_refcursor; begin + if a_path is null and a_object_name is not null then + select min(path) into l_path + from ut_suite_cache + where object_owner = upper(a_schema_name) and object_name = lower(a_object_name) and + name = nvl(lower(a_procedure_name), name); + else + l_path := lower( a_path ); + end if; + + open l_result for - select - case self_type - when 'UT_TEST' - then ut_test( - self_type => self_type, - object_owner => object_owner, object_name => object_name, name => name, - description => description, path => path, rollback_type => rollback_type, - disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, - start_time => null, end_time => null, result => null, warnings => warnings, - results_count => ut_results_counter(), transaction_invalidators => null, - before_each_list => before_each_list, before_test_list => before_test_list, - item => item, after_test_list => after_test_list, after_each_list => after_each_list, - all_expectations => null, failed_expectations => null, - parent_error_stack_trace => null, expected_error_codes => expected_error_codes - ) - end as test_item, - case self_type - when 'UT_SUITE' - then ut_suite( - self_type => self_type, - object_owner => object_owner, object_name => object_name, name => name, - description => description, path => path, rollback_type => rollback_type, - disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, - start_time => null, end_time => null, result => null, warnings => warnings, - results_count => ut_results_counter(), transaction_invalidators => null, - items => ut_suite_items(), - before_all_list => before_all_list, after_all_list => after_all_list - ) - when 'UT_SUITE_CONTEXT' - then ut_suite_context( - self_type => self_type, - object_owner => object_owner, object_name => object_name, name => name, - description => description, path => path, rollback_type => rollback_type, - disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, - start_time => null, end_time => null, result => null, warnings => warnings, - results_count => ut_results_counter(), transaction_invalidators => null, - items => ut_suite_items(), - before_all_list => before_all_list, after_all_list => after_all_list - ) - when 'UT_LOGICAL_SUITE' - then ut_logical_suite( - self_type => self_type, - object_owner => object_owner, object_name => object_name, name => name, - description => description, path => path, rollback_type => rollback_type, - disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, - start_time => null, end_time => null, result => null, warnings => warnings, - results_count => ut_results_counter(), transaction_invalidators => null, - items => ut_suite_items() - ) - end as logical_suite, - length(path) - length( replace(path, '.') )+1 as path_level - from ut_suite_cache x - where ( a_path like path ||'.'||'%' - or ( path like a_path || '%' - and object_name = nvl(lower(a_object_name), object_name) - and name = nvl(lower(a_procedure_name), name) - ) - ) - and object_owner = upper(a_schema_name) - order by path desc, object_name, line_no; - + select c.* + from ut_suite_cache c + -- join all_objects a + -- on a.owner = x.object_owner + -- and a.object_name = x.object_name + -- and a.object_type = 'PACKAGE' + where ( l_path like c.path || '.' || '%' + or ( c.path like l_path || '%' + and c.object_name = nvl(lower(a_object_name), c.object_name) + and c.name = nvl(lower(a_procedure_name), c.name) + ) + ) and c.object_owner = upper(a_schema_name) + order by c.object_owner, + replace(case + when c.self_type in ( 'UT_TEST' ) + then substr(c.path, 1, instr(c.path, '.', -1) - 1) + else c.path + end, '.', chr(0)) desc nulls last, + c.object_name desc, + c.line_no desc; + return l_result; end; - --- function get_suite_by(a_schema_name varchar2, a_path varchar2 := null, a_object_name varchar2 := null, a_procedure_name varchar2 := null) return sys_refcursor is --- l_filter varchar2(1000); --- l_result sys_refcursor; --- l_owner varchar2(250) := ut_utils.ut_owner(); --- begin --- if a_object_name is not null then --- l_filter := ' object_name = lower(:a_object_name)'; --- if a_procedure_name is not null then --- l_filter := l_filter || ' and name = lower(:a_procedure_name)'; --- else --- l_filter := l_filter || ' and :a_procedure_name is null'; --- end if; --- else --- l_filter := ' :a_object_name is null and :a_procedure_name is null'; --- end if; --- open l_result for q'[ --- select --- case self_type --- when 'UT_TEST' --- then ]'||l_owner||q'[.ut_test( --- self_type => self_type, --- object_owner => object_owner, object_name => object_name, name => name, --- description => description, path => path, rollback_type => rollback_type, --- disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, --- start_time => null, end_time => null, result => null, warnings => warnings, --- results_count => ut_results_counter(), transaction_invalidators => null, --- before_each_list => before_each_list, before_test_list => before_test_list, --- item => item, after_test_list => after_test_list, after_each_list => after_each_list, --- all_expectations => null, failed_expectations => null, --- parent_error_stack_trace => null, expected_error_codes => expected_error_codes --- ) --- end as test_item, --- case self_type --- when 'UT_SUITE' --- then ]'||l_owner||q'[.ut_suite( --- self_type => self_type, --- object_owner => object_owner, object_name => object_name, name => name, --- description => description, path => path, rollback_type => rollback_type, --- disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, --- start_time => null, end_time => null, result => null, warnings => warnings, --- results_count => ]'||l_owner||q'[.ut_results_counter(), transaction_invalidators => null, --- items => ut_suite_items(), --- before_all_list => before_all_list, after_all_list => after_all_list --- ) --- when 'UT_SUITE_CONTEXT' --- then ]'||l_owner||q'[.ut_suite_context( --- self_type => self_type, --- object_owner => object_owner, object_name => object_name, name => name, --- description => description, path => path, rollback_type => rollback_type, --- disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, --- start_time => null, end_time => null, result => null, warnings => warnings, --- results_count => ]'||l_owner||q'[.ut_results_counter(), transaction_invalidators => null, --- items => ut_suite_items(), --- before_all_list => before_all_list, after_all_list => after_all_list --- ) --- when 'UT_LOGICAL_SUITE' --- then ]'||l_owner||q'[.ut_logical_suite( --- self_type => self_type, --- object_owner => object_owner, object_name => object_name, name => name, --- description => description, path => path, rollback_type => rollback_type, --- disabled_flag => disabled_flag, line_no => line_no, parse_time => parse_time, --- start_time => null, end_time => null, result => null, warnings => warnings, --- results_count => ]'||l_owner||q'[.ut_results_counter(), transaction_invalidators => null, --- items => ut_suite_items() --- ) --- end as logical_suite, --- length(path) - length( replace(path, '.') )+1 as path_level --- from ]'||l_owner||q'[.ut_suite_cache x --- where ( :a_path like path ||'.'||'%' --- or path like :a_path ||'%' and ]'||l_filter||q'[ ) --- and object_owner = upper(:a_schema_name) --- order by path desc, object_name, line_no]' --- using a_path, a_path, a_object_name, a_procedure_name, a_schema_name; --- --- return l_result; --- end; --- - function cached_suite_by_path(a_schema_name varchar2, a_path varchar2) return sys_refcursor is - begin - return get_suite_by(a_schema_name, a_path); - end; - function cached_suite_by_package(a_schema_name varchar2, a_object_name varchar2, a_procedure_name varchar2) return sys_refcursor is - l_path varchar2(4000); - begin - select min(path) into l_path - from ut_suite_cache - where object_owner = upper(a_schema_name) - and object_name = lower(a_object_name) - and name = nvl(lower(a_procedure_name),name); - return get_suite_by(a_schema_name, l_path, a_object_name, a_procedure_name ); + function get_schema_ut_packages( a_schema_names ut_varchar2_rows ) return ut_object_names is + l_results ut_object_names := ut_object_names( ); + l_schema_names ut_varchar2_rows; + l_object_names ut_varchar2_rows; + begin + select distinct c.object_owner, c.object_name + bulk collect into l_schema_names, l_object_names + from ut_suite_cache c + -- join all_objects a + -- on a.owner = c.object_owner + -- and a.object_name = c.object_name + -- and a.object_type = 'PACKAGE' + join table ( a_schema_names ) s on c.object_owner = upper(s.column_value); + l_results.extend( l_schema_names.count ); + for i in 1 .. l_schema_names.count loop + l_results( i ) := ut_object_name( l_schema_names( i ), l_object_names( i ) ); + end loop; + return l_results; end; - function cached_suite_by_schema(a_schema_name varchar2) return sys_refcursor is + function get_schema_parse_time(a_schema_name varchar2) return timestamp result_cache is + l_cache_parse_time timestamp; begin - return get_suite_by(a_schema_name); + select min(t.parse_time) + into l_cache_parse_time + from ut_suite_cache_schema t + where object_owner = a_schema_name; + return l_cache_parse_time; end; - procedure save_cache(a_suite_items ut_suite_items) is + procedure save_cache(a_object_owner varchar2, a_suite_items ut_suite_items) is pragma autonomous_transaction; - l_annotation_parse_time date; - l_suite_parse_time date; + l_parse_time timestamp; + l_cached_parse_time timestamp; begin if a_suite_items.count = 0 then return; end if; + if a_suite_items(1).self_type != 'UT_LOGICAL_SUITE' then select min(parse_time) - into l_suite_parse_time from ut_suite_cache t + into l_cached_parse_time + from ut_suite_cache t where t.object_name = a_suite_items(1).object_name - and t.object_owner = a_suite_items(1).object_owner - and rownum = 1; + and t.object_owner = a_suite_items(1).object_owner + and rownum = 1; end if; - l_annotation_parse_time := a_suite_items(1).parse_time; + select max(parse_time) into l_parse_time from table(a_suite_items) s; - if l_annotation_parse_time > l_suite_parse_time or l_suite_parse_time is null then + if l_parse_time > l_cached_parse_time or l_cached_parse_time is null then - merge into ut_suite_cache_schema t - using(select object_owner, max(parse_time) parse_time from table(a_suite_items) group by object_owner) s - on (s.object_owner = t.object_owner) - when matched then update - set t.parse_time = s.parse_time - where s.parse_time > t.parse_time - when not matched then - insert (object_owner, parse_time) - values (s.object_owner, s.parse_time); + update ut_suite_cache_schema t + set t.parse_time = l_parse_time + where object_owner = a_object_owner; + + if sql%rowcount = 0 then + insert into ut_suite_cache_schema + (object_owner, parse_time) + values (a_object_owner, l_parse_time); + end if; delete from ut_suite_cache t where (t.object_name, t.object_owner) in (select s.object_name, s.object_owner from table(a_suite_items) s where s.self_type != 'UT_LOGICAL_SUITE'); - merge into ut_suite_cache t - using ( - select self_type, path, object_owner, object_name, name, - line_no, parse_time, description, - rollback_type, disabled_flag, warnings - from table(a_suite_items) x where x.self_type = 'UT_LOGICAL_SUITE' - ) s - on (t.object_name = s.object_name and t.object_owner = s.object_owner) - when not matched then - insert ( + + insert into ut_suite_cache t + ( self_type, path, object_owner, object_name, name, line_no, parse_time, description, rollback_type, disabled_flag, warnings ) - values ( - s.self_type, s.path, s.object_owner, s.object_name, s.name, - s.line_no, s.parse_time, s.description, - s.rollback_type, s.disabled_flag, s.warnings - ); - + select self_type, path, object_owner, object_name, name, + line_no, parse_time, description, + rollback_type, disabled_flag, warnings + from table(a_suite_items) s + where s.self_type = 'UT_LOGICAL_SUITE' + and (s.object_owner, s.path) not in (select c.object_owner, c.path from ut_suite_cache c); insert into ut_suite_cache t ( @@ -248,16 +151,9 @@ create or replace package body ut_suite_cache_manager is before_test_list, after_test_list, expected_error_codes, item ) - with - suite_items as ( select value(x) item from table(a_suite_items) x ), - suites as ( - select treat(item as ut_suite) i from suite_items s - where s.item.self_type in ('UT_SUITE','UT_SUITE_CONTEXT') - ), - tests as ( - select treat(item as ut_test) t from suite_items s - where s.item.self_type in ('UT_TEST') - ) + with suites as ( select treat(value(x) as ut_suite) i + from table(a_suite_items) x + where x.self_type in( 'UT_SUITE', 'UT_SUITE_CONTEXT' ) ) select s.i.self_type as self_type, s.i.path as path, s.i.object_owner as object_owner, s.i.object_name as object_name, s.i.name as name, s.i.line_no as line_no, s.i.parse_time as parse_time, s.i.description as description, @@ -266,19 +162,34 @@ create or replace package body ut_suite_cache_manager is null before_each_list, null after_each_list, null before_test_list, null after_test_list, null expected_error_codes, null item - from suites s - union all - select s.t.self_type as self_type, s.t.path as path, - s.t.object_owner as object_owner, s.t.object_name as object_name, s.t.name as name, - s.t.line_no as line_no, s.t.parse_time as parse_time, s.t.description as description, - s.t.rollback_type as rollback_type, s.t.disabled_flag as disabled_flag, s.t.warnings as warnings, - null before_all_list, null after_all_list, - s.t.before_each_list as before_each_list, s.t.after_each_list as after_each_list, - s.t.before_test_list as before_test_list, s.t.after_test_list as after_test_list, - s.t.expected_error_codes as expected_error_codes, s.t.item as item + from suites s; + + insert into ut_suite_cache t + ( + self_type, path, object_owner, object_name, name, + line_no, parse_time, description, + rollback_type, disabled_flag, warnings, + before_all_list, after_all_list, + before_each_list, after_each_list, + before_test_list, after_test_list, + expected_error_codes, item + ) + with tests as ( select treat(value(x) as ut_test) t + from table ( a_suite_items ) x + where x.self_type in ( 'UT_TEST' ) ) + select s.t.self_type as self_type, s.t.path as path, + s.t.object_owner as object_owner, s.t.object_name as object_name, s.t.name as name, + s.t.line_no as line_no, s.t.parse_time as parse_time, s.t.description as description, + s.t.rollback_type as rollback_type, s.t.disabled_flag as disabled_flag, s.t.warnings as warnings, + null before_all_list, null after_all_list, + s.t.before_each_list as before_each_list, s.t.after_each_list as after_each_list, + s.t.before_test_list as before_test_list, s.t.after_test_list as after_test_list, + s.t.expected_error_codes as expected_error_codes, s.t.item as item from tests s; + + commit; end if; - commit; end; + end ut_suite_cache_manager; / diff --git a/source/core/ut_suite_cache_manager.pks b/source/core/ut_suite_cache_manager.pks index 1b2d1f2f6..f5da97ec7 100644 --- a/source/core/ut_suite_cache_manager.pks +++ b/source/core/ut_suite_cache_manager.pks @@ -19,14 +19,22 @@ create or replace package ut_suite_cache_manager authid definer is /** * Responsible for storing and retrieving suite data from cache */ + subtype t_cached_suite is ut_suite_cache%rowtype; + type tt_cached_suites is table of t_cached_suite; + type t_cached_suites_cursor is ref cursor return t_cached_suite; - procedure save_cache(a_suite_items ut_suite_items); + procedure save_cache(a_object_owner varchar2, a_suite_items ut_suite_items); - function cached_suite_by_path(a_schema_name varchar2, a_path varchar2) return sys_refcursor; + function get_cached_suite_data( + a_schema_name varchar2, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null + ) return t_cached_suites_cursor; - function cached_suite_by_package(a_schema_name varchar2, a_object_name varchar2, a_procedure_name varchar2) return sys_refcursor; + function get_schema_ut_packages(a_schema_names ut_varchar2_rows) return ut_object_names; - function cached_suite_by_schema(a_schema_name varchar2) return sys_refcursor; + function get_schema_parse_time(a_schema_name varchar2) return timestamp result_cache; end ut_suite_cache_manager; / diff --git a/source/core/ut_suite_cache_schema.sql b/source/core/ut_suite_cache_schema.sql index 890c72e0b..ba257dafd 100644 --- a/source/core/ut_suite_cache_schema.sql +++ b/source/core/ut_suite_cache_schema.sql @@ -13,7 +13,7 @@ create table ut_suite_cache_schema ( limitations under the License. */ object_owner varchar2(250) not null, - parse_time date not null, + parse_time timestamp not null, constraint ut_suite_cache_schema_pk primary key(object_owner) ) organization index / diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index dd9ffb5de..04bc26f10 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -16,24 +16,6 @@ create or replace package body ut_suite_manager is limitations under the License. */ - subtype tt_schema_suites is ut_suite_builder.tt_schema_suites; - subtype t_object_suite_path is ut_suite_builder.t_object_suite_path; - subtype t_schema_suites_info is ut_suite_builder.t_schema_suites_info; - - type t_schema_info is record (changed_at date, obj_cnt integer); - - type t_schema_cache is record( - schema_suites tt_schema_suites - ,changed_at date - ,obj_cnt integer - ,suite_paths t_object_suite_path - ); - type tt_schema_suites_list is table of t_schema_cache index by varchar2(128 char); - - g_schema_suites tt_schema_suites_list; - - --- type t_schema_paths is table of ut_varchar2_list index by varchar2(4000 char); type t_path_item is record ( object_name varchar2(250), @@ -45,96 +27,9 @@ create or replace package body ut_suite_manager is ------------------ - function get_schema_info(a_owner_name varchar2) return t_schema_info is - l_info t_schema_info; - l_view_name varchar2(200) := ut_metadata.get_dba_view('dba_objects'); - begin - execute immediate q'[ - select nvl(max(t.last_ddl_time), date '4999-12-31'), count(*) - from ]'||l_view_name||q'[ t - where t.owner = :a_owner_name - and t.object_type in ('PACKAGE')]' - into l_info using a_owner_name; - return l_info; - end; - - procedure update_cache(a_owner_name varchar2, a_suites_info t_schema_suites_info, a_total_obj_cnt integer) is - begin - if a_suites_info.schema_suites.count > 0 then - g_schema_suites(a_owner_name).schema_suites := a_suites_info.schema_suites; - g_schema_suites(a_owner_name).changed_at := sysdate; - g_schema_suites(a_owner_name).obj_cnt := a_total_obj_cnt; - g_schema_suites(a_owner_name).suite_paths := a_suites_info.suite_paths; - elsif g_schema_suites.exists(a_owner_name) then - g_schema_suites.delete(a_owner_name); - end if; - end; - - function cache_valid(a_schema_name varchar2) return boolean is - l_info t_schema_info; - l_result boolean := true; - begin - if not g_schema_suites.exists(a_schema_name) then - l_result := false; - else - l_info := get_schema_info(a_schema_name); - if g_schema_suites(a_schema_name).changed_at <= l_info.changed_at or g_schema_suites(a_schema_name).obj_cnt != l_info.obj_cnt then - l_result := false; - else - l_result := true; - end if; - end if; - return l_result; - end; - - function get_schema_suites(a_schema_name in varchar2) return t_schema_suites_info is - l_result t_schema_suites_info; - begin - -- Currently cache invalidation on DDL is not implemented so schema is rescaned each time - if cache_valid(a_schema_name) then - l_result.schema_suites := g_schema_suites(a_schema_name).schema_suites; - l_result.suite_paths := g_schema_suites(a_schema_name).suite_paths; - else - ut_utils.debug_log('Rescanning schema ' || a_schema_name); - l_result := ut_suite_builder.build_schema_suites_old(a_schema_name); - update_cache(a_schema_name, l_result, get_schema_info(a_schema_name).obj_cnt ); - end if; - - return l_result; - end get_schema_suites; - function get_schema_ut_packages(a_schema_names ut_varchar2_rows) return ut_object_names is - l_schema_ut_packages ut_object_names := ut_object_names(); - l_schema_suites tt_schema_suites; - l_iter varchar2(4000); - procedure populate_suite_ut_packages(a_suite ut_logical_suite, a_packages in out nocopy ut_object_names) is - l_sub_suite ut_logical_suite; - begin - if a_suite is of (ut_suite) then - a_packages.extend; - a_packages(a_packages.last) := ut_object_name(a_suite.object_owner, a_suite.object_name); - end if; - for i in 1 .. a_suite.items.count loop - if a_suite.items(i) is of (ut_logical_suite) then - l_sub_suite := treat(a_suite.items(i) as ut_logical_suite); - populate_suite_ut_packages(l_sub_suite, a_packages); - end if; - end loop; - end; begin - if a_schema_names is not null then - for i in 1 .. a_schema_names.count loop - l_schema_suites := get_schema_suites(a_schema_names(i)).schema_suites; - l_iter := l_schema_suites.first; - while l_iter is not null loop - populate_suite_ut_packages(l_schema_suites(l_iter), l_schema_ut_packages); - l_iter := l_schema_suites.next(l_iter); - end loop; - end loop; - l_schema_ut_packages := set(l_schema_ut_packages); - end if; - - return l_schema_ut_packages; + return ut_suite_cache_manager.get_schema_ut_packages(a_schema_names); end; procedure validate_paths(a_paths in ut_varchar2_list) is @@ -220,169 +115,6 @@ create or replace package body ut_suite_manager is return resolve_schema_names(l_paths); end; - procedure filter_suite_by_path(a_suite in out nocopy ut_suite_item, a_path varchar2) is - c_item_name constant varchar2(32767) := lower(regexp_substr(a_path, '[A-Za-z0-9$#_]+')); - c_child_filter_path constant varchar2(32767) := regexp_substr(a_path, '\.(.+)', subexpression => 1); - l_suite ut_logical_suite; - l_item ut_suite_item; - l_items ut_suite_items := ut_suite_items(); - - function find_item_in_suite(a_suite ut_logical_suite, a_item_name varchar2) return ut_suite_item is - l_item_index binary_integer; - begin - l_item_index := a_suite.items.first; - while l_item_index is not null loop - if lower(a_suite.items(l_item_index).name) = a_item_name then - return a_suite.items(l_item_index); - end if; - l_item_index := a_suite.items.next(l_item_index); - end loop; - return null; - end; - - function find_item_in_suite_contexts(a_suite ut_logical_suite, a_item_name varchar2) return ut_suite_item is - l_item_index binary_integer; - l_context ut_suite_context; - l_item ut_suite_item; - begin - l_item_index := a_suite.items.first; - while l_item_index is not null loop - if a_suite.items(l_item_index) is of (ut_suite_context) then - l_item := find_item_in_suite( - treat(a_suite.items(l_item_index) as ut_suite_context) - , a_item_name - ); - end if; - - if l_item is not null then - l_context := treat(a_suite.items(l_item_index) as ut_suite_context); - l_context.items := ut_suite_items(l_item); - exit; - end if; - l_item_index := a_suite.items.next(l_item_index); - end loop; - return l_context; - end; - begin - if a_suite is of (ut_logical_suite) then - l_suite := treat(a_suite as ut_logical_suite); - - l_item := coalesce( - find_item_in_suite(l_suite, c_item_name) - , find_item_in_suite_contexts(l_suite, c_item_name) - ); - if l_item is not null then - if c_child_filter_path is not null then - filter_suite_by_path(l_item, c_child_filter_path); - end if; - l_items.extend; - l_items(l_items.count) := l_item; - else - raise_application_error(-20203, 'Suite item '||c_item_name||' not found'); - end if; - - l_suite.items := l_items; - a_suite := l_suite; - end if; - end filter_suite_by_path; - - function get_suite_filtered_by_path(a_path varchar2, a_schema_suites tt_schema_suites) return ut_logical_suite is - l_suite ut_logical_suite; - c_suite_path constant varchar2(32767) := regexp_substr(a_path, ':(.+)', subexpression => 1); - c_root_suite_name constant varchar2(32767) := regexp_substr(c_suite_path, '^[A-Za-z0-9$#_]+'); - c_child_filter_path constant varchar2(32767) := regexp_substr(c_suite_path, '\.(.+)', subexpression => 1); - begin - l_suite := a_schema_suites(c_root_suite_name); - if c_child_filter_path is not null then - filter_suite_by_path(l_suite, c_child_filter_path); - end if; - return l_suite; - exception - when no_data_found then - raise_application_error(-20203, 'Suite ' || c_root_suite_name || ' does not exist or is invalid'); - end; - - function convert_to_suite_path(a_path varchar2, a_suite_paths t_object_suite_path) return varchar2 is - c_package_path_regex constant varchar2(100) := '^([A-Za-z0-9$#_]+)\.([A-Za-z0-9$#_]+)(\.([A-Za-z0-9$#_]+))?$'; - l_schema_name varchar2(4000) := regexp_substr(a_path, c_package_path_regex, subexpression => 1); - l_package_name varchar2(4000) := regexp_substr(a_path, c_package_path_regex, subexpression => 2); - l_procedure_name varchar2(4000) := regexp_substr(a_path, c_package_path_regex, subexpression => 4); - l_path varchar2(4000) := a_path; - begin - if regexp_like(l_path, c_package_path_regex) then - if not a_suite_paths.exists(l_package_name) then - raise_application_error(ut_utils.gc_suite_package_not_found,'Suite package '||l_schema_name||'.'||l_package_name|| ' not found'); - end if; - l_path := rtrim(l_schema_name || ':' || a_suite_paths(l_package_name) || '.' || l_procedure_name, '.'); - end if; - return l_path; - end; - --- function group_paths_by_schema(a_paths ut_varchar2_list) return t_schema_paths is --- l_result t_schema_paths; --- l_schema varchar2(4000); --- begin --- for i in 1 .. a_paths.count loop --- l_schema := upper(regexp_substr(a_paths(i),'^[^.:]+')); --- if l_result.exists(l_schema) then --- l_result(l_schema).extend; --- l_result(l_schema)(l_result(l_schema).last) := a_paths(i); --- else --- l_result(l_schema) := ut_varchar2_list(a_paths(i)); --- end if; --- end loop; --- return l_result; --- end; --- --- function configure_execution_by_path(a_paths in ut_varchar2_list) return ut_suite_items is --- l_paths ut_varchar2_list := a_paths; --- l_path varchar2(32767); --- l_schema varchar2(4000); --- l_suites_info t_schema_suites_info; --- l_index varchar2(4000 char); --- l_suite ut_logical_suite; --- l_objects_to_run ut_suite_items; --- l_schema_paths t_schema_paths; --- begin --- --resolve schema names from paths and group paths by schema name --- resolve_schema_names(l_paths); --- --- l_schema_paths := group_paths_by_schema(l_paths); --- --- l_objects_to_run := ut_suite_items(); --- --- l_schema := l_schema_paths.first; --- while l_schema is not null loop --- l_paths := l_schema_paths(l_schema); --- l_suites_info := get_schema_suites(l_schema); --- --- for i in 1 .. l_paths.count loop --- l_path := l_paths(i); --- --run whole schema --- if regexp_like(l_path, '^[A-Za-z0-9$#_]+$') then --- l_index := l_suites_info.schema_suites.first; --- while l_index is not null loop --- l_objects_to_run.extend; --- l_objects_to_run(l_objects_to_run.count) := l_suites_info.schema_suites(l_index); --- l_index := l_suites_info.schema_suites.next(l_index); --- end loop; --- else --- l_suite := get_suite_filtered_by_path( convert_to_suite_path( l_path, l_suites_info.suite_paths ), l_suites_info.schema_suites ); --- l_objects_to_run.extend; --- l_objects_to_run(l_objects_to_run.count) := l_suite; --- end if; --- end loop; --- l_schema := l_schema_paths.next(l_schema); --- end loop; --- --- --propagate rollback type to suite items after organizing suites into hierarchy --- for i in 1 .. l_objects_to_run.count loop --- l_objects_to_run(i).set_rollback_type( l_objects_to_run(i).get_rollback_type() ); --- end loop; --- --- return l_objects_to_run; --- end configure_execution_by_path; - function group_paths_by_schema(a_paths ut_varchar2_list) return t_schema_paths is c_package_path_regex constant varchar2(100) := '^([A-Za-z0-9$#_]+)(\.([A-Za-z0-9$#_]+))?(\.([A-Za-z0-9$#_]+))?$'; l_schema varchar2(4000); @@ -409,6 +141,7 @@ create or replace package body ut_suite_manager is end loop; return l_results; end; + function configure_execution_by_path(a_paths in ut_varchar2_list) return ut_suite_items is l_paths ut_varchar2_list := a_paths; l_path_items t_path_items; @@ -431,15 +164,12 @@ create or replace package body ut_suite_manager is l_path_items := l_schema_paths(l_schema); for i in 1 .. l_path_items.count loop l_path_item := l_path_items(i); - --whole schema - if l_path_item.object_name is null and l_path_item.suite_path is null then - l_suites := ut_suite_builder.build_schema_suites(upper(l_schema)); - --suite path - elsif l_path_item.suite_path is not null then - l_suites := ut_suite_builder.build_schema_suites(upper(l_schema), l_path_item.suite_path); - else - l_suites := ut_suite_builder.build_schema_suites(upper(l_schema), l_path_item.object_name, l_path_item.procedure_name); - end if; + l_suites := ut_suite_builder.build_schema_suites( + upper(l_schema), + l_path_item.suite_path, + l_path_item.object_name, + l_path_item.procedure_name + ); l_index := l_suites.first; while l_index is not null loop l_objects_to_run.extend; diff --git a/test/core/test_suite_builder.pkb b/test/core/test_suite_builder.pkb index 3216da333..edbee1e1a 100644 --- a/test/core/test_suite_builder.pkb +++ b/test/core/test_suite_builder.pkb @@ -4,17 +4,23 @@ create or replace package body test_suite_builder is a_annotations ut3.ut_annotations, a_package_name varchar2 := 'TEST_SUITE_BUILDER_PACKAGE' ) return clob is - l_suites ut3.ut_suite_builder.tt_schema_suites; + l_suites ut3.ut_suite_items; l_suite ut3.ut_logical_suite; l_cursor sys_refcursor; l_xml xmltype; begin open l_cursor for select value(x) from table( ut3.ut_annotated_objects( - ut3.ut_annotated_object('UT3_TESTER', a_package_name, 'PACKAGE', SYSDATE, a_annotations) + ut3.ut_annotated_object('UT3_TESTER', a_package_name, 'PACKAGE', systimestamp, a_annotations) ) ) x; - l_suites := ut3.ut_suite_builder.build_suites(l_cursor).schema_suites; - l_suite := l_suites(l_suites.first); + + l_suites := ut3.ut_suite_builder.build_suites_from_annotations( + a_owner_name => 'UT3_TESTER', + a_annotated_objects => l_cursor, + a_path => null, + a_object_name => a_package_name + ); + l_suite := treat( l_suites(l_suites.first) as ut3.ut_logical_suite); select deletexml( xmltype(l_suite), @@ -634,6 +640,9 @@ create or replace package body test_suite_builder is '%' || '%' || '%' || + '' || + '%suite_level_testIn suitesome_package.suite_level_test' || + '%' || '' || '%a_contextA contextsome_package.a_context' || '%' || @@ -646,9 +655,6 @@ create or replace package body test_suite_builder is '%' || '' || '' || - '' || - '%suite_level_testIn suitesome_package.suite_level_test' || - '%' || '' || '' || '%some_packagesuite_level_beforeall' || From 4dc48e676f14bae492c5c511f2ac500afa6a2674 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 4 Nov 2018 01:32:48 +0000 Subject: [PATCH 03/33] Interim commit - performance check on Travis. --- .../ut_annotation_cache_manager.pkb | 2 +- .../annotations/ut_annotation_manager.pkb | 2 +- source/core/ut_suite_builder.pkb | 244 ++++++++++++++---- source/core/ut_suite_builder.pks | 5 +- source/core/ut_suite_cache_manager.pkb | 81 +----- source/core/ut_suite_cache_manager.pks | 12 - source/core/ut_suite_manager.pkb | 11 +- .../create_synonyms_and_grants_for_public.sql | 4 + source/create_user_grants.sql | 4 + test/core/test_suite_builder.pkb | 11 +- test/core/test_suite_manager.pkb | 37 +-- 11 files changed, 244 insertions(+), 169 deletions(-) diff --git a/source/core/annotations/ut_annotation_cache_manager.pkb b/source/core/annotations/ut_annotation_cache_manager.pkb index c54d7eec3..9d7d1b95e 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pkb +++ b/source/core/annotations/ut_annotation_cache_manager.pkb @@ -92,7 +92,7 @@ create or replace package body ut_annotation_cache_manager as 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 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'[ + 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; return l_results; diff --git a/source/core/annotations/ut_annotation_manager.pkb b/source/core/annotations/ut_annotation_manager.pkb index 9ad1a9e79..afa66b2e4 100644 --- a/source/core/annotations/ut_annotation_manager.pkb +++ b/source/core/annotations/ut_annotation_manager.pkb @@ -44,7 +44,7 @@ create or replace package body ut_annotation_manager as || case when a_parse_date is null then ':a_parse_date is null' - else 'o.last_ddl_time > cast(:a_parse_date as date)' + else 'o.last_ddl_time >= cast(:a_parse_date as date)' end; open l_rows for l_cursor_text using a_object_owner, a_object_type, a_parse_date; fetch l_rows bulk collect into l_result limit 1000000; diff --git a/source/core/ut_suite_builder.pkb b/source/core/ut_suite_builder.pkb index 21e784f7e..358a563f4 100644 --- a/source/core/ut_suite_builder.pkb +++ b/source/core/ut_suite_builder.pkb @@ -98,6 +98,10 @@ create or replace package body ut_suite_builder is by_name tt_annotations_by_name ); + subtype t_cached_suite is ut_suite_cache%rowtype; + type tt_cached_suites is table of t_cached_suite; + type t_cached_suites_cursor is ref cursor return t_cached_suite; + procedure delete_annotations_range( a_annotations in out nocopy t_annotations_info, a_start_pos t_annotation_position, @@ -318,7 +322,10 @@ create or replace package body ut_suite_builder is l_pos t_annotation_position := a_list.first; begin while l_pos is not null loop - l_result := l_result multiset union all a_list(l_pos); + for i in 1 .. a_list(l_pos).count loop + l_result.extend; + l_result(l_result.last) := a_list(l_pos)(i); + end loop; l_pos := a_list.next(l_pos); end loop; return l_result; @@ -832,25 +839,6 @@ create or replace package body ut_suite_builder is end loop; end; - procedure add_parent_logical_suites( a_suite ut_suite, a_suite_items in out nocopy ut_suite_items) is - l_path varchar2(200); - l_name varchar2(200); - begin - l_path := a_suite.path; - loop - l_path := substr( l_path, 1, instr(l_path,'.',-1)-1); - exit when l_path is null; - l_name := substr( l_path, instr(l_path,'.',-1)+1); - a_suite_items.extend; - a_suite_items( a_suite_items.last) := - ut_logical_suite( - a_object_owner => a_suite.object_owner, - a_object_name => l_name, a_name => l_name, a_path => l_path - ); - a_suite_items( a_suite_items.last).parse_time := a_suite.parse_time; - end loop; - end; - procedure create_suite_item_list( a_annotations t_annotations_info, a_suite_items out nocopy ut_suite_items ) is l_annotations t_annotations_info := a_annotations; l_annotation_pos t_annotation_position; @@ -875,7 +863,6 @@ create or replace package body ut_suite_builder is a_suite_items.extend; a_suite_items( a_suite_items.last) := l_suite; - add_parent_logical_suites( l_suite, a_suite_items ); end if; end; @@ -905,14 +892,31 @@ create or replace package body ut_suite_builder is return l_result; end; + procedure copy_list_reverse_order( + a_list in out nocopy ut_suite_items + ) is + l_start_idx pls_integer; + l_end_idx pls_integer; + l_item ut_suite_item; + begin + l_start_idx := a_list.first; + l_end_idx := a_list.last; + while l_start_idx < l_end_idx loop + l_item := a_list(l_start_idx); + a_list(l_start_idx) := a_list(l_end_idx); + a_list(l_end_idx) := l_item; + l_end_idx := a_list.prior(l_end_idx); + l_start_idx := a_list.next(l_start_idx); + end loop; + end; + procedure reconstruct_from_cache( - a_suites in out nocopy ut_suite_items, + a_suites out nocopy ut_suite_items, a_suite_data_cursor sys_refcursor ) is type t_item_levels is table of ut_suite_items index by binary_integer; l_items_at_level t_item_levels; - l_rows ut_suite_cache_manager.tt_cached_suites; --- l_items ut_suite_items := ut_suite_items(); + l_rows tt_cached_suites; l_tests ut_suite_items := ut_suite_items(); l_logical_suites ut_logical_suites := ut_logical_suites(); l_level pls_integer; @@ -923,8 +927,6 @@ create or replace package body ut_suite_builder is loop if l_idx is null then fetch a_suite_data_cursor bulk collect into l_rows limit 1000; --- l_items.delete; --- l_items.extend(l_rows.count); l_tests.delete; l_tests.extend(l_rows.count); l_logical_suites.delete; @@ -932,12 +934,11 @@ create or replace package body ut_suite_builder is for i in 1 .. l_rows.count loop case l_rows(i).self_type when 'UT_TEST' then --- l_items(i) := l_tests(i) := ut_test( self_type => l_rows(i).self_type, - object_owner => l_rows(i).object_owner, object_name => l_rows(i).object_name, - name => l_rows(i).name, description => l_rows(i).description, path => l_rows(i).path, + object_owner => l_rows(i).object_owner, object_name => lower(l_rows(i).object_name), + name => lower(l_rows(i).name), description => l_rows(i).description, path => l_rows(i).path, rollback_type => l_rows(i).rollback_type, disabled_flag => l_rows(i).disabled_flag, line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, @@ -949,12 +950,11 @@ create or replace package body ut_suite_builder is parent_error_stack_trace => null, expected_error_codes => l_rows(i).expected_error_codes ); when 'UT_SUITE' then --- l_items(i) := l_logical_suites(i) := ut_suite( self_type => l_rows(i).self_type, - object_owner => l_rows(i).object_owner, object_name => l_rows(i).object_name, - name => l_rows(i).name, description => l_rows(i).description, path => l_rows(i).path, + object_owner => l_rows(i).object_owner, object_name => lower(l_rows(i).object_name), + name => lower(l_rows(i).name), description => l_rows(i).description, path => l_rows(i).path, rollback_type => l_rows(i).rollback_type, disabled_flag => l_rows(i).disabled_flag, line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, @@ -963,26 +963,26 @@ create or replace package body ut_suite_builder is before_all_list => l_rows(i).before_all_list, after_all_list => l_rows(i).after_all_list ); when 'UT_SUITE_CONTEXT' then --- l_items(i) := l_logical_suites(i) := ut_suite_context( self_type => l_rows(i).self_type, - object_owner => l_rows(i).object_owner, object_name => l_rows(i).object_name, name => l_rows(i).name, - description => l_rows(i).description, path => l_rows(i).path, rollback_type => l_rows(i).rollback_type, - disabled_flag => l_rows(i).disabled_flag, line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, + object_owner => l_rows(i).object_owner, object_name => lower(l_rows(i).object_name), + name => lower(l_rows(i).name), description => l_rows(i).description, path => l_rows(i).path, + rollback_type => l_rows(i).rollback_type, disabled_flag => l_rows(i).disabled_flag, + line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), items => ut_suite_items(), before_all_list => l_rows(i).before_all_list, after_all_list => l_rows(i).after_all_list ); when 'UT_LOGICAL_SUITE' then --- l_items(i) := l_logical_suites(i) := ut_logical_suite( self_type => l_rows(i).self_type, - object_owner => l_rows(i).object_owner, object_name => l_rows(i).object_name, name => l_rows(i).name, - description => l_rows(i).description, path => l_rows(i).path, rollback_type => l_rows(i).rollback_type, - disabled_flag => l_rows(i).disabled_flag, line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, + object_owner => l_rows(i).object_owner, object_name => lower(l_rows(i).object_name), + name => lower(l_rows(i).name), description => l_rows(i).description, path => l_rows(i).path, + rollback_type => l_rows(i).rollback_type, disabled_flag => l_rows(i).disabled_flag, + line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), items => ut_suite_items() @@ -992,13 +992,15 @@ create or replace package body ut_suite_builder is l_idx := l_rows.first; end if; exit when l_idx is null; + l_level := length(l_rows(l_idx).path) - length( replace(l_rows(l_idx).path, '.') ) + 1; + if l_level > 1 then if l_prev_level > l_level then l_logical_suites(l_idx).items := l_items_at_level(l_prev_level); l_items_at_level(l_prev_level).delete; end if; - if not l_items_at_level.exists((l_level)) then + if not l_items_at_level.exists(l_level) then l_items_at_level(l_level) := ut_suite_items(); end if; l_items_at_level(l_level).extend; @@ -1019,29 +1021,140 @@ create or replace package body ut_suite_builder is a_suites(a_suites.last) := l_logical_suites(l_idx); end if; end if; --- if l_level = 0 then --- a_suites.extend; --- a_suites(a_suites.last) := l_items(l_idx); --- else --- a_suites(a_suites.last).add_item( l_items(l_idx), l_level ); --- end if; l_prev_level := l_level; l_idx := l_rows.next(l_idx); end loop; + copy_list_reverse_order( a_suites ); close a_suite_data_cursor; end; + function get_cached_suite_data( + a_object_owner varchar2, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null, + a_skip_all_objects boolean := false + ) return t_cached_suites_cursor is + l_path varchar2( 4000 ); + l_result sys_refcursor; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + begin + if a_path is null and a_object_name is not null then + execute immediate 'select min(path) + from '||l_ut_owner||q'[.ut_suite_cache + where object_owner = :a_object_owner + and object_name = :a_object_name + and name = nvl(:a_procedure_name, name)]' + into l_path using upper(a_object_owner), upper(a_object_name), upper(a_procedure_name); + else + l_path := lower( a_path ); + end if; + + open l_result for + q'[with + suite_items as ( + select c.* + from ]'||l_ut_owner||q'[.ut_suite_cache c + where 1 = 1 ]'||case when a_skip_all_objects is null then q'[ + and exists + ( select 1 + from all_objects a + where a.object_name = c.object_name + and a.owner = c.object_owner + and a.object_type = 'PACKAGE' + )]' end ||q'[ + and c.object_owner = :a_object_owner + and ( ]' || case when l_path is not null then q'[ + :l_path||'.' like c.path || '.%' /*all children and self*/ + or ( c.path||'.' like :l_path || '.%' --all parents + ]' + else ' :l_path is null and ( :l_path is null ' end + || case when a_object_name is not null + then 'and c.object_name = :a_object_name ' + else 'and :a_object_name is null' end ||' + '|| case when a_procedure_name is not null + then 'and c.name = :a_procedure_name' + else 'and :a_procedure_name is null' end ||q'[ + ) + ) + ), + gen as ( + select rownum as pos + from xmltable('1 to 100') + ), + suitepaths as ( + select distinct substr(path,1,instr(path,'.',-1)-1) as suitepath, + path, + object_owner + from suite_items + where self_type = 'UT_SUITE' + ), + gen as ( + select rownum as pos + from xmltable('1 to 10') + ), + suitepath_part AS ( + select distinct + substr(b.suitepath, 1, instr(b.suitepath || '.', '.', 1, g.pos) -1) as path, + object_owner + from suitepaths b + join gen g + on g.pos <= regexp_count(b.suitepath, '\w+') + ), + logical_suite_data as ( + select 'UT_LOGICAL_SUITE' as self_type, p.path, p.object_owner, + upper( substr(p.path, instr( p.path, '.', -1 ) + 1 ) ) as object_name, + cast(null as ]'||l_ut_owner||q'[.ut_executables) as x, + cast(null as ]'||l_ut_owner||q'[.ut_integer_list) as y, + cast(null as ]'||l_ut_owner||q'[.ut_executable_test) as z + from suitepath_part p + where p.path + not in (select s.path from suitepaths s) + ), + logical_suites as ( + select s.self_type, s.path, s.object_owner, s.object_name, + s.object_name as name, null as line_no, null as parse_time, + null as description, null as rollback_type, 0 as disabled_flag, + ]'||l_ut_owner||q'[.ut_varchar2_rows() as warnings, + s.x as before_all_list, s.x as after_all_list, + s.x as before_each_list, s.x as before_test_list, + s.x as after_each_list, s.x as after_test_list, + s.y as expected_error_codes, s.z as item + from logical_suite_data s + ), + items as ( + select * from suite_items + union all + select * from logical_suites + ) + select c.* + from items c + order by c.object_owner, + replace(case + when c.self_type in ( 'UT_TEST' ) + then substr(c.path, 1, instr(c.path, '.', -1) ) + else c.path + end, '.', chr(0)) desc nulls last, + c.object_name desc, + c.line_no]' + using upper(a_object_owner), l_path, l_path, upper(a_object_name), upper(a_procedure_name); + + return l_result; + end; + function build_suites_from_annotations( a_owner_name varchar2, a_annotated_objects sys_refcursor, a_path varchar2 := null, a_object_name varchar2 := null, - a_procedure_name varchar2 := null + a_procedure_name varchar2 := null, + a_skip_all_objects boolean := false ) return ut_suite_items is l_suites ut_suite_items; l_annotations_cursor sys_refcursor; l_annotated_objects ut_annotated_objects; l_suite_items ut_suite_items; + l_suite_data_cursor sys_refcursor; begin loop fetch a_annotated_objects bulk collect into l_annotated_objects limit 10; @@ -1059,11 +1172,13 @@ create or replace package body ut_suite_builder is reconstruct_from_cache( l_suites, - ut_suite_cache_manager.get_cached_suite_data( + get_cached_suite_data( a_owner_name, a_path, a_object_name, - a_procedure_name ) + a_procedure_name, + a_skip_all_objects + ) ); for i in 1 .. l_suites.count loop l_suites( i ).set_rollback_type( l_suites( i ).get_rollback_type ); @@ -1078,14 +1193,15 @@ create or replace package body ut_suite_builder is a_procedure_name varchar2 := null ) return ut_suite_items is l_annotations_cursor sys_refcursor; + l_suite_cache_time timestamp; begin - + l_suite_cache_time := ut_suite_cache_manager.get_schema_parse_time(a_owner_name); open l_annotations_cursor for q'[select value(x) from table( ]' || ut_utils.ut_owner || q'[.ut_annotation_manager.get_annotated_objects(:a_owner_name, 'PACKAGE', :a_suite_cache_parse_time) )x ]' - using a_owner_name, ut_suite_cache_manager.get_schema_parse_time(a_owner_name); + using a_owner_name, l_suite_cache_time; return build_suites_from_annotations( a_owner_name, @@ -1096,5 +1212,29 @@ create or replace package body ut_suite_builder is ); end; + function get_schema_ut_packages( a_schema_names ut_varchar2_rows ) return ut_object_names is + l_results ut_object_names := ut_object_names( ); + l_schema_names ut_varchar2_rows; + l_object_names ut_varchar2_rows; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + begin + execute immediate 'select distinct c.object_owner, c.object_name + from '||l_ut_owner||q'[.ut_suite_cache c + join table ( :a_schema_names ) s + on c.object_owner = upper(s.column_value) +-- where exists +-- (select 1 from all_objects a +-- where a.owner = c.object_owner +-- and a.object_name = c.object_name +-- and a.object_type = 'PACKAGE') + ]' + bulk collect into l_schema_names, l_object_names using a_schema_names; + l_results.extend( l_schema_names.count ); + for i in 1 .. l_schema_names.count loop + l_results( i ) := ut_object_name( l_schema_names( i ), l_object_names( i ) ); + end loop; + return l_results; + end; + end ut_suite_builder; / diff --git a/source/core/ut_suite_builder.pks b/source/core/ut_suite_builder.pks index b3d07b0a8..881df24c9 100644 --- a/source/core/ut_suite_builder.pks +++ b/source/core/ut_suite_builder.pks @@ -37,12 +37,15 @@ create or replace package ut_suite_builder authid current_user is a_procedure_name varchar2 := null ) return ut_suite_items; + function get_schema_ut_packages(a_schema_names ut_varchar2_rows) return ut_object_names; + function build_suites_from_annotations( a_owner_name varchar2, a_annotated_objects sys_refcursor, a_path varchar2 := null, a_object_name varchar2 := null, - a_procedure_name varchar2 := null + a_procedure_name varchar2 := null, + a_skip_all_objects boolean := false ) return ut_suite_items; end ut_suite_builder; diff --git a/source/core/ut_suite_cache_manager.pkb b/source/core/ut_suite_cache_manager.pkb index 33712c589..cad718ee3 100644 --- a/source/core/ut_suite_cache_manager.pkb +++ b/source/core/ut_suite_cache_manager.pkb @@ -16,71 +16,6 @@ create or replace package body ut_suite_cache_manager is limitations under the License. */ - function get_cached_suite_data( - a_schema_name varchar2, - a_path varchar2 := null, - a_object_name varchar2 := null, - a_procedure_name varchar2 := null - ) return t_cached_suites_cursor is - l_path varchar2( 4000 ); - l_result sys_refcursor; - begin - if a_path is null and a_object_name is not null then - select min(path) into l_path - from ut_suite_cache - where object_owner = upper(a_schema_name) and object_name = lower(a_object_name) and - name = nvl(lower(a_procedure_name), name); - else - l_path := lower( a_path ); - end if; - - - open l_result for - select c.* - from ut_suite_cache c - -- join all_objects a - -- on a.owner = x.object_owner - -- and a.object_name = x.object_name - -- and a.object_type = 'PACKAGE' - where ( l_path like c.path || '.' || '%' - or ( c.path like l_path || '%' - and c.object_name = nvl(lower(a_object_name), c.object_name) - and c.name = nvl(lower(a_procedure_name), c.name) - ) - ) and c.object_owner = upper(a_schema_name) - order by c.object_owner, - replace(case - when c.self_type in ( 'UT_TEST' ) - then substr(c.path, 1, instr(c.path, '.', -1) - 1) - else c.path - end, '.', chr(0)) desc nulls last, - c.object_name desc, - c.line_no desc; - - return l_result; - end; - - - function get_schema_ut_packages( a_schema_names ut_varchar2_rows ) return ut_object_names is - l_results ut_object_names := ut_object_names( ); - l_schema_names ut_varchar2_rows; - l_object_names ut_varchar2_rows; - begin - select distinct c.object_owner, c.object_name - bulk collect into l_schema_names, l_object_names - from ut_suite_cache c - -- join all_objects a - -- on a.owner = c.object_owner - -- and a.object_name = c.object_name - -- and a.object_type = 'PACKAGE' - join table ( a_schema_names ) s on c.object_owner = upper(s.column_value); - l_results.extend( l_schema_names.count ); - for i in 1 .. l_schema_names.count loop - l_results( i ) := ut_object_name( l_schema_names( i ), l_object_names( i ) ); - end loop; - return l_results; - end; - function get_schema_parse_time(a_schema_name varchar2) return timestamp result_cache is l_cache_parse_time timestamp; begin @@ -95,6 +30,7 @@ create or replace package body ut_suite_cache_manager is pragma autonomous_transaction; l_parse_time timestamp; l_cached_parse_time timestamp; + l_object_owner varchar2(250) := upper(a_object_owner); begin if a_suite_items.count = 0 then return; @@ -115,17 +51,20 @@ create or replace package body ut_suite_cache_manager is update ut_suite_cache_schema t set t.parse_time = l_parse_time - where object_owner = a_object_owner; + where object_owner = l_object_owner; if sql%rowcount = 0 then insert into ut_suite_cache_schema (object_owner, parse_time) - values (a_object_owner, l_parse_time); + values (l_object_owner, l_parse_time); end if; delete from ut_suite_cache t where (t.object_name, t.object_owner) - in (select s.object_name, s.object_owner from table(a_suite_items) s where s.self_type != 'UT_LOGICAL_SUITE'); + in ( + select upper(s.object_name), upper(s.object_owner) + from table(a_suite_items) s where s.self_type != 'UT_LOGICAL_SUITE' + ); insert into ut_suite_cache t @@ -134,7 +73,7 @@ create or replace package body ut_suite_cache_manager is line_no, parse_time, description, rollback_type, disabled_flag, warnings ) - select self_type, path, object_owner, object_name, name, + select self_type, path, upper(object_owner), upper(object_name), upper(name), line_no, parse_time, description, rollback_type, disabled_flag, warnings from table(a_suite_items) s @@ -155,7 +94,7 @@ create or replace package body ut_suite_cache_manager is from table(a_suite_items) x where x.self_type in( 'UT_SUITE', 'UT_SUITE_CONTEXT' ) ) select s.i.self_type as self_type, s.i.path as path, - s.i.object_owner as object_owner, s.i.object_name as object_name, s.i.name as name, + upper(s.i.object_owner) as object_owner, upper(s.i.object_name) as object_name, upper(s.i.name) as name, s.i.line_no as line_no, s.i.parse_time as parse_time, s.i.description as description, s.i.rollback_type as rollback_type, s.i.disabled_flag as disabled_flag, s.i.warnings as warnings, s.i.before_all_list as before_all_list, s.i.after_all_list as after_all_list, @@ -178,7 +117,7 @@ create or replace package body ut_suite_cache_manager is from table ( a_suite_items ) x where x.self_type in ( 'UT_TEST' ) ) select s.t.self_type as self_type, s.t.path as path, - s.t.object_owner as object_owner, s.t.object_name as object_name, s.t.name as name, + upper(s.t.object_owner) as object_owner, upper(s.t.object_name) as object_name, upper(s.t.name) as name, s.t.line_no as line_no, s.t.parse_time as parse_time, s.t.description as description, s.t.rollback_type as rollback_type, s.t.disabled_flag as disabled_flag, s.t.warnings as warnings, null before_all_list, null after_all_list, diff --git a/source/core/ut_suite_cache_manager.pks b/source/core/ut_suite_cache_manager.pks index f5da97ec7..919196efa 100644 --- a/source/core/ut_suite_cache_manager.pks +++ b/source/core/ut_suite_cache_manager.pks @@ -19,21 +19,9 @@ create or replace package ut_suite_cache_manager authid definer is /** * Responsible for storing and retrieving suite data from cache */ - subtype t_cached_suite is ut_suite_cache%rowtype; - type tt_cached_suites is table of t_cached_suite; - type t_cached_suites_cursor is ref cursor return t_cached_suite; procedure save_cache(a_object_owner varchar2, a_suite_items ut_suite_items); - function get_cached_suite_data( - a_schema_name varchar2, - a_path varchar2 := null, - a_object_name varchar2 := null, - a_procedure_name varchar2 := null - ) return t_cached_suites_cursor; - - function get_schema_ut_packages(a_schema_names ut_varchar2_rows) return ut_object_names; - function get_schema_parse_time(a_schema_name varchar2) return timestamp result_cache; end ut_suite_cache_manager; diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index 04bc26f10..4aab5503b 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -29,7 +29,7 @@ create or replace package body ut_suite_manager is function get_schema_ut_packages(a_schema_names ut_varchar2_rows) return ut_object_names is begin - return ut_suite_cache_manager.get_schema_ut_packages(a_schema_names); + return ut_suite_builder.get_schema_ut_packages(a_schema_names); end; procedure validate_paths(a_paths in ut_varchar2_list) is @@ -170,6 +170,15 @@ create or replace package body ut_suite_manager is l_path_item.object_name, l_path_item.procedure_name ); + if l_suites.count = 0 then + if l_path_item.suite_path is not null then + raise_application_error(ut_utils.gc_suite_package_not_found,'No suite packages found for path '||l_schema||':'||l_path_item.suite_path|| '.'); + elsif l_path_item.procedure_name is not null then + raise_application_error(ut_utils.gc_suite_package_not_found,'Suite test '||l_schema||'.'||l_path_item.object_name|| '.'||l_path_item.procedure_name||' does not exist'); + else + raise_application_error(ut_utils.gc_suite_package_not_found,'Suite package '||l_schema||'.'||l_path_item.object_name|| ' does not exist'); + end if; + end if; l_index := l_suites.first; while l_index is not null loop l_objects_to_run.extend; diff --git a/source/create_synonyms_and_grants_for_public.sql b/source/create_synonyms_and_grants_for_public.sql index 1ac5bb9ea..f22a61121 100644 --- a/source/create_synonyms_and_grants_for_public.sql +++ b/source/create_synonyms_and_grants_for_public.sql @@ -86,6 +86,10 @@ grant execute on &&ut3_owner..ut_annotated_object to public; grant execute on &&ut3_owner..ut_annotated_objects to public; grant select on &&ut3_owner..ut_annotation_cache_info to public; grant select on &&ut3_owner..ut_annotation_cache to public; +grant execute on &&ut3_owner..ut_executables to public; +grant execute on &&ut3_owner..ut_executable_test to public; +grant select on &&ut3_owner..ut_suite_cache to public; +grant select on &&ut3_owner..ut_suite_cache_schema to public; grant execute on &&ut3_owner..ut_annotation_cache_manager to public; grant execute on &&ut3_owner..ut_annotation_parser to public; grant execute on &&ut3_owner..ut_annotation_objs_cache_info to public; diff --git a/source/create_user_grants.sql b/source/create_user_grants.sql index 07d9097f3..723fcca58 100644 --- a/source/create_user_grants.sql +++ b/source/create_user_grants.sql @@ -106,6 +106,10 @@ grant execute on &&ut3_owner..ut_annotated_object to &ut3_user; grant execute on &&ut3_owner..ut_annotated_objects to &ut3_user; grant select on &&ut3_owner..ut_annotation_cache_info to &ut3_user; grant select on &&ut3_owner..ut_annotation_cache to &ut3_user; +grant execute on &&ut3_owner..ut_executables to &ut3_user; +grant execute on &&ut3_owner..ut_executable_test to &ut3_user; +grant select on &&ut3_owner..ut_suite_cache to &ut3_user; +grant select on &&ut3_owner..ut_suite_cache_schema to &ut3_user; grant execute on &&ut3_owner..ut_annotation_cache_manager to &ut3_user; grant execute on &&ut3_owner..ut_annotation_parser to &ut3_user; grant execute on &&ut3_owner..ut_annotation_objs_cache_info to &ut3_user; diff --git a/test/core/test_suite_builder.pkb b/test/core/test_suite_builder.pkb index edbee1e1a..e55830266 100644 --- a/test/core/test_suite_builder.pkb +++ b/test/core/test_suite_builder.pkb @@ -18,7 +18,8 @@ create or replace package body test_suite_builder is a_owner_name => 'UT3_TESTER', a_annotated_objects => l_cursor, a_path => null, - a_object_name => a_package_name + a_object_name => a_package_name, + a_skip_all_objects => true ); l_suite := treat( l_suites(l_suites.first) as ut3.ut_logical_suite); @@ -395,7 +396,7 @@ create or replace package body test_suite_builder is ut3.ut_annotation(1, 'suite','Cool', null), ut3.ut_annotation(2, 'beforeall',null, 'first_before_all'), ut3.ut_annotation(3, 'beforeall',null, 'another_before_all'), - ut3.ut_annotation(4, 'beforeeach',null, 'first_bfore_each'), + ut3.ut_annotation(4, 'beforeeach',null, 'first_before_each'), ut3.ut_annotation(5, 'beforeeach',null, 'another_before_each'), ut3.ut_annotation(6, 'aftereach',null, 'first_after_each'), ut3.ut_annotation(7, 'aftereach',null, 'another_after_each'), @@ -640,9 +641,6 @@ create or replace package body test_suite_builder is '%' || '%' || '%' || - '' || - '%suite_level_testIn suitesome_package.suite_level_test' || - '%' || '' || '%a_contextA contextsome_package.a_context' || '%' || @@ -655,6 +653,9 @@ create or replace package body test_suite_builder is '%' || '' || '' || + '' || + '%suite_level_testIn suitesome_package.suite_level_test' || + '%' || '' || '' || '%some_packagesuite_level_beforeall' || diff --git a/test/core/test_suite_manager.pkb b/test/core/test_suite_manager.pkb index 59f1f42ea..5d7e91f3d 100644 --- a/test/core/test_suite_manager.pkb +++ b/test/core/test_suite_manager.pkb @@ -313,7 +313,7 @@ end test_package_with_ctx;]'; ut.expect(l_test1_suite.name).to_equal('test_package_1'); ut.expect(l_test1_suite.items.count).to_equal(3); ut.expect(l_test1_suite.rollback_type).to_equal(ut3.ut_utils.gc_rollback_manual); - l_test2_suite := treat(l_test1_suite.items(3) as ut3.ut_logical_suite); + l_test2_suite := treat(l_test1_suite.items(1) as ut3.ut_logical_suite); ut.expect(l_test2_suite.name).to_equal('test_package_2'); ut.expect(l_test2_suite.items.count).to_equal(3); @@ -515,7 +515,6 @@ end test_package_with_ctx;]'; l_test0_suite ut3.ut_logical_suite; l_test1_suite ut3.ut_suite; - l_test2_suite ut3.ut_suite; begin --Act l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list(c_path)); @@ -529,7 +528,7 @@ end test_package_with_ctx;]'; l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_suite); ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.items.count).to_equal(3); + ut.expect(l_test1_suite.items.count).to_equal(2); ut.expect(l_test1_suite.items(1).name).to_equal('test1'); ut.expect(l_test1_suite.items(1).description).to_equal('Test1 from test package 1'); @@ -545,12 +544,6 @@ end test_package_with_ctx;]'; ut.expect(treat(l_test1_suite.items(2) as ut3.ut_test).before_each_list.count).to_be_greater_than(0); ut.expect(treat(l_test1_suite.items(2) as ut3.ut_test).disabled_flag).to_equal(0); - -- temporary behavior. - -- decided that when executed by package, not path, only that package has to execute - l_test2_suite := treat(l_test1_suite.items(3) as ut3.ut_suite); - - ut.expect(l_test2_suite.name).to_equal('test_package_2'); - ut.expect(l_test2_suite.items.count).to_equal(3); end; procedure test_top_pack_by_name_cu is @@ -573,7 +566,7 @@ end test_package_with_ctx;]'; l_test1_suite := treat(l_test0_suite.items(1) as ut3.ut_suite); ut.expect(l_test1_suite.name).to_equal('test_package_1'); - ut.expect(l_test1_suite.items.count).to_equal(3); + ut.expect(l_test1_suite.items.count).to_equal(2); ut.expect(l_test1_suite.items(1).name).to_equal('test1'); ut.expect(l_test1_suite.items(1).description).to_equal('Test1 from test package 1'); @@ -589,12 +582,6 @@ end test_package_with_ctx;]'; ut.expect(treat(l_test1_suite.items(2) as ut3.ut_test).before_each_list.count).to_be_greater_than(0); ut.expect(treat(l_test1_suite.items(2) as ut3.ut_test).disabled_flag).to_equal(0); - -- temporary behavior. - -- decided that when executed by package, not path, only that package has to execute - l_test2_suite := treat(l_test1_suite.items(3) as ut3.ut_suite); - - ut.expect(l_test2_suite.name).to_equal('test_package_2'); - ut.expect(l_test2_suite.items.count).to_equal(3); end; procedure test_top_pack_by_path is @@ -618,7 +605,7 @@ end test_package_with_ctx;]'; ut.expect(l_test1_suite.name).to_equal('test_package_1'); ut.expect(l_test1_suite.items.count).to_equal(3); - l_test2_suite := treat(l_test1_suite.items(3) as ut3.ut_logical_suite); + l_test2_suite := treat(l_test1_suite.items(1) as ut3.ut_logical_suite); ut.expect(l_test2_suite.name).to_equal('test_package_2'); ut.expect(l_test2_suite.items.count).to_equal(3); @@ -645,7 +632,7 @@ end test_package_with_ctx;]'; ut.expect(l_test1_suite.name).to_equal('test_package_1'); ut.expect(l_test1_suite.items.count).to_equal(3); - l_test2_suite := treat(l_test1_suite.items(3) as ut3.ut_logical_suite); + l_test2_suite := treat(l_test1_suite.items(1) as ut3.ut_logical_suite); ut.expect(l_test2_suite.name).to_equal('test_package_2'); ut.expect(l_test2_suite.items.count).to_equal(3); @@ -942,7 +929,7 @@ end;]'; l_objects_to_run ut3.ut_suite_items; begin l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list('ut3.failing_non_existing')); - ut.fail('Non existing package didnt raised exception'); + ut.fail('Non existing package did not raise exception'); exception when others then ut.expect(sqlerrm).to_be_like('%failing_non_existing%'); @@ -952,7 +939,7 @@ end;]'; l_objects_to_run ut3.ut_suite_items; begin l_objects_to_run := ut3.ut_suite_manager.configure_execution_by_path(ut3.ut_varchar2_list('failing_non_existing')); - ut.fail('Non existing package without schema didnt raised exception'); + ut.fail('Non existing package without schema did not raise exception'); exception when others then ut.expect(sqlerrm).to_be_like('%ORA-44001: invalid schema%'); @@ -979,10 +966,10 @@ end;]'; ut.expect(l_test.name).to_equal('test1'); ut.expect(l_test.description).to_equal('A test description, though with comma, is assigned by suite_manager'); - l_test := treat(l_suite.items(2) as ut3.ut_test); - - ut.expect(l_test.name).to_equal('test2'); - ut.expect(l_test.description).to_equal('A test description, though with comma, is assigned by suite_manager'); +-- l_test := treat(l_suite.items(2) as ut3.ut_test); +-- +-- ut.expect(l_test.name).to_equal('test2'); +-- ut.expect(l_test.description).to_equal('A test description, though with comma, is assigned by suite_manager'); end; procedure setup_desc_with_comma is @@ -1029,7 +1016,7 @@ end;'; ut.fail('Cache not invalidated on package drop'); exception when others then - ut.expect(sqlerrm).to_be_like('%tst_package_to_be_dropped%not found%'); + ut.expect(sqlerrm).to_be_like('%tst_package_to_be_dropped%does not exist%'); end; end; From 1611e09b15c5896c9146fe60c7f8b836250c3cea Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 4 Nov 2018 18:30:31 +0000 Subject: [PATCH 04/33] Interim commit some fixes to old tests, examples and code itself. One problem to be solved. Oracle nested tables are **unordered!** and we need an ordered list of before/after items that contain CLOB column, so cannot be varray. --- ...nExampleComplexSuiteWithCustomReporter.sql | 8 +- .../RunExampleTestSuite.sql | 6 +- ...nExampleTestSuiteWithCompositeReporter.sql | 6 +- .../RunExampleTestSuiteWithCustomReporter.sql | 6 +- ...rter.providesCorrectLineFromStacktrace.sql | 2 +- ...e_manager.CacheInvalidaesOnPackageDrop.sql | 12 +- ..._packages.IncludesPackagesWithSutePath.sql | 13 +- .../ut_test/ut_test.AfterEachExecuted.sql | 5 +- .../ut_test.AfterEachProcedureNameInvalid.sql | 5 +- .../ut_test.AfterEachProcedureNameNull.sql | 5 +- .../ut_test/ut_test.BeforeEachExecuted.sql | 5 +- ...ut_test.BeforeEachProcedureNameInvalid.sql | 5 +- .../ut_test.BeforeEachProcedureNameNull.sql | 5 +- ...est.IgnoreTollbackToSavepointException.sql | 2 +- .../ut_test/ut_test.OwnerNameInvalid.sql | 6 +- old_tests/ut_test/ut_test.OwnerNameNull.sql | 6 +- .../ut_test/ut_test.PackageInInvalidState.sql | 2 +- .../ut_test/ut_test.PackageNameInvalid.sql | 2 +- old_tests/ut_test/ut_test.PackageNameNull.sql | 2 +- .../ut_test/ut_test.ProcedureNameInvalid.sql | 2 +- .../ut_test/ut_test.ProcedureNameNull.sql | 2 +- .../ut_test.SetupExecutedBeforeTest.sql | 5 +- .../ut_test.SetupProcedureNameInvalid.sql | 5 +- .../ut_test.SetupProcedureNameNull.sql | 5 +- .../ut_test.TeardownExecutedAfterTest.sql | 5 +- .../ut_test.TeardownProcedureNameInvalid.sql | 5 +- .../ut_test.TeardownProcedureNameNull.sql | 5 +- .../annotations/ut_annotation_cache_seq.sql | 2 +- source/core/ut_suite_builder.pkb | 18 +- source/core/ut_suite_cache.sql | 12 +- source/core/ut_suite_cache_manager.pkb | 185 +++++++++--------- source/core/ut_suite_cache_manager.pks | 7 +- source/core/ut_suite_cache_package.sql | 23 +++ source/core/ut_suite_cache_seq.sql | 16 ++ .../create_synonyms_and_grants_for_public.sql | 1 + source/create_user_grants.sql | 1 + source/install.sql | 2 + test/core/test_suite_builder.pkb | 2 +- 38 files changed, 250 insertions(+), 156 deletions(-) create mode 100644 source/core/ut_suite_cache_package.sql create mode 100644 source/core/ut_suite_cache_seq.sql diff --git a/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql b/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql index 1b9e94bfb..406a1cba2 100644 --- a/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql +++ b/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql @@ -22,8 +22,8 @@ begin ut_event_manager.initialize(); l_parent_suite := ut_logical_suite( a_object_owner=>null, a_object_name => null, a_name => 'complex_test_suite', a_path => null); - l_suite := ut_suite(user, 'ut_exampletest'); - l_test := ut_test(user, 'ut_exampletest','ut_exAmpletest'); + l_suite := ut_suite(user, 'ut_exampletest',a_line_no=>1); + l_test := ut_test(user, 'ut_exampletest','ut_exAmpletest',a_line_no=>3); l_test.description := 'Example test1'; l_test.before_test_list := ut_executables(ut_executable(user, 'ut_exampletest','Setup',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'ut_exampletest','tEardown',ut_utils.gc_after_test)); @@ -32,8 +32,8 @@ begin l_parent_suite.add_item(l_suite); - l_suite := ut_suite(user, 'ut_exampletest2'); - l_test := ut_test(user, 'UT_EXAMPLETEST2','UT_EXAMPLETEST'); + l_suite := ut_suite(user, 'ut_exampletest2',a_line_no=>1); + l_test := ut_test(user, 'UT_EXAMPLETEST2','UT_EXAMPLETEST',a_line_no=>3); l_test.before_test_list := ut_executables(ut_executable(user, 'UT_EXAMPLETEST2','SETUP',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'UT_EXAMPLETEST2','TEARDOWN',ut_utils.gc_after_test)); diff --git a/examples/developer_examples/RunExampleTestSuite.sql b/examples/developer_examples/RunExampleTestSuite.sql index a0a470e46..7b01d1154 100644 --- a/examples/developer_examples/RunExampleTestSuite.sql +++ b/examples/developer_examples/RunExampleTestSuite.sql @@ -15,15 +15,15 @@ declare l_test ut_test; l_expectation ut_expectation_result; begin - l_suite := ut_suite(user, 'ut_exampletest'); + l_suite := ut_suite(user, 'ut_exampletest',a_line_no=>1); l_suite.description := 'Test Suite Name'; - l_test := ut_test(user, 'ut_exampletest','ut_exAmpletest'); + l_test := ut_test(user, 'ut_exampletest','ut_exAmpletest',a_line_no=>3); l_test.description := 'Example test1'; l_test.before_test_list := ut_executables(ut_executable(user, 'ut_exampletest','Setup',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'ut_exampletest','tEardown',ut_utils.gc_after_test)); l_suite.add_item(l_test); - l_test := ut_test(user, 'UT_EXAMPLETEST2','ut_exAmpletest'); + l_test := ut_test(user, 'UT_EXAMPLETEST2','ut_exAmpletest',a_line_no=>6); l_test.description := 'Another example test'; l_test.before_test_list := ut_executables(ut_executable(user, 'UT_EXAMPLETEST2','SETUP',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'UT_EXAMPLETEST2','TEARDOWN',ut_utils.gc_after_test)); diff --git a/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql b/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql index 4f9172510..8876f0874 100644 --- a/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql +++ b/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql @@ -21,11 +21,11 @@ begin ut_event_manager.add_listener(l_doc_reporter); ut_event_manager.add_listener(l_tc_reporter); - suite := ut_suite(user, 'ut_exampletest'); + suite := ut_suite(user, 'ut_exampletest',a_line_no=>1); suite.description := 'Test Suite Name'; - suite.add_item(ut_test(user,'ut_exampletest','ut_exAmpletest')); - suite.add_item(ut_test(user, 'UT_EXAMPLETEST2','UT_EXAMPLETEST')); + suite.add_item(ut_test(user,'ut_exampletest','ut_exAmpletest',a_line_no=>3)); + suite.add_item(ut_test(user, 'UT_EXAMPLETEST2','UT_EXAMPLETEST',a_line_no=>6)); -- provide a reporter to process results l_run := ut_run(ut_suite_items(suite)); diff --git a/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql b/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql index 59fe15662..e9403809e 100644 --- a/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql +++ b/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql @@ -22,15 +22,15 @@ begin ut_event_manager.initialize(); -- Install ut_custom_reporter first from example folder - l_suite := ut_suite(user, 'ut_exampletest'); + l_suite := ut_suite(user, 'ut_exampletest',a_line_no=>1); - l_test := ut_test(user, 'ut_exampletest','ut_exAmpletest'); + l_test := ut_test(user, 'ut_exampletest','ut_exAmpletest',a_line_no=>3); l_test.description := 'Example test1'; l_test.before_test_list := ut_executables(ut_executable(user, 'ut_exampletest','Setup',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'ut_exampletest','tEardown',ut_utils.gc_after_test)); l_suite.add_item(l_test); - l_test := ut_test(user, 'UT_EXAMPLETEST2','ut_exAmpletest'); + l_test := ut_test(user, 'UT_EXAMPLETEST2','ut_exAmpletest',a_line_no=>6); l_test.description := 'Another example test'; l_test.before_test_list := ut_executables(ut_executable(user, 'ut_exampletest','SETUP',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'ut_exampletest','TEARDOWN',ut_utils.gc_after_test)); diff --git a/old_tests/ut_reporters/ut_documentation_reporter.providesCorrectLineFromStacktrace.sql b/old_tests/ut_reporters/ut_documentation_reporter.providesCorrectLineFromStacktrace.sql index 66cf41b32..f155117fe 100644 --- a/old_tests/ut_reporters/ut_documentation_reporter.providesCorrectLineFromStacktrace.sql +++ b/old_tests/ut_reporters/ut_documentation_reporter.providesCorrectLineFromStacktrace.sql @@ -18,7 +18,7 @@ Finished % --act select * bulk collect into l_output_data - from table(ut.run('test_reporters',ut_documentation_reporter())); + from table(ut.run(':org.utplsql.utplsql.test.test_reporters',ut_documentation_reporter())); l_output := ut_utils.table_to_clob(l_output_data); diff --git a/old_tests/ut_suite_manager/ut_suite_manager.CacheInvalidaesOnPackageDrop.sql b/old_tests/ut_suite_manager/ut_suite_manager.CacheInvalidaesOnPackageDrop.sql index 6581a9eeb..9715eae8b 100644 --- a/old_tests/ut_suite_manager/ut_suite_manager.CacheInvalidaesOnPackageDrop.sql +++ b/old_tests/ut_suite_manager/ut_suite_manager.CacheInvalidaesOnPackageDrop.sql @@ -28,19 +28,23 @@ drop package tst_package_to_be_dropped set termout on declare - l_test_report ut_varchar2_list; + l_test_report ut_varchar2_list; + l_error_message varchar2(4000); + l_expected varchar2(4000); begin + l_expected := '%tst_package_to_be_dropped%does not exist%'; begin select * bulk collect into l_test_report from table(ut.run(user || '.tst_package_to_be_dropped')); exception when others then - if sqlerrm like '%tst_package_to_be_dropped%not found%' then + l_error_message := sqlerrm; + if l_error_message like l_expected then :test_result := ut_utils.gc_success; end if; end; if :test_result != ut_utils.gc_success or :test_result is null then - dbms_output.put_line('Failed: Expected exception with text like ''%tst_package_to_be_dropped%not found%'' but got:''' || - sqlerrm || ''''); + dbms_output.put_line('Failed: Expected exception with text like '''||l_expected||''' but got:''' || + l_error_message || ''''); end if; end; / diff --git a/old_tests/ut_suite_manager/ut_suite_manager.get_schema_ut_packages.IncludesPackagesWithSutePath.sql b/old_tests/ut_suite_manager/ut_suite_manager.get_schema_ut_packages.IncludesPackagesWithSutePath.sql index 3023c28f0..0f446b7bf 100644 --- a/old_tests/ut_suite_manager/ut_suite_manager.get_schema_ut_packages.IncludesPackagesWithSutePath.sql +++ b/old_tests/ut_suite_manager/ut_suite_manager.get_schema_ut_packages.IncludesPackagesWithSutePath.sql @@ -6,8 +6,9 @@ end; set termout on declare - l_expected ut_object_names; - l_actual ut_object_names; + l_expected ut_object_names; + l_actual ut_object_names; + l_not_found ut_object_names := ut_object_names(); begin l_expected := ut_object_names( ut_object_name(user,'TEST_PACKAGE_1'), @@ -17,7 +18,13 @@ begin ut_object_name(user,'TEST_REPORTERS') ); l_actual := ut_suite_manager.get_schema_ut_packages(ut_varchar2_rows(user)); - if l_actual = l_expected then + for i in 1 .. l_expected.count loop + if l_expected(i) not member of l_actual then + l_not_found.extend; + l_not_found(l_not_found.last) := l_expected(i); + end if; + end loop; + if l_not_found is empty then :test_result := ut_utils.gc_success; else dbms_output.put_line('actual:'||xmltype(anydata.convertcollection(l_actual)).getclobval()); diff --git a/old_tests/ut_test/ut_test.AfterEachExecuted.sql b/old_tests/ut_test/ut_test.AfterEachExecuted.sql index e35564b7b..5711c38e9 100644 --- a/old_tests/ut_test/ut_test.AfterEachExecuted.sql +++ b/old_tests/ut_test/ut_test.AfterEachExecuted.sql @@ -3,8 +3,9 @@ PROMPT Invoke aftereach procedure --Arrange declare simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' + a_object_name => 'ut_example_tests', + a_name => 'ut_passing_test', + a_line_no => null ); begin simple_test.after_each_list := ut_executables(ut_executable(user, 'ut_example_tests', 'aftereach', ut_utils.gc_after_each)); diff --git a/old_tests/ut_test/ut_test.AfterEachProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.AfterEachProcedureNameInvalid.sql index 4d12cd513..15765a811 100644 --- a/old_tests/ut_test/ut_test.AfterEachProcedureNameInvalid.sql +++ b/old_tests/ut_test/ut_test.AfterEachProcedureNameInvalid.sql @@ -3,8 +3,9 @@ PROMPT Does not execute test and reports error when test aftereach procedure nam --Arrange declare simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_exampletest' + a_object_name => 'ut_example_tests', + a_name => 'ut_exampletest', + a_line_no => null ); begin simple_test.after_each_list := ut_executables(ut_executable(user, 'ut_example_tests', 'invalid setup name', ut_utils.gc_after_each)); diff --git a/old_tests/ut_test/ut_test.AfterEachProcedureNameNull.sql b/old_tests/ut_test/ut_test.AfterEachProcedureNameNull.sql index 2700e1a10..f40ee8c04 100644 --- a/old_tests/ut_test/ut_test.AfterEachProcedureNameNull.sql +++ b/old_tests/ut_test/ut_test.AfterEachProcedureNameNull.sql @@ -3,8 +3,9 @@ PROMPT Does not invoke aftereach procedure when aftereach procedure name for a t --Arrange declare simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' + a_object_name => 'ut_example_tests', + a_name => 'ut_passing_test', + a_line_no => null ); begin simple_test.after_each_list := ut_executables(ut_executable(user, 'ut_example_tests', '', ut_utils.gc_after_each)); diff --git a/old_tests/ut_test/ut_test.BeforeEachExecuted.sql b/old_tests/ut_test/ut_test.BeforeEachExecuted.sql index 5015d69fd..9d40441ac 100644 --- a/old_tests/ut_test/ut_test.BeforeEachExecuted.sql +++ b/old_tests/ut_test/ut_test.BeforeEachExecuted.sql @@ -3,8 +3,9 @@ PROMPT Invoke beforeeach procedure --Arrange declare simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' + a_object_name => 'ut_example_tests', + a_name => 'ut_passing_test', + a_line_no => null ); begin simple_test.before_each_list := ut_executables(ut_executable(user, 'ut_example_tests', 'beforeeach', ut_utils.gc_before_each)); diff --git a/old_tests/ut_test/ut_test.BeforeEachProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.BeforeEachProcedureNameInvalid.sql index f03b76f08..5a9d40a58 100644 --- a/old_tests/ut_test/ut_test.BeforeEachProcedureNameInvalid.sql +++ b/old_tests/ut_test/ut_test.BeforeEachProcedureNameInvalid.sql @@ -3,8 +3,9 @@ PROMPT Does not execute test and reports error when test beforeeach procedure na --Arrange declare simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_exampletest' + a_object_name => 'ut_example_tests', + a_name => 'ut_exampletest', + a_line_no => null ); begin simple_test.before_each_list := ut_executables(ut_executable(user, 'ut_example_tests', 'invalid setup name', ut_utils.gc_before_each)); diff --git a/old_tests/ut_test/ut_test.BeforeEachProcedureNameNull.sql b/old_tests/ut_test/ut_test.BeforeEachProcedureNameNull.sql index e717b128f..66107c462 100644 --- a/old_tests/ut_test/ut_test.BeforeEachProcedureNameNull.sql +++ b/old_tests/ut_test/ut_test.BeforeEachProcedureNameNull.sql @@ -3,8 +3,9 @@ PROMPT Does not invoke setup procedure when beforeeach procedure name for a test --Arrange declare simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' + a_object_name => 'ut_example_tests', + a_name => 'ut_passing_test', + a_line_no => null ); begin simple_test.before_each_list := ut_executables(ut_executable(user, 'ut_example_tests', '', ut_utils.gc_before_each)); diff --git a/old_tests/ut_test/ut_test.IgnoreTollbackToSavepointException.sql b/old_tests/ut_test/ut_test.IgnoreTollbackToSavepointException.sql index 94ad60c3d..3e3c1a814 100644 --- a/old_tests/ut_test/ut_test.IgnoreTollbackToSavepointException.sql +++ b/old_tests/ut_test/ut_test.IgnoreTollbackToSavepointException.sql @@ -2,7 +2,7 @@ PROMPT Checks that rollback exception does not make run to fail --Arrange declare - simple_test ut_test := ut_test(a_object_name => 'ut_example_tests', a_name => 'ut_commit_test'); + simple_test ut_test := ut_test(a_object_name => 'ut_example_tests', a_name => 'ut_commit_test', a_line_no => null); begin simple_test.rollback_type := ut_utils.gc_rollback_auto; --Act diff --git a/old_tests/ut_test/ut_test.OwnerNameInvalid.sql b/old_tests/ut_test/ut_test.OwnerNameInvalid.sql index ba19e0767..5207af574 100644 --- a/old_tests/ut_test/ut_test.OwnerNameInvalid.sql +++ b/old_tests/ut_test/ut_test.OwnerNameInvalid.sql @@ -2,7 +2,11 @@ PROMPT Reports error when test owner name for a test is invalid --Arrange declare - simple_test ut_test := ut_test( a_object_owner => 'invalid owner name', a_object_name => 'ut_example_tests', a_name => 'ut_passing_test'); + simple_test ut_test := ut_test( + a_object_owner => 'invalid owner name', + a_object_name => 'ut_example_tests', + a_name => 'ut_passing_test', + a_line_no => null); begin --Act simple_test.do_execute(); diff --git a/old_tests/ut_test/ut_test.OwnerNameNull.sql b/old_tests/ut_test/ut_test.OwnerNameNull.sql index 68acf9144..f57aebf92 100644 --- a/old_tests/ut_test/ut_test.OwnerNameNull.sql +++ b/old_tests/ut_test/ut_test.OwnerNameNull.sql @@ -2,7 +2,11 @@ PROMPT Executes test in current schema when test owner name for a test is null --Arrange declare - simple_test ut_test:= ut_test(a_object_owner => null, a_object_name => 'ut_example_tests', a_name => 'ut_passing_test'); + simple_test ut_test:= ut_test( + a_object_owner => null, + a_object_name => 'ut_example_tests', + a_name => 'ut_passing_test', + a_line_no => null); begin --Act simple_test.do_execute(); diff --git a/old_tests/ut_test/ut_test.PackageInInvalidState.sql b/old_tests/ut_test/ut_test.PackageInInvalidState.sql index 31056dcfd..0b87a13d6 100644 --- a/old_tests/ut_test/ut_test.PackageInInvalidState.sql +++ b/old_tests/ut_test/ut_test.PackageInInvalidState.sql @@ -8,7 +8,7 @@ end; set termout on declare - simple_test ut_test := ut_test(a_object_name => 'invalid_package', a_name => 'ut_exampletest'); + simple_test ut_test := ut_test(a_object_name => 'invalid_package', a_name => 'ut_exampletest', a_line_no => null); begin --Act simple_test.do_execute(); diff --git a/old_tests/ut_test/ut_test.PackageNameInvalid.sql b/old_tests/ut_test/ut_test.PackageNameInvalid.sql index 246af45db..b615e7589 100644 --- a/old_tests/ut_test/ut_test.PackageNameInvalid.sql +++ b/old_tests/ut_test/ut_test.PackageNameInvalid.sql @@ -2,7 +2,7 @@ PROMPT Reports error when unit test package name for a test is invalid --Arrange declare - simple_test ut_test := ut_test(a_object_name => 'invalid test package name', a_name => 'ut_passing_test'); + simple_test ut_test := ut_test(a_object_name => 'invalid test package name', a_name => 'ut_passing_test', a_line_no => null); begin --Act simple_test.do_execute(); diff --git a/old_tests/ut_test/ut_test.PackageNameNull.sql b/old_tests/ut_test/ut_test.PackageNameNull.sql index f4420b6b0..59612fa3d 100644 --- a/old_tests/ut_test/ut_test.PackageNameNull.sql +++ b/old_tests/ut_test/ut_test.PackageNameNull.sql @@ -2,7 +2,7 @@ PROMPT Reports error when unit test package name for a test is null --Arrange declare - simple_test ut_test := ut_test(a_object_name => null, a_name => 'ut_passing_test'); + simple_test ut_test := ut_test(a_object_name => null, a_name => 'ut_passing_test', a_line_no => null); begin --Act simple_test.do_execute(); diff --git a/old_tests/ut_test/ut_test.ProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.ProcedureNameInvalid.sql index a66f0deff..2a8e80a9e 100644 --- a/old_tests/ut_test/ut_test.ProcedureNameInvalid.sql +++ b/old_tests/ut_test/ut_test.ProcedureNameInvalid.sql @@ -2,7 +2,7 @@ PROMPT Reports error when test procedure name for a test is invalid --Arrange declare - simple_test ut_test := ut_test(a_object_name => 'ut_example_tests' ,a_name => 'invalid procedure name'); + simple_test ut_test := ut_test(a_object_name => 'ut_example_tests' ,a_name => 'invalid procedure name', a_line_no => null); begin --Act simple_test.do_execute(); diff --git a/old_tests/ut_test/ut_test.ProcedureNameNull.sql b/old_tests/ut_test/ut_test.ProcedureNameNull.sql index 1e702ab2c..df4f0e593 100644 --- a/old_tests/ut_test/ut_test.ProcedureNameNull.sql +++ b/old_tests/ut_test/ut_test.ProcedureNameNull.sql @@ -2,7 +2,7 @@ PROMPT Reports error when test procedure name for a test is null --Arrange declare - simple_test ut_test := ut_test(a_object_name => 'ut_example_tests', a_name => null); + simple_test ut_test := ut_test(a_object_name => 'ut_example_tests', a_name => null, a_line_no => null); begin --Act simple_test.do_execute(); diff --git a/old_tests/ut_test/ut_test.SetupExecutedBeforeTest.sql b/old_tests/ut_test/ut_test.SetupExecutedBeforeTest.sql index e928443f3..2a80cf586 100644 --- a/old_tests/ut_test/ut_test.SetupExecutedBeforeTest.sql +++ b/old_tests/ut_test/ut_test.SetupExecutedBeforeTest.sql @@ -3,8 +3,9 @@ PROMPT Invoke setup procedure before test when setup procedure name is defined --Arrange declare simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' + a_object_name => 'ut_example_tests', + a_name => 'ut_passing_test', + a_line_no => null ); begin simple_test.before_test_list := ut_executables(ut_executable(user, 'ut_example_tests', 'setup', ut_utils.gc_before_test)); diff --git a/old_tests/ut_test/ut_test.SetupProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.SetupProcedureNameInvalid.sql index 3f6fab022..d81141031 100644 --- a/old_tests/ut_test/ut_test.SetupProcedureNameInvalid.sql +++ b/old_tests/ut_test/ut_test.SetupProcedureNameInvalid.sql @@ -3,8 +3,9 @@ PROMPT Does not execute test and reports error when test setup procedure name fo --Arrange declare simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_exampletest' + a_object_name => 'ut_example_tests', + a_name => 'ut_exampletest', + a_line_no => null ); begin simple_test.before_test_list := ut_executables(ut_executable(user, 'ut_example_tests', 'invalid setup name', ut_utils.gc_before_test)); diff --git a/old_tests/ut_test/ut_test.SetupProcedureNameNull.sql b/old_tests/ut_test/ut_test.SetupProcedureNameNull.sql index 0622a2295..9269fdd92 100644 --- a/old_tests/ut_test/ut_test.SetupProcedureNameNull.sql +++ b/old_tests/ut_test/ut_test.SetupProcedureNameNull.sql @@ -3,8 +3,9 @@ PROMPT Does not invoke setup procedure when setup procedure name for a test is n --Arrange declare simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' + a_object_name => 'ut_example_tests', + a_name => 'ut_passing_test', + a_line_no => null ); begin simple_test.before_test_list := ut_executables(ut_executable(user, 'ut_example_tests', null, ut_utils.gc_before_test)); diff --git a/old_tests/ut_test/ut_test.TeardownExecutedAfterTest.sql b/old_tests/ut_test/ut_test.TeardownExecutedAfterTest.sql index 55c0026c1..bc733614b 100644 --- a/old_tests/ut_test/ut_test.TeardownExecutedAfterTest.sql +++ b/old_tests/ut_test/ut_test.TeardownExecutedAfterTest.sql @@ -3,8 +3,9 @@ PROMPT Invoke teardown procedure after test when teardown procedure name is defi --Arrange declare simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' + a_object_name => 'ut_example_tests', + a_name => 'ut_passing_test', + a_line_no => null ); begin simple_test.after_test_list := ut_executables(ut_executable(user, 'ut_example_tests', 'teardown', ut_utils.gc_after_test)); diff --git a/old_tests/ut_test/ut_test.TeardownProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.TeardownProcedureNameInvalid.sql index 86bdff66a..5ae61cc13 100644 --- a/old_tests/ut_test/ut_test.TeardownProcedureNameInvalid.sql +++ b/old_tests/ut_test/ut_test.TeardownProcedureNameInvalid.sql @@ -3,8 +3,9 @@ PROMPT Does not execute test and reports error when test teardown procedure name --Arrange declare simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_exampletest' + a_object_name => 'ut_example_tests', + a_name => 'ut_exampletest', + a_line_no => null ); begin simple_test.after_test_list := ut_executables(ut_executable(user, 'ut_example_tests', 'invalid setup name', ut_utils.gc_after_test)); diff --git a/old_tests/ut_test/ut_test.TeardownProcedureNameNull.sql b/old_tests/ut_test/ut_test.TeardownProcedureNameNull.sql index a1837d20c..7460ca788 100644 --- a/old_tests/ut_test/ut_test.TeardownProcedureNameNull.sql +++ b/old_tests/ut_test/ut_test.TeardownProcedureNameNull.sql @@ -3,8 +3,9 @@ PROMPT Does not invoke teardown procedure when teardown procedure name for a tes --Arrange declare simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests' - ,a_name => 'ut_passing_test' + a_object_name => 'ut_example_tests', + a_name => 'ut_passing_test', + a_line_no => null ); begin simple_test.after_test_list := ut_executables(ut_executable(user, 'ut_example_tests', null, ut_utils.gc_after_test)); diff --git a/source/core/annotations/ut_annotation_cache_seq.sql b/source/core/annotations/ut_annotation_cache_seq.sql index 028225ddb..1cc97086e 100644 --- a/source/core/annotations/ut_annotation_cache_seq.sql +++ b/source/core/annotations/ut_annotation_cache_seq.sql @@ -12,5 +12,5 @@ create sequence ut_annotation_cache_seq See the License for the specific language governing permissions and limitations under the License. */ -cache 20; +cache 100; diff --git a/source/core/ut_suite_builder.pkb b/source/core/ut_suite_builder.pkb index 358a563f4..cc2b32309 100644 --- a/source/core/ut_suite_builder.pkb +++ b/source/core/ut_suite_builder.pkb @@ -992,7 +992,6 @@ create or replace package body ut_suite_builder is l_idx := l_rows.first; end if; exit when l_idx is null; - l_level := length(l_rows(l_idx).path) - length( replace(l_rows(l_idx).path, '.') ) + 1; if l_level > 1 then @@ -1055,7 +1054,7 @@ create or replace package body ut_suite_builder is suite_items as ( select c.* from ]'||l_ut_owner||q'[.ut_suite_cache c - where 1 = 1 ]'||case when a_skip_all_objects is null then q'[ + where 1 = 1 ]'||case when not a_skip_all_objects /*1 = 0*/ then q'[ and exists ( select 1 from all_objects a @@ -1112,7 +1111,7 @@ create or replace package body ut_suite_builder is not in (select s.path from suitepaths s) ), logical_suites as ( - select s.self_type, s.path, s.object_owner, s.object_name, + select to_number(null) as id, s.self_type, s.path, s.object_owner, s.object_name, s.object_name as name, null as line_no, null as parse_time, null as description, null as rollback_type, 0 as disabled_flag, ]'||l_ut_owner||q'[.ut_varchar2_rows() as warnings, @@ -1164,7 +1163,12 @@ create or replace package body ut_suite_builder is convert_package_annotations( l_annotated_objects( i ) ), l_suite_items ); - ut_suite_cache_manager.save_cache( a_owner_name, l_suite_items ); + ut_suite_cache_manager.save_object_cache( + a_owner_name, + l_annotated_objects( i ).object_name, + l_annotated_objects( i ).parse_time, + l_suite_items + ); end loop; exit when a_annotated_objects%notfound; end loop; @@ -1202,7 +1206,7 @@ create or replace package body ut_suite_builder is ]' || ut_utils.ut_owner || q'[.ut_annotation_manager.get_annotated_objects(:a_owner_name, 'PACKAGE', :a_suite_cache_parse_time) )x ]' using a_owner_name, l_suite_cache_time; - + return build_suites_from_annotations( a_owner_name, l_annotations_cursor, @@ -1218,8 +1222,8 @@ create or replace package body ut_suite_builder is l_object_names ut_varchar2_rows; l_ut_owner varchar2(250) := ut_utils.ut_owner; begin - execute immediate 'select distinct c.object_owner, c.object_name - from '||l_ut_owner||q'[.ut_suite_cache c + execute immediate 'select c.object_owner, c.object_name + from '||l_ut_owner||q'[.ut_suite_cache_package c join table ( :a_schema_names ) s on c.object_owner = upper(s.column_value) -- where exists diff --git a/source/core/ut_suite_cache.sql b/source/core/ut_suite_cache.sql index 09211722b..adbdf1734 100644 --- a/source/core/ut_suite_cache.sql +++ b/source/core/ut_suite_cache.sql @@ -17,6 +17,7 @@ create table ut_suite_cache ( See the License for the specific language governing permissions and limitations under the License. */ + id, self_type, path, object_owner, @@ -47,6 +48,7 @@ create table ut_suite_cache ( nested table expected_error_codes store as ut_suite_cache_trhows as select + cast(null as number(22)) id, c.self_type, c.path, c.object_owner, @@ -73,11 +75,15 @@ create table ut_suite_cache ( alter table ut_suite_cache modify (object_owner not null, path not null, self_type not null, object_name not null, name not null, parse_time not null) / -alter table ut_suite_cache add constraint ut_suite_cache_pk primary key (object_owner, path) +alter table ut_suite_cache add constraint ut_suite_cache_pk primary key (id) / -create index ut_suite_cache_nu1 on ut_suite_cache(object_owner, object_name, parse_time desc) +alter table ut_suite_cache add constraint ut_suite_cache_uk1 unique (object_owner, path) / -alter table ut_suite_cache add constraint ut_suite_cache_schema_fk foreign key (object_owner) references ut_suite_cache_schema(object_owner) +alter table ut_suite_cache add constraint ut_suite_cache_uk2 unique (object_owner, object_name, line_no) +/ + +alter table ut_suite_cache add constraint ut_suite_cache_schema_fk foreign key (object_owner, object_name) +references ut_suite_cache_package(object_owner, object_name) on delete cascade / drop type ut_tests diff --git a/source/core/ut_suite_cache_manager.pkb b/source/core/ut_suite_cache_manager.pkb index cad718ee3..9caf8a946 100644 --- a/source/core/ut_suite_cache_manager.pkb +++ b/source/core/ut_suite_cache_manager.pkb @@ -26,108 +26,113 @@ create or replace package body ut_suite_cache_manager is return l_cache_parse_time; end; - procedure save_cache(a_object_owner varchar2, a_suite_items ut_suite_items) is + procedure save_object_cache( + a_object_owner varchar2, + a_object_name varchar2, + a_parse_time timestamp, + a_suite_items ut_suite_items + ) is pragma autonomous_transaction; - l_parse_time timestamp; l_cached_parse_time timestamp; l_object_owner varchar2(250) := upper(a_object_owner); + l_object_name varchar2(250) := upper(a_object_name); begin if a_suite_items.count = 0 then - return; - end if; - if a_suite_items(1).self_type != 'UT_LOGICAL_SUITE' then - select min(parse_time) - into l_cached_parse_time - from ut_suite_cache t - where t.object_name = a_suite_items(1).object_name - and t.object_owner = a_suite_items(1).object_owner - and rownum = 1; - end if; - - select max(parse_time) into l_parse_time from table(a_suite_items) s; + delete from ut_suite_cache t + where t.object_owner = l_object_owner + and t.object_name = l_object_name; - if l_parse_time > l_cached_parse_time or l_cached_parse_time is null then + delete from ut_suite_cache_package t + where t.object_owner = l_object_owner + and t.object_name = l_object_name; - update ut_suite_cache_schema t - set t.parse_time = l_parse_time - where object_owner = l_object_owner; + else - if sql%rowcount = 0 then - insert into ut_suite_cache_schema - (object_owner, parse_time) - values (l_object_owner, l_parse_time); - end if; - - delete from ut_suite_cache t - where (t.object_name, t.object_owner) - in ( - select upper(s.object_name), upper(s.object_owner) - from table(a_suite_items) s where s.self_type != 'UT_LOGICAL_SUITE' - ); - - - insert into ut_suite_cache t - ( - self_type, path, object_owner, object_name, name, - line_no, parse_time, description, - rollback_type, disabled_flag, warnings - ) - select self_type, path, upper(object_owner), upper(object_name), upper(name), - line_no, parse_time, description, - rollback_type, disabled_flag, warnings - from table(a_suite_items) s - where s.self_type = 'UT_LOGICAL_SUITE' - and (s.object_owner, s.path) not in (select c.object_owner, c.path from ut_suite_cache c); - - insert into ut_suite_cache t + select min(parse_time) + into l_cached_parse_time + from ut_suite_cache_package t + where t.object_name = l_object_name + and t.object_owner = l_object_owner; + + if a_parse_time > l_cached_parse_time or l_cached_parse_time is null then + + update ut_suite_cache_schema t + set t.parse_time = a_parse_time + where object_owner = l_object_owner; + + if sql%rowcount = 0 then + insert into ut_suite_cache_schema + (object_owner, parse_time) + values (l_object_owner, a_parse_time); + end if; + + update ut_suite_cache_package t + set t.parse_time = a_parse_time + where t.object_owner = l_object_owner + and t.object_name = l_object_name; + + if sql%rowcount = 0 then + insert into ut_suite_cache_package + (object_owner, object_name, parse_time) + values (l_object_owner, l_object_name, a_parse_time ); + end if; + + delete from ut_suite_cache t + where t.object_owner = l_object_owner + and t.object_name = l_object_name; + + insert into ut_suite_cache t + ( + id, self_type, path, object_owner, object_name, name, + line_no, parse_time, description, + rollback_type, disabled_flag, warnings, + before_all_list, after_all_list, + before_each_list, after_each_list, + before_test_list, after_test_list, + expected_error_codes, item + ) + with suites as ( + select treat(value(x) as ut_suite) i + from table(a_suite_items) x + where x.self_type in( 'UT_SUITE', 'UT_SUITE_CONTEXT' ) ) + select ut_suite_cache_seq.nextval, s.i.self_type as self_type, s.i.path as path, + upper(s.i.object_owner) as object_owner, upper(s.i.object_name) as object_name, upper(s.i.name) as name, + s.i.line_no as line_no, s.i.parse_time as parse_time, s.i.description as description, + s.i.rollback_type as rollback_type, s.i.disabled_flag as disabled_flag, s.i.warnings as warnings, + s.i.before_all_list as before_all_list, s.i.after_all_list as after_all_list, + null before_each_list, null after_each_list, + null before_test_list, null after_test_list, + null expected_error_codes, null item + from suites s; + + insert into ut_suite_cache t ( - self_type, path, object_owner, object_name, name, - line_no, parse_time, description, - rollback_type, disabled_flag, warnings, - before_all_list, after_all_list, - before_each_list, after_each_list, - before_test_list, after_test_list, - expected_error_codes, item + id, self_type, path, object_owner, object_name, name, + line_no, parse_time, description, + rollback_type, disabled_flag, warnings, + before_all_list, after_all_list, + before_each_list, after_each_list, + before_test_list, after_test_list, + expected_error_codes, item ) - with suites as ( select treat(value(x) as ut_suite) i - from table(a_suite_items) x - where x.self_type in( 'UT_SUITE', 'UT_SUITE_CONTEXT' ) ) - select s.i.self_type as self_type, s.i.path as path, - upper(s.i.object_owner) as object_owner, upper(s.i.object_name) as object_name, upper(s.i.name) as name, - s.i.line_no as line_no, s.i.parse_time as parse_time, s.i.description as description, - s.i.rollback_type as rollback_type, s.i.disabled_flag as disabled_flag, s.i.warnings as warnings, - s.i.before_all_list as before_all_list, s.i.after_all_list as after_all_list, - null before_each_list, null after_each_list, - null before_test_list, null after_test_list, - null expected_error_codes, null item - from suites s; - - insert into ut_suite_cache t - ( - self_type, path, object_owner, object_name, name, - line_no, parse_time, description, - rollback_type, disabled_flag, warnings, - before_all_list, after_all_list, - before_each_list, after_each_list, - before_test_list, after_test_list, - expected_error_codes, item - ) - with tests as ( select treat(value(x) as ut_test) t - from table ( a_suite_items ) x - where x.self_type in ( 'UT_TEST' ) ) - select s.t.self_type as self_type, s.t.path as path, - upper(s.t.object_owner) as object_owner, upper(s.t.object_name) as object_name, upper(s.t.name) as name, - s.t.line_no as line_no, s.t.parse_time as parse_time, s.t.description as description, - s.t.rollback_type as rollback_type, s.t.disabled_flag as disabled_flag, s.t.warnings as warnings, - null before_all_list, null after_all_list, - s.t.before_each_list as before_each_list, s.t.after_each_list as after_each_list, - s.t.before_test_list as before_test_list, s.t.after_test_list as after_test_list, - s.t.expected_error_codes as expected_error_codes, s.t.item as item - from tests s; - - commit; + with tests as ( + select treat(value(x) as ut_test) t + from table ( a_suite_items ) x + where x.self_type in ( 'UT_TEST' ) ) + select ut_suite_cache_seq.nextval, s.t.self_type as self_type, s.t.path as path, + upper(s.t.object_owner) as object_owner, upper(s.t.object_name) as object_name, upper(s.t.name) as name, + s.t.line_no as line_no, s.t.parse_time as parse_time, s.t.description as description, + s.t.rollback_type as rollback_type, s.t.disabled_flag as disabled_flag, s.t.warnings as warnings, + null before_all_list, null after_all_list, + s.t.before_each_list as before_each_list, s.t.after_each_list as after_each_list, + s.t.before_test_list as before_test_list, s.t.after_test_list as after_test_list, + s.t.expected_error_codes as expected_error_codes, s.t.item as item + from tests s; + + end if; end if; + commit; end; end ut_suite_cache_manager; diff --git a/source/core/ut_suite_cache_manager.pks b/source/core/ut_suite_cache_manager.pks index 919196efa..3d5a21f10 100644 --- a/source/core/ut_suite_cache_manager.pks +++ b/source/core/ut_suite_cache_manager.pks @@ -20,7 +20,12 @@ create or replace package ut_suite_cache_manager authid definer is * Responsible for storing and retrieving suite data from cache */ - procedure save_cache(a_object_owner varchar2, a_suite_items ut_suite_items); + procedure save_object_cache( + a_object_owner varchar2, + a_object_name varchar2, + a_parse_time timestamp, + a_suite_items ut_suite_items + ); function get_schema_parse_time(a_schema_name varchar2) return timestamp result_cache; diff --git a/source/core/ut_suite_cache_package.sql b/source/core/ut_suite_cache_package.sql new file mode 100644 index 000000000..46f49e915 --- /dev/null +++ b/source/core/ut_suite_cache_package.sql @@ -0,0 +1,23 @@ +create table ut_suite_cache_package ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 utPLSQL Project + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + object_owner varchar2(250) not null, + object_name varchar2(250) not null, + parse_time timestamp not null, + constraint ut_suite_cache_package_pk primary key(object_owner, object_name), + constraint ut_suite_cache_package_fk foreign key (object_owner) references ut_suite_cache_schema(object_owner) on delete cascade +) organization index +/ + + diff --git a/source/core/ut_suite_cache_seq.sql b/source/core/ut_suite_cache_seq.sql new file mode 100644 index 000000000..0c9c835b8 --- /dev/null +++ b/source/core/ut_suite_cache_seq.sql @@ -0,0 +1,16 @@ +create sequence ut_suite_cache_seq + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 utPLSQL Project + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +cache 100; + diff --git a/source/create_synonyms_and_grants_for_public.sql b/source/create_synonyms_and_grants_for_public.sql index f22a61121..4928022eb 100644 --- a/source/create_synonyms_and_grants_for_public.sql +++ b/source/create_synonyms_and_grants_for_public.sql @@ -89,6 +89,7 @@ grant select on &&ut3_owner..ut_annotation_cache to public; grant execute on &&ut3_owner..ut_executables to public; grant execute on &&ut3_owner..ut_executable_test to public; grant select on &&ut3_owner..ut_suite_cache to public; +grant select on &&ut3_owner..ut_suite_cache_package to public; grant select on &&ut3_owner..ut_suite_cache_schema to public; grant execute on &&ut3_owner..ut_annotation_cache_manager to public; grant execute on &&ut3_owner..ut_annotation_parser to public; diff --git a/source/create_user_grants.sql b/source/create_user_grants.sql index 723fcca58..0967a0e8c 100644 --- a/source/create_user_grants.sql +++ b/source/create_user_grants.sql @@ -109,6 +109,7 @@ grant select on &&ut3_owner..ut_annotation_cache to &ut3_user; grant execute on &&ut3_owner..ut_executables to &ut3_user; grant execute on &&ut3_owner..ut_executable_test to &ut3_user; grant select on &&ut3_owner..ut_suite_cache to &ut3_user; +grant select on &&ut3_owner..ut_suite_cache_package to public; grant select on &&ut3_owner..ut_suite_cache_schema to &ut3_user; grant execute on &&ut3_owner..ut_annotation_cache_manager to &ut3_user; grant execute on &&ut3_owner..ut_annotation_parser to &ut3_user; diff --git a/source/install.sql b/source/install.sql index d71dcb1d1..2a7ff8343 100644 --- a/source/install.sql +++ b/source/install.sql @@ -111,6 +111,8 @@ alter session set current_schema = &&ut3_owner; --suite builder @@install_component.sql 'core/ut_suite_cache_schema.sql' +@@install_component.sql 'core/ut_suite_cache_package.sql' +@@install_component.sql 'core/ut_suite_cache_seq.sql' @@install_component.sql 'core/ut_suite_cache.sql' @@install_component.sql 'core/ut_suite_cache_manager.pks' @@install_component.sql 'core/ut_suite_cache_manager.pkb' diff --git a/test/core/test_suite_builder.pkb b/test/core/test_suite_builder.pkb index e55830266..423e29c0a 100644 --- a/test/core/test_suite_builder.pkb +++ b/test/core/test_suite_builder.pkb @@ -414,7 +414,7 @@ create or replace package body test_suite_builder is ut.expect(l_actual).to_be_like( '%%some_package%some_test' || '%' || - '%some_packagefirst_bfore_each' || + '%some_packagefirst_before_each' || '%some_packageanother_before_each' || '%' || '%' || From 15163a82f610bd5198ec0541105818501e82c44d Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 4 Nov 2018 19:52:45 +0000 Subject: [PATCH 05/33] Resolved issue with sorting of nested-tables. Added `seq_no`, numbering before storage and sorting after retrieval. --- source/core/types/ut_executable.tps | 4 ++ source/core/ut_suite_builder.pkb | 96 +++++++++++++++++------------ test/api/test_ut_run.pks | 2 - 3 files changed, 59 insertions(+), 43 deletions(-) diff --git a/source/core/types/ut_executable.tps b/source/core/types/ut_executable.tps index 5fa4f3566..8186e4bae 100644 --- a/source/core/types/ut_executable.tps +++ b/source/core/types/ut_executable.tps @@ -25,6 +25,10 @@ create or replace type ut_executable under ut_event_item( error_backtrace varchar2(4000), error_stack varchar2(4000), serveroutput clob, + /** + * Used for ordering of executables, as Oracle doesn not guarantee ordering of items in a nested table. + */ + seq_no integer, constructor function ut_executable( self in out nocopy ut_executable, a_owner varchar2, a_package varchar2, a_procedure_name varchar2, a_executable_type varchar2) return self as result, member function form_name return varchar2, member procedure do_execute(self in out nocopy ut_executable, a_item in out nocopy ut_suite_item), diff --git a/source/core/ut_suite_builder.pkb b/source/core/ut_suite_builder.pkb index cc2b32309..6191bc7e8 100644 --- a/source/core/ut_suite_builder.pkb +++ b/source/core/ut_suite_builder.pkb @@ -65,9 +65,6 @@ create or replace package body ut_suite_builder is type tt_executables is table of ut_executables index by t_annotation_position; - type tt_tests is table of ut_test index by t_annotation_position; - - type t_annotation is record( name t_annotation_name, text t_annotation_text, @@ -315,35 +312,46 @@ create or replace package body ut_suite_builder is end loop; end; - function convert_list( - a_list tt_executables + procedure set_seq_no( + a_list in out nocopy ut_executables + ) is + begin + if a_list is not null then + for i in 1 .. a_list.count loop + a_list(i).seq_no := i; + end loop; + end if; + end; + + function sort_by_seq_no( + a_list ut_executables ) return ut_executables is - l_result ut_executables := ut_executables(); - l_pos t_annotation_position := a_list.first; - begin - while l_pos is not null loop - for i in 1 .. a_list(l_pos).count loop - l_result.extend; - l_result(l_result.last) := a_list(l_pos)(i); - end loop; - l_pos := a_list.next(l_pos); + l_results ut_executables := ut_executables(); + begin + if a_list is not null then + l_results.extend(a_list.count); + for i in 1 .. a_list.count loop + l_results(a_list(i).seq_no) := a_list(i); end loop; - return l_result; - end; + end if; + return l_results; + end; function convert_list( - a_list tt_tests - ) return ut_suite_items is - l_result ut_suite_items := ut_suite_items(); + a_list tt_executables + ) return ut_executables is + l_result ut_executables := ut_executables(); l_pos t_annotation_position := a_list.first; - begin - while l_pos is not null loop + begin + while l_pos is not null loop + for i in 1 .. a_list(l_pos).count loop l_result.extend; - l_result(l_result.last) := a_list(l_pos); - l_pos := a_list.next(l_pos); + l_result(l_result.last) := a_list(l_pos)(i); end loop; - return l_result; - end; + l_pos := a_list.next(l_pos); + end loop; + return l_result; + end; function add_executables( a_owner t_object_name, @@ -492,11 +500,13 @@ create or replace package body ut_suite_builder is l_test.before_test_list := convert_list( add_executables( l_test.object_owner, l_test.object_name, l_proc_annotations( gc_beforetest ), gc_beforetest ) ); + set_seq_no(l_test.before_test_list); end if; if l_proc_annotations.exists( gc_aftertest) then l_test.after_test_list := convert_list( add_executables( l_test.object_owner, l_test.object_name, l_proc_annotations( gc_aftertest ), gc_aftertest ) ); + set_seq_no(l_test.after_test_list); end if; if l_proc_annotations.exists( gc_throws) then add_to_throws_numbers_list(a_suite, l_test.expected_error_codes, a_procedure_name, l_proc_annotations( gc_throws)); @@ -519,8 +529,10 @@ create or replace package body ut_suite_builder is for i in 1 .. a_suite.items.count loop if a_suite.items(i) is of (ut_test) then l_test := treat( a_suite.items(i) as ut_test); - l_test.before_each_list := coalesce(convert_list(a_before_each_list),ut_executables()) multiset union all l_test.before_each_list; - l_test.after_each_list := l_test.after_each_list multiset union all coalesce(convert_list(a_after_each_list),ut_executables()); + l_test.before_each_list := convert_list(a_before_each_list) multiset union all l_test.before_each_list; + set_seq_no(l_test.before_each_list); + l_test.after_each_list := l_test.after_each_list multiset union all convert_list(a_after_each_list); + set_seq_no(l_test.after_each_list); a_suite.items(i) := l_test; elsif a_suite.items(i) is of (ut_logical_suite) then l_context := treat(a_suite.items(i) as ut_logical_suite); @@ -543,8 +555,10 @@ create or replace package body ut_suite_builder is for i in 1 .. a_suite_items.count loop if a_suite_items(i) is of (ut_test) then l_test := treat( a_suite_items(i) as ut_test); - l_test.before_each_list := coalesce(convert_list(a_before_each_list),ut_executables()) multiset union all l_test.before_each_list; - l_test.after_each_list := l_test.after_each_list multiset union all coalesce(convert_list(a_after_each_list),ut_executables()); + l_test.before_each_list := convert_list(a_before_each_list) multiset union all l_test.before_each_list; + set_seq_no(l_test.before_each_list); + l_test.after_each_list := l_test.after_each_list multiset union all convert_list(a_after_each_list); + set_seq_no(l_test.after_each_list); a_suite_items(i) := l_test; elsif a_suite_items(i) is of (ut_logical_suite) then l_context := treat(a_suite_items(i) as ut_logical_suite); @@ -580,8 +594,6 @@ create or replace package body ut_suite_builder is a_after_all_list in out nocopy tt_executables ) is l_procedure_name t_object_name; - l_tests tt_tests; - begin l_procedure_name := a_proc_annotations.by_proc.first; while l_procedure_name is not null loop @@ -679,7 +691,9 @@ create or replace package body ut_suite_builder is a_suite.set_rollback_type(l_rollback_type); propagate_before_after_each( a_suite_items, l_before_each_list, l_after_each_list); a_suite.before_all_list := convert_list(l_before_all_list); + set_seq_no(a_suite.before_all_list); a_suite.after_all_list := convert_list(l_after_all_list); + set_seq_no(a_suite.after_all_list); end; function get_endcontext_position( @@ -943,9 +957,9 @@ create or replace package body ut_suite_builder is line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - before_each_list => l_rows(i).before_each_list, before_test_list => l_rows(i).before_test_list, + before_each_list => sort_by_seq_no(l_rows(i).before_each_list), before_test_list => sort_by_seq_no(l_rows(i).before_test_list), item => l_rows(i).item, - after_test_list => l_rows(i).after_test_list, after_each_list => l_rows(i).after_each_list, + after_test_list => sort_by_seq_no(l_rows(i).after_test_list), after_each_list => sort_by_seq_no(l_rows(i).after_each_list), all_expectations => ut_expectation_results(), failed_expectations => ut_expectation_results(), parent_error_stack_trace => null, expected_error_codes => l_rows(i).expected_error_codes ); @@ -960,7 +974,7 @@ create or replace package body ut_suite_builder is start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), items => ut_suite_items(), - before_all_list => l_rows(i).before_all_list, after_all_list => l_rows(i).after_all_list + before_all_list => sort_by_seq_no(l_rows(i).before_all_list), after_all_list => sort_by_seq_no(l_rows(i).after_all_list) ); when 'UT_SUITE_CONTEXT' then l_logical_suites(i) := @@ -973,7 +987,7 @@ create or replace package body ut_suite_builder is start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), items => ut_suite_items(), - before_all_list => l_rows(i).before_all_list, after_all_list => l_rows(i).after_all_list + before_all_list => sort_by_seq_no(l_rows(i).before_all_list), after_all_list => sort_by_seq_no(l_rows(i).after_all_list) ); when 'UT_LOGICAL_SUITE' then l_logical_suites(i) := @@ -1054,7 +1068,7 @@ create or replace package body ut_suite_builder is suite_items as ( select c.* from ]'||l_ut_owner||q'[.ut_suite_cache c - where 1 = 1 ]'||case when not a_skip_all_objects /*1 = 0*/ then q'[ + where 1 = 1 ]'||case when not a_skip_all_objects then q'[ and exists ( select 1 from all_objects a @@ -1226,11 +1240,11 @@ create or replace package body ut_suite_builder is from '||l_ut_owner||q'[.ut_suite_cache_package c join table ( :a_schema_names ) s on c.object_owner = upper(s.column_value) --- where exists --- (select 1 from all_objects a --- where a.owner = c.object_owner --- and a.object_name = c.object_name --- and a.object_type = 'PACKAGE') + where exists + (select 1 from all_objects a + where a.owner = c.object_owner + and a.object_name = c.object_name + and a.object_type = 'PACKAGE') ]' bulk collect into l_schema_names, l_object_names using a_schema_names; l_results.extend( l_schema_names.count ); diff --git a/test/api/test_ut_run.pks b/test/api/test_ut_run.pks index cfc06c80d..927abf6e2 100644 --- a/test/api/test_ut_run.pks +++ b/test/api/test_ut_run.pks @@ -24,7 +24,6 @@ create or replace package test_ut_run is --%test(Runs all tests in current schema with coverage file list) procedure run_proc_cov_file_list; - --%disabled(TODO - currently it executes the package and all child packages) --%test(Runs given package only with package name given as path) procedure run_proc_pkg_name; --%test(Runs all from given package with package name given as path and coverage file list) @@ -57,7 +56,6 @@ create or replace package test_ut_run is --%test(Runs all tests in current schema with coverage file list) procedure run_func_cov_file_list; - --%disabled(TODO - currently it executes the package and all child packages) --%test(Runs given package only with package name given as path) procedure run_func_pkg_name; --%test(Runs all from given package with package name given as path and coverage file list) From 1b14bb5a0909a9a74c153d7d7d0969b3b1b7db2c Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 4 Nov 2018 19:55:37 +0000 Subject: [PATCH 06/33] Fixing re-enabled test. --- test/api/test_ut_run.pkb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/test_ut_run.pkb b/test/api/test_ut_run.pkb index dae7e175a..9709058d4 100644 --- a/test/api/test_ut_run.pkb +++ b/test/api/test_ut_run.pkb @@ -391,7 +391,7 @@ create or replace package body test_ut_run is execute immediate 'begin :l_results := ut3$user#.test_package_1.run(:a_path); end;' using out l_results, in 'test_package_1'; --Assert - ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%test_package_bal%' ); + ut.expect( ut3.ut_utils.table_to_clob(l_results) ).to_be_like( '%test_package_1%' ); ut.expect( ut3.ut_utils.table_to_clob(l_results) ).not_to_be_like( '%test_package_2%' ); ut.expect( ut3.ut_utils.table_to_clob(l_results) ).not_to_be_like( '%test_package_3%' ); end; From 3bc8da55d8b7ef6bb8da56c4c1b3121c7126f90a Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 4 Nov 2018 20:43:25 +0000 Subject: [PATCH 07/33] Adding missing items to uninstall. --- source/uninstall_objects.sql | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/uninstall_objects.sql b/source/uninstall_objects.sql index 754a16a34..119695b6d 100644 --- a/source/uninstall_objects.sql +++ b/source/uninstall_objects.sql @@ -57,6 +57,10 @@ drop package ut_suite_builder; drop table ut_suite_cache; +drop sequence ut_suite_cache_seq; + +drop table ut_suite_cache_package; + drop table ut_suite_cache_schema; drop package ut; From 8911f974e6d832f90cb0213f93df88ba53636f3a Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Mon, 5 Nov 2018 23:25:28 +0000 Subject: [PATCH 08/33] Small improvements and cleanup. --- .../annotations/ut_annotation_manager.pkb | 61 ++--- source/core/types/ut_logical_suites.tps | 19 -- source/core/ut_suite_builder.pkb | 219 ++++++++---------- source/install.sql | 1 - 4 files changed, 126 insertions(+), 174 deletions(-) delete mode 100644 source/core/types/ut_logical_suites.tps diff --git a/source/core/annotations/ut_annotation_manager.pkb b/source/core/annotations/ut_annotation_manager.pkb index afa66b2e4..12eac0190 100644 --- a/source/core/annotations/ut_annotation_manager.pkb +++ b/source/core/annotations/ut_annotation_manager.pkb @@ -58,17 +58,18 @@ create or replace package body ut_annotation_manager as begin open l_result for q'[select s.name, s.text - from ]'||l_sources_view||q'[ s - where s.type = :a_object_type - and s.owner = :a_object_owner - and s.name - in (select x.name - from ]'||l_sources_view||q'[ x - where x.type = :a_object_type - and x.owner = :a_object_owner - and x.text like '%--%\%%' escape '\' - ) - order by name, line]' + from (select s.name, s.text, s.line, + max(case when s.text like '%--%\%%' escape '\' + and regexp_like(s.text,'--\s*%') + then 'Y' else 'N' end + ) + over(partition by s.name) is_annotated + from ]'||l_sources_view||q'[ s + where s.type = :a_object_type + and s.owner = :a_object_owner + ) s + where s.is_annotated = 'Y' + order by s.name, s.line]' using a_object_type, a_object_owner, a_object_type, a_object_owner; return l_result; @@ -81,25 +82,25 @@ 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 /*+ cardinality( r ]'||l_card||q'[ )*/ - s.name, s.text - from table(:a_objects_to_refresh) r - join ]'||l_sources_view||q'[ s - on s.name = r.object_name - where s.type = :a_object_type - and s.owner = :a_object_owner - and s.name - in (select /*+ cardinality( t ]'||l_card||q'[ )*/ - x.name - from table(:a_objects_to_refresh) t - join ]'||l_sources_view||q'[ x - on x.name = t.object_name - where x.type = :a_object_type - and x.owner = :a_object_owner - and x.text like '%--%\%%' escape '\' - ) - order by name, line]' - using a_objects_to_refresh, a_object_type, a_object_owner, a_objects_to_refresh, a_object_type, a_object_owner; + q'[select s.name, s.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*%') + 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 + and s.owner = r.object_owner + and s.type = r.object_type + where s.type = :a_object_type + and s.owner = :a_object_owner + ) s + where s.is_annotated = 'Y' + order by s.name, s.line]' + using a_objects_to_refresh, a_object_type, a_object_owner; return l_result; end; diff --git a/source/core/types/ut_logical_suites.tps b/source/core/types/ut_logical_suites.tps deleted file mode 100644 index 560f245d0..000000000 --- a/source/core/types/ut_logical_suites.tps +++ /dev/null @@ -1,19 +0,0 @@ -create or replace type ut_logical_suites as - /* - utPLSQL - Version 3 - Copyright 2016 - 2018 utPLSQL Project - - Licensed under the Apache License, Version 2.0 (the "License"): - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - table of ut_logical_suite -/ diff --git a/source/core/ut_suite_builder.pkb b/source/core/ut_suite_builder.pkb index 6191bc7e8..f63088811 100644 --- a/source/core/ut_suite_builder.pkb +++ b/source/core/ut_suite_builder.pkb @@ -517,32 +517,6 @@ create or replace package body ut_suite_builder is a_suite_items( a_suite_items.last ) := l_test; end; - procedure propagate_before_after_each( - a_suite in out nocopy ut_logical_suite, - a_before_each_list tt_executables, - a_after_each_list tt_executables - ) is - l_test ut_test; - l_context ut_logical_suite; - begin - if a_suite.items is not null then - for i in 1 .. a_suite.items.count loop - if a_suite.items(i) is of (ut_test) then - l_test := treat( a_suite.items(i) as ut_test); - l_test.before_each_list := convert_list(a_before_each_list) multiset union all l_test.before_each_list; - set_seq_no(l_test.before_each_list); - l_test.after_each_list := l_test.after_each_list multiset union all convert_list(a_after_each_list); - set_seq_no(l_test.after_each_list); - a_suite.items(i) := l_test; - elsif a_suite.items(i) is of (ut_logical_suite) then - l_context := treat(a_suite.items(i) as ut_logical_suite); - propagate_before_after_each( l_context, a_before_each_list, a_after_each_list); - a_suite.items(i) := l_context; - end if; - end loop; - end if; - end; - procedure propagate_before_after_each( a_suite_items in out nocopy ut_suite_items, a_before_each_list tt_executables, @@ -929,113 +903,110 @@ create or replace package body ut_suite_builder is a_suite_data_cursor sys_refcursor ) is type t_item_levels is table of ut_suite_items index by binary_integer; + c_bulk_limit constant pls_integer := 1000; l_items_at_level t_item_levels; l_rows tt_cached_suites; - l_tests ut_suite_items := ut_suite_items(); - l_logical_suites ut_logical_suites := ut_logical_suites(); + l_test ut_test; + l_logical_suite ut_logical_suite; l_level pls_integer; l_prev_level pls_integer; l_idx integer; begin a_suites := ut_suite_items(); loop - if l_idx is null then - fetch a_suite_data_cursor bulk collect into l_rows limit 1000; - l_tests.delete; - l_tests.extend(l_rows.count); - l_logical_suites.delete; - l_logical_suites.extend(l_rows.count); - for i in 1 .. l_rows.count loop - case l_rows(i).self_type - when 'UT_TEST' then - l_tests(i) := - ut_test( - self_type => l_rows(i).self_type, - object_owner => l_rows(i).object_owner, object_name => lower(l_rows(i).object_name), - name => lower(l_rows(i).name), description => l_rows(i).description, path => l_rows(i).path, - rollback_type => l_rows(i).rollback_type, disabled_flag => l_rows(i).disabled_flag, - line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - before_each_list => sort_by_seq_no(l_rows(i).before_each_list), before_test_list => sort_by_seq_no(l_rows(i).before_test_list), - item => l_rows(i).item, - after_test_list => sort_by_seq_no(l_rows(i).after_test_list), after_each_list => sort_by_seq_no(l_rows(i).after_each_list), - all_expectations => ut_expectation_results(), failed_expectations => ut_expectation_results(), - parent_error_stack_trace => null, expected_error_codes => l_rows(i).expected_error_codes - ); - when 'UT_SUITE' then - l_logical_suites(i) := - ut_suite( - self_type => l_rows(i).self_type, - object_owner => l_rows(i).object_owner, object_name => lower(l_rows(i).object_name), - name => lower(l_rows(i).name), description => l_rows(i).description, path => l_rows(i).path, - rollback_type => l_rows(i).rollback_type, disabled_flag => l_rows(i).disabled_flag, - line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => ut_suite_items(), - before_all_list => sort_by_seq_no(l_rows(i).before_all_list), after_all_list => sort_by_seq_no(l_rows(i).after_all_list) - ); - when 'UT_SUITE_CONTEXT' then - l_logical_suites(i) := - ut_suite_context( - self_type => l_rows(i).self_type, - object_owner => l_rows(i).object_owner, object_name => lower(l_rows(i).object_name), - name => lower(l_rows(i).name), description => l_rows(i).description, path => l_rows(i).path, - rollback_type => l_rows(i).rollback_type, disabled_flag => l_rows(i).disabled_flag, - line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => ut_suite_items(), - before_all_list => sort_by_seq_no(l_rows(i).before_all_list), after_all_list => sort_by_seq_no(l_rows(i).after_all_list) - ); - when 'UT_LOGICAL_SUITE' then - l_logical_suites(i) := - ut_logical_suite( - self_type => l_rows(i).self_type, - object_owner => l_rows(i).object_owner, object_name => lower(l_rows(i).object_name), - name => lower(l_rows(i).name), description => l_rows(i).description, path => l_rows(i).path, - rollback_type => l_rows(i).rollback_type, disabled_flag => l_rows(i).disabled_flag, - line_no => l_rows(i).line_no, parse_time => l_rows(i).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(i).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => ut_suite_items() - ); - end case; - end loop; - l_idx := l_rows.first; - end if; - exit when l_idx is null; - l_level := length(l_rows(l_idx).path) - length( replace(l_rows(l_idx).path, '.') ) + 1; + fetch a_suite_data_cursor bulk collect into l_rows limit c_bulk_limit; + exit when l_rows.count = 0; - if l_level > 1 then - if l_prev_level > l_level then - l_logical_suites(l_idx).items := l_items_at_level(l_prev_level); - l_items_at_level(l_prev_level).delete; - end if; - if not l_items_at_level.exists(l_level) then - l_items_at_level(l_level) := ut_suite_items(); - end if; - l_items_at_level(l_level).extend; - if l_tests(l_idx) is not null then - l_items_at_level(l_level)(l_items_at_level(l_level).last) := l_tests(l_idx); - else - l_items_at_level(l_level)(l_items_at_level(l_level).last) := l_logical_suites(l_idx); - end if; - else - if l_prev_level > l_level then - l_logical_suites(l_idx).items := l_items_at_level(l_prev_level); - l_items_at_level(l_prev_level).delete; - end if; - a_suites.extend; - if l_tests(l_idx) is not null then - a_suites(a_suites.last) := l_tests(l_idx); + l_idx := l_rows.first; + loop + l_test := null; + l_logical_suite := null; + case l_rows(l_idx).self_type + when 'UT_TEST' then + l_test := + ut_test( + self_type => l_rows(l_idx).self_type, + object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), + name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, + rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, + line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + before_each_list => sort_by_seq_no(l_rows(l_idx).before_each_list), before_test_list => sort_by_seq_no(l_rows(l_idx).before_test_list), + item => l_rows(l_idx).item, + after_test_list => sort_by_seq_no(l_rows(l_idx).after_test_list), after_each_list => sort_by_seq_no(l_rows(l_idx).after_each_list), + all_expectations => ut_expectation_results(), failed_expectations => ut_expectation_results(), + parent_error_stack_trace => null, expected_error_codes => l_rows(l_idx).expected_error_codes + ); + when 'UT_SUITE' then + l_logical_suite := + ut_suite( + self_type => l_rows(l_idx).self_type, + object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), + name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, + rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, + line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items(), + before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) + ); + when 'UT_SUITE_CONTEXT' then + l_logical_suite := + ut_suite_context( + self_type => l_rows(l_idx).self_type, + object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), + name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, + rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, + line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items(), + before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) + ); + when 'UT_LOGICAL_SUITE' then + l_logical_suite := + ut_logical_suite( + self_type => l_rows(l_idx).self_type, + object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), + name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, + rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, + line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items() + ); + end case; + + l_level := length(l_rows(l_idx).path) - length( replace(l_rows(l_idx).path, '.') ) + 1; + + if l_level > 1 then + if l_prev_level > l_level then + l_logical_suite.items := l_items_at_level(l_prev_level); + l_items_at_level(l_prev_level).delete; + end if; + if not l_items_at_level.exists(l_level) then + l_items_at_level(l_level) := ut_suite_items(); + end if; + l_items_at_level(l_level).extend; + if l_test is not null then + l_items_at_level(l_level)(l_items_at_level(l_level).last) := l_test; + else + l_items_at_level(l_level)(l_items_at_level(l_level).last) := l_logical_suite; + end if; else - a_suites(a_suites.last) := l_logical_suites(l_idx); + if l_prev_level > l_level then + l_logical_suite.items := l_items_at_level(l_prev_level); + l_items_at_level(l_prev_level).delete; + end if; + a_suites.extend; + a_suites(a_suites.last) := l_logical_suite; end if; - end if; - l_prev_level := l_level; - l_idx := l_rows.next(l_idx); + l_prev_level := l_level; + l_idx := l_rows.next(l_idx); + exit when l_idx is null; + end loop; + exit when l_rows.count < c_bulk_limit; end loop; copy_list_reverse_order( a_suites ); close a_suite_data_cursor; @@ -1066,7 +1037,7 @@ create or replace package body ut_suite_builder is open l_result for q'[with suite_items as ( - select c.* + select /*+ cardinality(c 100) */ c.* from ]'||l_ut_owner||q'[.ut_suite_cache c where 1 = 1 ]'||case when not a_skip_all_objects then q'[ and exists @@ -1093,7 +1064,7 @@ create or replace package body ut_suite_builder is ), gen as ( select rownum as pos - from xmltable('1 to 100') + from xmltable('1 to 20') ), suitepaths as ( select distinct substr(path,1,instr(path,'.',-1)-1) as suitepath, diff --git a/source/install.sql b/source/install.sql index 2a7ff8343..31b91a941 100644 --- a/source/install.sql +++ b/source/install.sql @@ -70,7 +70,6 @@ alter session set current_schema = &&ut3_owner; @@install_component.sql 'core/types/ut_executable_test.tps' @@install_component.sql 'core/types/ut_test.tps' @@install_component.sql 'core/types/ut_logical_suite.tps' -@@install_component.sql 'core/types/ut_logical_suites.tps' @@install_component.sql 'core/types/ut_suite.tps' @@install_component.sql 'core/types/ut_suite_context.tps' @@install_component.sql 'core/types/ut_file_mapping.tps' From a1f6b3499cc048d6ea4887546097c0e884845cd7 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Tue, 6 Nov 2018 00:33:39 +0000 Subject: [PATCH 09/33] Removing duplicate with block. --- source/core/ut_suite_builder.pkb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/source/core/ut_suite_builder.pkb b/source/core/ut_suite_builder.pkb index f63088811..f6aceae89 100644 --- a/source/core/ut_suite_builder.pkb +++ b/source/core/ut_suite_builder.pkb @@ -1062,10 +1062,6 @@ create or replace package body ut_suite_builder is ) ) ), - gen as ( - select rownum as pos - from xmltable('1 to 20') - ), suitepaths as ( select distinct substr(path,1,instr(path,'.',-1)-1) as suitepath, path, @@ -1075,7 +1071,7 @@ create or replace package body ut_suite_builder is ), gen as ( select rownum as pos - from xmltable('1 to 10') + from xmltable('1 to 20') ), suitepath_part AS ( select distinct From 59f773835e44baf785079d837985d22eebb2013b Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 11 Nov 2018 12:04:04 +0000 Subject: [PATCH 10/33] Adding cache cleanup and "intelligent" join to all_source, only when needed. --- .../ut_annotation_cache_manager.pkb | 17 ++- .../ut_annotation_cache_manager.pks | 9 +- .../annotations/ut_annotation_manager.pkb | 101 ++++++++++++++---- source/core/ut_metadata.pkb | 27 ++++- source/core/ut_metadata.pks | 12 +++ source/core/ut_suite_builder.pkb | 57 +++++++++- source/core/ut_suite_cache_manager.pkb | 12 +++ source/core/ut_suite_cache_manager.pks | 2 + .../annotations/test_annotation_manager.pkb | 54 +++++++++- .../annotations/test_annotation_manager.pks | 13 ++- 10 files changed, 268 insertions(+), 36 deletions(-) diff --git a/source/core/annotations/ut_annotation_cache_manager.pkb b/source/core/annotations/ut_annotation_cache_manager.pkb index 9d7d1b95e..4f9129650 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pkb +++ b/source/core/annotations/ut_annotation_cache_manager.pkb @@ -74,6 +74,21 @@ create or replace package body ut_annotation_cache_manager as commit; end; + procedure remove_from_cache(a_objects ut_annotation_objs_cache_info) is + pragma autonomous_transaction; + begin + + delete from ut_annotation_cache_info i + where exists ( + select 1 from table (a_objects) o + where o.object_name = i.object_name + and o.object_type = i.object_type + and o.object_owner = i.object_owner + ); + + 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; begin @@ -92,7 +107,7 @@ create or replace package body ut_annotation_cache_manager as 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 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'[ + 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; return l_results; diff --git a/source/core/annotations/ut_annotation_cache_manager.pks b/source/core/annotations/ut_annotation_cache_manager.pks index 2ee586d12..1279c8cc3 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pks +++ b/source/core/annotations/ut_annotation_cache_manager.pks @@ -37,10 +37,17 @@ create or replace package ut_annotation_cache_manager authid definer as /** * Removes 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 from cache + * @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); + /** + * Removes information about objects on the list + * + * @param a_objects a `ut_annotation_objs_cache_info` list with information about objects to remove from cache + */ + procedure remove_from_cache(a_objects ut_annotation_objs_cache_info); + /** * Removes cached information about annotations for objects of specified type and specified owner * diff --git a/source/core/annotations/ut_annotation_manager.pkb b/source/core/annotations/ut_annotation_manager.pkb index 12eac0190..3559982cf 100644 --- a/source/core/annotations/ut_annotation_manager.pkb +++ b/source/core/annotations/ut_annotation_manager.pkb @@ -19,6 +19,38 @@ 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_dba_view('dba_objects'); +-- l_cursor_text varchar2(32767); +-- l_result ut_annotation_objs_cache_info; +-- begin +-- l_cursor_text := +-- q'[select ]'||l_ut_owner||q'[.ut_annotation_obj_cache_info( +-- object_owner => i.object_owner, +-- object_name => i.object_name, +-- object_type => i.object_type, +-- needs_refresh => null +-- ) +-- from ]'||l_ut_owner||q'[.ut_annotation_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 = :a_object_owner +-- and o.object_type = :a_object_type +-- ) +-- and i.object_owner = :a_object_owner +-- and i.object_type = :a_object_type]'; +-- open l_rows for l_cursor_text using a_object_owner, a_object_type, a_object_owner, a_object_type; +-- fetch l_rows bulk collect into l_result limit 1000000; +-- close l_rows; +-- return l_result; +-- end; + function get_annotation_objs_info(a_object_owner varchar2, a_object_type varchar2, a_parse_date timestamp := null) return ut_annotation_objs_cache_info is l_rows sys_refcursor; l_ut_owner varchar2(250) := ut_utils.ut_owner; @@ -28,25 +60,36 @@ create or replace package body ut_annotation_manager as begin l_cursor_text := q'[select ]'||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 + object_owner => nvl( o.owner, i.object_owner ), + object_name => nvl( o.object_name, i.object_name ), + object_type => nvl( o.object_type, i.object_type ), + needs_refresh => + case + when o.last_ddl_time < cast(i.parse_time as date) then 'N' + when o.owner is null then null + else 'Y' + end ) - from ]'||l_objects_view||q'[ o - left join ]'||l_ut_owner||q'[.ut_annotation_cache_info i + from ( + select * from ]'||l_objects_view||q'[ o + where o.owner = :a_object_owner + and o.object_type = :a_object_type + ) o + full outer join ( + select * from ]'||l_ut_owner||q'[.ut_annotation_cache_info i + where i.object_owner = :a_object_owner + and i.object_type = :a_object_type + ) i on o.owner = i.object_owner and o.object_name = i.object_name and o.object_type = i.object_type - where o.owner = :a_object_owner - and o.object_type = :a_object_type - and ]' + where ]' || case when a_parse_date is null then ':a_parse_date is null' - else 'o.last_ddl_time >= cast(:a_parse_date as date)' + else 'o.last_ddl_time >= cast(:a_parse_date as date) or o.last_ddl_time is null' end; - open l_rows for l_cursor_text using a_object_owner, a_object_type, a_parse_date; + open l_rows for l_cursor_text using a_object_owner, a_object_type, a_object_owner, a_object_type, a_parse_date; fetch l_rows bulk collect into l_result limit 1000000; close l_rows; return l_result; @@ -106,8 +149,9 @@ create or replace package body ut_annotation_manager as end; procedure build_annot_cache_for_sources( - a_object_owner varchar2, a_object_type varchar2, a_sources_cursor sys_refcursor, - a_schema_objects ut_annotation_objs_cache_info + a_object_owner varchar2, + a_object_type varchar2, + a_sources_cursor sys_refcursor ) is l_annotations ut_annotations; c_lines_fetch_limit constant integer := 1000; @@ -118,7 +162,6 @@ create or replace package body ut_annotation_manager as l_parse_time date := sysdate; pragma autonomous_transaction; begin - ut_annotation_cache_manager.cleanup_cache(a_schema_objects); loop fetch a_sources_cursor bulk collect into l_names, l_lines limit c_lines_fetch_limit; for i in 1 .. l_names.count loop @@ -148,17 +191,37 @@ create or replace package body ut_annotation_manager as end; - procedure rebuild_annotation_cache( a_object_owner varchar2, a_object_type varchar2, a_info_rows ut_annotation_objs_cache_info) is - l_objects_to_parse ut_annotation_objs_cache_info := ut_annotation_objs_cache_info(); + procedure rebuild_annotation_cache( + a_object_owner varchar2, + a_object_type varchar2, + a_info_rows ut_annotation_objs_cache_info + ) is + l_objects_to_parse ut_annotation_objs_cache_info; + l_objects_to_remove ut_annotation_objs_cache_info; begin - select value(x)bulk collect into l_objects_to_parse from table(a_info_rows) x where x.needs_refresh = 'Y'; + select value(x)bulk collect into l_objects_to_parse + from table(a_info_rows) x where x.needs_refresh = 'Y'; + + ut_annotation_cache_manager.cleanup_cache(l_objects_to_parse); + + if sys_context('userenv','current_schema') = a_object_owner + or ut_metadata.is_object_visible('ut3.ut_utils') + or ut_metadata.is_object_visible('dba_objects') + then + select value(x)bulk collect into l_objects_to_remove + from table(a_info_rows) x where x.needs_refresh is null; + + ut_annotation_cache_manager.remove_from_cache(l_objects_to_remove); +-- ut_annotation_cache_manager.remove_from_cache( +-- get_missing_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 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), - l_objects_to_parse + get_sources_to_annotate(a_object_owner, a_object_type, l_objects_to_parse) ); end if; end; diff --git a/source/core/ut_metadata.pkb b/source/core/ut_metadata.pkb index 30b0da64e..1693066ec 100644 --- a/source/core/ut_metadata.pkb +++ b/source/core/ut_metadata.pkb @@ -148,15 +148,34 @@ create or replace package body ut_metadata as end; function get_dba_view(a_dba_view_name varchar2) return varchar2 is - l_invalid_object_name exception; l_result varchar2(128) := lower(a_dba_view_name); + begin + if not is_object_visible(a_dba_view_name) then + l_result := replace(l_result,'dba_','all_'); + end if; + return l_result; + end; + + function user_has_execute_any_proc return boolean is + l_ut_owner varchar2(250) := ut_utils.ut_owner; + l_dummy varchar2(250); + begin + execute immediate 'select '||l_ut_owner||'.ut_utils.ut_owner from dual' + into l_dummy; + return true; + exception + when others then + return false; + end; + + function is_object_visible(a_object_name varchar2) return boolean is + l_invalid_object_name exception; pragma exception_init(l_invalid_object_name,-44002); begin - l_result := dbms_assert.sql_object_name(l_result); - return l_result; + return dbms_assert.sql_object_name(a_object_name) is not null; exception when l_invalid_object_name then - return replace(l_result,'dba_','all_'); + return false; end; function package_exists_in_cur_schema(a_object_name varchar2) return boolean is diff --git a/source/core/ut_metadata.pks b/source/core/ut_metadata.pks index 121524a0b..d06c1ea9d 100644 --- a/source/core/ut_metadata.pks +++ b/source/core/ut_metadata.pks @@ -69,6 +69,18 @@ create or replace package ut_metadata authid current_user as */ function get_dba_view(a_dba_view_name varchar2) return varchar2; + /** + * Returns true if object is accessible to current user + * @param a_object_name fully qualified object name (with schema name) + */ + function is_object_visible(a_object_name varchar2) return boolean; + + /** + * Returns true if current user has execute any procedure privilege + * The check is performed by checking if user can execute ut_utils package + */ + function user_has_execute_any_proc return boolean; + /** * Returns true if given object is a package and it exists in current schema * @param a_object_name the name of the object to be checked diff --git a/source/core/ut_suite_builder.pkb b/source/core/ut_suite_builder.pkb index f6aceae89..4638f5dba 100644 --- a/source/core/ut_suite_builder.pkb +++ b/source/core/ut_suite_builder.pkb @@ -1012,6 +1012,31 @@ create or replace package body ut_suite_builder is close a_suite_data_cursor; end; + function get_missing_objects(a_object_owner varchar2) return ut_varchar2_rows is + l_rows sys_refcursor; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + l_objects_view varchar2(200) := ut_metadata.get_dba_view('dba_objects'); + l_cursor_text varchar2(32767); + l_result ut_varchar2_rows; + begin + l_cursor_text := + q'[select i.object_name + from ]'||l_ut_owner||q'[.ut_suite_cache_package 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 = 'PACKAGE' + and o.owner = :a_object_owner + ) + and i.object_owner = :a_object_owner]'; + open l_rows for l_cursor_text using a_object_owner, a_object_owner; + fetch l_rows bulk collect into l_result limit 1000000; + close l_rows; + return l_result; + end; + function get_cached_suite_data( a_object_owner varchar2, a_path varchar2 := null, @@ -1177,8 +1202,9 @@ create or replace package body ut_suite_builder is a_object_name varchar2 := null, a_procedure_name varchar2 := null ) return ut_suite_items is - l_annotations_cursor sys_refcursor; - l_suite_cache_time timestamp; + l_annotations_cursor sys_refcursor; + l_suite_cache_time timestamp; + l_skip_all_objects_scan boolean := false; begin l_suite_cache_time := ut_suite_cache_manager.get_schema_parse_time(a_owner_name); open l_annotations_cursor for @@ -1188,12 +1214,23 @@ create or replace package body ut_suite_builder is )x ]' using a_owner_name, l_suite_cache_time; + -- if current user is the onwer or current user has execute any procedure privilege + if sys_context('userenv','current_schema') = a_owner_name + or ut_metadata.is_object_visible('ut3.ut_utils') + then + l_skip_all_objects_scan := true; + end if; + if l_skip_all_objects_scan or ut_metadata.is_object_visible('dba_objects') then + ut_suite_cache_manager.remove_from_cache( a_owner_name, get_missing_objects(a_owner_name) ); + end if; + return build_suites_from_annotations( a_owner_name, l_annotations_cursor, a_path, a_object_name, - a_procedure_name + a_procedure_name, + l_skip_all_objects_scan ); end; @@ -1202,17 +1239,27 @@ create or replace package body ut_suite_builder is l_schema_names ut_varchar2_rows; l_object_names ut_varchar2_rows; l_ut_owner varchar2(250) := ut_utils.ut_owner; + l_need_all_objects_scan boolean := true; begin + -- if current user is the onwer or current user has execute any procedure privilege + if ut_metadata.is_object_visible('ut3.ut_utils') + or (a_schema_names is not null and a_schema_names.count = 1 + and sys_context('userenv','current_schema') = a_schema_names(1)) + then + l_need_all_objects_scan := false; + end if; + execute immediate 'select c.object_owner, c.object_name from '||l_ut_owner||q'[.ut_suite_cache_package c join table ( :a_schema_names ) s - on c.object_owner = upper(s.column_value) + on c.object_owner = upper(s.column_value)]' + || case when l_need_all_objects_scan then q'[ where exists (select 1 from all_objects a where a.owner = c.object_owner and a.object_name = c.object_name and a.object_type = 'PACKAGE') - ]' + ]' end bulk collect into l_schema_names, l_object_names using a_schema_names; l_results.extend( l_schema_names.count ); for i in 1 .. l_schema_names.count loop diff --git a/source/core/ut_suite_cache_manager.pkb b/source/core/ut_suite_cache_manager.pkb index 9caf8a946..081b2d590 100644 --- a/source/core/ut_suite_cache_manager.pkb +++ b/source/core/ut_suite_cache_manager.pkb @@ -135,5 +135,17 @@ create or replace package body ut_suite_cache_manager is commit; end; + procedure remove_from_cache(a_schema_name varchar2, a_objects ut_varchar2_rows) is + pragma autonomous_transaction; + begin + delete + from ut_suite_cache_package i + where i.object_owner = a_schema_name + and i.object_name in ( select column_value from table (a_objects) ); + + commit; + end; + + end ut_suite_cache_manager; / diff --git a/source/core/ut_suite_cache_manager.pks b/source/core/ut_suite_cache_manager.pks index 3d5a21f10..02c47988e 100644 --- a/source/core/ut_suite_cache_manager.pks +++ b/source/core/ut_suite_cache_manager.pks @@ -29,5 +29,7 @@ create or replace package ut_suite_cache_manager authid definer is function get_schema_parse_time(a_schema_name varchar2) return timestamp result_cache; + procedure remove_from_cache(a_schema_name varchar2, a_objects ut_varchar2_rows); + end ut_suite_cache_manager; / diff --git a/test/core/annotations/test_annotation_manager.pkb b/test/core/annotations/test_annotation_manager.pkb index 98bea7452..1fb8115ba 100644 --- a/test/core/annotations/test_annotation_manager.pkb +++ b/test/core/annotations/test_annotation_manager.pkb @@ -31,6 +31,7 @@ create or replace package body test_annotation_manager is --%beforetest(some_procedure) procedure some_dummy_test_procedure; end;]'; + execute immediate q'[grant execute on dummy_test_package to public]'; end; procedure modify_dummy_test_package is @@ -56,6 +57,28 @@ create or replace package body test_annotation_manager is execute immediate q'[alter package dummy_test_package compile]'; end; + procedure create_parse_proc_as_ut3$user# is + pragma autonomous_transaction; + begin + execute immediate q'[ + create or replace procedure ut3$user#.parse_annotations is + begin + ut3.ut_annotation_manager.rebuild_annotation_cache('UT3_TESTER','PACKAGE'); + end;]'; + end; + + procedure parse_dummy_test_as_ut3$user# is + pragma autonomous_transaction; + begin + execute immediate 'begin ut3$user#.parse_annotations; end;'; + end; + + procedure drop_parse_proc_as_ut3$user# is + pragma autonomous_transaction; + begin + execute immediate 'drop procedure ut3$user#.parse_annotations'; + end; + procedure cleanup_annotation_cache is pragma autonomous_transaction; begin @@ -204,12 +227,11 @@ create or replace package body test_annotation_manager is l_expected sys_refcursor; l_start_date date; begin - --Arrange - ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); + parse_dummy_test_as_ut3$user#(); l_start_date := sysdate; drop_dummy_test_package(); --Act - ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); + parse_dummy_test_as_ut3$user#(); --Assert select max(cache_id) into l_actual_cache_id @@ -217,7 +239,7 @@ create or replace package body test_annotation_manager is where object_owner = user and object_type = 'PACKAGE' and object_name = 'DUMMY_TEST_PACKAGE' and parse_time >= l_start_date; - ut.expect(l_actual_cache_id).to_be_not_null; + ut.expect(l_actual_cache_id).not_to_be_null(); open l_actual for select annotation_position, annotation_name, annotation_text, subobject_name @@ -252,5 +274,29 @@ create or replace package body test_annotation_manager is ut.expect(l_actual).to_be_empty(); end; + 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(user,'PACKAGE'); + l_start_date := sysdate; + drop_dummy_test_package(); + --Act + ut3.ut_annotation_manager.rebuild_annotation_cache(user,'PACKAGE'); + --Assert + select count(1) + into l_cache_count + from ut3.ut_annotation_cache_info + where object_owner = user + and object_type = 'PACKAGE' + and object_name = 'DUMMY_TEST_PACKAGE'; + + ut.expect(l_cache_count).to_equal(0); + + end; + end test_annotation_manager; / diff --git a/test/core/annotations/test_annotation_manager.pks b/test/core/annotations/test_annotation_manager.pks index fb5e0299d..0726c8256 100644 --- a/test/core/annotations/test_annotation_manager.pks +++ b/test/core/annotations/test_annotation_manager.pks @@ -12,6 +12,10 @@ create or replace package test_annotation_manager is procedure create_dummy_test_package; + procedure create_parse_proc_as_ut3$user#; + + procedure drop_parse_proc_as_ut3$user#; + procedure drop_dummy_test_package; --%test(Adds new package to annotation cache info) @@ -34,13 +38,18 @@ create or replace package test_annotation_manager is --%aftertest(drop_dummy_test_package) procedure update_modified_test_package; - --%test(Keeps annotations in cache after object was removed) - --%beforetest(create_dummy_test_package) + --%test(Keeps annotations in cache when object was removed but user can't see whole schema) + --%beforetest(create_dummy_test_package,create_parse_proc_as_ut3$user#) + --%aftertest(drop_parse_proc_as_ut3$user#) procedure keep_dropped_data_in_cache; --%test(Does not return data for dropped object) --%beforetest(create_dummy_test_package) procedure no_data_for_dropped_object; + --%test(Remove object from cache when object dropped and user can see whole schema) + --%beforetest(create_dummy_test_package) + procedure cleanup_dropped_data_in_cache; + end test_annotation_manager; / From cb9cf9790c869286f29363cffcce6aa48770e5fc Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 11 Nov 2018 12:35:01 +0000 Subject: [PATCH 11/33] Resolving some sonar violations. --- .../ut_annotation_cache_manager.pkb | 1 - source/core/ut_metadata.pkb | 1 - source/core/ut_suite_builder.pkb | 32 +++++++------------ 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/source/core/annotations/ut_annotation_cache_manager.pkb b/source/core/annotations/ut_annotation_cache_manager.pkb index 4f9129650..5c40be5b7 100644 --- a/source/core/annotations/ut_annotation_cache_manager.pkb +++ b/source/core/annotations/ut_annotation_cache_manager.pkb @@ -18,7 +18,6 @@ create or replace package body ut_annotation_cache_manager as procedure update_cache(a_object ut_annotated_object) is l_cache_id integer; - l_current_schema varchar2(250) := ut_utils.ut_owner; pragma autonomous_transaction; begin update ut_annotation_cache_info i diff --git a/source/core/ut_metadata.pkb b/source/core/ut_metadata.pkb index 1693066ec..1795c1a0c 100644 --- a/source/core/ut_metadata.pkb +++ b/source/core/ut_metadata.pkb @@ -116,7 +116,6 @@ create or replace package body ut_metadata as end; function get_source_definition_line(a_owner varchar2, a_object_name varchar2, a_line_no integer) return varchar2 is - l_cursor sys_refcursor; l_view_name varchar2(128) := get_dba_view('dba_source'); l_line all_source.text%type; c_key constant varchar2(500) := a_owner || '.' || a_object_name; diff --git a/source/core/ut_suite_builder.pkb b/source/core/ut_suite_builder.pkb index 4638f5dba..aa0b8ed29 100644 --- a/source/core/ut_suite_builder.pkb +++ b/source/core/ut_suite_builder.pkb @@ -58,8 +58,6 @@ create or replace package body ut_suite_builder is gc_endcontext ); - gc_placeholder constant varchar2(3) := '\\%'; - gc_integer_exception constant varchar2(1) := 'I'; gc_named_exception constant varchar2(1) := 'N'; @@ -218,7 +216,6 @@ create or replace package body ut_suite_builder is function get_exception_number (a_exception_var in varchar2) return integer is l_exc_no integer; l_exc_type varchar2(50); - l_sql varchar2(32767); function remap_no_data_found (a_number integer) return integer is begin return case a_number when 100 then -1403 else a_number end; @@ -260,7 +257,7 @@ create or replace package body ut_suite_builder is l_exception_number_list ut_integer_list := ut_integer_list(); c_regexp_for_exception_no constant varchar2(30) := '^-?[[:digit:]]{1,5}$'; begin - /*the a_expected_error_codes is converted to a ut_varchar2_list after that is trimmed and filtered to left only valid exception numbers*/ + --the a_expected_error_codes is converted to a ut_varchar2_list after that is trimmed and filtered to left only valid exception numbers l_throws_list := ut_utils.trim_list_elements(ut_utils.string_to_table(a_annotation_text, ',', 'Y')); for i in 1 .. l_throws_list.count @@ -407,18 +404,15 @@ create or replace package body ut_suite_builder is a_for_annotation varchar2, a_procedure_name t_object_name := null ) is - l_annotation_name t_annotation_name; l_line_no binary_integer; begin - if a_annotations.exists(a_for_annotation) then - if a_annotations(a_for_annotation).count > 1 then - --start from second occurrence of annotation - l_line_no := a_annotations(a_for_annotation).next( a_annotations(a_for_annotation).first ); - while l_line_no is not null loop - add_annotation_ignored_warning( a_suite, a_for_annotation, 'Duplicate annotation %%%.', l_line_no, a_procedure_name ); - l_line_no := a_annotations(a_for_annotation).next( l_line_no ); - end loop; - end if; + if a_annotations.exists(a_for_annotation) and a_annotations(a_for_annotation).count > 1 then + --start from second occurrence of annotation + l_line_no := a_annotations(a_for_annotation).next( a_annotations(a_for_annotation).first ); + while l_line_no is not null loop + add_annotation_ignored_warning( a_suite, a_for_annotation, 'Duplicate annotation %%%.', l_line_no, a_procedure_name ); + l_line_no := a_annotations(a_for_annotation).next( l_line_no ); + end loop; end if; end; @@ -430,8 +424,7 @@ create or replace package body ut_suite_builder is a_invalid_annotations ut_varchar2_list ) is l_annotation_name t_annotation_name; - l_warning varchar2(32767); - l_line_no binary_integer; + l_line_no binary_integer; begin if a_proc_annotations.exists(a_for_annotation) then l_annotation_name := a_proc_annotations.first; @@ -739,9 +732,8 @@ create or replace package body ut_suite_builder is while l_context_pos is not null loop l_end_context_pos := get_endcontext_position(l_context_pos, a_annotations.by_name ); - if l_end_context_pos is null then - exit; - end if; + + exit when l_end_context_pos is null; l_context_items := ut_suite_items(); --create a sub-set of annotations to process as sub-suite (context) @@ -1156,10 +1148,8 @@ create or replace package body ut_suite_builder is a_skip_all_objects boolean := false ) return ut_suite_items is l_suites ut_suite_items; - l_annotations_cursor sys_refcursor; l_annotated_objects ut_annotated_objects; l_suite_items ut_suite_items; - l_suite_data_cursor sys_refcursor; begin loop fetch a_annotated_objects bulk collect into l_annotated_objects limit 10; From 8779025d8ff01fc03a935e16e9199978d8877d52 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 11 Nov 2018 13:09:44 +0000 Subject: [PATCH 12/33] Moving away from full outer join. Added static schema name rather than bind variable. --- .../annotations/ut_annotation_manager.pkb | 112 ++++++++---------- source/core/ut_suite_builder.pkb | 13 +- 2 files changed, 55 insertions(+), 70 deletions(-) diff --git a/source/core/annotations/ut_annotation_manager.pkb b/source/core/annotations/ut_annotation_manager.pkb index 3559982cf..80de4d1a7 100644 --- a/source/core/annotations/ut_annotation_manager.pkb +++ b/source/core/annotations/ut_annotation_manager.pkb @@ -19,37 +19,37 @@ 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_dba_view('dba_objects'); --- l_cursor_text varchar2(32767); --- l_result ut_annotation_objs_cache_info; --- begin --- l_cursor_text := --- q'[select ]'||l_ut_owner||q'[.ut_annotation_obj_cache_info( --- object_owner => i.object_owner, --- object_name => i.object_name, --- object_type => i.object_type, --- needs_refresh => null --- ) --- from ]'||l_ut_owner||q'[.ut_annotation_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 = :a_object_owner --- and o.object_type = :a_object_type --- ) --- and i.object_owner = :a_object_owner --- and i.object_type = :a_object_type]'; --- open l_rows for l_cursor_text using a_object_owner, a_object_type, a_object_owner, a_object_type; --- fetch l_rows bulk collect into l_result limit 1000000; --- close l_rows; --- return l_result; --- end; + 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_dba_view('dba_objects'); + l_cursor_text varchar2(32767); + l_result ut_annotation_objs_cache_info; + begin + l_cursor_text := + q'[select ]'||l_ut_owner||q'[.ut_annotation_obj_cache_info( + object_owner => i.object_owner, + object_name => i.object_name, + object_type => i.object_type, + needs_refresh => null + ) + from ]'||l_ut_owner||q'[.ut_annotation_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 = :a_object_owner + and o.object_type = :a_object_type + ) + and i.object_owner = :a_object_owner + and i.object_type = :a_object_type]'; + open l_rows for l_cursor_text using a_object_owner, a_object_type, a_object_owner, a_object_type; + fetch l_rows bulk collect into l_result limit 1000000; + close l_rows; + return l_result; + end; function get_annotation_objs_info(a_object_owner varchar2, a_object_type varchar2, a_parse_date timestamp := null) return ut_annotation_objs_cache_info is l_rows sys_refcursor; @@ -60,36 +60,25 @@ create or replace package body ut_annotation_manager as begin l_cursor_text := q'[select ]'||l_ut_owner||q'[.ut_annotation_obj_cache_info( - object_owner => nvl( o.owner, i.object_owner ), - object_name => nvl( o.object_name, i.object_name ), - object_type => nvl( o.object_type, i.object_type ), - needs_refresh => - case - when o.last_ddl_time < cast(i.parse_time as date) then 'N' - when o.owner is null then null - else 'Y' - end + 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 ) - from ( - select * from ]'||l_objects_view||q'[ o - where o.owner = :a_object_owner - and o.object_type = :a_object_type - ) o - full outer join ( - select * from ]'||l_ut_owner||q'[.ut_annotation_cache_info i - where i.object_owner = :a_object_owner - and i.object_type = :a_object_type - ) i + from ]'||l_objects_view||q'[ o + left join ]'||l_ut_owner||q'[.ut_annotation_cache_info i on o.owner = i.object_owner and o.object_name = i.object_name and o.object_type = i.object_type - where ]' - || case + where o.owner = ']'||a_object_owner||q'[' + and o.object_type = ']'||a_object_type||q'[' + 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) or o.last_ddl_time is null' - end; - open l_rows for l_cursor_text using a_object_owner, a_object_type, a_object_owner, a_object_type, a_parse_date; + 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 a_parse_date; fetch l_rows bulk collect into l_result limit 1000000; close l_rows; return l_result; @@ -197,7 +186,6 @@ create or replace package body ut_annotation_manager as a_info_rows ut_annotation_objs_cache_info ) is l_objects_to_parse ut_annotation_objs_cache_info; - l_objects_to_remove ut_annotation_objs_cache_info; begin select value(x)bulk collect into l_objects_to_parse from table(a_info_rows) x where x.needs_refresh = 'Y'; @@ -208,13 +196,9 @@ create or replace package body ut_annotation_manager as or ut_metadata.is_object_visible('ut3.ut_utils') or ut_metadata.is_object_visible('dba_objects') then - select value(x)bulk collect into l_objects_to_remove - from table(a_info_rows) x where x.needs_refresh is null; - - ut_annotation_cache_manager.remove_from_cache(l_objects_to_remove); --- ut_annotation_cache_manager.remove_from_cache( --- get_missing_objects(a_object_owner, a_object_type) --- ); + ut_annotation_cache_manager.remove_from_cache( + get_missing_objects(a_object_owner, a_object_type) + ); end if; --if some source needs parsing and putting into cache diff --git a/source/core/ut_suite_builder.pkb b/source/core/ut_suite_builder.pkb index aa0b8ed29..fee7524b4 100644 --- a/source/core/ut_suite_builder.pkb +++ b/source/core/ut_suite_builder.pkb @@ -1020,10 +1020,10 @@ create or replace package body ut_suite_builder is where o.owner = i.object_owner and o.object_name = i.object_name and o.object_type = 'PACKAGE' - and o.owner = :a_object_owner + and o.owner = ']'||a_object_owner||q'[' ) - and i.object_owner = :a_object_owner]'; - open l_rows for l_cursor_text using a_object_owner, a_object_owner; + and i.object_owner = ']'||a_object_owner||q'[']'; + open l_rows for l_cursor_text; fetch l_rows bulk collect into l_result limit 1000000; close l_rows; return l_result; @@ -1061,10 +1061,11 @@ create or replace package body ut_suite_builder is ( select 1 from all_objects a where a.object_name = c.object_name + and a.object_owner = ']'||upper(a_object_owner)||q'[' and a.owner = c.object_owner and a.object_type = 'PACKAGE' )]' end ||q'[ - and c.object_owner = :a_object_owner + and c.object_owner = ']'||upper(a_object_owner)||q'[' and ( ]' || case when l_path is not null then q'[ :l_path||'.' like c.path || '.%' /*all children and self*/ or ( c.path||'.' like :l_path || '.%' --all parents @@ -1134,7 +1135,7 @@ create or replace package body ut_suite_builder is end, '.', chr(0)) desc nulls last, c.object_name desc, c.line_no]' - using upper(a_object_owner), l_path, l_path, upper(a_object_name), upper(a_procedure_name); + using l_path, l_path, upper(a_object_name), upper(a_procedure_name); return l_result; end; @@ -1238,7 +1239,7 @@ create or replace package body ut_suite_builder is then l_need_all_objects_scan := false; end if; - + execute immediate 'select c.object_owner, c.object_name from '||l_ut_owner||q'[.ut_suite_cache_package c join table ( :a_schema_names ) s From b3e98bec52c70450336dcfdded55a278782c4846 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 11 Nov 2018 23:15:44 +0000 Subject: [PATCH 13/33] Reorganizing code a bit. --- source/core/ut_suite_builder.pkb | 443 ++----------------------------- source/core/ut_suite_builder.pks | 30 +-- source/core/ut_suite_manager.pkb | 430 +++++++++++++++++++++++++++++- source/core/ut_suite_manager.pks | 15 ++ test/core/test_suite_builder.pkb | 2 +- 5 files changed, 457 insertions(+), 463 deletions(-) diff --git a/source/core/ut_suite_builder.pkb b/source/core/ut_suite_builder.pkb index fee7524b4..d946b2a5d 100644 --- a/source/core/ut_suite_builder.pkb +++ b/source/core/ut_suite_builder.pkb @@ -93,10 +93,6 @@ create or replace package body ut_suite_builder is by_name tt_annotations_by_name ); - subtype t_cached_suite is ut_suite_cache%rowtype; - type tt_cached_suites is table of t_cached_suite; - type t_cached_suites_cursor is ref cursor return t_cached_suite; - procedure delete_annotations_range( a_annotations in out nocopy t_annotations_info, a_start_pos t_annotation_position, @@ -320,20 +316,6 @@ create or replace package body ut_suite_builder is end if; end; - function sort_by_seq_no( - a_list ut_executables - ) return ut_executables is - l_results ut_executables := ut_executables(); - begin - if a_list is not null then - l_results.extend(a_list.count); - for i in 1 .. a_list.count loop - l_results(a_list(i).seq_no) := a_list(i); - end loop; - end if; - return l_results; - end; - function convert_list( a_list tt_executables ) return ut_executables is @@ -819,33 +801,6 @@ create or replace package body ut_suite_builder is end loop; end; - procedure create_suite_item_list( a_annotations t_annotations_info, a_suite_items out nocopy ut_suite_items ) is - l_annotations t_annotations_info := a_annotations; - l_annotation_pos t_annotation_position; - l_suite ut_suite; - begin - if l_annotations.by_name.exists(gc_suite) then - l_annotation_pos := l_annotations.by_name(gc_suite).first; - l_suite := ut_suite(l_annotations.owner, l_annotations.name, l_annotation_pos); - l_suite.description := l_annotations.by_name( gc_suite)( l_annotation_pos); - l_suite.parse_time := l_annotations.parse_time; - warning_on_unknown_annotations(l_suite, l_annotations.by_line); - - warning_on_duplicate_annot( l_suite, l_annotations.by_name, gc_suite ); - - build_suitepath( l_suite, l_annotations ); - get_suite_contexts_items( l_suite, l_annotations, a_suite_items ); - --create suite tests and add - add_suite_tests( l_suite, l_annotations, a_suite_items ); - - --by this time all contexts were consumed and l_annotations should not have any context/endcontext annotation in it. - warning_on_incomplete_context( l_suite, l_annotations.by_name ); - - a_suite_items.extend; - a_suite_items( a_suite_items.last) := l_suite; - end if; - end; - function convert_package_annotations(a_object ut_annotated_object) return t_annotations_info is l_result t_annotations_info; l_annotation t_annotation; @@ -872,391 +827,33 @@ create or replace package body ut_suite_builder is return l_result; end; - procedure copy_list_reverse_order( - a_list in out nocopy ut_suite_items - ) is - l_start_idx pls_integer; - l_end_idx pls_integer; - l_item ut_suite_item; - begin - l_start_idx := a_list.first; - l_end_idx := a_list.last; - while l_start_idx < l_end_idx loop - l_item := a_list(l_start_idx); - a_list(l_start_idx) := a_list(l_end_idx); - a_list(l_end_idx) := l_item; - l_end_idx := a_list.prior(l_end_idx); - l_start_idx := a_list.next(l_start_idx); - end loop; - end; - - procedure reconstruct_from_cache( - a_suites out nocopy ut_suite_items, - a_suite_data_cursor sys_refcursor - ) is - type t_item_levels is table of ut_suite_items index by binary_integer; - c_bulk_limit constant pls_integer := 1000; - l_items_at_level t_item_levels; - l_rows tt_cached_suites; - l_test ut_test; - l_logical_suite ut_logical_suite; - l_level pls_integer; - l_prev_level pls_integer; - l_idx integer; - begin - a_suites := ut_suite_items(); - loop - fetch a_suite_data_cursor bulk collect into l_rows limit c_bulk_limit; - exit when l_rows.count = 0; - - l_idx := l_rows.first; - loop - l_test := null; - l_logical_suite := null; - case l_rows(l_idx).self_type - when 'UT_TEST' then - l_test := - ut_test( - self_type => l_rows(l_idx).self_type, - object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), - name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, - rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, - line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - before_each_list => sort_by_seq_no(l_rows(l_idx).before_each_list), before_test_list => sort_by_seq_no(l_rows(l_idx).before_test_list), - item => l_rows(l_idx).item, - after_test_list => sort_by_seq_no(l_rows(l_idx).after_test_list), after_each_list => sort_by_seq_no(l_rows(l_idx).after_each_list), - all_expectations => ut_expectation_results(), failed_expectations => ut_expectation_results(), - parent_error_stack_trace => null, expected_error_codes => l_rows(l_idx).expected_error_codes - ); - when 'UT_SUITE' then - l_logical_suite := - ut_suite( - self_type => l_rows(l_idx).self_type, - object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), - name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, - rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, - line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => ut_suite_items(), - before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) - ); - when 'UT_SUITE_CONTEXT' then - l_logical_suite := - ut_suite_context( - self_type => l_rows(l_idx).self_type, - object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), - name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, - rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, - line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => ut_suite_items(), - before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) - ); - when 'UT_LOGICAL_SUITE' then - l_logical_suite := - ut_logical_suite( - self_type => l_rows(l_idx).self_type, - object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), - name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, - rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, - line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => ut_suite_items() - ); - end case; - - l_level := length(l_rows(l_idx).path) - length( replace(l_rows(l_idx).path, '.') ) + 1; - - if l_level > 1 then - if l_prev_level > l_level then - l_logical_suite.items := l_items_at_level(l_prev_level); - l_items_at_level(l_prev_level).delete; - end if; - if not l_items_at_level.exists(l_level) then - l_items_at_level(l_level) := ut_suite_items(); - end if; - l_items_at_level(l_level).extend; - if l_test is not null then - l_items_at_level(l_level)(l_items_at_level(l_level).last) := l_test; - else - l_items_at_level(l_level)(l_items_at_level(l_level).last) := l_logical_suite; - end if; - else - if l_prev_level > l_level then - l_logical_suite.items := l_items_at_level(l_prev_level); - l_items_at_level(l_prev_level).delete; - end if; - a_suites.extend; - a_suites(a_suites.last) := l_logical_suite; - end if; - l_prev_level := l_level; - l_idx := l_rows.next(l_idx); - exit when l_idx is null; - end loop; - exit when l_rows.count < c_bulk_limit; - end loop; - copy_list_reverse_order( a_suites ); - close a_suite_data_cursor; - end; - - function get_missing_objects(a_object_owner varchar2) return ut_varchar2_rows is - l_rows sys_refcursor; - l_ut_owner varchar2(250) := ut_utils.ut_owner; - l_objects_view varchar2(200) := ut_metadata.get_dba_view('dba_objects'); - l_cursor_text varchar2(32767); - l_result ut_varchar2_rows; - begin - l_cursor_text := - q'[select i.object_name - from ]'||l_ut_owner||q'[.ut_suite_cache_package 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 = 'PACKAGE' - and o.owner = ']'||a_object_owner||q'[' - ) - and i.object_owner = ']'||a_object_owner||q'[']'; - open l_rows for l_cursor_text; - fetch l_rows bulk collect into l_result limit 1000000; - close l_rows; - return l_result; - end; - - function get_cached_suite_data( - a_object_owner varchar2, - a_path varchar2 := null, - a_object_name varchar2 := null, - a_procedure_name varchar2 := null, - a_skip_all_objects boolean := false - ) return t_cached_suites_cursor is - l_path varchar2( 4000 ); - l_result sys_refcursor; - l_ut_owner varchar2(250) := ut_utils.ut_owner; + procedure create_suite_item_list( a_annotated_object ut_annotated_object, a_suite_items out nocopy ut_suite_items ) is + l_annotations t_annotations_info; + l_annotation_pos t_annotation_position; + l_suite ut_suite; begin - if a_path is null and a_object_name is not null then - execute immediate 'select min(path) - from '||l_ut_owner||q'[.ut_suite_cache - where object_owner = :a_object_owner - and object_name = :a_object_name - and name = nvl(:a_procedure_name, name)]' - into l_path using upper(a_object_owner), upper(a_object_name), upper(a_procedure_name); - else - l_path := lower( a_path ); - end if; - - open l_result for - q'[with - suite_items as ( - select /*+ cardinality(c 100) */ c.* - from ]'||l_ut_owner||q'[.ut_suite_cache c - where 1 = 1 ]'||case when not a_skip_all_objects then q'[ - and exists - ( select 1 - from all_objects a - where a.object_name = c.object_name - and a.object_owner = ']'||upper(a_object_owner)||q'[' - and a.owner = c.object_owner - and a.object_type = 'PACKAGE' - )]' end ||q'[ - and c.object_owner = ']'||upper(a_object_owner)||q'[' - and ( ]' || case when l_path is not null then q'[ - :l_path||'.' like c.path || '.%' /*all children and self*/ - or ( c.path||'.' like :l_path || '.%' --all parents - ]' - else ' :l_path is null and ( :l_path is null ' end - || case when a_object_name is not null - then 'and c.object_name = :a_object_name ' - else 'and :a_object_name is null' end ||' - '|| case when a_procedure_name is not null - then 'and c.name = :a_procedure_name' - else 'and :a_procedure_name is null' end ||q'[ - ) - ) - ), - suitepaths as ( - select distinct substr(path,1,instr(path,'.',-1)-1) as suitepath, - path, - object_owner - from suite_items - where self_type = 'UT_SUITE' - ), - gen as ( - select rownum as pos - from xmltable('1 to 20') - ), - suitepath_part AS ( - select distinct - substr(b.suitepath, 1, instr(b.suitepath || '.', '.', 1, g.pos) -1) as path, - object_owner - from suitepaths b - join gen g - on g.pos <= regexp_count(b.suitepath, '\w+') - ), - logical_suite_data as ( - select 'UT_LOGICAL_SUITE' as self_type, p.path, p.object_owner, - upper( substr(p.path, instr( p.path, '.', -1 ) + 1 ) ) as object_name, - cast(null as ]'||l_ut_owner||q'[.ut_executables) as x, - cast(null as ]'||l_ut_owner||q'[.ut_integer_list) as y, - cast(null as ]'||l_ut_owner||q'[.ut_executable_test) as z - from suitepath_part p - where p.path - not in (select s.path from suitepaths s) - ), - logical_suites as ( - select to_number(null) as id, s.self_type, s.path, s.object_owner, s.object_name, - s.object_name as name, null as line_no, null as parse_time, - null as description, null as rollback_type, 0 as disabled_flag, - ]'||l_ut_owner||q'[.ut_varchar2_rows() as warnings, - s.x as before_all_list, s.x as after_all_list, - s.x as before_each_list, s.x as before_test_list, - s.x as after_each_list, s.x as after_test_list, - s.y as expected_error_codes, s.z as item - from logical_suite_data s - ), - items as ( - select * from suite_items - union all - select * from logical_suites - ) - select c.* - from items c - order by c.object_owner, - replace(case - when c.self_type in ( 'UT_TEST' ) - then substr(c.path, 1, instr(c.path, '.', -1) ) - else c.path - end, '.', chr(0)) desc nulls last, - c.object_name desc, - c.line_no]' - using l_path, l_path, upper(a_object_name), upper(a_procedure_name); - - return l_result; - end; + l_annotations := convert_package_annotations( a_annotated_object ); - function build_suites_from_annotations( - a_owner_name varchar2, - a_annotated_objects sys_refcursor, - a_path varchar2 := null, - a_object_name varchar2 := null, - a_procedure_name varchar2 := null, - a_skip_all_objects boolean := false - ) return ut_suite_items is - l_suites ut_suite_items; - l_annotated_objects ut_annotated_objects; - l_suite_items ut_suite_items; - begin - loop - fetch a_annotated_objects bulk collect into l_annotated_objects limit 10; + if l_annotations.by_name.exists(gc_suite) then + l_annotation_pos := l_annotations.by_name(gc_suite).first; + l_suite := ut_suite(l_annotations.owner, l_annotations.name, l_annotation_pos); + l_suite.description := l_annotations.by_name( gc_suite)( l_annotation_pos); + l_suite.parse_time := l_annotations.parse_time; + warning_on_unknown_annotations(l_suite, l_annotations.by_line); - for i in 1 .. l_annotated_objects.count loop - create_suite_item_list( - convert_package_annotations( l_annotated_objects( i ) ), - l_suite_items - ); - ut_suite_cache_manager.save_object_cache( - a_owner_name, - l_annotated_objects( i ).object_name, - l_annotated_objects( i ).parse_time, - l_suite_items - ); - end loop; - exit when a_annotated_objects%notfound; - end loop; - close a_annotated_objects; - - reconstruct_from_cache( - l_suites, - get_cached_suite_data( - a_owner_name, - a_path, - a_object_name, - a_procedure_name, - a_skip_all_objects - ) - ); - for i in 1 .. l_suites.count loop - l_suites( i ).set_rollback_type( l_suites( i ).get_rollback_type ); - end loop; - return l_suites; - end; + warning_on_duplicate_annot( l_suite, l_annotations.by_name, gc_suite ); - function build_schema_suites( - a_owner_name varchar2, - a_path varchar2 := null, - a_object_name varchar2 := null, - a_procedure_name varchar2 := null - ) return ut_suite_items is - l_annotations_cursor sys_refcursor; - l_suite_cache_time timestamp; - l_skip_all_objects_scan boolean := false; - begin - l_suite_cache_time := ut_suite_cache_manager.get_schema_parse_time(a_owner_name); - open l_annotations_cursor for - q'[select value(x) - from table( - ]' || ut_utils.ut_owner || q'[.ut_annotation_manager.get_annotated_objects(:a_owner_name, 'PACKAGE', :a_suite_cache_parse_time) - )x ]' - using a_owner_name, l_suite_cache_time; - - -- if current user is the onwer or current user has execute any procedure privilege - if sys_context('userenv','current_schema') = a_owner_name - or ut_metadata.is_object_visible('ut3.ut_utils') - then - l_skip_all_objects_scan := true; - end if; - if l_skip_all_objects_scan or ut_metadata.is_object_visible('dba_objects') then - ut_suite_cache_manager.remove_from_cache( a_owner_name, get_missing_objects(a_owner_name) ); - end if; + build_suitepath( l_suite, l_annotations ); + get_suite_contexts_items( l_suite, l_annotations, a_suite_items ); + --create suite tests and add + add_suite_tests( l_suite, l_annotations, a_suite_items ); - return build_suites_from_annotations( - a_owner_name, - l_annotations_cursor, - a_path, - a_object_name, - a_procedure_name, - l_skip_all_objects_scan - ); - end; + --by this time all contexts were consumed and l_annotations should not have any context/endcontext annotation in it. + warning_on_incomplete_context( l_suite, l_annotations.by_name ); - function get_schema_ut_packages( a_schema_names ut_varchar2_rows ) return ut_object_names is - l_results ut_object_names := ut_object_names( ); - l_schema_names ut_varchar2_rows; - l_object_names ut_varchar2_rows; - l_ut_owner varchar2(250) := ut_utils.ut_owner; - l_need_all_objects_scan boolean := true; - begin - -- if current user is the onwer or current user has execute any procedure privilege - if ut_metadata.is_object_visible('ut3.ut_utils') - or (a_schema_names is not null and a_schema_names.count = 1 - and sys_context('userenv','current_schema') = a_schema_names(1)) - then - l_need_all_objects_scan := false; + a_suite_items.extend; + a_suite_items( a_suite_items.last) := l_suite; end if; - - execute immediate 'select c.object_owner, c.object_name - from '||l_ut_owner||q'[.ut_suite_cache_package c - join table ( :a_schema_names ) s - on c.object_owner = upper(s.column_value)]' - || case when l_need_all_objects_scan then q'[ - where exists - (select 1 from all_objects a - where a.owner = c.object_owner - and a.object_name = c.object_name - and a.object_type = 'PACKAGE') - ]' end - bulk collect into l_schema_names, l_object_names using a_schema_names; - l_results.extend( l_schema_names.count ); - for i in 1 .. l_schema_names.count loop - l_results( i ) := ut_object_name( l_schema_names( i ), l_object_names( i ) ); - end loop; - return l_results; end; end ut_suite_builder; diff --git a/source/core/ut_suite_builder.pks b/source/core/ut_suite_builder.pks index 881df24c9..5e2624a30 100644 --- a/source/core/ut_suite_builder.pks +++ b/source/core/ut_suite_builder.pks @@ -21,32 +21,12 @@ create or replace package ut_suite_builder authid current_user is */ /** - * Builds set of hierarchical suites for a given schema - * - * @param a_owner_name name of the schema to builds suite for - * @param a_path suite path to build suite for (optional) - * @param a_object_name object name to build suite for (optional) - * @param a_object_name procedure name to build suite for (optional) - * @return list of suites organized into hierarchy - * + * Creates a list of suite items for an annotated object */ - function build_schema_suites( - a_owner_name varchar2, - a_path varchar2 := null, - a_object_name varchar2 := null, - a_procedure_name varchar2 := null - ) return ut_suite_items; - - function get_schema_ut_packages(a_schema_names ut_varchar2_rows) return ut_object_names; - - function build_suites_from_annotations( - a_owner_name varchar2, - a_annotated_objects sys_refcursor, - a_path varchar2 := null, - a_object_name varchar2 := null, - a_procedure_name varchar2 := null, - a_skip_all_objects boolean := false - ) return ut_suite_items; + procedure create_suite_item_list( + a_annotated_object ut_annotated_object, + a_suite_items out nocopy ut_suite_items + ); end ut_suite_builder; / diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index 4aab5503b..5e296f02e 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -25,12 +25,11 @@ create or replace package body ut_suite_manager is type t_path_items is table of t_path_item; type t_schema_paths is table of t_path_items index by varchar2(250 char); - ------------------ + subtype t_cached_suite is ut_suite_cache%rowtype; + type tt_cached_suites is table of t_cached_suite; + type t_cached_suites_cursor is ref cursor return t_cached_suite; - function get_schema_ut_packages(a_schema_names ut_varchar2_rows) return ut_object_names is - begin - return ut_suite_builder.get_schema_ut_packages(a_schema_names); - end; + ------------------ procedure validate_paths(a_paths in ut_varchar2_list) is l_path varchar2(32767); @@ -108,13 +107,6 @@ create or replace package body ut_suite_manager is l_schema_names := resolve_schema_names(a_paths); end; - function get_schema_names(a_paths ut_varchar2_list) return ut_varchar2_rows is - l_paths ut_varchar2_list; - begin - l_paths := a_paths; - return resolve_schema_names(l_paths); - end; - function group_paths_by_schema(a_paths ut_varchar2_list) return t_schema_paths is c_package_path_regex constant varchar2(100) := '^([A-Za-z0-9$#_]+)(\.([A-Za-z0-9$#_]+))?(\.([A-Za-z0-9$#_]+))?$'; l_schema varchar2(4000); @@ -141,7 +133,417 @@ create or replace package body ut_suite_manager is end loop; return l_results; end; - + + + function sort_by_seq_no( + a_list ut_executables + ) return ut_executables is + l_results ut_executables := ut_executables(); + begin + if a_list is not null then + l_results.extend(a_list.count); + for i in 1 .. a_list.count loop + l_results(a_list(i).seq_no) := a_list(i); + end loop; + end if; + return l_results; + end; + + procedure copy_list_reverse_order( + a_list in out nocopy ut_suite_items + ) is + l_start_idx pls_integer; + l_end_idx pls_integer; + l_item ut_suite_item; + begin + l_start_idx := a_list.first; + l_end_idx := a_list.last; + while l_start_idx < l_end_idx loop + l_item := a_list(l_start_idx); + a_list(l_start_idx) := a_list(l_end_idx); + a_list(l_end_idx) := l_item; + l_end_idx := a_list.prior(l_end_idx); + l_start_idx := a_list.next(l_start_idx); + end loop; + end; + + procedure reconstruct_from_cache( + a_suites out nocopy ut_suite_items, + a_suite_data_cursor sys_refcursor + ) is + type t_item_levels is table of ut_suite_items index by binary_integer; + c_bulk_limit constant pls_integer := 1000; + l_items_at_level t_item_levels; + l_rows tt_cached_suites; + l_test ut_test; + l_logical_suite ut_logical_suite; + l_level pls_integer; + l_prev_level pls_integer; + l_idx integer; + begin + a_suites := ut_suite_items(); + loop + fetch a_suite_data_cursor bulk collect into l_rows limit c_bulk_limit; + exit when l_rows.count = 0; + + l_idx := l_rows.first; + loop + l_test := null; + l_logical_suite := null; + case l_rows(l_idx).self_type + when 'UT_TEST' then + l_test := + ut_test( + self_type => l_rows(l_idx).self_type, + object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), + name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, + rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, + line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + before_each_list => sort_by_seq_no(l_rows(l_idx).before_each_list), before_test_list => sort_by_seq_no(l_rows(l_idx).before_test_list), + item => l_rows(l_idx).item, + after_test_list => sort_by_seq_no(l_rows(l_idx).after_test_list), after_each_list => sort_by_seq_no(l_rows(l_idx).after_each_list), + all_expectations => ut_expectation_results(), failed_expectations => ut_expectation_results(), + parent_error_stack_trace => null, expected_error_codes => l_rows(l_idx).expected_error_codes + ); + when 'UT_SUITE' then + l_logical_suite := + ut_suite( + self_type => l_rows(l_idx).self_type, + object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), + name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, + rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, + line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items(), + before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) + ); + when 'UT_SUITE_CONTEXT' then + l_logical_suite := + ut_suite_context( + self_type => l_rows(l_idx).self_type, + object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), + name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, + rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, + line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items(), + before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) + ); + when 'UT_LOGICAL_SUITE' then + l_logical_suite := + ut_logical_suite( + self_type => l_rows(l_idx).self_type, + object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), + name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, + rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, + line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items() + ); + end case; + + l_level := length(l_rows(l_idx).path) - length( replace(l_rows(l_idx).path, '.') ) + 1; + + if l_level > 1 then + if l_prev_level > l_level then + l_logical_suite.items := l_items_at_level(l_prev_level); + l_items_at_level(l_prev_level).delete; + end if; + if not l_items_at_level.exists(l_level) then + l_items_at_level(l_level) := ut_suite_items(); + end if; + l_items_at_level(l_level).extend; + if l_test is not null then + l_items_at_level(l_level)(l_items_at_level(l_level).last) := l_test; + else + l_items_at_level(l_level)(l_items_at_level(l_level).last) := l_logical_suite; + end if; + else + if l_prev_level > l_level then + l_logical_suite.items := l_items_at_level(l_prev_level); + l_items_at_level(l_prev_level).delete; + end if; + a_suites.extend; + a_suites(a_suites.last) := l_logical_suite; + end if; + l_prev_level := l_level; + l_idx := l_rows.next(l_idx); + exit when l_idx is null; + end loop; + exit when l_rows.count < c_bulk_limit; + end loop; + copy_list_reverse_order( a_suites ); + close a_suite_data_cursor; + end; + + function get_missing_objects(a_object_owner varchar2) return ut_varchar2_rows is + l_rows sys_refcursor; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + l_objects_view varchar2(200) := ut_metadata.get_dba_view('dba_objects'); + l_cursor_text varchar2(32767); + l_result ut_varchar2_rows; + begin + l_cursor_text := + q'[select i.object_name + from ]'||l_ut_owner||q'[.ut_suite_cache_package 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 = 'PACKAGE' + and o.owner = ']'||a_object_owner||q'[' + ) + and i.object_owner = ']'||a_object_owner||q'[']'; + open l_rows for l_cursor_text; + fetch l_rows bulk collect into l_result limit 1000000; + close l_rows; + return l_result; + end; + + function get_cached_suite_data( + a_object_owner varchar2, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null, + a_skip_all_objects boolean := false + ) return t_cached_suites_cursor is + l_path varchar2( 4000 ); + l_result sys_refcursor; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + begin + if a_path is null and a_object_name is not null then + execute immediate 'select min(path) + from '||l_ut_owner||q'[.ut_suite_cache + where object_owner = :a_object_owner + and object_name = :a_object_name + and name = nvl(:a_procedure_name, name)]' + into l_path using upper(a_object_owner), upper(a_object_name), upper(a_procedure_name); + else + l_path := lower( a_path ); + end if; + + open l_result for + q'[with + suite_items as ( + select /*+ cardinality(c 100) */ c.* + from ]'||l_ut_owner||q'[.ut_suite_cache c + where 1 = 1 ]'||case when not a_skip_all_objects then q'[ + and exists + ( select 1 + from all_objects a + where a.object_name = c.object_name + and a.object_owner = ']'||upper(a_object_owner)||q'[' + and a.owner = c.object_owner + and a.object_type = 'PACKAGE' + )]' end ||q'[ + and c.object_owner = ']'||upper(a_object_owner)||q'[' + and ( ]' || case when l_path is not null then q'[ + :l_path||'.' like c.path || '.%' /*all children and self*/ + or ( c.path||'.' like :l_path || '.%' --all parents + ]' + else ' :l_path is null and ( :l_path is null ' end + || case when a_object_name is not null + then 'and c.object_name = :a_object_name ' + else 'and :a_object_name is null' end ||' + '|| case when a_procedure_name is not null + then 'and c.name = :a_procedure_name' + else 'and :a_procedure_name is null' end ||q'[ + ) + ) + ), + suitepaths as ( + select distinct substr(path,1,instr(path,'.',-1)-1) as suitepath, + path, + object_owner + from suite_items + where self_type = 'UT_SUITE' + ), + gen as ( + select rownum as pos + from xmltable('1 to 20') + ), + suitepath_part AS ( + select distinct + substr(b.suitepath, 1, instr(b.suitepath || '.', '.', 1, g.pos) -1) as path, + object_owner + from suitepaths b + join gen g + on g.pos <= regexp_count(b.suitepath, '\w+') + ), + logical_suite_data as ( + select 'UT_LOGICAL_SUITE' as self_type, p.path, p.object_owner, + upper( substr(p.path, instr( p.path, '.', -1 ) + 1 ) ) as object_name, + cast(null as ]'||l_ut_owner||q'[.ut_executables) as x, + cast(null as ]'||l_ut_owner||q'[.ut_integer_list) as y, + cast(null as ]'||l_ut_owner||q'[.ut_executable_test) as z + from suitepath_part p + where p.path + not in (select s.path from suitepaths s) + ), + logical_suites as ( + select to_number(null) as id, s.self_type, s.path, s.object_owner, s.object_name, + s.object_name as name, null as line_no, null as parse_time, + null as description, null as rollback_type, 0 as disabled_flag, + ]'||l_ut_owner||q'[.ut_varchar2_rows() as warnings, + s.x as before_all_list, s.x as after_all_list, + s.x as before_each_list, s.x as before_test_list, + s.x as after_each_list, s.x as after_test_list, + s.y as expected_error_codes, s.z as item + from logical_suite_data s + ), + items as ( + select * from suite_items + union all + select * from logical_suites + ) + select c.* + from items c + order by c.object_owner, + replace(case + when c.self_type in ( 'UT_TEST' ) + then substr(c.path, 1, instr(c.path, '.', -1) ) + else c.path + end, '.', chr(0)) desc nulls last, + c.object_name desc, + c.line_no]' + using l_path, l_path, upper(a_object_name), upper(a_procedure_name); + + return l_result; + end; + + function build_schema_suites( + a_owner_name varchar2, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null + ) return ut_suite_items is + l_annotations_cursor sys_refcursor; + l_suite_cache_time timestamp; + l_skip_all_objects_scan boolean := false; + begin + l_suite_cache_time := ut_suite_cache_manager.get_schema_parse_time(a_owner_name); + open l_annotations_cursor for + q'[select value(x) + from table( + ]' || ut_utils.ut_owner || q'[.ut_annotation_manager.get_annotated_objects(:a_owner_name, 'PACKAGE', :a_suite_cache_parse_time) + )x ]' + using a_owner_name, l_suite_cache_time; + + -- if current user is the onwer or current user has execute any procedure privilege + if sys_context('userenv','current_schema') = a_owner_name + or ut_metadata.is_object_visible('ut3.ut_utils') + then + l_skip_all_objects_scan := true; + end if; + if l_skip_all_objects_scan or ut_metadata.is_object_visible('dba_objects') then + ut_suite_cache_manager.remove_from_cache( a_owner_name, get_missing_objects(a_owner_name) ); + end if; + + return build_suites_from_annotations( + a_owner_name, + l_annotations_cursor, + a_path, + a_object_name, + a_procedure_name, + l_skip_all_objects_scan + ); + end; + + ----------------------------------------------- + ----------------------------------------------- + ------------- Public definitions ------------- + + function build_suites_from_annotations( + a_owner_name varchar2, + a_annotated_objects sys_refcursor, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null, + a_skip_all_objects boolean := false + ) return ut_suite_items is + l_suites ut_suite_items; + l_annotated_objects ut_annotated_objects; + l_suite_items ut_suite_items; + begin + loop + fetch a_annotated_objects bulk collect into l_annotated_objects limit 10; + + for i in 1 .. l_annotated_objects.count loop + ut_suite_builder.create_suite_item_list( l_annotated_objects( i ), l_suite_items ); + ut_suite_cache_manager.save_object_cache( + a_owner_name, + l_annotated_objects( i ).object_name, + l_annotated_objects( i ).parse_time, + l_suite_items + ); + end loop; + exit when a_annotated_objects%notfound; + end loop; + close a_annotated_objects; + + reconstruct_from_cache( + l_suites, + get_cached_suite_data( + a_owner_name, + a_path, + a_object_name, + a_procedure_name, + a_skip_all_objects + ) + ); + for i in 1 .. l_suites.count loop + l_suites( i ).set_rollback_type( l_suites( i ).get_rollback_type ); + end loop; + return l_suites; + end; + + function get_schema_ut_packages(a_schema_names ut_varchar2_rows) return ut_object_names is + l_results ut_object_names := ut_object_names( ); + l_schema_names ut_varchar2_rows; + l_object_names ut_varchar2_rows; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + l_need_all_objects_scan boolean := true; + begin + -- if current user is the onwer or current user has execute any procedure privilege + if ut_metadata.is_object_visible('ut3.ut_utils') + or (a_schema_names is not null and a_schema_names.count = 1 + and sys_context('userenv','current_schema') = a_schema_names(1)) + then + l_need_all_objects_scan := false; + end if; + + execute immediate 'select c.object_owner, c.object_name + from '||l_ut_owner||q'[.ut_suite_cache_package c + join table ( :a_schema_names ) s + on c.object_owner = upper(s.column_value)]' + || case when l_need_all_objects_scan then q'[ + where exists + (select 1 from all_objects a + where a.owner = c.object_owner + and a.object_name = c.object_name + and a.object_type = 'PACKAGE') + ]' end + bulk collect into l_schema_names, l_object_names using a_schema_names; + l_results.extend( l_schema_names.count ); + for i in 1 .. l_schema_names.count loop + l_results( i ) := ut_object_name( l_schema_names( i ), l_object_names( i ) ); + end loop; + return l_results; + end; + + function get_schema_names(a_paths ut_varchar2_list) return ut_varchar2_rows is + l_paths ut_varchar2_list; + begin + l_paths := a_paths; + return resolve_schema_names(l_paths); + end; + function configure_execution_by_path(a_paths in ut_varchar2_list) return ut_suite_items is l_paths ut_varchar2_list := a_paths; l_path_items t_path_items; @@ -164,7 +566,7 @@ create or replace package body ut_suite_manager is l_path_items := l_schema_paths(l_schema); for i in 1 .. l_path_items.count loop l_path_item := l_path_items(i); - l_suites := ut_suite_builder.build_schema_suites( + l_suites := build_schema_suites( upper(l_schema), l_path_item.suite_path, l_path_item.object_name, diff --git a/source/core/ut_suite_manager.pks b/source/core/ut_suite_manager.pks index 3fde7f6b5..22c27fea9 100644 --- a/source/core/ut_suite_manager.pks +++ b/source/core/ut_suite_manager.pks @@ -45,5 +45,20 @@ create or replace package ut_suite_manager authid current_user is */ function get_schema_names(a_paths ut_varchar2_list) return ut_varchar2_rows; + + /** + * Constructs a list of suites based on the list of annotations passed + * the suites are stored in cache + */ + function build_suites_from_annotations( + a_owner_name varchar2, + a_annotated_objects sys_refcursor, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null, + a_skip_all_objects boolean := false + ) return ut_suite_items; + + end ut_suite_manager; / diff --git a/test/core/test_suite_builder.pkb b/test/core/test_suite_builder.pkb index 423e29c0a..bd76e88d8 100644 --- a/test/core/test_suite_builder.pkb +++ b/test/core/test_suite_builder.pkb @@ -14,7 +14,7 @@ create or replace package body test_suite_builder is ut3.ut_annotated_object('UT3_TESTER', a_package_name, 'PACKAGE', systimestamp, a_annotations) ) ) x; - l_suites := ut3.ut_suite_builder.build_suites_from_annotations( + l_suites := ut3.ut_suite_manager.build_suites_from_annotations( a_owner_name => 'UT3_TESTER', a_annotated_objects => l_cursor, a_path => null, From 64dfb41ab3ca8165ca976c0ab9624820ee7b8692 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Mon, 12 Nov 2018 01:18:20 +0000 Subject: [PATCH 14/33] Output buffer&reporters performance improvements --- .../output_buffers/ut_output_buffer_base.tps | 1 + .../output_buffers/ut_output_table_buffer.tpb | 23 +++-- .../output_buffers/ut_output_table_buffer.tps | 1 + source/core/types/ut_output_reporter_base.tpb | 5 ++ source/core/types/ut_output_reporter_base.tps | 2 +- source/core/ut_utils.pkb | 48 +++++++++- source/core/ut_utils.pks | 15 ++++ .../ut_coverage_cobertura_reporter.tpb | 79 +++++++++-------- .../reporters/ut_coverage_html_reporter.tpb | 3 +- .../ut_coverage_report_html_helper.pkb | 87 +++++++++---------- .../ut_coverage_report_html_helper.pks | 2 +- .../reporters/ut_coverage_sonar_reporter.tpb | 65 +++++++------- source/reporters/ut_coveralls_reporter.tpb | 48 +++++----- source/reporters/ut_junit_reporter.tpb | 82 +++++++++-------- source/reporters/ut_sonar_test_reporter.tpb | 27 +++--- source/reporters/ut_teamcity_reporter.tpb | 56 ++++++++---- source/reporters/ut_tfs_junit_reporter.tpb | 55 ++++++------ .../test_cov_cobertura_reporter.pkb | 7 +- .../test_coverage/test_coveralls_reporter.pkb | 15 +++- 19 files changed, 372 insertions(+), 249 deletions(-) diff --git a/source/core/output_buffers/ut_output_buffer_base.tps b/source/core/output_buffers/ut_output_buffer_base.tps index f1d71c502..6f69047d9 100644 --- a/source/core/output_buffers/ut_output_buffer_base.tps +++ b/source/core/output_buffers/ut_output_buffer_base.tps @@ -20,6 +20,7 @@ create or replace type ut_output_buffer_base authid definer as object( member procedure init(self in out nocopy ut_output_buffer_base), not instantiable member procedure close(self in ut_output_buffer_base), not instantiable member procedure send_line(self in ut_output_buffer_base, a_text varchar2), + not instantiable member procedure send_lines(self in ut_output_buffer_base, a_text_list ut_varchar2_rows), not instantiable member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_varchar2_rows pipelined, not instantiable member function get_lines_cursor(a_initial_timeout natural := null, a_timeout_sec natural := null) return sys_refcursor, not instantiable member procedure lines_to_dbms_output(self in ut_output_buffer_base, a_initial_timeout natural := null, a_timeout_sec natural := null) diff --git a/source/core/output_buffers/ut_output_table_buffer.tpb b/source/core/output_buffers/ut_output_table_buffer.tpb index 0cc68b76b..e7045b9df 100644 --- a/source/core/output_buffers/ut_output_table_buffer.tpb +++ b/source/core/output_buffers/ut_output_table_buffer.tpb @@ -47,16 +47,15 @@ create or replace type body ut_output_table_buffer is end; overriding member procedure send_line(self in ut_output_table_buffer, a_text varchar2) is - l_text_list ut_varchar2_rows; pragma autonomous_transaction; begin if a_text is not null then if length(a_text) > ut_utils.gc_max_storage_varchar2_len then - l_text_list := ut_utils.convert_collection(ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len)); - insert - into ut_output_buffer_tmp(output_id, message_id, text) - select self.output_id, ut_message_id_seq.nextval, t.column_value - from table(l_text_list) t; + self.send_lines( + ut_utils.convert_collection( + ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len) + ) + ); else insert into ut_output_buffer_tmp(output_id, message_id, text) values (self.output_id, ut_message_id_seq.nextval, a_text); @@ -65,6 +64,18 @@ create or replace type body ut_output_table_buffer is end if; end; + overriding member procedure send_lines(self in ut_output_table_buffer, a_text_list ut_varchar2_rows) is + pragma autonomous_transaction; + begin + insert into ut_output_buffer_tmp(output_id, message_id, text) + select self.output_id, ut_message_id_seq.nextval, t.column_value + from table(a_text_list) t + where t.column_value is not null; + + commit; + end; + + overriding member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_varchar2_rows pipelined is l_buffer_data ut_varchar2_rows; l_already_waited_for number(10,2) := 0; diff --git a/source/core/output_buffers/ut_output_table_buffer.tps b/source/core/output_buffers/ut_output_table_buffer.tps index 96628de77..0e6f83770 100644 --- a/source/core/output_buffers/ut_output_table_buffer.tps +++ b/source/core/output_buffers/ut_output_table_buffer.tps @@ -20,6 +20,7 @@ create or replace type ut_output_table_buffer under ut_output_buffer_base ( constructor function ut_output_table_buffer(self in out nocopy ut_output_table_buffer, a_output_id raw := null) return self as result, overriding member procedure init(self in out nocopy ut_output_table_buffer), overriding member procedure send_line(self in ut_output_table_buffer, a_text varchar2), + overriding member procedure send_lines(self in ut_output_table_buffer, a_text_list ut_varchar2_rows), overriding member procedure close(self in ut_output_table_buffer), overriding member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_varchar2_rows pipelined, overriding member function get_lines_cursor(a_initial_timeout natural := null, a_timeout_sec natural := null) return sys_refcursor, diff --git a/source/core/types/ut_output_reporter_base.tpb b/source/core/types/ut_output_reporter_base.tpb index 32e8b225b..3f62d6546 100644 --- a/source/core/types/ut_output_reporter_base.tpb +++ b/source/core/types/ut_output_reporter_base.tpb @@ -46,6 +46,11 @@ create or replace type body ut_output_reporter_base is self.output_buffer.send_line(a_text); end; + member procedure print_text_lines(self in out nocopy ut_output_reporter_base, a_text_lines ut_varchar2_rows) is + begin + self.output_buffer.send_lines(a_text_lines); + end; + final member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural) return ut_varchar2_rows pipelined is begin for i in (select column_value from table(self.output_buffer.get_lines(a_initial_timeout, a_timeout_sec))) loop diff --git a/source/core/types/ut_output_reporter_base.tps b/source/core/types/ut_output_reporter_base.tps index a0a9f63f6..e23ac9273 100644 --- a/source/core/types/ut_output_reporter_base.tps +++ b/source/core/types/ut_output_reporter_base.tps @@ -22,7 +22,7 @@ create or replace type ut_output_reporter_base under ut_reporter_base( overriding member procedure before_calling_run(self in out nocopy ut_output_reporter_base, a_run in ut_run), member procedure print_text(self in out nocopy ut_output_reporter_base, a_text varchar2), - + member procedure print_text_lines(self in out nocopy ut_output_reporter_base, a_text_lines ut_varchar2_rows), member procedure print_clob(self in out nocopy ut_output_reporter_base, a_clob clob), final member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_varchar2_rows pipelined, diff --git a/source/core/ut_utils.pkb b/source/core/ut_utils.pkb index 2528c04e7..d70357462 100644 --- a/source/core/ut_utils.pkb +++ b/source/core/ut_utils.pkb @@ -326,7 +326,51 @@ create or replace package body ut_utils is end if; end append_to_list; -procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, a_delimiter varchar2:= chr(10)) is + procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_items ut_varchar2_rows) is + begin + if a_items is not null then + if a_list is null then + a_list := ut_varchar2_rows(); + end if; + for i in 1 .. a_items.count loop + a_list.extend; + a_list(a_list.last) := a_items(i); + end loop; + end if; + end; + + procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_item clob) is + begin + append_to_list( + a_list, + convert_collection( + clob_to_table( a_item, ut_utils.gc_max_storage_varchar2_len ) + ) + ); + end; + + procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_item varchar2) is + l_items ut_varchar2_rows; + begin + if a_item is not null then + if a_list is null then + a_list := ut_varchar2_rows(); + end if; + if length(a_item) > gc_max_storage_varchar2_len then + append_to_list( + a_list, + ut_utils.convert_collection( + ut_utils.clob_to_table( a_item, gc_max_storage_varchar2_len ) + ) + ); + else + a_list.extend; + a_list(a_list.last) := a_item; + end if; + end if; + end append_to_list; + + procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, a_delimiter varchar2:= chr(10)) is begin if a_clob_table is not null and cardinality(a_clob_table) > 0 then if a_src_clob is null then @@ -522,7 +566,7 @@ procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, ||'?>'; end; - function trim_list_elements(a_list IN ut_varchar2_list, a_regexp_to_trim in varchar2 default '[:space:]') return ut_varchar2_list is + function trim_list_elements(a_list ut_varchar2_list, a_regexp_to_trim varchar2 default '[:space:]') return ut_varchar2_list is l_trimmed_list ut_varchar2_list; l_index integer; begin diff --git a/source/core/ut_utils.pks b/source/core/ut_utils.pks index 60f189a66..2a892c1e9 100644 --- a/source/core/ut_utils.pks +++ b/source/core/ut_utils.pks @@ -247,6 +247,21 @@ create or replace package ut_utils authid definer is */ procedure append_to_list(a_list in out nocopy ut_varchar2_list, a_item varchar2); + /** + * Append a item to the end of ut_varchar2_rows + */ + procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_item varchar2); + + /** + * Append a item to the end of ut_varchar2_rows + */ + procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_item clob); + + /** + * Append a list of items to the end of ut_varchar2_rows + */ + procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_items ut_varchar2_rows); + procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab, a_delimiter varchar2 := chr(10)); procedure append_to_clob(a_src_clob in out nocopy clob, a_new_data clob); diff --git a/source/reporters/ut_coverage_cobertura_reporter.tpb b/source/reporters/ut_coverage_cobertura_reporter.tpb index 0d702dbbd..18221e3d9 100644 --- a/source/reporters/ut_coverage_cobertura_reporter.tpb +++ b/source/reporters/ut_coverage_cobertura_reporter.tpb @@ -39,8 +39,7 @@ create or replace type body ut_coverage_cobertura_reporter is l_line_no := a_unit_coverage.lines.first; if l_line_no is null then for i in 1 .. a_unit_coverage.total_lines loop - l_file_part := ''||chr(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_clob(l_result, ''); end loop; else while l_line_no is not null loop @@ -68,71 +67,75 @@ create or replace type body ut_coverage_cobertura_reporter is function get_coverage_xml( a_coverage_data ut_coverage.t_coverage, a_run ut_run - ) return clob is + ) return ut_varchar2_rows is l_file_part varchar2(32767); - l_result clob; + l_result ut_varchar2_rows := ut_varchar2_rows(); l_unit ut_coverage.t_full_name; l_obj_name ut_coverage.t_object_name; - c_coverage_def constant varchar2(200) := ''||chr(10); - c_file_footer constant varchar2(30) := ''||chr(10); + c_coverage_def constant varchar2(200) := ''; + c_file_footer constant varchar2(30) := ''; c_coverage_footer constant varchar2(30) := ''; - c_sources_footer constant varchar2(30) := ''||chr(10); - c_packages_footer constant varchar2(30) := ''||chr(10); - c_package_footer constant varchar2(30) := ''||chr(10); - c_class_footer constant varchar2(30) := ''||chr(10); - c_lines_footer constant varchar2(30) := ''||chr(10); + c_sources_footer constant varchar2(30) := ''; + c_packages_footer constant varchar2(30) := ''; + c_package_footer constant varchar2(30) := ''; + c_class_footer constant varchar2(30) := ''; + c_lines_footer constant varchar2(30) := ''; l_epoch varchar2(50) := (sysdate - to_date('01-01-1970 00:00:00', 'dd-mm-yyyy hh24:mi:ss')) * 24 * 60 * 60; begin - dbms_lob.createtemporary(l_result,true); - - ut_utils.append_to_clob(l_result, ut_utils.get_xml_header(a_run.client_character_set)||chr(10)); - ut_utils.append_to_clob(l_result, c_coverage_def); + ut_utils.append_to_list( l_result, ut_utils.get_xml_header(a_run.client_character_set) ); + ut_utils.append_to_list( l_result, c_coverage_def ); --write header - l_file_part:= ''; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( + l_result, + '' + ); --Write sources l_unit := a_coverage_data.objects.first; - l_file_part := ''||CHR(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( l_result, '' ); while l_unit is not null loop - l_file_part := ''||dbms_xmlgen.convert(l_unit)||''||chr(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, ''||dbms_xmlgen.convert(l_unit)||''); l_unit := a_coverage_data.objects.next(l_unit); end loop; - ut_utils.append_to_clob(l_result, c_sources_footer); + ut_utils.append_to_list(l_result, c_sources_footer); --write packages l_unit := a_coverage_data.objects.first; - l_file_part := ''||CHR(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, ''); while l_unit is not null loop l_obj_name := a_coverage_data.objects(l_unit).name; - l_file_part := ''||CHR(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( + l_result, + '' + ); - l_file_part := ''||CHR(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( + l_result, + '' + ); - l_file_part := ''||CHR(10); - ut_utils.append_to_clob(l_result, l_file_part); - - dbms_lob.append(l_result,get_lines_xml(a_coverage_data.objects(l_unit))); + ut_utils.append_to_list(l_result, ''); + + ut_utils.append_to_list( l_result, get_lines_xml(a_coverage_data.objects(l_unit)) ); - ut_utils.append_to_clob(l_result, c_lines_footer); - ut_utils.append_to_clob(l_result, c_class_footer); - ut_utils.append_to_clob(l_result, c_package_footer); + ut_utils.append_to_list(l_result, c_lines_footer); + ut_utils.append_to_list(l_result, c_class_footer); + ut_utils.append_to_list(l_result, c_package_footer); l_unit := a_coverage_data.objects.next(l_unit); end loop; - ut_utils.append_to_clob(l_result, c_packages_footer); - ut_utils.append_to_clob(l_result, c_coverage_footer); + ut_utils.append_to_list(l_result, c_packages_footer); + ut_utils.append_to_list(l_result, c_coverage_footer); return l_result; end; begin @@ -140,7 +143,7 @@ create or replace type body ut_coverage_cobertura_reporter is l_coverage_data := ut_coverage.get_coverage_data(a_run.coverage_options); - self.print_clob( get_coverage_xml( l_coverage_data, a_run ) ); + self.print_text_lines( get_coverage_xml( l_coverage_data, a_run ) ); (self as ut_reporter_base).after_calling_run(a_run); end; diff --git a/source/reporters/ut_coverage_html_reporter.tpb b/source/reporters/ut_coverage_html_reporter.tpb index a6b5b4517..77d4b46ff 100644 --- a/source/reporters/ut_coverage_html_reporter.tpb +++ b/source/reporters/ut_coverage_html_reporter.tpb @@ -29,13 +29,12 @@ create or replace type body ut_coverage_html_reporter is end; overriding member procedure after_calling_run(self in out nocopy ut_coverage_html_reporter, a_run in ut_run) as - l_report_lines ut_varchar2_list; l_coverage_data ut_coverage.t_coverage; begin ut_coverage.coverage_stop(); l_coverage_data := ut_coverage.get_coverage_data(a_run.coverage_options); - self.print_clob( + self.print_text_lines( ut_coverage_report_html_helper.get_index( a_coverage_data => l_coverage_data, a_assets_path => self.assets_path, diff --git a/source/reporters/ut_coverage_report_html_helper.pkb b/source/reporters/ut_coverage_report_html_helper.pkb index 725a232f2..3ab0b1fb6 100644 --- a/source/reporters/ut_coverage_report_html_helper.pkb +++ b/source/reporters/ut_coverage_report_html_helper.pkb @@ -101,11 +101,12 @@ create or replace package body ut_coverage_report_html_helper is -function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a_unit_coverage ut_coverage.t_unit_coverage) - return clob is - l_source_code ut_varchar2_list; - l_result clob; - + function get_details_file_content( + a_object_id varchar2, + a_unit ut_object_name, + a_unit_coverage ut_coverage.t_unit_coverage + ) return ut_varchar2_rows is + function get_block_file_attributes(a_coverage_unit ut_coverage.t_unit_coverage) return varchar2 is l_result varchar2(32767); begin @@ -129,15 +130,14 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a end; function build_details_file_content(a_object_id varchar2, a_object_full_name varchar2, a_source_code ut_varchar2_list, a_coverage_unit ut_coverage.t_unit_coverage) - return clob is - l_file_part varchar2(32767); - l_result clob; - l_coverage_pct number(5, 2); + return ut_varchar2_rows is + l_file_part varchar2(32767); + l_result ut_varchar2_rows := ut_varchar2_rows(); + l_coverage_pct number(5, 2); l_coverage_block_pct number(5, 2); - l_hits varchar2(30); - l_blocks varchar2(30); + l_hits varchar2(30); + l_blocks varchar2(30); begin - dbms_lob.createtemporary(l_result, true); l_coverage_pct := coverage_pct(a_coverage_unit.covered_lines, a_coverage_unit.uncovered_lines); @@ -145,7 +145,7 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a dbms_xmlgen.convert(a_object_full_name) || '

' || l_coverage_pct || ' % lines covered

' ||get_common_file_attributes(a_coverage_unit) ||'
    '; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, l_file_part); for line_no in 1 .. a_source_code.count loop if not a_coverage_unit.lines.exists(line_no) then @@ -191,22 +191,20 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a ' || (dbms_xmlgen.convert(a_source_code(line_no))) || ''; end if; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, l_file_part); end loop; l_file_part := '
'; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, l_file_part); return l_result; end; begin - l_source_code := ut_coverage_helper.get_tmp_table_object_lines(a_unit.owner, a_unit.name); - dbms_lob.createtemporary(l_result, true); - l_result := build_details_file_content(a_object_id - ,a_unit.identity - ,l_source_code - ,a_unit_coverage - ); - return l_result; + return build_details_file_content( + a_object_id, + a_unit.identity, + ut_coverage_helper.get_tmp_table_object_lines(a_unit.owner, a_unit.name), + a_unit_coverage + ); end; function get_block_list_attributes(a_coverage_unit ut_coverage.t_coverage) return varchar2 is @@ -220,20 +218,18 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a return l_result; end; - function file_list(a_title varchar2, a_coverage ut_coverage.t_coverage) return clob is + function file_list(a_title varchar2, a_coverage ut_coverage.t_coverage) return ut_varchar2_rows is l_file_part varchar2(32767); l_title varchar2(100) := 'All files'; l_coverage_pct number(5, 2); l_coverage_block_pct number(5, 2); - l_result clob; + l_result ut_varchar2_rows; l_id varchar2(50) := object_id(a_title); l_unit_coverage ut_coverage.t_unit_coverage; l_unit ut_coverage.t_object_name; begin l_coverage_pct := coverage_pct(a_coverage.covered_lines, a_coverage.uncovered_lines); - dbms_lob.createtemporary(l_result, true); - l_file_part := '
' || '

' || l_title || '' || ' (' || l_coverage_pct || '%' || ' lines covered'|| @@ -251,7 +247,7 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a 'File% coveredLinesRelevant LinesLines coveredLines missed' ||'Avg. Hits / Line ' || ''; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( l_result, l_file_part ); l_unit := a_coverage.objects.first; loop exit when l_unit is null; @@ -266,11 +262,11 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a '' || to_char(executions_per_line(l_unit_coverage.executions ,l_unit_coverage.uncovered_lines + l_unit_coverage.covered_lines)) || ''; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( l_result, l_file_part ); l_unit := a_coverage.objects.next(l_unit); end loop; l_file_part := '

'; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list( l_result, l_file_part ); return l_result; end; @@ -283,10 +279,10 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a a_project_name varchar2 := null, a_command_line varchar2 := null, a_charset varchar2 := null - ) return clob is + ) return ut_varchar2_rows is l_file_part varchar2(32767); - l_result clob; + l_result ut_varchar2_rows := ut_varchar2_rows(); l_title varchar2(250); l_coverage_pct number(5, 2); l_time_str varchar2(50); @@ -302,8 +298,6 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a when a_command_line is not null then '
using ' || dbms_xmlgen.convert(a_command_line) end; - dbms_lob.createtemporary(l_result, true); - l_title := case when a_project_name is null then 'Code coverage' @@ -323,32 +317,35 @@ function get_details_file_content(a_object_id varchar2, a_unit ut_object_name, a ''; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, l_file_part); return l_result; end; diff --git a/source/reporters/ut_coverage_report_html_helper.pks b/source/reporters/ut_coverage_report_html_helper.pks index d140588ad..bc4d025f3 100644 --- a/source/reporters/ut_coverage_report_html_helper.pks +++ b/source/reporters/ut_coverage_report_html_helper.pks @@ -37,7 +37,7 @@ create or replace package ut_coverage_report_html_helper authid current_user is a_project_name varchar2 := null, a_command_line varchar2 := null, a_charset varchar2 := null - ) return clob; + ) return ut_varchar2_rows; end; / diff --git a/source/reporters/ut_coverage_sonar_reporter.tpb b/source/reporters/ut_coverage_sonar_reporter.tpb index 249736f92..fcc213665 100644 --- a/source/reporters/ut_coverage_sonar_reporter.tpb +++ b/source/reporters/ut_coverage_sonar_reporter.tpb @@ -26,73 +26,72 @@ create or replace type body ut_coverage_sonar_reporter is overriding member procedure after_calling_run(self in out nocopy ut_coverage_sonar_reporter, a_run in ut_run) as - l_report_lines ut_varchar2_list; - l_coverage_data ut_coverage.t_coverage; - function get_lines_xml(a_unit_coverage ut_coverage.t_unit_coverage) return clob is + + function get_lines_xml(a_unit_coverage ut_coverage.t_unit_coverage) return ut_varchar2_rows is l_file_part varchar2(32767); - l_result clob; + l_result ut_varchar2_rows := ut_varchar2_rows(); l_line_no binary_integer; begin - dbms_lob.createtemporary(l_result, true); l_line_no := a_unit_coverage.lines.first; if l_line_no is null then for i in 1 .. a_unit_coverage.total_lines loop - l_file_part := ''||chr(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, ''); end loop; else while l_line_no is not null loop if a_unit_coverage.lines(l_line_no).executions = 0 then - l_file_part := ''||chr(10); + l_file_part := ''; else l_file_part := ''||chr(10); + l_file_part := l_file_part ||'/>'; end if; - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, l_file_part); l_line_no := a_unit_coverage.lines.next(l_line_no); end loop; end if; return l_result; end; + function get_coverage_xml( a_coverage_data ut_coverage.t_coverage, a_run ut_run - ) return clob is - l_file_part varchar2(32767); - l_result clob; + ) return ut_varchar2_rows is + l_result ut_varchar2_rows := ut_varchar2_rows(); l_unit ut_coverage.t_full_name; - c_coverage_header constant varchar2(30) := ''||chr(10); - c_file_footer constant varchar2(30) := ''||chr(10); + c_coverage_header constant varchar2(30) := ''; + c_file_footer constant varchar2(30) := ''; c_coverage_footer constant varchar2(30) := ''; - begin - dbms_lob.createtemporary(l_result,true); + begin - ut_utils.append_to_clob(l_result, ut_utils.get_xml_header(a_run.client_character_set)||chr(10)); - ut_utils.append_to_clob(l_result, c_coverage_header); - l_unit := a_coverage_data.objects.first; - while l_unit is not null loop - l_file_part := ''||chr(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, ut_utils.get_xml_header(a_run.client_character_set)); + ut_utils.append_to_list(l_result, c_coverage_header); + l_unit := a_coverage_data.objects.first; + while l_unit is not null loop + ut_utils.append_to_list(l_result, ''); - dbms_lob.append(l_result,get_lines_xml(a_coverage_data.objects(l_unit))); + ut_utils.append_to_list(l_result,get_lines_xml(a_coverage_data.objects(l_unit))); - ut_utils.append_to_clob(l_result, c_file_footer); + ut_utils.append_to_list(l_result, c_file_footer); - l_unit := a_coverage_data.objects.next(l_unit); - end loop; - ut_utils.append_to_clob(l_result, c_coverage_footer); - return l_result; - end; + l_unit := a_coverage_data.objects.next(l_unit); + end loop; + ut_utils.append_to_list(l_result, c_coverage_footer); + return l_result; + end; + begin ut_coverage.coverage_stop(); - l_coverage_data := ut_coverage.get_coverage_data(a_run.coverage_options); - - self.print_clob( get_coverage_xml( l_coverage_data, a_run ) ); + self.print_text_lines( + get_coverage_xml( + ut_coverage.get_coverage_data(a_run.coverage_options), + a_run + ) + ); end; overriding member function get_description return varchar2 as diff --git a/source/reporters/ut_coveralls_reporter.tpb b/source/reporters/ut_coveralls_reporter.tpb index 3681147f3..8be96715f 100644 --- a/source/reporters/ut_coveralls_reporter.tpb +++ b/source/reporters/ut_coveralls_reporter.tpb @@ -25,22 +25,19 @@ create or replace type body ut_coveralls_reporter is end; overriding member procedure after_calling_run(self in out nocopy ut_coveralls_reporter, a_run in ut_run) as - l_report_lines ut_varchar2_list; - l_coverage_data ut_coverage.t_coverage; - function get_lines_json(a_unit_coverage ut_coverage.t_unit_coverage) return clob is + function get_lines_json(a_unit_coverage ut_coverage.t_unit_coverage) return ut_varchar2_rows is l_file_part varchar2(32767); - l_result clob; + l_result ut_varchar2_rows := ut_varchar2_rows(); l_last_line_no binary_integer; c_coverage_header constant varchar2(30) := '"coverage": ['; c_null constant varchar2(4) := 'null'; begin - dbms_lob.createtemporary(l_result, true); - ut_utils.append_to_clob(l_result, c_coverage_header); + ut_utils.append_to_list(l_result, c_coverage_header); l_last_line_no := a_unit_coverage.lines.last; if l_last_line_no is null then - ut_utils.append_to_clob( + ut_utils.append_to_list( l_result , rpad( to_clob( '0' ), ( a_unit_coverage.total_lines * 3 ) - 2, ','||chr(10)||'0' ) ); @@ -54,48 +51,47 @@ create or replace type body ut_coveralls_reporter is if line_no < l_last_line_no then l_file_part := l_file_part ||','; end if; - ut_utils.append_to_clob(l_result, l_file_part||chr(10)); + ut_utils.append_to_list(l_result, l_file_part); end loop; end if; - ut_utils.append_to_clob(l_result, ']'); + ut_utils.append_to_list(l_result, ']'); return l_result; end; function get_coverage_json( a_coverage_data ut_coverage.t_coverage - ) return clob is + ) return ut_varchar2_rows is l_file_part varchar2(32767); - l_result clob; + l_result ut_varchar2_rows := ut_varchar2_rows(); l_unit ut_coverage.t_full_name; - c_coverage_header constant varchar2(30) := '{"source_files":['||chr(10); - c_coverage_footer constant varchar2(30) := ']}'||chr(10)||chr(10)||chr(10)||chr(10)||' '; - begin - dbms_lob.createtemporary(l_result,true); - - ut_utils.append_to_clob(l_result, c_coverage_header); + c_coverage_header constant varchar2(30) := '{"source_files":['; + c_coverage_footer constant varchar2(30) := ']}'||chr(10)||' '; + begin + ut_utils.append_to_list(l_result, c_coverage_header); l_unit := a_coverage_data.objects.first; while l_unit is not null loop - l_file_part := '{ "name": "'||l_unit||'",'||chr(10); - ut_utils.append_to_clob(l_result, l_file_part); + ut_utils.append_to_list(l_result, '{ "name": "'||l_unit||'",'); - dbms_lob.append(l_result,get_lines_json(a_coverage_data.objects(l_unit))); + ut_utils.append_to_list(l_result,get_lines_json(a_coverage_data.objects(l_unit))); - ut_utils.append_to_clob(l_result, '}'); + ut_utils.append_to_list(l_result, '}'); l_unit := a_coverage_data.objects.next(l_unit); if l_unit is not null then - ut_utils.append_to_clob(l_result, ','||chr(10)); + ut_utils.append_to_list(l_result, ','); end if; end loop; - ut_utils.append_to_clob(l_result, c_coverage_footer); + ut_utils.append_to_list(l_result, c_coverage_footer); return l_result; end; begin ut_coverage.coverage_stop(); - l_coverage_data := ut_coverage.get_coverage_data(a_run.coverage_options); - - self.print_clob( get_coverage_json( l_coverage_data ) ); + self.print_text_lines( + get_coverage_json( + ut_coverage.get_coverage_data(a_run.coverage_options) + ) + ); end; overriding member function get_description return varchar2 as diff --git a/source/reporters/ut_junit_reporter.tpb b/source/reporters/ut_junit_reporter.tpb index 63d256aab..bc88aa8af 100644 --- a/source/reporters/ut_junit_reporter.tpb +++ b/source/reporters/ut_junit_reporter.tpb @@ -35,48 +35,54 @@ create or replace type body ut_junit_reporter is end; procedure print_test_elements(a_test ut_test) is - l_lines ut_varchar2_list; + l_results ut_varchar2_rows := ut_varchar2_rows(); + l_lines ut_varchar2_list; l_output clob; begin - self.print_text(''); + ut_utils.append_to_list( + l_results, + '' + ); if a_test.result = ut_utils.gc_disabled then - self.print_text(''); + ut_utils.append_to_list( l_results, '' ); end if; if a_test.result = ut_utils.gc_error then - self.print_text(''); - self.print_text(c_cddata_tag_start); - self.print_clob(ut_utils.table_to_clob(a_test.get_error_stack_traces())); - self.print_text(c_cddata_tag_end); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, c_cddata_tag_start); + ut_utils.append_to_list( l_results, ut_utils.convert_collection(a_test.get_error_stack_traces()) ); + ut_utils.append_to_list( l_results, c_cddata_tag_end); + ut_utils.append_to_list( l_results, ''); elsif a_test.result > ut_utils.gc_success then - self.print_text(''); + ut_utils.append_to_list( l_results, ''); for i in 1 .. a_test.failed_expectations.count loop l_lines := a_test.failed_expectations(i).get_result_lines(); for j in 1 .. l_lines.count loop - self.print_text(dbms_xmlgen.convert(l_lines(j))); + ut_utils.append_to_list( l_results, dbms_xmlgen.convert(l_lines(j)) ); end loop; - self.print_text(dbms_xmlgen.convert(a_test.failed_expectations(i).caller_info)); + ut_utils.append_to_list( l_results, dbms_xmlgen.convert(a_test.failed_expectations(i).caller_info) ); end loop; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; -- TODO - decide if we need/want to use the tag too l_output := a_test.get_serveroutputs(); if l_output is not null then - self.print_text(''); - self.print_text(c_cddata_tag_start); - self.print_clob(l_output); - self.print_text(c_cddata_tag_end); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, c_cddata_tag_start); + ut_utils.append_to_list( l_results, l_output); + ut_utils.append_to_list( l_results, c_cddata_tag_end ); + ut_utils.append_to_list( l_results, '' ); else - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; - self.print_text(''); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); + + self.print_text_lines(l_results); end; procedure print_suite_elements(a_suite ut_logical_suite, a_suite_id in out nocopy integer) is @@ -84,6 +90,7 @@ create or replace type body ut_junit_reporter is a_suite.results_count.failure_count + a_suite.results_count.errored_count; l_suite ut_suite; l_tests ut_suite_items := ut_suite_items(); + l_results ut_varchar2_rows := ut_varchar2_rows(); l_data clob; l_errors ut_varchar2_list; begin @@ -111,28 +118,31 @@ create or replace type body ut_junit_reporter is l_data := l_suite.get_serveroutputs(); if l_data is not null and l_data != empty_clob() then - self.print_text(''); - self.print_text(c_cddata_tag_start); - self.print_clob(l_data); - self.print_text(c_cddata_tag_end); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, c_cddata_tag_start); + ut_utils.append_to_list( l_results, l_data); + ut_utils.append_to_list( l_results, c_cddata_tag_end); + ut_utils.append_to_list( l_results, ''); else - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; l_errors := l_suite.get_error_stack_traces(); if l_errors is not empty then - self.print_text(''); - self.print_text(c_cddata_tag_start); - self.print_clob(ut_utils.table_to_clob(l_errors)); - self.print_text(c_cddata_tag_end); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, c_cddata_tag_start); + ut_utils.append_to_list( l_results, ut_utils.table_to_clob(l_errors)); + ut_utils.append_to_list( l_results, c_cddata_tag_end); + ut_utils.append_to_list( l_results, ''); else - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; end if; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + + self.print_text_lines(l_results); end; + begin l_suite_id := 0; self.print_text(ut_utils.get_xml_header(a_run.client_character_set)); diff --git a/source/reporters/ut_sonar_test_reporter.tpb b/source/reporters/ut_sonar_test_reporter.tpb index 913ae8b50..1da349d83 100644 --- a/source/reporters/ut_sonar_test_reporter.tpb +++ b/source/reporters/ut_sonar_test_reporter.tpb @@ -43,28 +43,31 @@ create or replace type body ut_sonar_test_reporter is end; procedure print_test_results(a_test ut_test) is - l_lines ut_varchar2_list; + l_results ut_varchar2_rows := ut_varchar2_rows(); + l_lines ut_varchar2_list; begin - self.print_text(''); + ut_utils.append_to_list( l_results, ''); if a_test.result = ut_utils.gc_disabled then - self.print_text(''); + ut_utils.append_to_list( l_results, ''); elsif a_test.result = ut_utils.gc_error then - self.print_text(''); - self.print_text(''); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); elsif a_test.result > ut_utils.gc_success then - self.print_text(''); + ut_utils.append_to_list( l_results, ''); for i in 1 .. a_test.failed_expectations.count loop l_lines := a_test.failed_expectations(i).get_result_lines(); for i in 1 .. l_lines.count loop - self.print_text(dbms_xmlgen.convert(l_lines(i))); + ut_utils.append_to_list( l_results, dbms_xmlgen.convert(l_lines(i))); end loop; end loop; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + + self.print_text_lines(l_results); end; procedure print_suite_results(a_suite ut_logical_suite, a_file_mappings ut_file_mappings) is diff --git a/source/reporters/ut_teamcity_reporter.tpb b/source/reporters/ut_teamcity_reporter.tpb index 086775254..a8a7ad45b 100644 --- a/source/reporters/ut_teamcity_reporter.tpb +++ b/source/reporters/ut_teamcity_reporter.tpb @@ -57,6 +57,7 @@ create or replace type body ut_teamcity_reporter is end; overriding member procedure after_calling_test(self in out nocopy ut_teamcity_reporter, a_test in ut_test) is + l_results ut_varchar2_rows := ut_varchar2_rows(); l_test_full_name varchar2(4000); l_std_err_msg varchar2(32767); begin @@ -64,10 +65,10 @@ create or replace type body ut_teamcity_reporter is lower(a_test.item.procedure_name); if a_test.result = ut_utils.gc_disabled then - self.print_text(ut_teamcity_reporter_helper.test_disabled(l_test_full_name)); + ut_utils.append_to_list( l_results, ut_teamcity_reporter_helper.test_disabled(l_test_full_name)); else - self.print_clob(a_test.get_serveroutputs()); + ut_utils.append_to_list( l_results, a_test.get_serveroutputs()); if a_test.result = ut_utils.gc_error then for i in 1 .. a_test.before_each_list.count loop @@ -98,27 +99,52 @@ create or replace type body ut_teamcity_reporter is end if; end loop; - self.print_text(ut_teamcity_reporter_helper.test_std_err(a_test_name => l_test_full_name - ,a_out => trim(l_std_err_msg))); - self.print_text(ut_teamcity_reporter_helper.test_failed(a_test_name => l_test_full_name - ,a_msg => 'Error occured' - ,a_details => trim(l_std_err_msg) || case when a_test.failed_expectations is not null and a_test.failed_expectations.count>0 then a_test.failed_expectations(1) - .message end)); + ut_utils.append_to_list( + l_results, + ut_teamcity_reporter_helper.test_std_err( + a_test_name => l_test_full_name, + a_out => trim(l_std_err_msg) + ) + ); + ut_utils.append_to_list( + l_results, + ut_teamcity_reporter_helper.test_failed( + a_test_name => l_test_full_name, + a_msg => 'Error occured', + a_details => + trim(l_std_err_msg) + || case when a_test.failed_expectations is not null + and a_test.failed_expectations.count>0 + then a_test.failed_expectations(1).message end + ) + ); elsif a_test.failed_expectations is not null and a_test.failed_expectations.count > 0 then -- Teamcity supports only a single failure message - self.print_text(ut_teamcity_reporter_helper.test_failed(a_test_name => l_test_full_name - ,a_msg => a_test.failed_expectations(a_test.failed_expectations.first).description - ,a_details => a_test.failed_expectations(a_test.failed_expectations.first).message )); + ut_utils.append_to_list( + l_results, + ut_teamcity_reporter_helper.test_failed( + a_test_name => l_test_full_name, + a_msg => a_test.failed_expectations(a_test.failed_expectations.first).description, + a_details => a_test.failed_expectations(a_test.failed_expectations.first).message ) + ); elsif a_test.result = ut_utils.gc_failure then - self.print_text(ut_teamcity_reporter_helper.test_failed(a_test_name => l_test_full_name - ,a_msg => 'Test failed')); + ut_utils.append_to_list( + l_results, + ut_teamcity_reporter_helper.test_failed( + a_test_name => l_test_full_name, + a_msg => 'Test failed' + ) + ); end if; - self.print_text(ut_teamcity_reporter_helper.test_finished(l_test_full_name, trunc(a_test.execution_time * 1e3))); + ut_utils.append_to_list( + l_results, + ut_teamcity_reporter_helper.test_finished(l_test_full_name, trunc(a_test.execution_time * 1e3)) + ); end if; - + self.print_text_lines(l_results); end; overriding member function get_description return varchar2 as diff --git a/source/reporters/ut_tfs_junit_reporter.tpb b/source/reporters/ut_tfs_junit_reporter.tpb index d3edd1208..5f3770b23 100644 --- a/source/reporters/ut_tfs_junit_reporter.tpb +++ b/source/reporters/ut_tfs_junit_reporter.tpb @@ -54,8 +54,8 @@ create or replace type body ut_tfs_junit_reporter is end; procedure print_test_results(a_test ut_test) is - l_lines ut_varchar2_list; - l_output clob; + l_results ut_varchar2_rows := ut_varchar2_rows(); + l_lines ut_varchar2_list; begin self.print_text(''); @@ -68,30 +68,33 @@ create or replace type body ut_tfs_junit_reporter is */ if a_test.result = ut_utils.gc_error then - self.print_text(''); - self.print_text(''); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); -- Do not count error as failure elsif a_test.result = ut_utils.gc_failure then - self.print_text(''); + ut_utils.append_to_list( l_results, ''); for i in 1 .. a_test.failed_expectations.count loop l_lines := a_test.failed_expectations(i).get_result_lines(); for j in 1 .. l_lines.count loop - self.print_text(dbms_xmlgen.convert(l_lines(j))); + ut_utils.append_to_list( l_results, dbms_xmlgen.convert(l_lines(j))); end loop; - self.print_text(dbms_xmlgen.convert(a_test.failed_expectations(i).caller_info)); + ut_utils.append_to_list( l_results, dbms_xmlgen.convert(a_test.failed_expectations(i).caller_info)); end loop; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + + self.print_text_lines(l_results); end; procedure print_suite_results(a_suite ut_logical_suite, a_suite_id in out nocopy integer) is l_tests_count integer := a_suite.results_count.disabled_count + a_suite.results_count.success_count + a_suite.results_count.failure_count + a_suite.results_count.errored_count; + l_results ut_varchar2_rows := ut_varchar2_rows(); l_suite ut_suite; l_outputs clob; l_errors ut_varchar2_list; @@ -116,26 +119,28 @@ create or replace type body ut_tfs_junit_reporter is l_suite := treat(a_suite as ut_suite); l_outputs := l_suite.get_serveroutputs(); if l_outputs is not null and l_outputs != empty_clob() then - self.print_text(''); - self.print_text(''); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); else - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; l_errors := l_suite.get_error_stack_traces(); if l_errors is not empty then - self.print_text(''); - self.print_text(''); - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); + ut_utils.append_to_list( l_results, ''); else - self.print_text(''); + ut_utils.append_to_list( l_results, ''); end if; - self.print_text(''); + ut_utils.append_to_list( l_results, ''); + + self.print_text_lines(l_results); end if; end; diff --git a/test/core/reporters/test_coverage/test_cov_cobertura_reporter.pkb b/test/core/reporters/test_coverage/test_cov_cobertura_reporter.pkb index e89fbd283..cabf64e90 100644 --- a/test/core/reporters/test_coverage/test_cov_cobertura_reporter.pkb +++ b/test/core/reporters/test_coverage/test_cov_cobertura_reporter.pkb @@ -7,9 +7,10 @@ create or replace package body test_cov_cobertura_reporter is begin --Arrange l_expected := - ' + q'[ - + + test/ut3.dummy_coverage.pkb @@ -23,7 +24,7 @@ create or replace package body test_cov_cobertura_reporter is
-
'; +
]'; --Act select * bulk collect into l_results diff --git a/test/core/reporters/test_coverage/test_coveralls_reporter.pkb b/test/core/reporters/test_coverage/test_coveralls_reporter.pkb index 3b6b88346..774e796a0 100644 --- a/test/core/reporters/test_coverage/test_coveralls_reporter.pkb +++ b/test/core/reporters/test_coverage/test_coveralls_reporter.pkb @@ -8,14 +8,17 @@ create or replace package body test_coveralls_reporter is --Arrange l_expected := q'[{"source_files":[ { "name": "test/ut3.dummy_coverage.pkb", -"coverage": [null, +"coverage": [ +null, null, null, 1, 0, null, 1 -]}]} +] +} +]} ]'; --Act select * @@ -42,7 +45,8 @@ null, --Arrange l_expected := q'[{"source_files":[ { "name": "ut3.dummy_coverage", -"coverage": [0, +"coverage": [ +0, 0, 0, 0, @@ -51,7 +55,10 @@ null, 0, 0, 0, -0]}]} +0 +] +} +]} ]'; test_coverage.cleanup_dummy_coverage; From 9ea805b61eb7392deed411da6b04fe5fdcc4ccd8 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Mon, 12 Nov 2018 01:37:48 +0000 Subject: [PATCH 15/33] Increased fetch size for coverage sources tmp seeding. --- source/core/coverage/ut_coverage.pkb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/core/coverage/ut_coverage.pkb b/source/core/coverage/ut_coverage.pkb index 64d625d84..06a738f0c 100644 --- a/source/core/coverage/ut_coverage.pkb +++ b/source/core/coverage/ut_coverage.pkb @@ -135,7 +135,7 @@ create or replace package body ut_coverage is l_cov_sources_crsr := get_cov_sources_cursor(a_coverage_options,a_sql); loop - fetch l_cov_sources_crsr bulk collect into l_cov_sources_data limit 1000; + fetch l_cov_sources_crsr bulk collect into l_cov_sources_data limit 10000; ut_coverage_helper.insert_into_tmp_table(l_cov_sources_data); From 248bf8c7c4f50195ef33865a657e7bf3904fa596 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Tue, 13 Nov 2018 00:56:43 +0000 Subject: [PATCH 16/33] Small refactoring. Adding new function to return list of suites and tests. --- source/core/ut_suite_manager.pkb | 215 +++++++++++++++++++++++-------- source/core/ut_suite_manager.pks | 15 +++ 2 files changed, 177 insertions(+), 53 deletions(-) diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index 5e296f02e..82376a846 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -149,7 +149,7 @@ create or replace package body ut_suite_manager is return l_results; end; - procedure copy_list_reverse_order( + procedure reverse_list_order( a_list in out nocopy ut_suite_items ) is l_start_idx pls_integer; @@ -277,9 +277,14 @@ create or replace package body ut_suite_manager is end loop; exit when l_rows.count < c_bulk_limit; end loop; - copy_list_reverse_order( a_suites ); + + reverse_list_order( a_suites ); + + for i in 1 .. a_suites.count loop + a_suites( i ).set_rollback_type( a_suites( i ).get_rollback_type ); + end loop; close a_suite_data_cursor; - end; + end reconstruct_from_cache; function get_missing_objects(a_object_owner varchar2) return ut_varchar2_rows is l_rows sys_refcursor; @@ -338,7 +343,7 @@ create or replace package body ut_suite_manager is ( select 1 from all_objects a where a.object_name = c.object_name - and a.object_owner = ']'||upper(a_object_owner)||q'[' + and a.owner = ']'||upper(a_object_owner)||q'[' and a.owner = c.object_owner and a.object_type = 'PACKAGE' )]' end ||q'[ @@ -417,44 +422,91 @@ create or replace package body ut_suite_manager is return l_result; end; - function build_schema_suites( - a_owner_name varchar2, - a_path varchar2 := null, - a_object_name varchar2 := null, - a_procedure_name varchar2 := null - ) return ut_suite_items is + function can_skip_all_objects_scan( + a_owner_name varchar2 + ) return boolean is + begin + return sys_context( 'userenv', 'current_schema' ) = a_owner_name or ut_metadata.is_object_visible( ut_utils.ut_owner ||'.ut_utils' ); + end; + + procedure build_and_cache_suites( + a_owner_name varchar2, + a_annotated_objects sys_refcursor + ) is + l_annotated_objects ut_annotated_objects; + l_suite_items ut_suite_items; + begin + loop + fetch a_annotated_objects bulk collect into l_annotated_objects limit 10; + + for i in 1 .. l_annotated_objects.count loop + ut_suite_builder.create_suite_item_list( l_annotated_objects( i ), l_suite_items ); + ut_suite_cache_manager.save_object_cache( + a_owner_name, + l_annotated_objects( i ).object_name, + l_annotated_objects( i ).parse_time, + l_suite_items + ); + end loop; + exit when a_annotated_objects%notfound; + end loop; + close a_annotated_objects; + + end; + + procedure refresh_cache( + a_owner_name varchar2, + a_annotations_cursor sys_refcursor := null + ) is l_annotations_cursor sys_refcursor; l_suite_cache_time timestamp; - l_skip_all_objects_scan boolean := false; begin l_suite_cache_time := ut_suite_cache_manager.get_schema_parse_time(a_owner_name); - open l_annotations_cursor for - q'[select value(x) - from table( - ]' || ut_utils.ut_owner || q'[.ut_annotation_manager.get_annotated_objects(:a_owner_name, 'PACKAGE', :a_suite_cache_parse_time) - )x ]' - using a_owner_name, l_suite_cache_time; - - -- if current user is the onwer or current user has execute any procedure privilege - if sys_context('userenv','current_schema') = a_owner_name - or ut_metadata.is_object_visible('ut3.ut_utils') - then - l_skip_all_objects_scan := true; + if a_annotations_cursor is not null then + l_annotations_cursor := a_annotations_cursor; + else + open l_annotations_cursor for + q'[select value(x) + from table( + ]' || ut_utils.ut_owner || q'[.ut_annotation_manager.get_annotated_objects( + :a_owner_name, 'PACKAGE', :a_suite_cache_parse_time + ) + )x ]' + using a_owner_name, l_suite_cache_time; end if; - if l_skip_all_objects_scan or ut_metadata.is_object_visible('dba_objects') then + + build_and_cache_suites(a_owner_name, l_annotations_cursor); + + if can_skip_all_objects_scan(a_owner_name) or ut_metadata.is_object_visible( 'dba_objects') then ut_suite_cache_manager.remove_from_cache( a_owner_name, get_missing_objects(a_owner_name) ); end if; - return build_suites_from_annotations( - a_owner_name, - l_annotations_cursor, - a_path, - a_object_name, - a_procedure_name, - l_skip_all_objects_scan - ); end; + function get_suites_for_path( + a_owner_name varchar2, + a_path varchar2 := null, + a_object_name varchar2 := null, + a_procedure_name varchar2 := null + ) return ut_suite_items is + l_suites ut_suite_items; + begin + refresh_cache(a_owner_name); + + reconstruct_from_cache( + l_suites, + get_cached_suite_data( + a_owner_name, + a_path, + a_object_name, + a_procedure_name, + can_skip_all_objects_scan(a_owner_name) + ) + ); + return l_suites; + + end get_suites_for_path; + ----------------------------------------------- ----------------------------------------------- ------------- Public definitions ------------- @@ -468,24 +520,8 @@ create or replace package body ut_suite_manager is a_skip_all_objects boolean := false ) return ut_suite_items is l_suites ut_suite_items; - l_annotated_objects ut_annotated_objects; - l_suite_items ut_suite_items; begin - loop - fetch a_annotated_objects bulk collect into l_annotated_objects limit 10; - - for i in 1 .. l_annotated_objects.count loop - ut_suite_builder.create_suite_item_list( l_annotated_objects( i ), l_suite_items ); - ut_suite_cache_manager.save_object_cache( - a_owner_name, - l_annotated_objects( i ).object_name, - l_annotated_objects( i ).parse_time, - l_suite_items - ); - end loop; - exit when a_annotated_objects%notfound; - end loop; - close a_annotated_objects; + build_and_cache_suites(a_owner_name, a_annotated_objects); reconstruct_from_cache( l_suites, @@ -497,9 +533,6 @@ create or replace package body ut_suite_manager is a_skip_all_objects ) ); - for i in 1 .. l_suites.count loop - l_suites( i ).set_rollback_type( l_suites( i ).get_rollback_type ); - end loop; return l_suites; end; @@ -566,7 +599,7 @@ create or replace package body ut_suite_manager is l_path_items := l_schema_paths(l_schema); for i in 1 .. l_path_items.count loop l_path_item := l_path_items(i); - l_suites := build_schema_suites( + l_suites := get_suites_for_path( upper(l_schema), l_path_item.suite_path, l_path_item.object_name, @@ -599,5 +632,81 @@ create or replace package body ut_suite_manager is return l_objects_to_run; end configure_execution_by_path; + function get_suites_info(a_owner_name varchar2) return tt_suite_items pipelined is + l_cursor sys_refcursor; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + c_bulk_limit constant integer := 100; + l_results tt_suite_items; + begin + refresh_cache(a_owner_name); + + open l_cursor for + q'[with + suite_items as ( + select /*+ cardinality(c 100) */ c.* + from ]'||l_ut_owner||q'[.ut_suite_cache c + where 1 = 1 ]'||case when can_skip_all_objects_scan(a_owner_name) then q'[ + and exists + ( select 1 + from all_objects a + where a.object_name = c.object_name + and a.owner = ']'||upper(a_owner_name)||q'[' + and a.owner = c.object_owner + and a.object_type = 'PACKAGE' + )]' end ||q'[ + and c.object_owner = ']'||upper(a_owner_name)||q'[' + ), + suitepaths as ( + select distinct + substr(path,1,instr(path,'.',-1)-1) as suitepath, + path, + object_owner + from suite_items + where self_type = 'UT_SUITE' + ), + gen as ( + select rownum as pos + from xmltable('1 to 20') + ), + suitepath_part AS ( + select distinct + substr(b.suitepath, 1, instr(b.suitepath || '.', '.', 1, g.pos) -1) as path, + object_owner + from suitepaths b + join gen g + on g.pos <= regexp_count(b.suitepath, '\w+') + ), + logical_suites as ( + select 'UT_LOGICAL_SUITE' as item_type, + p.path, p.object_owner, + upper( substr(p.path, instr( p.path, '.', -1 ) + 1 ) ) as object_name + from suitepath_part p + where p.path + not in (select s.path from suitepaths s) + ), + items as ( + select object_owner, object_name, name as item_name, + description as item_description, self_type as item_type, line_no as item_line_no, + path, disabled_flag + from suite_items + union all + select object_owner, object_name, object_name as item_name, + null as item_description, item_type, null as item_line_no, + s.path, 0 as disabled_flag + from logical_suites s + ) + select c.* + from items c]'; + loop + fetch l_cursor bulk collect into l_results limit c_bulk_limit; + for i in 1 .. l_results.count loop + pipe row (l_results(i)); + end loop; + exit when l_cursor%notfound; + end loop; + close l_cursor; + + end; + end ut_suite_manager; / diff --git a/source/core/ut_suite_manager.pks b/source/core/ut_suite_manager.pks index 22c27fea9..65440b22b 100644 --- a/source/core/ut_suite_manager.pks +++ b/source/core/ut_suite_manager.pks @@ -59,6 +59,21 @@ create or replace package ut_suite_manager authid current_user is a_skip_all_objects boolean := false ) return ut_suite_items; + type t_suite_item_rec is record ( + object_owner varchar2(250), + object_name varchar2(250), + item_name varchar2(250), + item_description varchar2(250), + item_type varchar2(250), + item_line_no varchar2(250), + path varchar2(4000), + disabled_flag integer + ); + + type tt_suite_items is table of t_suite_item_rec; + + function get_suites_info(a_owner_name varchar2) return tt_suite_items pipelined; + end ut_suite_manager; / From 8fc2ea6e3364ad9e1180700f8e214641089ec09d Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Thu, 15 Nov 2018 00:25:39 +0000 Subject: [PATCH 17/33] Further optimizations to suite parsing. Changed functions to procedures to avoid copying of large memmory segments. --- source/api/ut_runner.pkb | 3 +- .../core/annotations/ut_annotation_parser.pkb | 2 +- source/core/ut_suite_cache_manager.pkb | 7 +- source/core/ut_suite_manager.pkb | 200 +++++++++++------- source/core/ut_suite_manager.pks | 9 + 5 files changed, 136 insertions(+), 85 deletions(-) diff --git a/source/api/ut_runner.pkb b/source/api/ut_runner.pkb index c04fa5112..3a2d6583b 100644 --- a/source/api/ut_runner.pkb +++ b/source/api/ut_runner.pkb @@ -128,7 +128,7 @@ create or replace package body ut_runner is l_include_object_names := to_ut_object_list(a_include_objects, l_coverage_schema_names); l_run := ut_run( - ut_suite_manager.configure_execution_by_path(l_paths), + null, l_paths, l_coverage_schema_names, l_exclude_object_names, @@ -137,6 +137,7 @@ create or replace package body ut_runner is set(a_test_file_mappings), a_client_character_set ); + ut_suite_manager.configure_execution_by_path(l_paths, l_run.items); l_run.do_execute(); finish_run(l_run); diff --git a/source/core/annotations/ut_annotation_parser.pkb b/source/core/annotations/ut_annotation_parser.pkb index 2467c6262..aec9e7585 100644 --- a/source/core/annotations/ut_annotation_parser.pkb +++ b/source/core/annotations/ut_annotation_parser.pkb @@ -155,7 +155,7 @@ create or replace package body ut_annotation_parser as -- position index is shifted by 1 because gc_annot_comment_pattern contains ^ as first sign -- but after instr index already points to the char on that line l_comment_pos := l_comment_pos-1; - l_comment_line := regexp_count(substr(a_source,1,l_comment_pos),chr(10),1,'m')+1; + l_comment_line := length(substr(a_source,1,l_comment_pos))-length(replace(substr(a_source,1,l_comment_pos),chr(10)))+1; l_comments(l_comment_line) := trim(regexp_substr(srcstr => a_source ,pattern => gc_annot_comment_pattern ,occurrence => 1 diff --git a/source/core/ut_suite_cache_manager.pkb b/source/core/ut_suite_cache_manager.pkb index 081b2d590..ba51a242f 100644 --- a/source/core/ut_suite_cache_manager.pkb +++ b/source/core/ut_suite_cache_manager.pkb @@ -138,8 +138,11 @@ create or replace package body ut_suite_cache_manager is procedure remove_from_cache(a_schema_name varchar2, a_objects ut_varchar2_rows) is pragma autonomous_transaction; begin - delete - from ut_suite_cache_package i + delete from ut_suite_cache i + where i.object_owner = a_schema_name + and i.object_name in ( select column_value from table (a_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 (a_objects) ); diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index 82376a846..4c2d06ab9 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -29,6 +29,7 @@ create or replace package body ut_suite_manager is type tt_cached_suites is table of t_cached_suite; type t_cached_suites_cursor is ref cursor return t_cached_suite; + type t_item_levels is table of ut_suite_items index by binary_integer; ------------------ procedure validate_paths(a_paths in ut_varchar2_list) is @@ -167,33 +168,19 @@ create or replace package body ut_suite_manager is end loop; end; - procedure reconstruct_from_cache( - a_suites out nocopy ut_suite_items, - a_suite_data_cursor sys_refcursor - ) is - type t_item_levels is table of ut_suite_items index by binary_integer; - c_bulk_limit constant pls_integer := 1000; - l_items_at_level t_item_levels; - l_rows tt_cached_suites; - l_test ut_test; - l_logical_suite ut_logical_suite; - l_level pls_integer; - l_prev_level pls_integer; - l_idx integer; + function get_logical_suite( + l_rows tt_cached_suites, + l_idx pls_integer, + l_level pls_integer, + l_prev_level pls_integer, + l_items_at_level t_item_levels + ) return ut_logical_suite is begin - a_suites := ut_suite_items(); - loop - fetch a_suite_data_cursor bulk collect into l_rows limit c_bulk_limit; - exit when l_rows.count = 0; - - l_idx := l_rows.first; - loop - l_test := null; - l_logical_suite := null; - case l_rows(l_idx).self_type - when 'UT_TEST' then - l_test := - ut_test( + return + case l_rows(l_idx).self_type + when 'UT_SUITE' then + case when l_prev_level > l_level then + ut_suite( self_type => l_rows(l_idx).self_type, object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, @@ -201,14 +188,10 @@ create or replace package body ut_suite_manager is line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - before_each_list => sort_by_seq_no(l_rows(l_idx).before_each_list), before_test_list => sort_by_seq_no(l_rows(l_idx).before_test_list), - item => l_rows(l_idx).item, - after_test_list => sort_by_seq_no(l_rows(l_idx).after_test_list), after_each_list => sort_by_seq_no(l_rows(l_idx).after_each_list), - all_expectations => ut_expectation_results(), failed_expectations => ut_expectation_results(), - parent_error_stack_trace => null, expected_error_codes => l_rows(l_idx).expected_error_codes - ); - when 'UT_SUITE' then - l_logical_suite := + items => l_items_at_level(l_prev_level), + before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) + ) + else ut_suite( self_type => l_rows(l_idx).self_type, object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), @@ -219,9 +202,22 @@ create or replace package body ut_suite_manager is results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), items => ut_suite_items(), before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) - ); - when 'UT_SUITE_CONTEXT' then - l_logical_suite := + ) + end + when 'UT_SUITE_CONTEXT' then + case when l_prev_level > l_level then + ut_suite_context( + self_type => l_rows(l_idx).self_type, + object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), + name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, + rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, + line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => l_items_at_level(l_prev_level), + before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) + ) + else ut_suite_context( self_type => l_rows(l_idx).self_type, object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), @@ -232,9 +228,21 @@ create or replace package body ut_suite_manager is results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), items => ut_suite_items(), before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) - ); - when 'UT_LOGICAL_SUITE' then - l_logical_suite := + ) + end + when 'UT_LOGICAL_SUITE' then + case when l_prev_level > l_level then + ut_logical_suite( + self_type => l_rows(l_idx).self_type, + object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), + name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, + rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, + line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => l_items_at_level(l_prev_level) + ) + else ut_logical_suite( self_type => l_rows(l_idx).self_type, object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), @@ -244,32 +252,62 @@ create or replace package body ut_suite_manager is start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), items => ut_suite_items() - ); - end case; + ) + end + end; + end; + + procedure reconstruct_from_cache( + a_suites in out nocopy ut_suite_items, + a_suite_data_cursor sys_refcursor + ) is + c_bulk_limit constant pls_integer := 1000; + l_items_at_level t_item_levels; + l_rows tt_cached_suites; + l_logical_suite ut_logical_suite; + l_level pls_integer; + l_prev_level pls_integer; + l_idx integer; + begin + loop + fetch a_suite_data_cursor bulk collect into l_rows limit c_bulk_limit; + exit when l_rows.count = 0; + l_idx := l_rows.first; + loop l_level := length(l_rows(l_idx).path) - length( replace(l_rows(l_idx).path, '.') ) + 1; - if l_level > 1 then - if l_prev_level > l_level then - l_logical_suite.items := l_items_at_level(l_prev_level); - l_items_at_level(l_prev_level).delete; - end if; if not l_items_at_level.exists(l_level) then l_items_at_level(l_level) := ut_suite_items(); end if; l_items_at_level(l_level).extend; - if l_test is not null then - l_items_at_level(l_level)(l_items_at_level(l_level).last) := l_test; + if l_rows(l_idx).self_type = 'UT_TEST' then + l_items_at_level(l_level)(l_items_at_level(l_level).last) := + ut_test( + self_type => l_rows(l_idx).self_type, + object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), + name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, + rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, + line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, + start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + before_each_list => sort_by_seq_no(l_rows(l_idx).before_each_list), before_test_list => sort_by_seq_no(l_rows(l_idx).before_test_list), + item => l_rows(l_idx).item, + after_test_list => sort_by_seq_no(l_rows(l_idx).after_test_list), after_each_list => sort_by_seq_no(l_rows(l_idx).after_each_list), + all_expectations => ut_expectation_results(), failed_expectations => ut_expectation_results(), + parent_error_stack_trace => null, expected_error_codes => l_rows(l_idx).expected_error_codes + ); else - l_items_at_level(l_level)(l_items_at_level(l_level).last) := l_logical_suite; - end if; + pragma inline(get_logical_suite, 'YES'); + l_items_at_level(l_level)(l_items_at_level(l_level).last) := get_logical_suite(l_rows, l_idx, l_level,l_prev_level, l_items_at_level ); + end if; else - if l_prev_level > l_level then - l_logical_suite.items := l_items_at_level(l_prev_level); - l_items_at_level(l_prev_level).delete; - end if; a_suites.extend; - a_suites(a_suites.last) := l_logical_suite; + pragma inline(get_logical_suite, 'YES'); + a_suites(a_suites.last) := get_logical_suite(l_rows, l_idx, l_level,l_prev_level, l_items_at_level ); + end if; + if l_prev_level > l_level then + l_items_at_level(l_prev_level).delete; end if; l_prev_level := l_level; l_idx := l_rows.next(l_idx); @@ -483,18 +521,18 @@ create or replace package body ut_suite_manager is end; - function get_suites_for_path( + procedure add_suites_for_path( a_owner_name varchar2, a_path varchar2 := null, a_object_name varchar2 := null, - a_procedure_name varchar2 := null - ) return ut_suite_items is - l_suites ut_suite_items; + a_procedure_name varchar2 := null, + a_suites in out nocopy ut_suite_items + ) is begin refresh_cache(a_owner_name); reconstruct_from_cache( - l_suites, + a_suites, get_cached_suite_data( a_owner_name, a_path, @@ -503,9 +541,8 @@ create or replace package body ut_suite_manager is can_skip_all_objects_scan(a_owner_name) ) ); - return l_suites; - end get_suites_for_path; + end; ----------------------------------------------- ----------------------------------------------- @@ -519,7 +556,7 @@ create or replace package body ut_suite_manager is a_procedure_name varchar2 := null, a_skip_all_objects boolean := false ) return ut_suite_items is - l_suites ut_suite_items; + l_suites ut_suite_items := ut_suite_items(); begin build_and_cache_suites(a_owner_name, a_annotated_objects); @@ -578,58 +615,59 @@ create or replace package body ut_suite_manager is end; function configure_execution_by_path(a_paths in ut_varchar2_list) return ut_suite_items is + l_suites ut_suite_items := ut_suite_items(); + begin + configure_execution_by_path(a_paths, l_suites ); + return l_suites; + end; + + procedure configure_execution_by_path(a_paths in ut_varchar2_list, a_suites out nocopy ut_suite_items) is l_paths ut_varchar2_list := a_paths; l_path_items t_path_items; l_path_item t_path_item; l_schema varchar2(4000); - l_suites ut_suite_items; + l_suites_count pls_integer := 0; l_index varchar2(4000 char); - l_objects_to_run ut_suite_items; l_schema_paths t_schema_paths; begin + a_suites := ut_suite_items(); --resolve schema names from paths and group paths by schema name resolve_schema_names(l_paths); l_schema_paths := group_paths_by_schema(l_paths); - l_objects_to_run := ut_suite_items(); - l_schema := l_schema_paths.first; while l_schema is not null loop l_path_items := l_schema_paths(l_schema); for i in 1 .. l_path_items.count loop l_path_item := l_path_items(i); - l_suites := get_suites_for_path( + add_suites_for_path( upper(l_schema), l_path_item.suite_path, l_path_item.object_name, - l_path_item.procedure_name + l_path_item.procedure_name, + a_suites ); - if l_suites.count = 0 then + if a_suites.count = l_suites_count then if l_path_item.suite_path is not null then raise_application_error(ut_utils.gc_suite_package_not_found,'No suite packages found for path '||l_schema||':'||l_path_item.suite_path|| '.'); elsif l_path_item.procedure_name is not null then raise_application_error(ut_utils.gc_suite_package_not_found,'Suite test '||l_schema||'.'||l_path_item.object_name|| '.'||l_path_item.procedure_name||' does not exist'); - else + elsif l_path_item.object_name is not null then raise_application_error(ut_utils.gc_suite_package_not_found,'Suite package '||l_schema||'.'||l_path_item.object_name|| ' does not exist'); end if; end if; - l_index := l_suites.first; - while l_index is not null loop - l_objects_to_run.extend; - l_objects_to_run(l_objects_to_run.count) := l_suites(l_index); - l_index := l_suites.next(l_index); - end loop; + l_index := a_suites.first; + l_suites_count := a_suites.count; end loop; l_schema := l_schema_paths.next(l_schema); end loop; --propagate rollback type to suite items after organizing suites into hierarchy - for i in 1 .. l_objects_to_run.count loop - l_objects_to_run(i).set_rollback_type( l_objects_to_run(i).get_rollback_type() ); + for i in 1 .. a_suites.count loop + a_suites(i).set_rollback_type( a_suites(i).get_rollback_type() ); end loop; - return l_objects_to_run; end configure_execution_by_path; function get_suites_info(a_owner_name varchar2) return tt_suite_items pipelined is diff --git a/source/core/ut_suite_manager.pks b/source/core/ut_suite_manager.pks index 65440b22b..408a8a355 100644 --- a/source/core/ut_suite_manager.pks +++ b/source/core/ut_suite_manager.pks @@ -39,6 +39,15 @@ create or replace package ut_suite_manager authid current_user is */ function configure_execution_by_path(a_paths in ut_varchar2_list) return ut_suite_items; + /** + * Builds a hierarchical suites based on given suite-paths + * + * @param a_paths list of suite-paths or procedure names or package names or schema names + * @param a_suites returned array containing root suites-ready to be executed + * + */ + procedure configure_execution_by_path(a_paths in ut_varchar2_list, a_suites out nocopy ut_suite_items); + /** * Cleanup paths by removing leading/trailing whitespace and making paths lowercase * Get list of schema names from execution paths. From 3543e3d905dfe76c322ab527ca5d5007a34f901f Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Thu, 15 Nov 2018 00:26:55 +0000 Subject: [PATCH 18/33] Disabled `PLSQL_OPTIMIZE_LEVEL=0` for testing --- .travis/install.sh | 4 ++-- .travis/install_utplsql_release.sh | 2 +- test/core.pkb | 2 +- test/install_tests.sql | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis/install.sh b/.travis/install.sh index e37cfa35f..03b69a8b1 100644 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -9,7 +9,7 @@ set feedback off set verify off --alter session set plsql_warnings = 'ENABLE:ALL', 'DISABLE:(5004,5018,6000,6001,6003,6009,6010,7206)'; -alter session set plsql_optimize_level=0; +--alter session set plsql_optimize_level=0; @install_headless.sql $UT3_OWNER $UT3_OWNER_PASSWORD SQL @@ -45,7 +45,7 @@ SQL set feedback off set verify off - alter session set plsql_optimize_level=0; + --alter session set plsql_optimize_level=0; @install.sql $UT3_OWNER SQL diff --git a/.travis/install_utplsql_release.sh b/.travis/install_utplsql_release.sh index 889e098da..7d1c24df7 100644 --- a/.travis/install_utplsql_release.sh +++ b/.travis/install_utplsql_release.sh @@ -37,7 +37,7 @@ end; SQL "$SQLCLI" sys/$ORACLE_PWD@//$CONNECTION_STR AS SYSDBA < Date: Thu, 15 Nov 2018 00:33:56 +0000 Subject: [PATCH 19/33] Fixed formal parameter names --- source/core/ut_suite_manager.pkb | 108 ++++++++++++++++--------------- 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index 4c2d06ab9..03eb35a86 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -169,87 +169,91 @@ create or replace package body ut_suite_manager is end; function get_logical_suite( - l_rows tt_cached_suites, - l_idx pls_integer, - l_level pls_integer, - l_prev_level pls_integer, - l_items_at_level t_item_levels + a_rows tt_cached_suites, + a_idx pls_integer, + a_level pls_integer, + a_prev_level pls_integer, + a_items_at_level t_item_levels ) return ut_logical_suite is begin return - case l_rows(l_idx).self_type + case a_rows( a_idx ).self_type when 'UT_SUITE' then - case when l_prev_level > l_level then + case when a_prev_level > a_level then ut_suite( - self_type => l_rows(l_idx).self_type, - object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), - name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, - rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, - line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => l_items_at_level(l_prev_level), - before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) + items => a_items_at_level(a_prev_level), + before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( + a_rows( a_idx ).after_all_list) ) else ut_suite( - self_type => l_rows(l_idx).self_type, - object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), - name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, - rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, - line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), items => ut_suite_items(), - before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) + before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( + a_rows( a_idx ).after_all_list) ) end when 'UT_SUITE_CONTEXT' then - case when l_prev_level > l_level then + case when a_prev_level > a_level then ut_suite_context( - self_type => l_rows(l_idx).self_type, - object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), - name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, - rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, - line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => l_items_at_level(l_prev_level), - before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) + items => a_items_at_level(a_prev_level), + before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( + a_rows( a_idx ).after_all_list) ) else ut_suite_context( - self_type => l_rows(l_idx).self_type, - object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), - name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, - rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, - line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), items => ut_suite_items(), - before_all_list => sort_by_seq_no(l_rows(l_idx).before_all_list), after_all_list => sort_by_seq_no(l_rows(l_idx).after_all_list) + before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( + a_rows( a_idx ).after_all_list) ) end when 'UT_LOGICAL_SUITE' then - case when l_prev_level > l_level then + case when a_prev_level > a_level then ut_logical_suite( - self_type => l_rows(l_idx).self_type, - object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), - name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, - rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, - line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => l_items_at_level(l_prev_level) + items => a_items_at_level(a_prev_level) ) else ut_logical_suite( - self_type => l_rows(l_idx).self_type, - object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), - name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, - rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, - line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), items => ut_suite_items() ) From f7f68116bbe600ea9dc049b8dff6fd41ce4dd981 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Thu, 15 Nov 2018 01:09:49 +0000 Subject: [PATCH 20/33] Revert "Disabled `PLSQL_OPTIMIZE_LEVEL=0` for testing" This reverts commit 3543e3d --- .travis/install.sh | 4 ++-- .travis/install_utplsql_release.sh | 2 +- test/core.pkb | 2 +- test/install_tests.sql | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis/install.sh b/.travis/install.sh index 03b69a8b1..e37cfa35f 100644 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -9,7 +9,7 @@ set feedback off set verify off --alter session set plsql_warnings = 'ENABLE:ALL', 'DISABLE:(5004,5018,6000,6001,6003,6009,6010,7206)'; ---alter session set plsql_optimize_level=0; +alter session set plsql_optimize_level=0; @install_headless.sql $UT3_OWNER $UT3_OWNER_PASSWORD SQL @@ -45,7 +45,7 @@ SQL set feedback off set verify off - --alter session set plsql_optimize_level=0; + alter session set plsql_optimize_level=0; @install.sql $UT3_OWNER SQL diff --git a/.travis/install_utplsql_release.sh b/.travis/install_utplsql_release.sh index 7d1c24df7..889e098da 100644 --- a/.travis/install_utplsql_release.sh +++ b/.travis/install_utplsql_release.sh @@ -37,7 +37,7 @@ end; SQL "$SQLCLI" sys/$ORACLE_PWD@//$CONNECTION_STR AS SYSDBA < Date: Fri, 16 Nov 2018 01:11:03 +0000 Subject: [PATCH 21/33] Refactored procedure `get_unit_test_info` to return more relevant information based on info suite cache. Suite cache is refreshed when calling procedure (as needed). --- source/api/ut_runner.pkb | 15 ++------- source/api/ut_runner.pks | 16 ++-------- source/api/ut_suite_item_info.tps | 27 ++++++++++++++++ source/api/ut_suite_items_info.tps | 19 +++++++++++ source/core/ut_suite_manager.pkb | 32 +++++++++---------- source/core/ut_suite_manager.pks | 20 ++++-------- .../create_synonyms_and_grants_for_public.sql | 4 +++ source/install.sql | 2 ++ source/uninstall_objects.sql | 4 +++ test/api/test_ut_runner.pkb | 14 +++++--- 10 files changed, 94 insertions(+), 59 deletions(-) create mode 100644 source/api/ut_suite_item_info.tps create mode 100644 source/api/ut_suite_items_info.tps diff --git a/source/api/ut_runner.pkb b/source/api/ut_runner.pkb index 3a2d6583b..e59caccb6 100644 --- a/source/api/ut_runner.pkb +++ b/source/api/ut_runner.pkb @@ -165,21 +165,12 @@ create or replace package body ut_runner is ut_annotation_manager.purge_cache(a_object_owner, a_object_type); end; - function get_unit_test_info(a_owner varchar2, a_package_name varchar2 := null) return tt_annotations pipelined is + function get_unit_test_info(a_owner varchar2, a_package_name varchar2 ) return ut_suite_items_info pipelined is l_cursor sys_refcursor; - l_filter varchar2(100); - l_ut_owner varchar2(250) := ut_utils.ut_owner; - l_results tt_annotations; + l_results ut_suite_items_info; c_bulk_limit constant integer := 10; begin - l_filter := case when a_package_name is null then 'is null' else '= o.object_name' end; - open l_cursor for - 'select o.object_owner, o.object_name, upper(a.subobject_name),' || - ' a.position, a.name, a.text' || - ' from table('||l_ut_owner||'.ut_annotation_manager.get_annotated_objects(:a_owner, ''PACKAGE'')) o,' || - ' table(o.annotations) a' || - ' where :a_package_name ' || l_filter - using a_owner, a_package_name; + l_cursor := ut_suite_manager.get_suites_info( a_owner, a_package_name ); loop fetch l_cursor bulk collect into l_results limit c_bulk_limit; for i in 1 .. l_results.count loop diff --git a/source/api/ut_runner.pks b/source/api/ut_runner.pks index 45b8cb642..e7e53a5e2 100644 --- a/source/api/ut_runner.pks +++ b/source/api/ut_runner.pks @@ -87,24 +87,14 @@ create or replace package ut_runner authid current_user is procedure purge_cache(a_object_owner varchar2 := null, a_object_type varchar2 := null); - type t_annotation_rec is record ( - package_owner varchar2(250), - package_name varchar2(250), - procedure_name varchar2(250), - annotation_pos number(5,0), - annotation_name varchar2(1000), - annotation_text varchar2(4000) - ); - type tt_annotations is table of t_annotation_rec; - /** - * Returns a pipelined collection containing information about unit tests package/packages for a given owner + * Returns a pipelined collection containing information about unit test suites and the tests contained in them * * @param a_owner owner of unit tests to retrieve * @param a_package_name optional name of unit test package to retrieve, if NULLm all unit test packages are returned - * @return tt_annotations table of records + * @return ut_suite_items_info table of objects */ - function get_unit_test_info(a_owner varchar2, a_package_name varchar2 := null) return tt_annotations pipelined; + function get_unit_test_info(a_owner varchar2, a_package_name varchar2) return ut_suite_items_info pipelined; type t_reporter_rec is record ( reporter_object_name varchar2(250), diff --git a/source/api/ut_suite_item_info.tps b/source/api/ut_suite_item_info.tps new file mode 100644 index 000000000..eefef4db0 --- /dev/null +++ b/source/api/ut_suite_item_info.tps @@ -0,0 +1,27 @@ +create or replace type ut_suite_item_info as object ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + object_owner varchar2(250), + object_name varchar2(250), + item_name varchar2(250), + item_description varchar2(250), + item_type varchar2(250), + item_line_no integer, + path varchar2(4000), + disabled_flag integer +) +/ diff --git a/source/api/ut_suite_items_info.tps b/source/api/ut_suite_items_info.tps new file mode 100644 index 000000000..d84ed9092 --- /dev/null +++ b/source/api/ut_suite_items_info.tps @@ -0,0 +1,19 @@ +create or replace type ut_suite_items_info as + /* + utPLSQL - Version 3 + Copyright 2016 - 2018 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + table of ut_suite_item_info +/ diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index 03eb35a86..628350b10 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -674,15 +674,14 @@ create or replace package body ut_suite_manager is end configure_execution_by_path; - function get_suites_info(a_owner_name varchar2) return tt_suite_items pipelined is - l_cursor sys_refcursor; + function get_suites_info(a_owner_name varchar2, a_package_name varchar2) return sys_refcursor is + l_result sys_refcursor; l_ut_owner varchar2(250) := ut_utils.ut_owner; - c_bulk_limit constant integer := 100; - l_results tt_suite_items; begin + refresh_cache(a_owner_name); - open l_cursor for + open l_result for q'[with suite_items as ( select /*+ cardinality(c 100) */ c.* @@ -696,7 +695,12 @@ create or replace package body ut_suite_manager is and a.owner = c.object_owner and a.object_type = 'PACKAGE' )]' end ||q'[ - and c.object_owner = ']'||upper(a_owner_name)||q'[' + and c.object_owner = ']'||upper(a_owner_name) ||q'[' + and ]' + || case when a_package_name is not null + then 'c.object_name = :a_package_name' + else ':a_package_name is null' end + || q'[ ), suitepaths as ( select distinct @@ -737,17 +741,13 @@ create or replace package body ut_suite_manager is s.path, 0 as disabled_flag from logical_suites s ) - select c.* - from items c]'; - loop - fetch l_cursor bulk collect into l_results limit c_bulk_limit; - for i in 1 .. l_results.count loop - pipe row (l_results(i)); - end loop; - exit when l_cursor%notfound; - end loop; - close l_cursor; + select ]'||l_ut_owner||q'[.ut_suite_item_info( + object_owner, object_name, item_name, item_description, + item_type, item_line_no, path, disabled_flag + ) + from items c]' using upper(a_package_name); + return l_result; end; end ut_suite_manager; diff --git a/source/core/ut_suite_manager.pks b/source/core/ut_suite_manager.pks index 408a8a355..6e87b08a8 100644 --- a/source/core/ut_suite_manager.pks +++ b/source/core/ut_suite_manager.pks @@ -68,20 +68,14 @@ create or replace package ut_suite_manager authid current_user is a_skip_all_objects boolean := false ) return ut_suite_items; - type t_suite_item_rec is record ( - object_owner varchar2(250), - object_name varchar2(250), - item_name varchar2(250), - item_description varchar2(250), - item_type varchar2(250), - item_line_no varchar2(250), - path varchar2(4000), - disabled_flag integer - ); - type tt_suite_items is table of t_suite_item_rec; - - function get_suites_info(a_owner_name varchar2) return tt_suite_items pipelined; + /** + * Returns a ref cursor containing information about unit test suites and the tests contained in them + * + * @param a_owner owner of unit tests to retrieve + * @return ut_suite_items_info table of objects + */ + function get_suites_info(a_owner_name varchar2, a_package_name varchar2) return sys_refcursor; end ut_suite_manager; diff --git a/source/create_synonyms_and_grants_for_public.sql b/source/create_synonyms_and_grants_for_public.sql index 4928022eb..b8daca313 100644 --- a/source/create_synonyms_and_grants_for_public.sql +++ b/source/create_synonyms_and_grants_for_public.sql @@ -95,6 +95,8 @@ grant execute on &&ut3_owner..ut_annotation_cache_manager to public; grant execute on &&ut3_owner..ut_annotation_parser to public; grant execute on &&ut3_owner..ut_annotation_objs_cache_info to public; grant execute on &&ut3_owner..ut_annotation_obj_cache_info to public; +grant execute on &&ut3_owner..ut_suite_items_info to public; +grant execute on &&ut3_owner..ut_suite_item_info to public; begin $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then execute immediate 'grant select, insert, delete, update on &&ut3_owner..dbmspcc_blocks to public'; @@ -152,6 +154,8 @@ create public synonym ut_file_mapper for &&ut3_owner..ut_file_mapper; create public synonym ut_key_value_pairs for &&ut3_owner..ut_key_value_pairs; create public synonym ut_key_value_pair for &&ut3_owner..ut_key_value_pair; create public synonym ut_sonar_test_reporter for &&ut3_owner..ut_sonar_test_reporter; +create public synonym ut_suite_items_info for &&ut3_owner..ut_suite_items_info; +create public synonym ut_suite_item_info for &&ut3_owner..ut_suite_item_info; begin $if dbms_db_version.version = 12 and dbms_db_version.release >= 2 or dbms_db_version.version > 12 $then execute immediate 'create public synonym dbmspcc_blocks for &&ut3_owner..dbmspcc_blocks'; diff --git a/source/install.sql b/source/install.sql index 31b91a941..50d70c944 100644 --- a/source/install.sql +++ b/source/install.sql @@ -259,6 +259,8 @@ prompt Installing DBMSPLSQL Tables objects into &&ut3_owner schema @@install_component.sql 'reporters/ut_documentation_reporter.tpb' --plugin interface API for running utPLSQL +@@install_component.sql 'api/ut_suite_item_info.tps' +@@install_component.sql 'api/ut_suite_items_info.tps' @@install_component.sql 'api/ut_runner.pks' @@install_component.sql 'api/ut_runner.pkb' diff --git a/source/uninstall_objects.sql b/source/uninstall_objects.sql index 119695b6d..97f2c5a5d 100644 --- a/source/uninstall_objects.sql +++ b/source/uninstall_objects.sql @@ -51,6 +51,10 @@ drop package ut_teamcity_reporter_helper; drop package ut_runner; +drop type ut_suite_items_info force; + +drop type ut_suite_item_info force; + drop package ut_suite_manager; drop package ut_suite_builder; diff --git a/test/api/test_ut_runner.pkb b/test/api/test_ut_runner.pkb index 3a8f6f670..5a9e4830a 100644 --- a/test/api/test_ut_runner.pkb +++ b/test/api/test_ut_runner.pkb @@ -273,12 +273,16 @@ end;'; begin --Arrange open l_expected for - select 'UT3_TESTER' package_owner, 'DUMMY_TEST_PACKAGE' package_name, - to_char(null) procedure_name, 2 annotation_pos, 'suite' annotation_name, 'dummy_test_suite' annotation_text + select + 'UT3_TESTER' object_owner, 'DUMMY_TEST_PACKAGE' object_name, 'DUMMY_TEST_PACKAGE' item_name, + 'dummy_test_suite' item_description, 'UT_SUITE' item_type, 2 item_line_no, + 'dummy_test_package' path, 0 disabled_flag from dual union all - select 'UT3_TESTER', 'DUMMY_TEST_PACKAGE', to_char(null), 3, 'rollback', 'manual' from dual union all - select 'UT3_TESTER', 'DUMMY_TEST_PACKAGE', 'SOME_DUMMY_TEST_PROCEDURE', 5, 'test', 'dummy_test' from dual union all - select 'UT3_TESTER', 'DUMMY_TEST_PACKAGE', 'SOME_DUMMY_TEST_PROCEDURE', 6, 'beforetest', 'some_procedure' from dual; + select + 'UT3_TESTER' object_owner, 'DUMMY_TEST_PACKAGE' object_name, 'SOME_DUMMY_TEST_PROCEDURE' item_name, + 'dummy_test' item_description, 'UT_TEST' item_type, 5 item_line_no, + 'dummy_test_package.some_dummy_test_procedure' path, 0 disabled_flag + from dual; --Act open l_actual for select * from table(ut3.ut_runner.get_unit_test_info('UT3_TESTER','DUMMY_TEST_PACKAGE')); --Assert From e1f1eec2024126a50168c2613bfeb9b2e989f7c1 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Fri, 16 Nov 2018 23:35:06 +0000 Subject: [PATCH 22/33] Renamed `get_unit_test_info` to `get_suites_info` - the latter one was not used uin prior versions. Added functions `is_test`, `is_suite`, `has_suite` to perform checks for test/suite existance at prcedure, package, schema level. --- source/api/ut_runner.pkb | 38 ++++++++++++++++- source/api/ut_runner.pks | 28 ++++++++++++- source/core/ut_suite_cache_manager.pkb | 2 +- source/core/ut_suite_manager.pkb | 51 ++++++++++++++++++++++- source/core/ut_suite_manager.pks | 25 ++++++++++- test/api/test_ut_runner.pkb | 57 +++++++++++++++++++++++++- test/api/test_ut_runner.pks | 40 +++++++++++++++++- 7 files changed, 231 insertions(+), 10 deletions(-) diff --git a/source/api/ut_runner.pkb b/source/api/ut_runner.pkb index e59caccb6..64faf91ed 100644 --- a/source/api/ut_runner.pkb +++ b/source/api/ut_runner.pkb @@ -165,7 +165,7 @@ create or replace package body ut_runner is ut_annotation_manager.purge_cache(a_object_owner, a_object_type); end; - function get_unit_test_info(a_owner varchar2, a_package_name varchar2 ) return ut_suite_items_info pipelined is + function get_suites_info(a_owner varchar2, a_package_name varchar2 := null) return ut_suite_items_info pipelined is l_cursor sys_refcursor; l_results ut_suite_items_info; c_bulk_limit constant integer := 10; @@ -182,6 +182,42 @@ create or replace package body ut_runner is return; end; + function is_test(a_owner varchar2, a_package_name varchar2, a_procedure_name varchar2) return boolean is + l_result boolean := false; + begin + if a_owner is not null and a_package_name is not null and a_procedure_name is not null then + + l_result := ut_suite_manager.suite_item_exists( a_owner, a_package_name, a_procedure_name ); + + end if; + + return l_result; + end; + + function is_suite(a_owner varchar2, a_package_name varchar2) return boolean is + l_result boolean := false; + begin + if a_owner is not null and a_package_name is not null then + + l_result := ut_suite_manager.suite_item_exists( a_owner, a_package_name ); + + end if; + + return l_result; + end; + + function has_suites(a_owner varchar2) return boolean is + l_result boolean := false; + begin + if a_owner is not null then + + l_result := ut_suite_manager.suite_item_exists( a_owner ); + + end if; + + return l_result; + end; + function get_reporters_list return tt_reporters_info pipelined is l_cursor sys_refcursor; l_owner varchar2(128) := upper(ut_utils.ut_owner()); diff --git a/source/api/ut_runner.pks b/source/api/ut_runner.pks index e7e53a5e2..9dc18b9b9 100644 --- a/source/api/ut_runner.pks +++ b/source/api/ut_runner.pks @@ -94,7 +94,33 @@ create or replace package ut_runner authid current_user is * @param a_package_name optional name of unit test package to retrieve, if NULLm all unit test packages are returned * @return ut_suite_items_info table of objects */ - function get_unit_test_info(a_owner varchar2, a_package_name varchar2) return ut_suite_items_info pipelined; + function get_suites_info(a_owner varchar2, a_package_name varchar2 := null) return ut_suite_items_info pipelined; + + + /** + * Returns true if given procedure is a test in a test suite, false otherwise + * + * @param a_owner owner of test package + * @param a_package_name name of test package + * @param a_procedure_name name of test procedure + */ + function is_test(a_owner varchar2, a_package_name varchar2, a_procedure_name varchar2) return boolean; + + /** + * Returns true if given package is a test suite, false otherwise + * + * @param a_owner owner of test package + * @param a_package_name name of test package + */ + function is_suite(a_owner varchar2, a_package_name varchar2) return boolean; + + /** + * Returns true if given schema contains test suites, false otherwise + * + * @param a_owner owner of test package + */ + function has_suites(a_owner varchar2) return boolean; + type t_reporter_rec is record ( reporter_object_name varchar2(250), diff --git a/source/core/ut_suite_cache_manager.pkb b/source/core/ut_suite_cache_manager.pkb index ba51a242f..ce7f018e0 100644 --- a/source/core/ut_suite_cache_manager.pkb +++ b/source/core/ut_suite_cache_manager.pkb @@ -37,7 +37,7 @@ create or replace package body ut_suite_cache_manager is l_object_owner varchar2(250) := upper(a_object_owner); l_object_name varchar2(250) := upper(a_object_name); begin - if a_suite_items.count = 0 then + if a_suite_items is not null and a_suite_items.count = 0 then delete from ut_suite_cache t where t.object_owner = l_object_owner diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index 628350b10..5dfeedfc8 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -674,7 +674,10 @@ create or replace package body ut_suite_manager is end configure_execution_by_path; - function get_suites_info(a_owner_name varchar2, a_package_name varchar2) return sys_refcursor is + function get_suites_info( + a_owner_name varchar2, + a_package_name varchar2 := null + ) return sys_refcursor is l_result sys_refcursor; l_ut_owner varchar2(250) := ut_utils.ut_owner; begin @@ -750,5 +753,51 @@ create or replace package body ut_suite_manager is return l_result; end; + function suite_item_exists( + a_owner_name varchar2, + a_package_name varchar2 := null, + a_procedure_name varchar2 := null, + a_item_type varchar2 := null + ) return boolean is + l_result integer; + l_ut_owner varchar2(250) := ut_utils.ut_owner; + begin + refresh_cache(a_owner_name); + + execute immediate q'[ + select count(1) from dual + where exists ( + select 1 + from ]'||l_ut_owner||q'[.ut_suite_cache c + where 1 = 1 ]'||case when can_skip_all_objects_scan(a_owner_name) then q'[ + and exists + ( select 1 + from all_objects a + where a.object_name = c.object_name + and a.owner = :a_owner_name + and a.owner = c.object_owner + and a.object_type = 'PACKAGE' + )]' else q'[ + and :a_owner_name is not null ]' end ||q'[ + and c.object_owner = :a_owner_name + and ]' + || case when a_package_name is not null + then 'c.object_name = :a_package_name' + else ':a_package_name is null' end + || q'[ + and ]' + || case when a_procedure_name is not null + then 'c.name = :a_procedure_name' + else ':a_procedure_name is null' end + || q'[ + )]' + into l_result + using + upper(a_owner_name), upper(a_owner_name), + upper(a_package_name), upper(a_procedure_name); + + return l_result > 0; + end; + end ut_suite_manager; / diff --git a/source/core/ut_suite_manager.pks b/source/core/ut_suite_manager.pks index 6e87b08a8..5fd82f9be 100644 --- a/source/core/ut_suite_manager.pks +++ b/source/core/ut_suite_manager.pks @@ -72,10 +72,31 @@ create or replace package ut_suite_manager authid current_user is /** * Returns a ref cursor containing information about unit test suites and the tests contained in them * - * @param a_owner owner of unit tests to retrieve + * @param a_owner owner of unit tests to retrieve + * @param a_package_name name of test package (optional) + * @param a_procedure_name name of test procedure (optional) * @return ut_suite_items_info table of objects */ - function get_suites_info(a_owner_name varchar2, a_package_name varchar2) return sys_refcursor; + function get_suites_info( + a_owner_name varchar2, + a_package_name varchar2 := null + ) return sys_refcursor; + + /** + * Returns true if given suite item exists + * + * @param a_owner owner of items to retrieve + * @param a_package_name name of suite package (optional) + * @param a_procedure_name name of suite item (optional) + * @param a_item_type suite_item type (optional) + * @return ut_suite_items_info table of objects + */ + function suite_item_exists( + a_owner_name varchar2, + a_package_name varchar2 := null, + a_procedure_name varchar2 := null, + a_item_type varchar2 := null + ) return boolean; end ut_suite_manager; diff --git a/test/api/test_ut_runner.pkb b/test/api/test_ut_runner.pkb index 5a9e4830a..496099b77 100644 --- a/test/api/test_ut_runner.pkb +++ b/test/api/test_ut_runner.pkb @@ -267,7 +267,7 @@ end;'; ut.expect(l_actual).to_equal(0); end; - procedure test_get_unit_test_info is + procedure test_get_suites_info is l_expected sys_refcursor; l_actual sys_refcursor; begin @@ -284,7 +284,7 @@ end;'; 'dummy_test_package.some_dummy_test_procedure' path, 0 disabled_flag from dual; --Act - open l_actual for select * from table(ut3.ut_runner.get_unit_test_info('UT3_TESTER','DUMMY_TEST_PACKAGE')); + open l_actual for select * from table(ut3.ut_runner.get_suites_info('UT3_TESTER','DUMMY_TEST_PACKAGE')); --Assert ut.expect(l_actual).to_equal(l_expected); end; @@ -534,6 +534,59 @@ end;'; ut.expect(l_actual).to_be_like('%Finished in % seconds %2 tests, 0 failed, 0 errored, 0 disabled, 0 warning(s)%'); end; + + procedure is_test_true is + begin + ut.expect( + ut3.ut_runner.is_test( + a_owner => 'UT3_TESTER', + a_package_name => 'DUMMY_TEST_PACKAGE', + a_procedure_name => 'SOME_DUMMY_TEST_PROCEDURE' + ) + ).to_be_true(); + ut.expect( ut3.ut_runner.is_test( 'ut3_tester','dummy_test_package','some_dummy_test_procedure' ) ).to_be_true(); + end; + + procedure is_test_false is + begin + ut.expect( ut3.ut_runner.is_test( 'UT3_TESTER','DUMMY_TEST_PACKAGE', 'BAD' ) ).to_be_false(); + ut.expect( ut3.ut_runner.is_test( 'UT3_TESTER','DUMMY_TEST_PACKAGE', null ) ).to_be_false(); + ut.expect( ut3.ut_runner.is_test( 'UT3_TESTER',null,'some_dummy_test_procedure' ) ).to_be_false(); + ut.expect( ut3.ut_runner.is_test( null,'DUMMY_TEST_PACKAGE','some_dummy_test_procedure' ) ).to_be_false(); + end; + + procedure is_suite_true is + begin + ut.expect( + ut3.ut_runner.is_suite( + a_owner => 'UT3_TESTER', + a_package_name => 'DUMMY_TEST_PACKAGE' + ) + ).to_be_true(); + + ut.expect( ut3.ut_runner.is_suite( 'ut3_tester','dummy_test_package' ) ).to_be_true(); + end; + + procedure is_suite_false is + begin + ut.expect( ut3.ut_runner.is_suite( 'UT3_TESTER','BAD' ) ).to_be_false(); + ut.expect( ut3.ut_runner.is_suite( 'UT3_TESTER', null ) ).to_be_false(); + ut.expect( ut3.ut_runner.is_suite( null,'DUMMY_TEST_PACKAGE' ) ).to_be_false(); + end; + + procedure has_suites_true is + begin + ut.expect( ut3.ut_runner.has_suites( a_owner => 'UT3_TESTER' ) ).to_be_true(); + + ut.expect( ut3.ut_runner.has_suites( 'ut3_tester' ) ).to_be_true(); + end; + + procedure has_suites_false is + begin + ut.expect( ut3.ut_runner.has_suites( 'UT3' ) ).to_be_false(); + ut.expect( ut3.ut_runner.has_suites( 'BAD' ) ).to_be_false(); + ut.expect( ut3.ut_runner.has_suites( null ) ).to_be_false(); + end; end; / diff --git a/test/api/test_ut_runner.pks b/test/api/test_ut_runner.pks index 74c93dbae..54300af1b 100644 --- a/test/api/test_ut_runner.pks +++ b/test/api/test_ut_runner.pks @@ -43,10 +43,10 @@ create or replace package test_ut_runner is --%aftertest(cleanup_cache) procedure test_rebuild_cache_schema_type; - --%test(get_unit_tests_info returns a cursor containing records for a newly created test) + --%test(get_suites_info returns a cursor containing records for a newly created test) --%beforetest(setup_cache_objects) --%aftertest(cleanup_cache) - procedure test_get_unit_test_info; + procedure test_get_suites_info; --%test(get_reporters_list returns a cursor containing all built-in reporters and information about output-reporter) --%beforetest(setup_cache_objects) @@ -91,5 +91,41 @@ create or replace package test_ut_runner is --%endcontext + --%context(is_test) + --%beforeall(setup_cache_objects) + --%afterall(cleanup_cache) + + --%test(Returns true when procedure is a test) + procedure is_test_true; + + --%test(Returns false when procedure is not a test) + procedure is_test_false; + + --%endcontext + + --%context(is_suite) + --%beforeall(setup_cache_objects) + --%afterall(cleanup_cache) + + --%test(Returns true when package is a test suite) + procedure is_suite_true; + + --%test(Returns false when package is not a test suite) + procedure is_suite_false; + + --%endcontext + + --%context(has_suites) + --%beforeall(setup_cache_objects) + --%afterall(cleanup_cache) + + --%test(Returns true when schema contains test suites) + procedure has_suites_true; + + --%test(Returns false when schema does not contain test suites) + procedure has_suites_false; + + --%endcontext + end; / From d8d251fad3c877f86f9cd66ebcde5ee0d885c793 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Fri, 16 Nov 2018 23:36:16 +0000 Subject: [PATCH 23/33] Improved automation of `refresh_sources.sh` The script will now automatically copy `*.jar` files into `/utPLSQL-cli/lib` directory. --- .gitignore | 1 + CONTRIBUTING.md | 8 ++++++-- development/refresh_sources.sh | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 197d0f5e9..a6f721188 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ node_modules/ utPLSQL_latest_release/ utPLSQL-cli/ development/env.sh +development/*.jar *.log # exclusions based on artifacts created via actions documented in CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0e82a4ce4..ffb8bba69 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -89,14 +89,18 @@ export CONNECTION_STR=127.0.0.1:1521/xe # Adjust the connect string export ORACLE_PWD=oracle # Adjust your local SYS password ``` +### Download Oracle JDBC drivers + +Download `ojdbc8-xxx.jar` and `orai18n-xxx.jar` from [Oracle](https://www.oracle.com/technetwork/database/features/jdbc/jdbc-ucp-122-3110062.html). +Place them in `development` directory of the project. + + ### Download utPLSQL release sources and utplsq-cli The below script is fetching latest release version from utPLSQL repository. Latest release version is used for self-testing. ```bash development/refresh_sources.sh ``` -> **Important notice:** -> You'll have to provide the ojdbc.jar in the folder utPLSQL-cli/lib manually due to Oracle licensing restrictions. ### Setup local database for utPLSQL development diff --git a/development/refresh_sources.sh b/development/refresh_sources.sh index e051787a1..9474c3553 100755 --- a/development/refresh_sources.sh +++ b/development/refresh_sources.sh @@ -16,3 +16,4 @@ curl -Lk -o utPLSQL-cli.zip https://github.com/utPLSQL/utPLSQL-cli/releases/down # unzip utPLSQL-cli and remove the zip file unzip utPLSQL-cli.zip && chmod u+x utPLSQL-cli/bin/utplsql && rm utPLSQL-cli.zip +cp development/*.jar utPLSQL-cli/lib/ From eb3df218fc958977735f196bb7474628ae8ac40e Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Fri, 16 Nov 2018 23:54:37 +0000 Subject: [PATCH 24/33] Fixing failing test. --- test/api/test_ut_runner.pkb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/test_ut_runner.pkb b/test/api/test_ut_runner.pkb index 496099b77..0b9b85f9a 100644 --- a/test/api/test_ut_runner.pkb +++ b/test/api/test_ut_runner.pkb @@ -583,7 +583,7 @@ end;'; procedure has_suites_false is begin - ut.expect( ut3.ut_runner.has_suites( 'UT3' ) ).to_be_false(); + ut.expect( ut3.ut_runner.has_suites( 'UT3_LATEST_RELEASE' ) ).to_be_false(); ut.expect( ut3.ut_runner.has_suites( 'BAD' ) ).to_be_false(); ut.expect( ut3.ut_runner.has_suites( null ) ).to_be_false(); end; From d21134858d2ec73a955070fb2048e408c9a7e7ae Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sat, 17 Nov 2018 02:01:24 +0000 Subject: [PATCH 25/33] Added control over rollback behavior in `ut_runner.run` Fixed failing test. --- source/api/ut_runner.pkb | 11 ++++++++--- source/api/ut_runner.pks | 6 +++++- source/core/annotations/ut_annotation_manager.pkb | 8 ++++---- source/core/coverage/ut_coverage.pkb | 2 +- source/core/ut_metadata.pkb | 15 +++++++++++++-- source/core/ut_metadata.pks | 12 +++++++++++- source/core/ut_suite_manager.pkb | 9 +++------ source/core/ut_utils.pkb | 1 - source/reporters/ut_coveralls_reporter.tpb | 1 - test/api/test_ut_runner.pkb | 7 ++----- test/api/test_ut_runner.pks | 12 ++++++++---- 11 files changed, 55 insertions(+), 29 deletions(-) diff --git a/source/api/ut_runner.pkb b/source/api/ut_runner.pkb index 64faf91ed..f6d7a6d92 100644 --- a/source/api/ut_runner.pkb +++ b/source/api/ut_runner.pkb @@ -83,7 +83,8 @@ create or replace package body ut_runner is a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, a_fail_on_errors boolean := false, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_perform_rollback boolean := true ) is l_run ut_run; l_coverage_schema_names ut_varchar2_rows; @@ -141,13 +142,17 @@ create or replace package body ut_runner is l_run.do_execute(); finish_run(l_run); - rollback; + if a_perform_rollback then + rollback; + end if; exception when others then finish_run(l_run); dbms_output.put_line(dbms_utility.format_error_backtrace); dbms_output.put_line(dbms_utility.format_error_stack); - rollback; + if a_perform_rollback then + rollback; + end if; raise; end; if a_fail_on_errors and l_run.result in (ut_utils.gc_failure, ut_utils.gc_error) then diff --git a/source/api/ut_runner.pks b/source/api/ut_runner.pks index 9dc18b9b9..1ea997031 100644 --- a/source/api/ut_runner.pks +++ b/source/api/ut_runner.pks @@ -43,6 +43,9 @@ create or replace package ut_runner authid current_user is * @param a_include_objects list of database objects (in format 'owner.name') that coverage should be reported on * @param a_exclude_objects list of database objects (in format 'owner.name') that coverage should be skipped for * @param a_fail_on_errors true/false - should an exception be thrown when tests are completed with failures/errors + * @param a_client_character_set if provided, affects some of reporters by setting specific character set for XML/HTML reports + * @param a_perform_rollback true/false - should rollback be performed as part of test execution (default true) + * * @example * Parameter `a_paths` accepts values of the following formats: @@ -65,7 +68,8 @@ create or replace package ut_runner authid current_user is a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, a_fail_on_errors boolean := false, - a_client_character_set varchar2 := null + a_client_character_set varchar2 := null, + a_perform_rollback boolean := true ); /** diff --git a/source/core/annotations/ut_annotation_manager.pkb b/source/core/annotations/ut_annotation_manager.pkb index 80de4d1a7..1c7e39273 100644 --- a/source/core/annotations/ut_annotation_manager.pkb +++ b/source/core/annotations/ut_annotation_manager.pkb @@ -22,7 +22,7 @@ create or replace package body ut_annotation_manager as 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_dba_view('dba_objects'); + l_objects_view varchar2(200) := ut_metadata.get_objects_view_name(); l_cursor_text varchar2(32767); l_result ut_annotation_objs_cache_info; begin @@ -54,7 +54,7 @@ create or replace package body ut_annotation_manager as function get_annotation_objs_info(a_object_owner varchar2, a_object_type varchar2, a_parse_date timestamp := null) 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_dba_view('dba_objects'); + l_objects_view varchar2(200) := ut_metadata.get_objects_view_name(); l_cursor_text varchar2(32767); l_result ut_annotation_objs_cache_info; begin @@ -86,7 +86,7 @@ create or replace package body ut_annotation_manager as function get_sources_to_annotate(a_object_owner varchar2, a_object_type varchar2) return sys_refcursor is l_result sys_refcursor; - l_sources_view varchar2(200) := ut_metadata.get_dba_view('dba_source'); + l_sources_view varchar2(200) := ut_metadata.get_source_view_name(); begin open l_result for q'[select s.name, s.text @@ -109,7 +109,7 @@ create or replace package body ut_annotation_manager as function get_sources_to_annotate(a_object_owner varchar2, a_object_type varchar2, a_objects_to_refresh ut_annotation_objs_cache_info) return sys_refcursor is l_result sys_refcursor; - l_sources_view varchar2(200) := ut_metadata.get_dba_view('dba_source'); + l_sources_view varchar2(200) := ut_metadata.get_source_view_name(); l_card natural; begin l_card := ut_utils.scale_cardinality(cardinality(a_objects_to_refresh)); diff --git a/source/core/coverage/ut_coverage.pkb b/source/core/coverage/ut_coverage.pkb index 06a738f0c..6acca42bd 100644 --- a/source/core/coverage/ut_coverage.pkb +++ b/source/core/coverage/ut_coverage.pkb @@ -38,7 +38,7 @@ create or replace package body ut_coverage is function get_cov_sources_sql(a_coverage_options ut_coverage_options) return varchar2 is l_result varchar2(32767); l_full_name varchar2(100); - l_view_name varchar2(200) := ut_metadata.get_dba_view('dba_source'); + l_view_name varchar2(200) := ut_metadata.get_source_view_name(); begin if a_coverage_options.file_mappings is not null and a_coverage_options.file_mappings.count > 0 then l_full_name := 'f.file_name'; diff --git a/source/core/ut_metadata.pkb b/source/core/ut_metadata.pkb index 1795c1a0c..d500bff61 100644 --- a/source/core/ut_metadata.pkb +++ b/source/core/ut_metadata.pkb @@ -66,7 +66,7 @@ create or replace package body ut_metadata as l_schema varchar2(200); l_package_name varchar2(200); l_procedure_name varchar2(200); - l_view_name varchar2(200) := get_dba_view('dba_objects'); + l_view_name varchar2(200) := get_objects_view_name; begin l_schema := a_owner_name; @@ -116,7 +116,7 @@ create or replace package body ut_metadata as end; function get_source_definition_line(a_owner varchar2, a_object_name varchar2, a_line_no integer) return varchar2 is - l_view_name varchar2(128) := get_dba_view('dba_source'); + l_view_name varchar2(128) := get_source_view_name(); l_line all_source.text%type; c_key constant varchar2(500) := a_owner || '.' || a_object_name; begin @@ -155,6 +155,17 @@ create or replace package body ut_metadata as return l_result; end; + function get_source_view_name return varchar2 is + begin + return get_dba_view('dba_source'); + end; + + + function get_objects_view_name return varchar2 is + begin + return get_dba_view('dba_objects'); + end; + function user_has_execute_any_proc return boolean is l_ut_owner varchar2(250) := ut_utils.ut_owner; l_dummy varchar2(250); diff --git a/source/core/ut_metadata.pks b/source/core/ut_metadata.pks index d06c1ea9d..16172a1f1 100644 --- a/source/core/ut_metadata.pks +++ b/source/core/ut_metadata.pks @@ -64,11 +64,21 @@ create or replace package ut_metadata authid current_user as procedure reset_source_definition_cache; /** - * Returns dba_... view name if it is accessible, otherwise it returns all_xxx view + * Returns dba_... view name if it is accessible, otherwise it returns all_... view * @param a_dba_view_name the name of dba view requested */ function get_dba_view(a_dba_view_name varchar2) return varchar2; + /** + * Returns dba_source if accessible otherwise returns all_source + */ + function get_source_view_name return varchar2; + + /** + * Returns dba_objects if accessible otherwise returns all_objects + */ + function get_objects_view_name return varchar2; + /** * Returns true if object is accessible to current user * @param a_object_name fully qualified object name (with schema name) diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index 5dfeedfc8..fe76b2ed7 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -268,17 +268,15 @@ create or replace package body ut_suite_manager is c_bulk_limit constant pls_integer := 1000; l_items_at_level t_item_levels; l_rows tt_cached_suites; - l_logical_suite ut_logical_suite; l_level pls_integer; l_prev_level pls_integer; l_idx integer; begin loop fetch a_suite_data_cursor bulk collect into l_rows limit c_bulk_limit; - exit when l_rows.count = 0; l_idx := l_rows.first; - loop + while l_idx is not null loop l_level := length(l_rows(l_idx).path) - length( replace(l_rows(l_idx).path, '.') ) + 1; if l_level > 1 then if not l_items_at_level.exists(l_level) then @@ -315,9 +313,8 @@ create or replace package body ut_suite_manager is end if; l_prev_level := l_level; l_idx := l_rows.next(l_idx); - exit when l_idx is null; end loop; - exit when l_rows.count < c_bulk_limit; + exit when a_suite_data_cursor%NOTFOUND; end loop; reverse_list_order( a_suites ); @@ -331,7 +328,7 @@ create or replace package body ut_suite_manager is function get_missing_objects(a_object_owner varchar2) return ut_varchar2_rows is l_rows sys_refcursor; l_ut_owner varchar2(250) := ut_utils.ut_owner; - l_objects_view varchar2(200) := ut_metadata.get_dba_view('dba_objects'); + l_objects_view varchar2(200) := ut_metadata.get_objects_view_name(); l_cursor_text varchar2(32767); l_result ut_varchar2_rows; begin diff --git a/source/core/ut_utils.pkb b/source/core/ut_utils.pkb index d70357462..928da6ca1 100644 --- a/source/core/ut_utils.pkb +++ b/source/core/ut_utils.pkb @@ -350,7 +350,6 @@ create or replace package body ut_utils is end; procedure append_to_list(a_list in out nocopy ut_varchar2_rows, a_item varchar2) is - l_items ut_varchar2_rows; begin if a_item is not null then if a_list is null then diff --git a/source/reporters/ut_coveralls_reporter.tpb b/source/reporters/ut_coveralls_reporter.tpb index 8be96715f..46c0947d0 100644 --- a/source/reporters/ut_coveralls_reporter.tpb +++ b/source/reporters/ut_coveralls_reporter.tpb @@ -61,7 +61,6 @@ create or replace type body ut_coveralls_reporter is function get_coverage_json( a_coverage_data ut_coverage.t_coverage ) return ut_varchar2_rows is - l_file_part varchar2(32767); l_result ut_varchar2_rows := ut_varchar2_rows(); l_unit ut_coverage.t_full_name; c_coverage_header constant varchar2(30) := '{"source_files":['; diff --git a/test/api/test_ut_runner.pkb b/test/api/test_ut_runner.pkb index 0b9b85f9a..8b0b6f630 100644 --- a/test/api/test_ut_runner.pkb +++ b/test/api/test_ut_runner.pkb @@ -81,16 +81,13 @@ end;'; procedure keep_an_open_transaction is l_expected varchar2(300); - l_output_data dbms_output.chararr; - l_num_lines integer := 100000; begin --Arrange create_test_spec(); create_test_body(0); l_expected := dbms_transaction.local_transaction_id(true); --Act - ut3.ut.run('test_cache'); - dbms_output.get_lines( l_output_data, l_num_lines); + ut3.ut_runner.run(ut3.ut_varchar2_list('test_cache'),null, a_perform_rollback => false); --Assert ut.expect(dbms_transaction.local_transaction_id()).to_equal(l_expected); drop_test_package(); @@ -105,7 +102,7 @@ end;'; create_test_body(0); rollback; --Act - ut3.ut.run('test_cache'); + ut3.ut_runner.run(ut3.ut_varchar2_list('test_cache'),null); dbms_output.get_lines( l_output_data, l_num_lines); --Assert ut.expect(dbms_transaction.local_transaction_id()).to_be_null(); diff --git a/test/api/test_ut_runner.pks b/test/api/test_ut_runner.pks index 54300af1b..d67ee45fc 100644 --- a/test/api/test_ut_runner.pks +++ b/test/api/test_ut_runner.pks @@ -10,18 +10,22 @@ create or replace package test_ut_runner is --%test(closes open transactions if no transaction was open before run) procedure close_newly_opened_transaction; - --%test(version_compatibility_check compares major, minor and bugfix number) + --%context(version_compatibility_check) + + --%test(compares major, minor and bugfix number) procedure version_comp_check_compare; - --%test(version_compatibility_check ignores build number) + --%test(ignores build number) procedure version_comp_check_ignore; - --%test(version_compatibility_check compares short version to a full version) + --%test(compares short version to a full version) procedure version_comp_check_short; - --%test(version_compatibility_check raises exception when invalid version passed) + --%test(raises exception when invalid version passed) procedure version_comp_check_exception; + --%endcontext + --%test(run resets cache of package body after every run) procedure run_reset_package_body_cache; From f3421958d1cfa6bb90924cd923cb25cadced80f7 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sat, 17 Nov 2018 21:11:56 +0000 Subject: [PATCH 26/33] Reverting rollback changes - they should go as a separate PR. --- development/releasing.md | 3 ++- source/api/ut_runner.pkb | 11 +++-------- source/api/ut_runner.pks | 5 +---- source/api/ut_suite_item_info.tps | 16 ++++++++-------- test/api/test_ut_runner.pkb | 7 +++++-- 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/development/releasing.md b/development/releasing.md index added5a92..7c8d779ef 100644 --- a/development/releasing.md +++ b/development/releasing.md @@ -9,7 +9,8 @@ To create a release: - wait for th build to complete successfully - merge the release branch to master and wait for master build to complete successfully - create a release from the master branch using [github releases page](https://github.com/utPLSQL/utPLSQL/releases) and populate release description using information found on the issues and pull requests since previous release. - To find issues closed after certain date use [advanced filters](https://help.github.com/articles/searching-issues-and-pull-requests/#search-by-open-or-closed-state) + To find issues closed after certain date use [advanced filters](https://help.github.com/articles/searching-issues-and-pull-requests/#search-by-open-or-closed-state). + Example: [`is:issue closed:>2018-07-22`](https://github.com/utPLSQL/utPLSQL/issues?utf8=%E2%9C%93&q=is%3Aissue+closed%3A%3E2018-07-22+) The following will happen: - build executed on branch `release/vX.Y.Z-[something]` updates files `sonar-project.properties`, `VERSION` with project version derived from the release branch name diff --git a/source/api/ut_runner.pkb b/source/api/ut_runner.pkb index f6d7a6d92..64faf91ed 100644 --- a/source/api/ut_runner.pkb +++ b/source/api/ut_runner.pkb @@ -83,8 +83,7 @@ create or replace package body ut_runner is a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, a_fail_on_errors boolean := false, - a_client_character_set varchar2 := null, - a_perform_rollback boolean := true + a_client_character_set varchar2 := null ) is l_run ut_run; l_coverage_schema_names ut_varchar2_rows; @@ -142,17 +141,13 @@ create or replace package body ut_runner is l_run.do_execute(); finish_run(l_run); - if a_perform_rollback then - rollback; - end if; + rollback; exception when others then finish_run(l_run); dbms_output.put_line(dbms_utility.format_error_backtrace); dbms_output.put_line(dbms_utility.format_error_stack); - if a_perform_rollback then - rollback; - end if; + rollback; raise; end; if a_fail_on_errors and l_run.result in (ut_utils.gc_failure, ut_utils.gc_error) then diff --git a/source/api/ut_runner.pks b/source/api/ut_runner.pks index 1ea997031..8791a4e36 100644 --- a/source/api/ut_runner.pks +++ b/source/api/ut_runner.pks @@ -44,8 +44,6 @@ create or replace package ut_runner authid current_user is * @param a_exclude_objects list of database objects (in format 'owner.name') that coverage should be skipped for * @param a_fail_on_errors true/false - should an exception be thrown when tests are completed with failures/errors * @param a_client_character_set if provided, affects some of reporters by setting specific character set for XML/HTML reports - * @param a_perform_rollback true/false - should rollback be performed as part of test execution (default true) - * * @example * Parameter `a_paths` accepts values of the following formats: @@ -68,8 +66,7 @@ create or replace package ut_runner authid current_user is a_include_objects ut_varchar2_list := null, a_exclude_objects ut_varchar2_list := null, a_fail_on_errors boolean := false, - a_client_character_set varchar2 := null, - a_perform_rollback boolean := true + a_client_character_set varchar2 := null ); /** diff --git a/source/api/ut_suite_item_info.tps b/source/api/ut_suite_item_info.tps index eefef4db0..bf6fd6ecf 100644 --- a/source/api/ut_suite_item_info.tps +++ b/source/api/ut_suite_item_info.tps @@ -15,13 +15,13 @@ create or replace type ut_suite_item_info as object ( See the License for the specific language governing permissions and limitations under the License. */ - object_owner varchar2(250), - object_name varchar2(250), - item_name varchar2(250), - item_description varchar2(250), - item_type varchar2(250), - item_line_no integer, - path varchar2(4000), - disabled_flag integer + object_owner varchar2( 250 ), -- the owner of test suite packages + object_name varchar2( 250 ), -- the name of test suite package + item_name varchar2( 250 ), -- the name of suite/test + item_description varchar2( 250 ), -- the description of suite/suite item + item_type varchar2( 250 ), -- the type of item (UT_SUITE/UT_SUITE_CONTEXT/UT_TEST) + item_line_no integer, -- line_number where annotation identifying the item exists + path varchar2( 4000 ),-- suitepath of the item + disabled_flag integer -- 0 (zero) if item is not disabled, 1 if item is disabled by --%disabled annotation ) / diff --git a/test/api/test_ut_runner.pkb b/test/api/test_ut_runner.pkb index 8b0b6f630..0b9b85f9a 100644 --- a/test/api/test_ut_runner.pkb +++ b/test/api/test_ut_runner.pkb @@ -81,13 +81,16 @@ end;'; procedure keep_an_open_transaction is l_expected varchar2(300); + l_output_data dbms_output.chararr; + l_num_lines integer := 100000; begin --Arrange create_test_spec(); create_test_body(0); l_expected := dbms_transaction.local_transaction_id(true); --Act - ut3.ut_runner.run(ut3.ut_varchar2_list('test_cache'),null, a_perform_rollback => false); + ut3.ut.run('test_cache'); + dbms_output.get_lines( l_output_data, l_num_lines); --Assert ut.expect(dbms_transaction.local_transaction_id()).to_equal(l_expected); drop_test_package(); @@ -102,7 +105,7 @@ end;'; create_test_body(0); rollback; --Act - ut3.ut_runner.run(ut3.ut_varchar2_list('test_cache'),null); + ut3.ut.run('test_cache'); dbms_output.get_lines( l_output_data, l_num_lines); --Assert ut.expect(dbms_transaction.local_transaction_id()).to_be_null(); From eeae79be2df3efad9c8a58a54407470afbda1d8a Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sat, 17 Nov 2018 21:55:19 +0000 Subject: [PATCH 27/33] Added documentation for new functionality. Added default value for owner, when calling `get_suites_info` --- docs/index.md | 1 + docs/userguide/querying_suites.md | 83 ++++++++++++++++++++++++++++ docs/userguide/running-unit-tests.md | 4 +- mkdocs.yml | 1 + source/api/ut_runner.pkb | 4 +- source/api/ut_runner.pks | 6 +- test/api/test_ut_runner.pkb | 2 +- 7 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 docs/userguide/querying_suites.md diff --git a/docs/index.md b/docs/index.md index 693c8076b..b92a78688 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,6 +10,7 @@ The framework follows industry standards and best patterns of modern Unit Testin - [Expectations](userguide/expectations.md) - [Advanced data comparison](userguide/advanced_data_comparison.md) - [Running unit tests](userguide/running-unit-tests.md) + - [Querying for test suites](userguide/querying_suites.md) - [Testing best pracitces](userguide/best-practices.md) - [Upgrade utPLSQL](userguide/upgrade.md) - Reporting diff --git a/docs/userguide/querying_suites.md b/docs/userguide/querying_suites.md new file mode 100644 index 000000000..1b1c64185 --- /dev/null +++ b/docs/userguide/querying_suites.md @@ -0,0 +1,83 @@ +# Qyerying for test suites + + +## Obtaining information about suites + +utPLSQL framework provides ability to read inforamtion about unit test suites that exist in a schema. + +Pipelined table function `ut_runner.get_suites_info(a_owner, a_package_name)` allows you to retrieve information about: + +- all suites that exist in a given user/schema +- individual test suite pacakage + +Querying the data from function provides the follwing details: + +- `object_owner` - the owner of test suite packages +- `object_name` - the name of test suite package +- `item_name` - the name of suite/test +- `item_description` - the description of suite/suite item +- `item_type` - the type of item (UT_SUITE/UT_SUITE_CONTEXT/UT_TEST/UT_LOGICAL_SUITE) +- `item_line_no` - line_number where annotation identifying the item exists +- `path` - suitepath of the item +- `disabled_flag` - (0/1) indicator if item is disabled by --%disabled annotation + +To get list of all test suites in current schema +```sql +select * from table(ut_runner.get_suites_info()) where item_type = 'UT_SUITE'; +``` + +To get list of all tests for test suite `TEST_STUFF` in current user schema +```sql +select * from table(ut_runner.get_suites_info(USER, 'TEST_STUFF')) where item_type = 'UT_TEST'; +``` + +To get a full information about suite `TEST_STUFF` including suite description, all contexts and tests in a suite +```sql +select * from table(ut_runner.get_suites_info(USER, 'TEST_STUFF')) where item_type = 'UT_TEST'; +``` + +## Checking if schema contains tests + +Function `ut_runner.has_suites(a_owner)` returns boolean value indicating if given schema contains test suites. + +Example: +```sql +begin + if ut_runner.has_suites(USER) then + dbms_output.put_line( 'User '||USER||' owns test suites' ); + else + dbms_output.put_line( 'User '||USER||' does not own test suites' ); + end if; +end; +``` + +## Checking if package is a test suite + +Function `ut_runner.is_suite(a_owner, a_package_name) ` returns boolean value indicating if given package is a test suites. + +Example: +```sql +begin + if ut_runner.is_suite(USER,'TEST_STUFF') then + dbms_output.put_line( 'Package '||USER||'.TEST_STUFF is a test suite' ); + else + dbms_output.put_line( 'Package '||USER||'.TEST_STUFF is not a test suite' ); + end if; +end; +``` + +## Checking if procedure is a test within a suite + +Function `ut_runner.is_test(a_owner, a_package_name, a_procedure_name) ` returns boolean value indicating if given package is a test suites. + +Example: +```sql +begin + if ut_runner.is_test(USER,'TEST_STUFF','A_TEST_TO_CHECK_STUFF') then + dbms_output.put_line( 'Procedure '||USER||'.TEST_STUFF.A_TEST_TO_CHECK_STUFF is a test' ); + else + dbms_output.put_line( 'Procedure '||USER||'.TEST_STUFF.A_TEST_TO_CHECK_STUFF is not a test' ); + end if; +end; +``` + diff --git a/docs/userguide/running-unit-tests.md b/docs/userguide/running-unit-tests.md index 54116cf65..f680a2e38 100644 --- a/docs/userguide/running-unit-tests.md +++ b/docs/userguide/running-unit-tests.md @@ -1,12 +1,12 @@ # Running tests -The utPLSQL framework provides two main entry points to run unit tests from within the database: +utPLSQL framework provides two main entry points to run unit tests from within the database: - `ut.run` procedures and functions - `ut_runner.run` procedures These two entry points differ in purpose and behavior. -Most of the time you will want to use `ut.run` as `ut_runner` is designed for API integration and does not output the results to the screen directly. +Most of the time you will want to use `ut.run` as `ut_runner.run` is designed for API integration and does not display the results to the screen. # Running from CI servers and command line diff --git a/mkdocs.yml b/mkdocs.yml index 7bffe0c71..f9a2687a8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -18,6 +18,7 @@ nav: - Expectations: userguide/expectations.md - Advanced data comparison: userguide/advanced_data_comparison.md - Running unit tests: userguide/running-unit-tests.md + - Querying for test suites: userguide/querying_suites.md - Testing best pracitces: userguide/best-practices.md - Upgrade utPLSQL: userguide/upgrade.md - Reporting: diff --git a/source/api/ut_runner.pkb b/source/api/ut_runner.pkb index 64faf91ed..816e9e302 100644 --- a/source/api/ut_runner.pkb +++ b/source/api/ut_runner.pkb @@ -165,12 +165,12 @@ create or replace package body ut_runner is ut_annotation_manager.purge_cache(a_object_owner, a_object_type); end; - function get_suites_info(a_owner varchar2, a_package_name varchar2 := null) return ut_suite_items_info pipelined is + function get_suites_info(a_owner varchar2 := null, a_package_name varchar2 := null) return ut_suite_items_info pipelined is l_cursor sys_refcursor; l_results ut_suite_items_info; c_bulk_limit constant integer := 10; begin - l_cursor := ut_suite_manager.get_suites_info( a_owner, a_package_name ); + l_cursor := ut_suite_manager.get_suites_info( nvl(a_owner,sys_context('userenv', 'current_schema')), a_package_name ); loop fetch l_cursor bulk collect into l_results limit c_bulk_limit; for i in 1 .. l_results.count loop diff --git a/source/api/ut_runner.pks b/source/api/ut_runner.pks index 8791a4e36..acef16c50 100644 --- a/source/api/ut_runner.pks +++ b/source/api/ut_runner.pks @@ -91,11 +91,11 @@ create or replace package ut_runner authid current_user is /** * Returns a pipelined collection containing information about unit test suites and the tests contained in them * - * @param a_owner owner of unit tests to retrieve - * @param a_package_name optional name of unit test package to retrieve, if NULLm all unit test packages are returned + * @param a_owner owner of unit tests to retrieve (optional), if NULL, current schema is used + * @param a_package_name name of unit test package to retrieve (optional), if NULL all unit test packages are returned * @return ut_suite_items_info table of objects */ - function get_suites_info(a_owner varchar2, a_package_name varchar2 := null) return ut_suite_items_info pipelined; + function get_suites_info(a_owner varchar2 := null, a_package_name varchar2 := null) return ut_suite_items_info pipelined; /** diff --git a/test/api/test_ut_runner.pkb b/test/api/test_ut_runner.pkb index 0b9b85f9a..96ae08a94 100644 --- a/test/api/test_ut_runner.pkb +++ b/test/api/test_ut_runner.pkb @@ -284,7 +284,7 @@ end;'; 'dummy_test_package.some_dummy_test_procedure' path, 0 disabled_flag from dual; --Act - open l_actual for select * from table(ut3.ut_runner.get_suites_info('UT3_TESTER','DUMMY_TEST_PACKAGE')); + open l_actual for select * from table(ut3.ut_runner.get_suites_info(NULL,'DUMMY_TEST_PACKAGE')); --Assert ut.expect(l_actual).to_equal(l_expected); end; From 74ec9a1f3cefa713d49cf777c731290552bb1c8b Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 18 Nov 2018 14:50:10 +0000 Subject: [PATCH 28/33] Removed unused code. Added additional tests to: - cover functionality of reporting warnings on transaction invalidation with sub-suites. - cover functionality of failing a test in sub-suite when beforeall fails in parent suite with logical suites in between. Refactored `ut_teamcity_reporter` a bit. --- examples/RunDeveloperExamples.sql | 2 - ...nExampleComplexSuiteWithCustomReporter.sql | 56 ------------ .../RunExampleTestSuite.sql | 6 +- ...nExampleTestSuiteWithCompositeReporter.sql | 14 +-- .../RunExampleTestSuiteWithCustomReporter.sql | 6 +- .../annotations/ut_annotation_manager.pkb | 2 +- .../core/types/ut_console_reporter_base.tpb | 10 --- .../core/types/ut_console_reporter_base.tps | 6 +- source/core/types/ut_logical_suite.tpb | 39 -------- source/core/types/ut_logical_suite.tps | 10 --- source/core/types/ut_run.tpb | 24 +---- source/core/types/ut_run.tps | 6 -- source/core/types/ut_suite_item.tps | 6 -- source/core/types/ut_test.tpb | 10 --- source/core/types/ut_test.tps | 6 -- source/core/ut_metadata.pkb | 20 +---- source/core/ut_metadata.pks | 6 -- source/core/ut_suite_manager.pkb | 4 +- source/core/ut_utils.pkb | 16 +--- source/core/ut_utils.pks | 6 -- source/reporters/ut_ansiconsole_helper.pkb | 10 --- source/reporters/ut_ansiconsole_helper.pks | 4 - source/reporters/ut_teamcity_reporter.tpb | 51 +++++------ test/api/test_ut_run.pkb | 88 +++++++++++++++++++ test/api/test_ut_run.pks | 15 ++++ test/core/test_ut_suite.pkb | 24 +++-- test/core/test_ut_test.pkb | 30 ++++--- 27 files changed, 186 insertions(+), 291 deletions(-) delete mode 100644 examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql diff --git a/examples/RunDeveloperExamples.sql b/examples/RunDeveloperExamples.sql index ec4301e88..d34914b58 100644 --- a/examples/RunDeveloperExamples.sql +++ b/examples/RunDeveloperExamples.sql @@ -6,8 +6,6 @@ set linesize 1000 exec ut_ansiconsole_helper.color_enabled(true); --developer examples -prompt RunExampleComplexSuiteWithCustomReporter -@@developer_examples/RunExampleComplexSuiteWithCustomReporter.sql prompt RunExampleTestSuiteWithCustomReporter @@developer_examples/RunExampleTestSuiteWithCustomReporter.sql prompt RunExampleTestAnnotationsParsingTimeHugePackage diff --git a/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql b/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql deleted file mode 100644 index 406a1cba2..000000000 --- a/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql +++ /dev/null @@ -1,56 +0,0 @@ ---Shows how to create a test suite with the default reporter which is dbms_output ---No tables are used for this. ---Suite Management packages are when developed will make this easier. ---Clear Screen -Set Serveroutput On Size Unlimited format truncated -set echo off ---install the example unit test packages -@@ut_exampletest.pks -@@ut_exampletest.pkb -@@ut_exampletest2.pks -@@ut_exampletest2.pkb -@@ut_custom_reporter.tps -@@ut_custom_reporter.tpb - -declare - l_parent_suite ut_logical_suite; - l_suite ut_suite; - l_test ut_test; - l_reporter ut_output_reporter_base; - l_run ut_run; -begin - ut_event_manager.initialize(); - l_parent_suite := ut_logical_suite( a_object_owner=>null, a_object_name => null, a_name => 'complex_test_suite', a_path => null); - - l_suite := ut_suite(user, 'ut_exampletest',a_line_no=>1); - l_test := ut_test(user, 'ut_exampletest','ut_exAmpletest',a_line_no=>3); - l_test.description := 'Example test1'; - l_test.before_test_list := ut_executables(ut_executable(user, 'ut_exampletest','Setup',ut_utils.gc_before_test)); - l_test.after_test_list := ut_executables(ut_executable(user, 'ut_exampletest','tEardown',ut_utils.gc_after_test)); - - l_suite.add_item(l_test); - l_parent_suite.add_item(l_suite); - - - l_suite := ut_suite(user, 'ut_exampletest2',a_line_no=>1); - l_test := ut_test(user, 'UT_EXAMPLETEST2','UT_EXAMPLETEST',a_line_no=>3); - l_test.before_test_list := ut_executables(ut_executable(user, 'UT_EXAMPLETEST2','SETUP',ut_utils.gc_before_test)); - l_test.after_test_list := ut_executables(ut_executable(user, 'UT_EXAMPLETEST2','TEARDOWN',ut_utils.gc_after_test)); - - l_suite.add_item(l_test); - l_parent_suite.add_item(l_suite); - - -- provide a reporter to process results - l_reporter := ut_custom_reporter(a_tab_size => 2); - ut_event_manager.add_listener(l_reporter); - l_run := ut_run(ut_suite_items(l_parent_suite)); - l_run.do_execute(); - ut_event_manager.trigger_event(ut_utils.gc_finalize, l_run); - l_reporter.lines_to_dbms_output(); -end; -/ - -drop type ut_custom_reporter; -drop package ut_exampletest; -drop package ut_exampletest2; -exec dbms_session.reset_package; diff --git a/examples/developer_examples/RunExampleTestSuite.sql b/examples/developer_examples/RunExampleTestSuite.sql index 7b01d1154..950450cd5 100644 --- a/examples/developer_examples/RunExampleTestSuite.sql +++ b/examples/developer_examples/RunExampleTestSuite.sql @@ -21,13 +21,15 @@ begin l_test.description := 'Example test1'; l_test.before_test_list := ut_executables(ut_executable(user, 'ut_exampletest','Setup',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'ut_exampletest','tEardown',ut_utils.gc_after_test)); - l_suite.add_item(l_test); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; l_test := ut_test(user, 'UT_EXAMPLETEST2','ut_exAmpletest',a_line_no=>6); l_test.description := 'Another example test'; l_test.before_test_list := ut_executables(ut_executable(user, 'UT_EXAMPLETEST2','SETUP',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'UT_EXAMPLETEST2','TEARDOWN',ut_utils.gc_after_test)); - l_suite.add_item(l_test); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; l_suite.do_execute(); diff --git a/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql b/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql index 8876f0874..f247e06db 100644 --- a/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql +++ b/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql @@ -12,7 +12,7 @@ set echo off PROMPT Runs test report using composite reporter declare - suite ut_logical_suite; + l_suite ut_logical_suite; l_doc_reporter ut_output_reporter_base := ut_documentation_reporter(); l_tc_reporter ut_output_reporter_base := ut_teamcity_reporter(); l_run ut_run; @@ -21,14 +21,16 @@ begin ut_event_manager.add_listener(l_doc_reporter); ut_event_manager.add_listener(l_tc_reporter); - suite := ut_suite(user, 'ut_exampletest',a_line_no=>1); - suite.description := 'Test Suite Name'; + l_suite := ut_suite(user, 'ut_exampletest',a_line_no=>1); + l_suite.description := 'Test Suite Name'; - suite.add_item(ut_test(user,'ut_exampletest','ut_exAmpletest',a_line_no=>3)); - suite.add_item(ut_test(user, 'UT_EXAMPLETEST2','UT_EXAMPLETEST',a_line_no=>6)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut_test(user,'ut_exampletest','ut_exAmpletest',a_line_no=>3); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut_test(user, 'UT_EXAMPLETEST2','UT_EXAMPLETEST',a_line_no=>6); -- provide a reporter to process results - l_run := ut_run(ut_suite_items(suite)); + l_run := ut_run(ut_suite_items(l_suite)); l_run.do_execute(); ut_event_manager.trigger_event(ut_utils.gc_finalize, l_run); diff --git a/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql b/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql index e9403809e..2cae9db53 100644 --- a/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql +++ b/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql @@ -28,13 +28,15 @@ begin l_test.description := 'Example test1'; l_test.before_test_list := ut_executables(ut_executable(user, 'ut_exampletest','Setup',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'ut_exampletest','tEardown',ut_utils.gc_after_test)); - l_suite.add_item(l_test); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; l_test := ut_test(user, 'UT_EXAMPLETEST2','ut_exAmpletest',a_line_no=>6); l_test.description := 'Another example test'; l_test.before_test_list := ut_executables(ut_executable(user, 'ut_exampletest','SETUP',ut_utils.gc_before_test)); l_test.after_test_list := ut_executables(ut_executable(user, 'ut_exampletest','TEARDOWN',ut_utils.gc_after_test)); - l_suite.add_item(l_test); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; -- provide a reporter to process results tabbing each hierarcy level by tab_size l_reporter := ut_custom_reporter(a_tab_size => 2); diff --git a/source/core/annotations/ut_annotation_manager.pkb b/source/core/annotations/ut_annotation_manager.pkb index 1c7e39273..6dbe1d3ec 100644 --- a/source/core/annotations/ut_annotation_manager.pkb +++ b/source/core/annotations/ut_annotation_manager.pkb @@ -193,7 +193,7 @@ create or replace package body ut_annotation_manager as ut_annotation_cache_manager.cleanup_cache(l_objects_to_parse); if sys_context('userenv','current_schema') = a_object_owner - or ut_metadata.is_object_visible('ut3.ut_utils') + or ut_metadata.user_has_execute_any_proc() or ut_metadata.is_object_visible('dba_objects') then ut_annotation_cache_manager.remove_from_cache( diff --git a/source/core/types/ut_console_reporter_base.tpb b/source/core/types/ut_console_reporter_base.tpb index 70513223c..0245edde3 100644 --- a/source/core/types/ut_console_reporter_base.tpb +++ b/source/core/types/ut_console_reporter_base.tpb @@ -36,20 +36,10 @@ create or replace type body ut_console_reporter_base is self.print_text(ut_ansiconsole_helper.yellow(a_text)); end; - member procedure print_blue_text(self in out nocopy ut_console_reporter_base, a_text varchar2) is - begin - self.print_text(ut_ansiconsole_helper.red(a_text)); - end; - member procedure print_cyan_text(self in out nocopy ut_console_reporter_base, a_text varchar2) is begin self.print_text(ut_ansiconsole_helper.cyan(a_text)); end; - member procedure print_magenta_text(self in out nocopy ut_console_reporter_base, a_text varchar2) is - begin - self.print_text(ut_ansiconsole_helper.magenta(a_text)); - end; - end; / diff --git a/source/core/types/ut_console_reporter_base.tps b/source/core/types/ut_console_reporter_base.tps index b74b08033..3736e4d33 100644 --- a/source/core/types/ut_console_reporter_base.tps +++ b/source/core/types/ut_console_reporter_base.tps @@ -23,11 +23,7 @@ create or replace type ut_console_reporter_base under ut_output_reporter_base( member procedure print_yellow_text(self in out nocopy ut_console_reporter_base, a_text varchar2), - member procedure print_blue_text(self in out nocopy ut_console_reporter_base, a_text varchar2), - - member procedure print_cyan_text(self in out nocopy ut_console_reporter_base, a_text varchar2), - - member procedure print_magenta_text(self in out nocopy ut_console_reporter_base, a_text varchar2) + member procedure print_cyan_text(self in out nocopy ut_console_reporter_base, a_text varchar2) ) not final not instantiable / diff --git a/source/core/types/ut_logical_suite.tpb b/source/core/types/ut_logical_suite.tpb index 70e0ca462..306ef3b36 100644 --- a/source/core/types/ut_logical_suite.tpb +++ b/source/core/types/ut_logical_suite.tpb @@ -16,45 +16,6 @@ create or replace type body ut_logical_suite as limitations under the License. */ - constructor function ut_logical_suite( - self in out nocopy ut_logical_suite,a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_path varchar2 - ) return self as result is - begin - self.self_type := $$plsql_unit; - self.init(a_object_owner, a_object_name, a_name, null); - self.path := a_path; - self.disabled_flag := ut_utils.boolean_to_int(false); - self.items := ut_suite_items(); - return; - end; - - member function is_valid(self in out nocopy ut_logical_suite) return boolean is - begin - return true; - end; - - overriding member procedure add_item( - self in out nocopy ut_logical_suite, - a_item ut_suite_item, - a_expected_level integer := 1, - a_current_level integer :=1 - ) is - begin - if a_expected_level > a_current_level then - if self.items.last is not null then - self.items(self.items.last).add_item(a_item, a_expected_level, a_current_level+1); - else - raise_application_error(-20000, 'cannot add suite item to sub suite at level '||a_expected_level||'. suite items at level '||a_current_level||' are empty'); - end if; - else - if self.items is null then - self.items := ut_suite_items(); - end if; - self.items.extend; - self.items(self.items.last) := a_item; - end if; - end; - overriding member procedure mark_as_skipped(self in out nocopy ut_logical_suite) is begin ut_event_manager.trigger_event(ut_utils.gc_before_suite, self); diff --git a/source/core/types/ut_logical_suite.tps b/source/core/types/ut_logical_suite.tps index 2672cacd3..a9043c87e 100644 --- a/source/core/types/ut_logical_suite.tps +++ b/source/core/types/ut_logical_suite.tps @@ -21,16 +21,6 @@ create or replace type ut_logical_suite under ut_suite_item ( */ items ut_suite_items, - constructor function ut_logical_suite( - self in out nocopy ut_logical_suite, a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_path varchar2 - ) return self as result, - member function is_valid(self in out nocopy ut_logical_suite) return boolean, - overriding member procedure add_item( - self in out nocopy ut_logical_suite, - a_item ut_suite_item, - a_expected_level integer := 1, - a_current_level integer :=1 - ), overriding member procedure mark_as_skipped(self in out nocopy ut_logical_suite), overriding member procedure set_rollback_type(self in out nocopy ut_logical_suite, a_rollback_type integer), overriding member function do_execute(self in out nocopy ut_logical_suite) return boolean, diff --git a/source/core/types/ut_run.tpb b/source/core/types/ut_run.tpb index f7756cf37..a1ee19bd2 100644 --- a/source/core/types/ut_run.tpb +++ b/source/core/types/ut_run.tpb @@ -51,16 +51,6 @@ create or replace type body ut_run as null; end; - overriding member procedure add_item( - self in out nocopy ut_run, - a_item ut_suite_item, - a_expected_level integer := 1, - a_current_level integer :=1 - ) is - begin - raise_application_error(-20000, 'Cannot add a suite item to ut_run'); - end; - overriding member function do_execute(self in out nocopy ut_run) return boolean is l_completed_without_errors boolean; begin @@ -103,19 +93,7 @@ create or replace type body ut_run as overriding member procedure mark_as_errored(self in out nocopy ut_run, a_error_stack_trace varchar2) is begin - ut_utils.debug_log('ut_run.fail'); - - ut_event_manager.trigger_event(ut_utils.gc_before_run, self); - self.start_time := current_timestamp; - - for i in 1 .. self.items.count loop - self.items(i).mark_as_errored(a_error_stack_trace); - end loop; - - self.calc_execution_result(); - self.end_time := self.start_time; - - ut_event_manager.trigger_event(ut_utils.gc_after_run, self); + null; end; overriding member function get_error_stack_traces return ut_varchar2_list is diff --git a/source/core/types/ut_run.tps b/source/core/types/ut_run.tps index 3807a2a75..5dc8e0399 100644 --- a/source/core/types/ut_run.tps +++ b/source/core/types/ut_run.tps @@ -36,12 +36,6 @@ create or replace type ut_run under ut_suite_item ( a_client_character_set varchar2 := null ) return self as result, overriding member procedure mark_as_skipped(self in out nocopy ut_run), - overriding member procedure add_item( - self in out nocopy ut_run, - a_item ut_suite_item, - a_expected_level integer := 1, - a_current_level integer :=1 - ), overriding member function do_execute(self in out nocopy ut_run) return boolean, overriding member procedure calc_execution_result(self in out nocopy ut_run), overriding member procedure mark_as_errored(self in out nocopy ut_run, a_error_stack_trace varchar2), diff --git a/source/core/types/ut_suite_item.tps b/source/core/types/ut_suite_item.tps index 927ad3807..e91b2afd0 100644 --- a/source/core/types/ut_suite_item.tps +++ b/source/core/types/ut_suite_item.tps @@ -63,12 +63,6 @@ create or replace type ut_suite_item force under ut_event_item ( member procedure init(self in out nocopy ut_suite_item, a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_line_no integer), member function get_disabled_flag return boolean, not instantiable member procedure mark_as_skipped(self in out nocopy ut_suite_item), - not instantiable member procedure add_item( - self in out nocopy ut_suite_item, - a_item ut_suite_item, - a_expected_level integer := 1, - a_current_level integer :=1 - ), member procedure set_rollback_type(self in out nocopy ut_suite_item, a_rollback_type integer), member function get_rollback_type return integer, member function create_savepoint_if_needed return varchar2, diff --git a/source/core/types/ut_test.tpb b/source/core/types/ut_test.tpb index d68b19a87..ed9692e14 100644 --- a/source/core/types/ut_test.tpb +++ b/source/core/types/ut_test.tpb @@ -34,16 +34,6 @@ create or replace type body ut_test as return; end; - overriding member procedure add_item( - self in out nocopy ut_test, - a_item ut_suite_item, - a_expected_level integer := 1, - a_current_level integer :=1 - ) is - begin - raise_application_error(-20000, 'Cannot add a suite item to ut_test'); - end; - overriding member procedure mark_as_skipped(self in out nocopy ut_test) is begin ut_event_manager.trigger_event(ut_utils.gc_before_test, self); diff --git a/source/core/types/ut_test.tps b/source/core/types/ut_test.tps index 9e26508e4..752ef3ef7 100644 --- a/source/core/types/ut_test.tps +++ b/source/core/types/ut_test.tps @@ -60,12 +60,6 @@ create or replace type ut_test under ut_suite_item ( a_line_no integer, a_expected_error_codes ut_integer_list := null ) return self as result, overriding member procedure mark_as_skipped(self in out nocopy ut_test), - overriding member procedure add_item( - self in out nocopy ut_test, - a_item ut_suite_item, - a_expected_level integer := 1, - a_current_level integer :=1 - ), overriding member function do_execute(self in out nocopy ut_test) return boolean, overriding member procedure calc_execution_result(self in out nocopy ut_test), overriding member procedure mark_as_errored(self in out nocopy ut_test, a_error_stack_trace varchar2), diff --git a/source/core/ut_metadata.pkb b/source/core/ut_metadata.pkb index d500bff61..92afa706e 100644 --- a/source/core/ut_metadata.pkb +++ b/source/core/ut_metadata.pkb @@ -22,12 +22,6 @@ create or replace package body ut_metadata as ------------------------------ --public definitions - procedure do_resolve(a_owner in out nocopy varchar2, a_object in out nocopy varchar2) is - l_procedure_name varchar2(200); - begin - do_resolve(a_owner, a_object, l_procedure_name ); - end do_resolve; - procedure do_resolve(a_owner in out nocopy varchar2, a_object in out nocopy varchar2, a_procedure_name in out nocopy varchar2) is l_name varchar2(200); l_context integer := 1; --plsql @@ -83,9 +77,6 @@ create or replace package body ut_metadata as -- expect both package and body to be valid return l_cnt = 1; - exception - when others then - return false; end; function procedure_exists(a_owner_name varchar2, a_package_name in varchar2, a_procedure_name in varchar2) @@ -110,9 +101,6 @@ create or replace package body ut_metadata as --expect one method only for the package with that name. return l_cnt = 1; - exception - when others then - return false; end; function get_source_definition_line(a_owner varchar2, a_object_name varchar2, a_line_no integer) return varchar2 is @@ -168,14 +156,8 @@ 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; - l_dummy varchar2(250); begin - execute immediate 'select '||l_ut_owner||'.ut_utils.ut_owner from dual' - into l_dummy; - return true; - exception - when others then - return false; + return is_object_visible(l_ut_owner||'.ut_utils'); end; function is_object_visible(a_object_name varchar2) return boolean is diff --git a/source/core/ut_metadata.pks b/source/core/ut_metadata.pks index 16172a1f1..9a0ac2b00 100644 --- a/source/core/ut_metadata.pks +++ b/source/core/ut_metadata.pks @@ -39,12 +39,6 @@ create or replace package ut_metadata authid current_user as function procedure_exists(a_owner_name varchar2, a_package_name in varchar2, a_procedure_name in varchar2) return boolean; - /** - * Resolves [owner.]object using dbms_utility.name_resolve and returns resolved parts - * - */ - procedure do_resolve(a_owner in out nocopy varchar2, a_object in out nocopy varchar2); - /** * Resolves [owner.]object[.procedure] using dbms_utility.name_resolve and returns resolved parts * diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index fe76b2ed7..19862992d 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -465,7 +465,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.is_object_visible( ut_utils.ut_owner ||'.ut_utils' ); + return sys_context( 'userenv', 'current_schema' ) = a_owner_name or ut_metadata.user_has_execute_any_proc(); end; procedure build_and_cache_suites( @@ -582,7 +582,7 @@ create or replace package body ut_suite_manager is l_need_all_objects_scan boolean := true; begin -- if current user is the onwer or current user has execute any procedure privilege - if ut_metadata.is_object_visible('ut3.ut_utils') + if ut_metadata.user_has_execute_any_proc() or (a_schema_names is not null and a_schema_names.count = 1 and sys_context('userenv','current_schema') = a_schema_names(1)) then diff --git a/source/core/ut_utils.pkb b/source/core/ut_utils.pkb index 928da6ca1..dbe57f866 100644 --- a/source/core/ut_utils.pkb +++ b/source/core/ut_utils.pkb @@ -55,18 +55,6 @@ create or replace package body ut_utils is return '"'|| utl_raw.cast_to_varchar2(utl_encode.base64_encode(sys_guid()))||'"'; end; - /* - Procedure: validate_rollback_type - - Validates passed value against supported rollback types - */ - procedure validate_rollback_type(a_rollback_type number) is - begin - if a_rollback_type not in (gc_rollback_auto, gc_rollback_manual) then - raise_application_error(-20200,'Rollback type is not supported'); - end if; - end validate_rollback_type; - procedure debug_log(a_message varchar2) is begin $if $$ut_trace $then @@ -604,15 +592,13 @@ create or replace package body ut_utils is end; function xmlgen_escaped_string(a_string in varchar2) return varchar2 is - l_result varchar2(4000); + l_result varchar2(4000) := a_string; l_sql varchar2(32767) := q'!select q'[!'||a_string||q'!]' as "!'||a_string||'" from dual'; begin if a_string is not null then select extract(dbms_xmlgen.getxmltype(l_sql),'/*/*/*').getRootElement() into l_result from dual; - else - l_result := a_string; end if; return l_result; end; diff --git a/source/core/ut_utils.pks b/source/core/ut_utils.pks index 2a892c1e9..40b084d30 100644 --- a/source/core/ut_utils.pks +++ b/source/core/ut_utils.pks @@ -183,12 +183,6 @@ create or replace package ut_utils authid definer is function int_to_boolean(a_value integer) return boolean; - /** - * Validates passed value against supported rollback types - */ - procedure validate_rollback_type(a_rollback_type number); - - /** * * Splits a given string into table of string by delimiter. diff --git a/source/reporters/ut_ansiconsole_helper.pkb b/source/reporters/ut_ansiconsole_helper.pkb index ceb0cf53f..d9c0617e0 100644 --- a/source/reporters/ut_ansiconsole_helper.pkb +++ b/source/reporters/ut_ansiconsole_helper.pkb @@ -53,16 +53,6 @@ create or replace package body ut_ansiconsole_helper as return add_color(a_text, gc_yellow); end; - function blue(a_text varchar2) return varchar2 is - begin - return add_color(a_text, gc_blue); - end; - - function magenta(a_text varchar2) return varchar2 is - begin - return add_color(a_text, gc_magenta); - end; - function cyan(a_text varchar2) return varchar2 is begin return add_color(a_text, gc_cyan); diff --git a/source/reporters/ut_ansiconsole_helper.pks b/source/reporters/ut_ansiconsole_helper.pks index 29d746c7b..f34ff12bd 100644 --- a/source/reporters/ut_ansiconsole_helper.pks +++ b/source/reporters/ut_ansiconsole_helper.pks @@ -23,10 +23,6 @@ create or replace package ut_ansiconsole_helper as function yellow(a_text varchar2) return varchar2; - function blue(a_text varchar2) return varchar2; - - function magenta(a_text varchar2) return varchar2; - function cyan(a_text varchar2) return varchar2; end; / diff --git a/source/reporters/ut_teamcity_reporter.tpb b/source/reporters/ut_teamcity_reporter.tpb index a8a7ad45b..d01e85153 100644 --- a/source/reporters/ut_teamcity_reporter.tpb +++ b/source/reporters/ut_teamcity_reporter.tpb @@ -60,6 +60,25 @@ create or replace type body ut_teamcity_reporter is l_results ut_varchar2_rows := ut_varchar2_rows(); l_test_full_name varchar2(4000); l_std_err_msg varchar2(32767); + function add_error_message( a_message varchar2, a_message_name varchar2) return varchar2 is + begin + return + case + when a_message is not null + then a_message_name || chr(10) || a_message || chr(10) + end; + end; + function add_error_messages(a_executables ut_executables, a_message_name varchar2) return varchar2 is + l_message varchar2(32767); + l_idx binary_integer; + begin + l_idx := a_executables.first; + while l_idx is not null loop + l_message := l_message || add_error_message(a_executables(l_idx).error_backtrace, a_message_name); + l_idx := a_executables.next(l_idx); + end loop; + return l_message; + end; begin l_test_full_name := lower(a_test.item.owner_name) || '.' || lower(a_test.item.object_name) || '.' || lower(a_test.item.procedure_name); @@ -71,33 +90,11 @@ create or replace type body ut_teamcity_reporter is ut_utils.append_to_list( l_results, a_test.get_serveroutputs()); if a_test.result = ut_utils.gc_error then - for i in 1 .. a_test.before_each_list.count loop - if a_test.before_each_list(i).error_backtrace is not null then - l_std_err_msg := l_std_err_msg || 'Before each exception:' || chr(10) || a_test.before_each_list(i).error_backtrace || chr(10); - end if; - end loop; - - for i in 1 .. a_test.before_test_list.count loop - if a_test.before_test_list(i).error_backtrace is not null then - l_std_err_msg := l_std_err_msg || 'Before test exception:' || chr(10) || a_test.before_test_list(i).error_backtrace || chr(10); - end if; - end loop; - - if a_test.item.error_backtrace is not null then - l_std_err_msg := l_std_err_msg || 'Test exception:' || chr(10) || a_test.item.error_backtrace || chr(10); - end if; - - for i in 1 .. a_test.after_test_list.count loop - if a_test.after_test_list(i).error_backtrace is not null then - l_std_err_msg := l_std_err_msg || 'After test exception:' || chr(10) || a_test.after_test_list(i).error_backtrace || chr(10); - end if; - end loop; - - for i in 1 .. a_test.after_each_list.count loop - if a_test.after_each_list(i).error_backtrace is not null then - l_std_err_msg := l_std_err_msg || 'After each exception:' || chr(10) || a_test.after_each_list(i).error_backtrace || chr(10); - end if; - end loop; + l_std_err_msg := l_std_err_msg || add_error_messages(a_test.before_each_list, 'Before each exception:'); + l_std_err_msg := l_std_err_msg || add_error_messages(a_test.before_test_list, 'Before test exception:'); + l_std_err_msg := l_std_err_msg || add_error_message(a_test.item.error_backtrace, 'Test exception:'); + l_std_err_msg := l_std_err_msg || add_error_messages(a_test.after_test_list, 'After test exception:'); + l_std_err_msg := l_std_err_msg || add_error_messages(a_test.after_each_list, 'After each exception:'); ut_utils.append_to_list( l_results, diff --git a/test/api/test_ut_run.pkb b/test/api/test_ut_run.pkb index 9709058d4..ecf123d5e 100644 --- a/test/api/test_ut_run.pkb +++ b/test/api/test_ut_run.pkb @@ -355,6 +355,94 @@ create or replace package body test_ut_run is ut.expect( l_results ).to_be_like( '%test_package_1%test_package_2%test_package_3%' ); end; + procedure create_suite_with_commit is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package test_commit_warning is + --%suite + --%suitepath(ut.run.transaction) + + --%test + procedure does_commit; + end;'; + execute immediate 'create or replace package body test_commit_warning is + procedure does_commit is + begin + ut3.ut.expect(1).to_equal(1); + commit; + end; + end;'; + end; + + procedure drop_suite_with_commit is + pragma autonomous_transaction; + begin + execute immediate 'drop package test_commit_warning'; + end; + + procedure run_proc_warn_on_commit is + l_results clob; + begin + ut3.ut.run('test_commit_warning'); + l_results := get_dbms_output_as_clob(); + ut.expect(l_results).to_be_like( + '%Unable to perform automatic rollback after test%'|| + 'An implicit or explicit commit/rollback occurred in procedures:%' || + 'does_commit%' || + 'Use the "--%rollback(manual)" annotation or remove commit/rollback/ddl statements that are causing the issue.%' + ); + end; + + procedure create_failing_beforeall_suite is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package parent_suite is + --%suite + --%suitepath(ut.run.failing_setup) + + --%beforeall + procedure failing_setup; + end;'; + execute immediate 'create or replace package body parent_suite is + procedure failing_setup is + begin + raise no_data_found; + end; + end;'; + execute immediate 'create or replace package child_suite is + --%suite + --%suitepath(ut.run.failing_setup.parent_suite.some_sub_suite) + + --%test + procedure does_stuff; + end;'; + execute immediate 'create or replace package body child_suite is + procedure does_stuff is + begin + ut3.ut.expect(1).to_equal(1); + end; + end;'; + end; + + procedure drop_failing_beforeall_suite is + pragma autonomous_transaction; + begin + execute immediate 'drop package parent_suite'; + execute immediate 'drop package child_suite'; + end; + + procedure run_proc_fail_child_suites is + l_results clob; + begin + ut3.ut.run('child_suite'); + l_results := get_dbms_output_as_clob(); + ut.expect(l_results).to_be_like( + '%1) does_stuff%' || + 'ORA-01403: no data found%' || + 'ORA-06512: at "UT3_TESTER.PARENT_SUITE%' + ); + end; + procedure run_func_no_params is l_results ut3.ut_varchar2_list; begin diff --git a/test/api/test_ut_run.pks b/test/api/test_ut_run.pks index 927abf6e2..81eb801a3 100644 --- a/test/api/test_ut_run.pks +++ b/test/api/test_ut_run.pks @@ -41,6 +41,21 @@ create or replace package test_ut_run is --%test(Runs all tests in current schema with empty path list given) procedure run_proc_empty_path_list; + procedure create_suite_with_commit; + procedure drop_suite_with_commit; + --%test(Reports a warning if transaction was invalidated by test with automatic rollback) + --%beforetest(create_suite_with_commit) + --%aftertest(drop_suite_with_commit) + procedure run_proc_warn_on_commit; + + + procedure create_failing_beforeall_suite; + procedure drop_failing_beforeall_suite; + --%test(Marks child suite as failed when parent's suite beforeall fails) + --%beforetest(create_failing_beforeall_suite) + --%aftertest(drop_failing_beforeall_suite) + procedure run_proc_fail_child_suites; + --%endcontext diff --git a/test/core/test_ut_suite.pkb b/test/core/test_ut_suite.pkb index 9955aa048..557d3cb7b 100644 --- a/test/core/test_ut_suite.pkb +++ b/test/core/test_ut_suite.pkb @@ -14,8 +14,10 @@ create or replace package body test_ut_suite is l_suite.disabled_flag := ut3.ut_utils.boolean_to_int(true); l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); l_suite.after_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_before_all)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -35,7 +37,8 @@ create or replace package body test_ut_suite is l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_EXAMPLE_TESTS', a_line_no=> 1); l_suite.path := 'ut_example_tests'; l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_before_all)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'set_g_number_0', a_line_no=> 1)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'set_g_number_0', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -56,8 +59,10 @@ create or replace package body test_ut_suite is l_suite.path := 'ut_example_tests'; l_suite.after_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_after_all)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'set_g_number_0', a_line_no=> 1)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'set_g_number_0', a_line_no=> 1); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -75,7 +80,8 @@ create or replace package body test_ut_suite is begin l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_WITHOUT_BODY', a_line_no=> 1); l_suite.path := 'UT_WITHOUT_BODY'; - l_suite.add_item(ut3.ut_test(a_object_name => 'ut_without_body',a_name => 'test1', a_line_no=> 1)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'ut_without_body',a_name => 'test1', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -87,7 +93,8 @@ create or replace package body test_ut_suite is begin l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_WITH_INVALID_BODY', a_line_no=> 1); l_suite.path := 'UT_WITH_INVALID_BODY'; - l_suite.add_item(ut3.ut_test(a_object_name => 'ut_with_invalid_body',a_name => 'test1', a_line_no=> 1)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'ut_with_invalid_body',a_name => 'test1', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -102,7 +109,8 @@ create or replace package body test_ut_suite is l_suite := ut3.ut_suite(a_object_owner => USER, a_object_name => 'UT_TRANSACTION_CONTROL', a_line_no=> 1); l_suite.path := 'ut_transaction_control'; l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_TRANSACTION_CONTROL', 'setup', ut3.ut_utils.gc_before_all)); - l_suite.add_item(ut3.ut_test(a_object_owner => USER, a_object_name => 'ut_transaction_control',a_name => a_procedure_name, a_line_no=> 1)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_owner => USER, a_object_name => 'ut_transaction_control',a_name => a_procedure_name, a_line_no=> 1); l_suite.set_rollback_type(a_rollback_type); --Act diff --git a/test/core/test_ut_test.pkb b/test/core/test_ut_test.pkb index 857ef5e99..5b401463c 100644 --- a/test/core/test_ut_test.pkb +++ b/test/core/test_ut_test.pkb @@ -14,8 +14,10 @@ create or replace package body test_ut_test is l_suite.path := 'ut_example_tests'; l_suite.before_all_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'set_g_number_0', ut3.ut_utils.gc_before_all)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 2)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 2); l_suite.items(l_suite.items.last).disabled_flag := ut3.ut_utils.boolean_to_int(true); --Act l_suite.do_execute(); @@ -41,8 +43,10 @@ create or replace package body test_ut_test is l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); l_test.before_test_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_before_test)); l_test.after_test_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_after_test)); - l_suite.add_item(l_test); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -65,8 +69,10 @@ create or replace package body test_ut_test is l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); l_test.before_each_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_before_each)); l_test.after_each_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_after_each)); - l_suite.add_item(l_test); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -89,8 +95,10 @@ create or replace package body test_ut_test is l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); l_test.before_test_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_before_test)); l_test.after_test_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_after_test)); - l_suite.add_item(l_test); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); --Act l_suite.do_execute(); --Assert @@ -113,8 +121,10 @@ create or replace package body test_ut_test is l_test := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); l_test.before_each_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'failing_procedure', ut3.ut_utils.gc_before_each)); l_test.after_each_list := ut3.ut_executables(ut3.ut_executable(USER, 'UT_EXAMPLE_TESTS', 'add_1_to_g_number', ut3.ut_utils.gc_after_each)); - l_suite.add_item(l_test); - l_suite.add_item(ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1)); + l_suite.items.extend; + l_suite.items(l_suite.items.last) := l_test; + l_suite.items.extend; + l_suite.items(l_suite.items.last) := ut3.ut_test(a_object_name => 'UT_EXAMPLE_TESTS',a_name => 'add_1_to_g_number', a_line_no=> 1); --Act l_suite.do_execute(); --Assert From 44d61d921406077a58080c3538448217d07b5d7d Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 18 Nov 2018 15:35:50 +0000 Subject: [PATCH 29/33] Recovering exception handlers as they are needed for handling invalid object names. --- source/core/ut_metadata.pkb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/core/ut_metadata.pkb b/source/core/ut_metadata.pkb index 92afa706e..c905ebefe 100644 --- a/source/core/ut_metadata.pkb +++ b/source/core/ut_metadata.pkb @@ -77,6 +77,9 @@ create or replace package body ut_metadata as -- expect both package and body to be valid return l_cnt = 1; + exception + when others then + return false; end; function procedure_exists(a_owner_name varchar2, a_package_name in varchar2, a_procedure_name in varchar2) @@ -101,6 +104,9 @@ create or replace package body ut_metadata as --expect one method only for the package with that name. return l_cnt = 1; + exception + when others then + return false; end; function get_source_definition_line(a_owner varchar2, a_object_name varchar2, a_line_no integer) return varchar2 is From 360a8895645d9065cb48ebf3d8af6fb175c4eec9 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 18 Nov 2018 18:26:05 +0000 Subject: [PATCH 30/33] Moved some of old tests into new tests. Disabled coverage gathering on old tests. --- old_tests/RunAll.sql | 633 +++++++++--------- ...e_manager.CacheInvalidaesOnPackageDrop.sql | 50 -- .../ut_suite_manager.emptySuitePath.sql | 41 -- .../ut_test/ut_test.AfterEachExecuted.sql | 20 - .../ut_test.AfterEachProcedureNameInvalid.sql | 21 - .../ut_test.AfterEachProcedureNameNull.sql | 21 - .../ut_test.ApplicationInfoOnExecution.sql | 149 ----- .../ut_test/ut_test.BeforeEachExecuted.sql | 21 - ...ut_test.BeforeEachProcedureNameInvalid.sql | 20 - .../ut_test.BeforeEachProcedureNameNull.sql | 22 - ...est.IgnoreTollbackToSavepointException.sql | 17 - .../ut_test/ut_test.OwnerNameInvalid.sql | 21 - old_tests/ut_test/ut_test.OwnerNameNull.sql | 18 - .../ut_test/ut_test.PackageInInvalidState.sql | 27 - .../ut_test/ut_test.PackageNameInvalid.sql | 16 - old_tests/ut_test/ut_test.PackageNameNull.sql | 16 - .../ut_test/ut_test.ProcedureNameInvalid.sql | 16 - .../ut_test/ut_test.ProcedureNameNull.sql | 16 - .../ut_test.ReportWarningOnRollbackFailed.sql | 58 -- .../ut_test.SetupExecutedBeforeTest.sql | 21 - .../ut_test.SetupProcedureNameInvalid.sql | 20 - .../ut_test.SetupProcedureNameNull.sql | 22 - .../ut_test.TeardownExecutedAfterTest.sql | 20 - .../ut_test.TeardownProcedureNameInvalid.sql | 20 - .../ut_test.TeardownProcedureNameNull.sql | 21 - .../ut_test/ut_test.TestOutputGathering.sql | 103 --- .../ut_test.TestOutputGatheringWhenEmpty.sql | 55 -- sonar-project.properties | 2 +- test/core/test_ut_test.pkb | 556 +++++++++++++++ test/core/test_ut_test.pks | 66 ++ test/helpers/ut_example_tests.pkb | 4 + test/helpers/ut_example_tests.pks | 12 +- 32 files changed, 936 insertions(+), 1189 deletions(-) delete mode 100644 old_tests/ut_suite_manager/ut_suite_manager.CacheInvalidaesOnPackageDrop.sql delete mode 100644 old_tests/ut_suite_manager/ut_suite_manager.emptySuitePath.sql delete mode 100644 old_tests/ut_test/ut_test.AfterEachExecuted.sql delete mode 100644 old_tests/ut_test/ut_test.AfterEachProcedureNameInvalid.sql delete mode 100644 old_tests/ut_test/ut_test.AfterEachProcedureNameNull.sql delete mode 100644 old_tests/ut_test/ut_test.ApplicationInfoOnExecution.sql delete mode 100644 old_tests/ut_test/ut_test.BeforeEachExecuted.sql delete mode 100644 old_tests/ut_test/ut_test.BeforeEachProcedureNameInvalid.sql delete mode 100644 old_tests/ut_test/ut_test.BeforeEachProcedureNameNull.sql delete mode 100644 old_tests/ut_test/ut_test.IgnoreTollbackToSavepointException.sql delete mode 100644 old_tests/ut_test/ut_test.OwnerNameInvalid.sql delete mode 100644 old_tests/ut_test/ut_test.OwnerNameNull.sql delete mode 100644 old_tests/ut_test/ut_test.PackageInInvalidState.sql delete mode 100644 old_tests/ut_test/ut_test.PackageNameInvalid.sql delete mode 100644 old_tests/ut_test/ut_test.PackageNameNull.sql delete mode 100644 old_tests/ut_test/ut_test.ProcedureNameInvalid.sql delete mode 100644 old_tests/ut_test/ut_test.ProcedureNameNull.sql delete mode 100644 old_tests/ut_test/ut_test.ReportWarningOnRollbackFailed.sql delete mode 100644 old_tests/ut_test/ut_test.SetupExecutedBeforeTest.sql delete mode 100644 old_tests/ut_test/ut_test.SetupProcedureNameInvalid.sql delete mode 100644 old_tests/ut_test/ut_test.SetupProcedureNameNull.sql delete mode 100644 old_tests/ut_test/ut_test.TeardownExecutedAfterTest.sql delete mode 100644 old_tests/ut_test/ut_test.TeardownProcedureNameInvalid.sql delete mode 100644 old_tests/ut_test/ut_test.TeardownProcedureNameNull.sql delete mode 100644 old_tests/ut_test/ut_test.TestOutputGathering.sql delete mode 100644 old_tests/ut_test/ut_test.TestOutputGatheringWhenEmpty.sql diff --git a/old_tests/RunAll.sql b/old_tests/RunAll.sql index f785aabc1..282a01ff7 100644 --- a/old_tests/RunAll.sql +++ b/old_tests/RunAll.sql @@ -50,41 +50,14 @@ exec ut_coverage.set_develop_mode(true); @@lib/RunTest.sql ut_reporters/ut_html_reporter.UserOverrideSchemaCoverage.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.AllowsDescriptionsWithComma.sql -@@lib/RunTest.sql ut_suite_manager/ut_suite_manager.emptySuitePath.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.get_schema_ut_packages.IncludesPackagesWithSutePath.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.IncludesInvalidPackageBodiesInTheRun.sql -@@lib/RunTest.sql ut_suite_manager/ut_suite_manager.CacheInvalidaesOnPackageDrop.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.PackageWithDollarSign.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.PackageWithHash.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.TestWithDollarSign.sql @@lib/RunTest.sql ut_suite_manager/ut_suite_manager.TestWithHashSign.sql -@@lib/RunTest.sql ut_test/ut_test.OwnerNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.OwnerNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.PackageInInvalidState.sql -@@lib/RunTest.sql ut_test/ut_test.PackageNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.PackageNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.ProcedureNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.ProcedureNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.SetupExecutedBeforeTest.sql -@@lib/RunTest.sql ut_test/ut_test.SetupProcedureNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.SetupProcedureNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.TeardownExecutedAfterTest.sql -@@lib/RunTest.sql ut_test/ut_test.TeardownProcedureNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.TeardownProcedureNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.IgnoreTollbackToSavepointException.sql -@@lib/RunTest.sql ut_test/ut_test.AfterEachExecuted.sql -@@lib/RunTest.sql ut_test/ut_test.AfterEachProcedureNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.AfterEachProcedureNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.BeforeEachExecuted.sql -@@lib/RunTest.sql ut_test/ut_test.BeforeEachProcedureNameInvalid.sql -@@lib/RunTest.sql ut_test/ut_test.BeforeEachProcedureNameNull.sql -@@lib/RunTest.sql ut_test/ut_test.TestOutputGathering.sql -@@lib/RunTest.sql ut_test/ut_test.TestOutputGatheringWhenEmpty.sql -@@lib/RunTest.sql ut_test/ut_test.ReportWarningOnRollbackFailed.sql -@@lib/RunTest.sql ut_test/ut_test.ApplicationInfoOnExecution.sql - @@ut_utils/ut_utils.clob_to_table.sql @@ut_utils/ut_utils.table_to_clob.sql @@lib/RunTest.sql ut_utils/ut_utils.append_to_clob.worksWithMultiByteChars.sql @@ -110,309 +83,309 @@ drop type utplsql_test_reporter; drop package test_reporters; drop package ut3$user#.html_coverage_test; -set timing on -prompt Generating coverage data to reporter outputs - -var html_reporter_id varchar2(32); -var sonar_reporter_id varchar2(32); -var coveralls_reporter_id varchar2(32); -declare - l_reporter ut_reporter_base; - l_project_file_list ut_varchar2_list; - l_test_run ut_run; -begin - l_project_file_list := ut_varchar2_list( - 'source/api', - 'source/core', - 'source/create_synonyms_and_grants_for_public.sql', - 'source/create_synonyms_and_grants_for_user.sql', - 'source/create_utplsql_owner.sql', - 'source/expectations', - 'source/install.log', - 'source/install.sql', - 'source/install_headless.sql', - 'source/license.txt', - 'source/readme.md', - 'source/reporters', - 'source/uninstall.log', - 'source/uninstall.sql', - 'source/api/be_between.syn', - 'source/api/be_empty.syn', - 'source/api/be_false.syn', - 'source/api/be_greater_or_equal.syn', - 'source/api/be_greater_than.syn', - 'source/api/be_less_or_equal.syn', - 'source/api/be_less_than.syn', - 'source/api/be_like.syn', - 'source/api/be_not_null.syn', - 'source/api/be_null.syn', - 'source/api/be_true.syn', - 'source/api/equal.syn', - 'source/api/match.syn', - 'source/api/ut.pkb', - 'source/api/ut.pks', - 'source/api/ut_runner.pkb', - 'source/api/ut_runner.pks', - 'source/core/coverage', - 'source/core/output_buffers', - 'source/core/types', - 'source/core/annotations/ut_annotation_manager.pkb', - 'source/core/annotations/ut_annotation_manager.pks', - 'source/core/annotations/ut_annotation_parser.pkb', - 'source/core/annotations/ut_annotation_parser.pks', - 'source/core/annotations/ut_annotation_cache_manager.pkb', - 'source/core/annotations/ut_annotation_cache_manager.pks', - 'source/core/ut_expectation_processor.pkb', - 'source/core/ut_expectation_processor.pks', - 'source/core/ut_file_mapper.pkb', - 'source/core/ut_file_mapper.pks', - 'source/core/ut_metadata.pkb', - 'source/core/ut_metadata.pks', - 'source/core/ut_suite_manager.pkb', - 'source/core/ut_suite_manager.pks', - 'source/core/ut_utils.pkb', - 'source/core/ut_utils.pks', - 'source/core/coverage/proftab.sql', - 'source/core/coverage/ut_coverage.pkb', - 'source/core/coverage/ut_coverage.pks', - 'source/core/coverage/ut_coverage_helper.pkb', - 'source/core/coverage/ut_coverage_helper.pks', - 'source/core/coverage/ut_coverage_sources_tmp.sql', - 'source/core/coverage/ut_coverage_reporter_base.tpb', - 'source/core/coverage/ut_coverage_reporter_base.tps', - 'source/core/output_buffers/ut_message_id_seq.sql', - 'source/core/output_buffers/ut_output_buffer_base.tps', - 'source/core/output_buffers/ut_output_buffer_info_tmp.sql', - 'source/core/output_buffers/ut_output_buffer_tmp.sql', - 'source/core/output_buffers/ut_output_table_buffer.tpb', - 'source/core/output_buffers/ut_output_table_buffer.tps', - 'source/core/types/ut_console_reporter_base.tpb', - 'source/core/types/ut_console_reporter_base.tps', - 'source/core/types/ut_coverage_options.tps', - 'source/core/types/ut_event_listener.tpb', - 'source/core/types/ut_event_listener.tps', - 'source/core/types/ut_event_listener_base.tps', - 'source/core/types/ut_executable.tpb', - 'source/core/types/ut_executable.tps', - 'source/core/types/ut_expectation_result.tpb', - 'source/core/types/ut_expectation_result.tps', - 'source/core/types/ut_expectation_results.tps', - 'source/core/types/ut_file_mapping.tpb', - 'source/core/types/ut_file_mapping.tps', - 'source/core/types/ut_file_mappings.tps', - 'source/core/types/ut_key_value_pair.tps', - 'source/core/types/ut_key_value_pairs.tps', - 'source/core/types/ut_logical_suite.tpb', - 'source/core/types/ut_logical_suite.tps', - 'source/core/types/ut_object_name.tpb', - 'source/core/types/ut_object_name.tps', - 'source/core/types/ut_object_names.tps', - 'source/core/types/ut_output_reporter_base.tpb', - 'source/core/types/ut_output_reporter_base.tps', - 'source/core/types/ut_reporters.tps', - 'source/core/types/ut_reporter_base.tpb', - 'source/core/types/ut_reporter_base.tps', - 'source/core/types/ut_results_counter.tpb', - 'source/core/types/ut_results_counter.tps', - 'source/core/types/ut_run.tpb', - 'source/core/types/ut_run.tps', - 'source/core/types/ut_suite.tpb', - 'source/core/types/ut_suite.tps', - 'source/core/types/ut_suite_item.tpb', - 'source/core/types/ut_suite_item.tps', - 'source/core/types/ut_suite_items.tps', - 'source/core/types/ut_test.tpb', - 'source/core/types/ut_test.tps', - 'source/core/types/ut_varchar2_list.tps', - 'source/core/types/ut_varchar2_rows.tps', - 'source/expectations/data_values', - 'source/expectations/matchers', - 'source/expectations/ut_expectation.tpb', - 'source/expectations/ut_expectation.tps', - 'source/expectations/ut_expectation_anydata.tpb', - 'source/expectations/ut_expectation_anydata.tps', - 'source/expectations/ut_expectation_blob.tpb', - 'source/expectations/ut_expectation_blob.tps', - 'source/expectations/ut_expectation_boolean.tpb', - 'source/expectations/ut_expectation_boolean.tps', - 'source/expectations/ut_expectation_clob.tpb', - 'source/expectations/ut_expectation_clob.tps', - 'source/expectations/ut_expectation_date.tpb', - 'source/expectations/ut_expectation_date.tps', - 'source/expectations/ut_expectation_dsinterval.tpb', - 'source/expectations/ut_expectation_dsinterval.tps', - 'source/expectations/ut_expectation_number.tpb', - 'source/expectations/ut_expectation_number.tps', - 'source/expectations/ut_expectation_refcursor.tpb', - 'source/expectations/ut_expectation_refcursor.tps', - 'source/expectations/ut_expectation_timestamp.tpb', - 'source/expectations/ut_expectation_timestamp.tps', - 'source/expectations/ut_expectation_timestamp_ltz.tpb', - 'source/expectations/ut_expectation_timestamp_ltz.tps', - 'source/expectations/ut_expectation_timestamp_tz.tpb', - 'source/expectations/ut_expectation_timestamp_tz.tps', - 'source/expectations/ut_expectation_varchar2.tpb', - 'source/expectations/ut_expectation_varchar2.tps', - 'source/expectations/ut_expectation_yminterval.tpb', - 'source/expectations/ut_expectation_yminterval.tps', - 'source/expectations/data_values/ut_cursor_data.sql', - 'source/expectations/data_values/ut_data_value.tpb', - 'source/expectations/data_values/ut_data_value.tps', - 'source/expectations/data_values/ut_data_value_anydata.tpb', - 'source/expectations/data_values/ut_data_value_anydata.tps', - 'source/expectations/data_values/ut_data_value_blob.tpb', - 'source/expectations/data_values/ut_data_value_blob.tps', - 'source/expectations/data_values/ut_data_value_boolean.tpb', - 'source/expectations/data_values/ut_data_value_boolean.tps', - 'source/expectations/data_values/ut_data_value_clob.tpb', - 'source/expectations/data_values/ut_data_value_clob.tps', - 'source/expectations/data_values/ut_data_value_collection.tpb', - 'source/expectations/data_values/ut_data_value_collection.tps', - 'source/expectations/data_values/ut_data_value_date.tpb', - 'source/expectations/data_values/ut_data_value_date.tps', - 'source/expectations/data_values/ut_data_value_dsinterval.tpb', - 'source/expectations/data_values/ut_data_value_dsinterval.tps', - 'source/expectations/data_values/ut_data_value_number.tpb', - 'source/expectations/data_values/ut_data_value_number.tps', - 'source/expectations/data_values/ut_data_value_object.tpb', - 'source/expectations/data_values/ut_data_value_object.tps', - 'source/expectations/data_values/ut_data_value_refcursor.tpb', - 'source/expectations/data_values/ut_data_value_refcursor.tps', - 'source/expectations/data_values/ut_data_value_timestamp.tpb', - 'source/expectations/data_values/ut_data_value_timestamp.tps', - 'source/expectations/data_values/ut_data_value_timestamp_ltz.tpb', - 'source/expectations/data_values/ut_data_value_timestamp_ltz.tps', - 'source/expectations/data_values/ut_data_value_timestamp_tz.tpb', - 'source/expectations/data_values/ut_data_value_timestamp_tz.tps', - 'source/expectations/data_values/ut_data_value_varchar2.tpb', - 'source/expectations/data_values/ut_data_value_varchar2.tps', - 'source/expectations/data_values/ut_data_value_yminterval.tpb', - 'source/expectations/data_values/ut_data_value_yminterval.tps', - 'source/expectations/matchers/ut_be_between.tpb', - 'source/expectations/matchers/ut_be_between.tps', - 'source/expectations/matchers/ut_be_empty.tpb', - 'source/expectations/matchers/ut_be_empty.tps', - 'source/expectations/matchers/ut_be_false.tpb', - 'source/expectations/matchers/ut_be_false.tps', - 'source/expectations/matchers/ut_be_greater_or_equal.tpb', - 'source/expectations/matchers/ut_be_greater_or_equal.tps', - 'source/expectations/matchers/ut_be_greater_than.tpb', - 'source/expectations/matchers/ut_be_greater_than.tps', - 'source/expectations/matchers/ut_be_less_or_equal.tpb', - 'source/expectations/matchers/ut_be_less_or_equal.tps', - 'source/expectations/matchers/ut_be_less_than.tpb', - 'source/expectations/matchers/ut_be_less_than.tps', - 'source/expectations/matchers/ut_be_like.tpb', - 'source/expectations/matchers/ut_be_like.tps', - 'source/expectations/matchers/ut_be_not_null.tpb', - 'source/expectations/matchers/ut_be_not_null.tps', - 'source/expectations/matchers/ut_be_null.tpb', - 'source/expectations/matchers/ut_be_null.tps', - 'source/expectations/matchers/ut_be_true.tpb', - 'source/expectations/matchers/ut_be_true.tps', - 'source/expectations/matchers/ut_equal.tpb', - 'source/expectations/matchers/ut_equal.tps', - 'source/expectations/matchers/ut_match.tpb', - 'source/expectations/matchers/ut_match.tps', - 'source/expectations/matchers/ut_matcher.tpb', - 'source/expectations/matchers/ut_matcher.tps', - 'source/expectations/matchers/ut_comparison_matcher.tpb', - 'source/expectations/matchers/ut_comparison_matcher.tps', - 'source/reporters/ut_ansiconsole_helper.pkb', - 'source/reporters/ut_ansiconsole_helper.pks', - 'source/reporters/ut_coverage_html_reporter.tpb', - 'source/reporters/ut_coverage_html_reporter.tps', - 'source/reporters/ut_coverage_report_html_helper.pkb', - 'source/reporters/ut_coverage_report_html_helper.pks', - 'source/reporters/ut_coveralls_reporter.tpb', - 'source/reporters/ut_coveralls_reporter.tps', - 'source/reporters/ut_coverage_sonar_reporter.tpb', - 'source/reporters/ut_coverage_sonar_reporter.tps', - 'source/reporters/ut_documentation_reporter.tpb', - 'source/reporters/ut_documentation_reporter.tps', - 'source/reporters/ut_sonar_test_reporter.tpb', - 'source/reporters/ut_sonar_test_reporter.tps', - 'source/reporters/ut_teamcity_reporter.tpb', - 'source/reporters/ut_teamcity_reporter.tps', - 'source/reporters/ut_teamcity_reporter_helper.pkb', - 'source/reporters/ut_teamcity_reporter_helper.pks'); - - l_test_run := ut_run(a_items => ut_suite_items(), a_project_file_mappings => ut_file_mapper.build_file_mappings( user,l_project_file_list)); - - --run for the first time to gather coverage and timings on reporters too - l_reporter := ut_coverage_html_reporter(a_project_name => 'utPLSQL v3'); - l_reporter.after_calling_run(l_test_run); - l_reporter.on_finalize(l_test_run); - - l_reporter := ut_coverage_sonar_reporter(); - l_reporter.after_calling_run(l_test_run); - l_reporter.on_finalize(l_test_run); - - l_reporter := ut_coveralls_reporter(); - l_reporter.after_calling_run(l_test_run); - l_reporter.on_finalize(l_test_run); - - ut_coverage.set_develop_mode(false); - ut_coverage.coverage_stop(); - - --run for the second time to get the coverage report - l_reporter := ut_coverage_html_reporter(a_project_name => 'utPLSQL v3'); - l_reporter.after_calling_run(l_test_run); - l_reporter.on_finalize(l_test_run); - :html_reporter_id := l_reporter.get_reporter_id; - - l_reporter := ut_coverage_sonar_reporter(); - l_reporter.after_calling_run(l_test_run); - l_reporter.on_finalize(l_test_run); - :sonar_reporter_id := l_reporter.get_reporter_id; - - l_reporter := ut_coveralls_reporter(); - l_reporter.after_calling_run(l_test_run); - l_reporter.on_finalize(l_test_run); - :coveralls_reporter_id := l_reporter.get_reporter_id; -end; -/ - -set timing off -prompt Spooling outcomes to coverage.xml -set termout off -set feedback off -set arraysize 50 -spool coverage.xml -declare - l_reporter ut_output_reporter_base := ut_coverage_sonar_reporter(); -begin - l_reporter.set_reporter_id(:sonar_reporter_id); - l_reporter.lines_to_dbms_output(a_initial_timeout=>1, a_timeout_sec=>1); -end; -/ -spool off - -set termout on -prompt Spooling outcomes to coverage.json -set termout off -spool coverage.json -declare - l_reporter ut_output_reporter_base := ut_coveralls_reporter(); -begin - l_reporter.set_reporter_id(:coveralls_reporter_id); - l_reporter.lines_to_dbms_output(a_initial_timeout=>1, a_timeout_sec=>1); -end; -/ -spool off - -set termout on -prompt Spooling outcomes to coverage.html -set termout off -spool coverage.html -declare - l_reporter ut_output_reporter_base := ut_coverage_html_reporter(); -begin - l_reporter.set_reporter_id(:html_reporter_id); - l_reporter.lines_to_dbms_output(a_initial_timeout=>1, a_timeout_sec=>1); -end; -/ -spool off +-- set timing on +-- prompt Generating coverage data to reporter outputs +-- +-- var html_reporter_id varchar2(32); +-- var sonar_reporter_id varchar2(32); +-- var coveralls_reporter_id varchar2(32); +-- declare +-- l_reporter ut_reporter_base; +-- l_project_file_list ut_varchar2_list; +-- l_test_run ut_run; +-- begin +-- l_project_file_list := ut_varchar2_list( +-- 'source/api', +-- 'source/core', +-- 'source/create_synonyms_and_grants_for_public.sql', +-- 'source/create_synonyms_and_grants_for_user.sql', +-- 'source/create_utplsql_owner.sql', +-- 'source/expectations', +-- 'source/install.log', +-- 'source/install.sql', +-- 'source/install_headless.sql', +-- 'source/license.txt', +-- 'source/readme.md', +-- 'source/reporters', +-- 'source/uninstall.log', +-- 'source/uninstall.sql', +-- 'source/api/be_between.syn', +-- 'source/api/be_empty.syn', +-- 'source/api/be_false.syn', +-- 'source/api/be_greater_or_equal.syn', +-- 'source/api/be_greater_than.syn', +-- 'source/api/be_less_or_equal.syn', +-- 'source/api/be_less_than.syn', +-- 'source/api/be_like.syn', +-- 'source/api/be_not_null.syn', +-- 'source/api/be_null.syn', +-- 'source/api/be_true.syn', +-- 'source/api/equal.syn', +-- 'source/api/match.syn', +-- 'source/api/ut.pkb', +-- 'source/api/ut.pks', +-- 'source/api/ut_runner.pkb', +-- 'source/api/ut_runner.pks', +-- 'source/core/coverage', +-- 'source/core/output_buffers', +-- 'source/core/types', +-- 'source/core/annotations/ut_annotation_manager.pkb', +-- 'source/core/annotations/ut_annotation_manager.pks', +-- 'source/core/annotations/ut_annotation_parser.pkb', +-- 'source/core/annotations/ut_annotation_parser.pks', +-- 'source/core/annotations/ut_annotation_cache_manager.pkb', +-- 'source/core/annotations/ut_annotation_cache_manager.pks', +-- 'source/core/ut_expectation_processor.pkb', +-- 'source/core/ut_expectation_processor.pks', +-- 'source/core/ut_file_mapper.pkb', +-- 'source/core/ut_file_mapper.pks', +-- 'source/core/ut_metadata.pkb', +-- 'source/core/ut_metadata.pks', +-- 'source/core/ut_suite_manager.pkb', +-- 'source/core/ut_suite_manager.pks', +-- 'source/core/ut_utils.pkb', +-- 'source/core/ut_utils.pks', +-- 'source/core/coverage/proftab.sql', +-- 'source/core/coverage/ut_coverage.pkb', +-- 'source/core/coverage/ut_coverage.pks', +-- 'source/core/coverage/ut_coverage_helper.pkb', +-- 'source/core/coverage/ut_coverage_helper.pks', +-- 'source/core/coverage/ut_coverage_sources_tmp.sql', +-- 'source/core/coverage/ut_coverage_reporter_base.tpb', +-- 'source/core/coverage/ut_coverage_reporter_base.tps', +-- 'source/core/output_buffers/ut_message_id_seq.sql', +-- 'source/core/output_buffers/ut_output_buffer_base.tps', +-- 'source/core/output_buffers/ut_output_buffer_info_tmp.sql', +-- 'source/core/output_buffers/ut_output_buffer_tmp.sql', +-- 'source/core/output_buffers/ut_output_table_buffer.tpb', +-- 'source/core/output_buffers/ut_output_table_buffer.tps', +-- 'source/core/types/ut_console_reporter_base.tpb', +-- 'source/core/types/ut_console_reporter_base.tps', +-- 'source/core/types/ut_coverage_options.tps', +-- 'source/core/types/ut_event_listener.tpb', +-- 'source/core/types/ut_event_listener.tps', +-- 'source/core/types/ut_event_listener_base.tps', +-- 'source/core/types/ut_executable.tpb', +-- 'source/core/types/ut_executable.tps', +-- 'source/core/types/ut_expectation_result.tpb', +-- 'source/core/types/ut_expectation_result.tps', +-- 'source/core/types/ut_expectation_results.tps', +-- 'source/core/types/ut_file_mapping.tpb', +-- 'source/core/types/ut_file_mapping.tps', +-- 'source/core/types/ut_file_mappings.tps', +-- 'source/core/types/ut_key_value_pair.tps', +-- 'source/core/types/ut_key_value_pairs.tps', +-- 'source/core/types/ut_logical_suite.tpb', +-- 'source/core/types/ut_logical_suite.tps', +-- 'source/core/types/ut_object_name.tpb', +-- 'source/core/types/ut_object_name.tps', +-- 'source/core/types/ut_object_names.tps', +-- 'source/core/types/ut_output_reporter_base.tpb', +-- 'source/core/types/ut_output_reporter_base.tps', +-- 'source/core/types/ut_reporters.tps', +-- 'source/core/types/ut_reporter_base.tpb', +-- 'source/core/types/ut_reporter_base.tps', +-- 'source/core/types/ut_results_counter.tpb', +-- 'source/core/types/ut_results_counter.tps', +-- 'source/core/types/ut_run.tpb', +-- 'source/core/types/ut_run.tps', +-- 'source/core/types/ut_suite.tpb', +-- 'source/core/types/ut_suite.tps', +-- 'source/core/types/ut_suite_item.tpb', +-- 'source/core/types/ut_suite_item.tps', +-- 'source/core/types/ut_suite_items.tps', +-- 'source/core/types/ut_test.tpb', +-- 'source/core/types/ut_test.tps', +-- 'source/core/types/ut_varchar2_list.tps', +-- 'source/core/types/ut_varchar2_rows.tps', +-- 'source/expectations/data_values', +-- 'source/expectations/matchers', +-- 'source/expectations/ut_expectation.tpb', +-- 'source/expectations/ut_expectation.tps', +-- 'source/expectations/ut_expectation_anydata.tpb', +-- 'source/expectations/ut_expectation_anydata.tps', +-- 'source/expectations/ut_expectation_blob.tpb', +-- 'source/expectations/ut_expectation_blob.tps', +-- 'source/expectations/ut_expectation_boolean.tpb', +-- 'source/expectations/ut_expectation_boolean.tps', +-- 'source/expectations/ut_expectation_clob.tpb', +-- 'source/expectations/ut_expectation_clob.tps', +-- 'source/expectations/ut_expectation_date.tpb', +-- 'source/expectations/ut_expectation_date.tps', +-- 'source/expectations/ut_expectation_dsinterval.tpb', +-- 'source/expectations/ut_expectation_dsinterval.tps', +-- 'source/expectations/ut_expectation_number.tpb', +-- 'source/expectations/ut_expectation_number.tps', +-- 'source/expectations/ut_expectation_refcursor.tpb', +-- 'source/expectations/ut_expectation_refcursor.tps', +-- 'source/expectations/ut_expectation_timestamp.tpb', +-- 'source/expectations/ut_expectation_timestamp.tps', +-- 'source/expectations/ut_expectation_timestamp_ltz.tpb', +-- 'source/expectations/ut_expectation_timestamp_ltz.tps', +-- 'source/expectations/ut_expectation_timestamp_tz.tpb', +-- 'source/expectations/ut_expectation_timestamp_tz.tps', +-- 'source/expectations/ut_expectation_varchar2.tpb', +-- 'source/expectations/ut_expectation_varchar2.tps', +-- 'source/expectations/ut_expectation_yminterval.tpb', +-- 'source/expectations/ut_expectation_yminterval.tps', +-- 'source/expectations/data_values/ut_cursor_data.sql', +-- 'source/expectations/data_values/ut_data_value.tpb', +-- 'source/expectations/data_values/ut_data_value.tps', +-- 'source/expectations/data_values/ut_data_value_anydata.tpb', +-- 'source/expectations/data_values/ut_data_value_anydata.tps', +-- 'source/expectations/data_values/ut_data_value_blob.tpb', +-- 'source/expectations/data_values/ut_data_value_blob.tps', +-- 'source/expectations/data_values/ut_data_value_boolean.tpb', +-- 'source/expectations/data_values/ut_data_value_boolean.tps', +-- 'source/expectations/data_values/ut_data_value_clob.tpb', +-- 'source/expectations/data_values/ut_data_value_clob.tps', +-- 'source/expectations/data_values/ut_data_value_collection.tpb', +-- 'source/expectations/data_values/ut_data_value_collection.tps', +-- 'source/expectations/data_values/ut_data_value_date.tpb', +-- 'source/expectations/data_values/ut_data_value_date.tps', +-- 'source/expectations/data_values/ut_data_value_dsinterval.tpb', +-- 'source/expectations/data_values/ut_data_value_dsinterval.tps', +-- 'source/expectations/data_values/ut_data_value_number.tpb', +-- 'source/expectations/data_values/ut_data_value_number.tps', +-- 'source/expectations/data_values/ut_data_value_object.tpb', +-- 'source/expectations/data_values/ut_data_value_object.tps', +-- 'source/expectations/data_values/ut_data_value_refcursor.tpb', +-- 'source/expectations/data_values/ut_data_value_refcursor.tps', +-- 'source/expectations/data_values/ut_data_value_timestamp.tpb', +-- 'source/expectations/data_values/ut_data_value_timestamp.tps', +-- 'source/expectations/data_values/ut_data_value_timestamp_ltz.tpb', +-- 'source/expectations/data_values/ut_data_value_timestamp_ltz.tps', +-- 'source/expectations/data_values/ut_data_value_timestamp_tz.tpb', +-- 'source/expectations/data_values/ut_data_value_timestamp_tz.tps', +-- 'source/expectations/data_values/ut_data_value_varchar2.tpb', +-- 'source/expectations/data_values/ut_data_value_varchar2.tps', +-- 'source/expectations/data_values/ut_data_value_yminterval.tpb', +-- 'source/expectations/data_values/ut_data_value_yminterval.tps', +-- 'source/expectations/matchers/ut_be_between.tpb', +-- 'source/expectations/matchers/ut_be_between.tps', +-- 'source/expectations/matchers/ut_be_empty.tpb', +-- 'source/expectations/matchers/ut_be_empty.tps', +-- 'source/expectations/matchers/ut_be_false.tpb', +-- 'source/expectations/matchers/ut_be_false.tps', +-- 'source/expectations/matchers/ut_be_greater_or_equal.tpb', +-- 'source/expectations/matchers/ut_be_greater_or_equal.tps', +-- 'source/expectations/matchers/ut_be_greater_than.tpb', +-- 'source/expectations/matchers/ut_be_greater_than.tps', +-- 'source/expectations/matchers/ut_be_less_or_equal.tpb', +-- 'source/expectations/matchers/ut_be_less_or_equal.tps', +-- 'source/expectations/matchers/ut_be_less_than.tpb', +-- 'source/expectations/matchers/ut_be_less_than.tps', +-- 'source/expectations/matchers/ut_be_like.tpb', +-- 'source/expectations/matchers/ut_be_like.tps', +-- 'source/expectations/matchers/ut_be_not_null.tpb', +-- 'source/expectations/matchers/ut_be_not_null.tps', +-- 'source/expectations/matchers/ut_be_null.tpb', +-- 'source/expectations/matchers/ut_be_null.tps', +-- 'source/expectations/matchers/ut_be_true.tpb', +-- 'source/expectations/matchers/ut_be_true.tps', +-- 'source/expectations/matchers/ut_equal.tpb', +-- 'source/expectations/matchers/ut_equal.tps', +-- 'source/expectations/matchers/ut_match.tpb', +-- 'source/expectations/matchers/ut_match.tps', +-- 'source/expectations/matchers/ut_matcher.tpb', +-- 'source/expectations/matchers/ut_matcher.tps', +-- 'source/expectations/matchers/ut_comparison_matcher.tpb', +-- 'source/expectations/matchers/ut_comparison_matcher.tps', +-- 'source/reporters/ut_ansiconsole_helper.pkb', +-- 'source/reporters/ut_ansiconsole_helper.pks', +-- 'source/reporters/ut_coverage_html_reporter.tpb', +-- 'source/reporters/ut_coverage_html_reporter.tps', +-- 'source/reporters/ut_coverage_report_html_helper.pkb', +-- 'source/reporters/ut_coverage_report_html_helper.pks', +-- 'source/reporters/ut_coveralls_reporter.tpb', +-- 'source/reporters/ut_coveralls_reporter.tps', +-- 'source/reporters/ut_coverage_sonar_reporter.tpb', +-- 'source/reporters/ut_coverage_sonar_reporter.tps', +-- 'source/reporters/ut_documentation_reporter.tpb', +-- 'source/reporters/ut_documentation_reporter.tps', +-- 'source/reporters/ut_sonar_test_reporter.tpb', +-- 'source/reporters/ut_sonar_test_reporter.tps', +-- 'source/reporters/ut_teamcity_reporter.tpb', +-- 'source/reporters/ut_teamcity_reporter.tps', +-- 'source/reporters/ut_teamcity_reporter_helper.pkb', +-- 'source/reporters/ut_teamcity_reporter_helper.pks'); +-- +-- l_test_run := ut_run(a_items => ut_suite_items(), a_project_file_mappings => ut_file_mapper.build_file_mappings( user,l_project_file_list)); +-- +-- --run for the first time to gather coverage and timings on reporters too +-- l_reporter := ut_coverage_html_reporter(a_project_name => 'utPLSQL v3'); +-- l_reporter.after_calling_run(l_test_run); +-- l_reporter.on_finalize(l_test_run); +-- +-- l_reporter := ut_coverage_sonar_reporter(); +-- l_reporter.after_calling_run(l_test_run); +-- l_reporter.on_finalize(l_test_run); +-- +-- l_reporter := ut_coveralls_reporter(); +-- l_reporter.after_calling_run(l_test_run); +-- l_reporter.on_finalize(l_test_run); +-- +-- ut_coverage.set_develop_mode(false); +-- ut_coverage.coverage_stop(); +-- +-- --run for the second time to get the coverage report +-- l_reporter := ut_coverage_html_reporter(a_project_name => 'utPLSQL v3'); +-- l_reporter.after_calling_run(l_test_run); +-- l_reporter.on_finalize(l_test_run); +-- :html_reporter_id := l_reporter.get_reporter_id; +-- +-- l_reporter := ut_coverage_sonar_reporter(); +-- l_reporter.after_calling_run(l_test_run); +-- l_reporter.on_finalize(l_test_run); +-- :sonar_reporter_id := l_reporter.get_reporter_id; +-- +-- l_reporter := ut_coveralls_reporter(); +-- l_reporter.after_calling_run(l_test_run); +-- l_reporter.on_finalize(l_test_run); +-- :coveralls_reporter_id := l_reporter.get_reporter_id; +-- end; +-- / +-- +-- set timing off +-- prompt Spooling outcomes to coverage.xml +-- set termout off +-- set feedback off +-- set arraysize 50 +-- spool coverage.xml +-- declare +-- l_reporter ut_output_reporter_base := ut_coverage_sonar_reporter(); +-- begin +-- l_reporter.set_reporter_id(:sonar_reporter_id); +-- l_reporter.lines_to_dbms_output(a_initial_timeout=>1, a_timeout_sec=>1); +-- end; +-- / +-- spool off +-- +-- set termout on +-- prompt Spooling outcomes to coverage.json +-- set termout off +-- spool coverage.json +-- declare +-- l_reporter ut_output_reporter_base := ut_coveralls_reporter(); +-- begin +-- l_reporter.set_reporter_id(:coveralls_reporter_id); +-- l_reporter.lines_to_dbms_output(a_initial_timeout=>1, a_timeout_sec=>1); +-- end; +-- / +-- spool off +-- +-- set termout on +-- prompt Spooling outcomes to coverage.html +-- set termout off +-- spool coverage.html +-- declare +-- l_reporter ut_output_reporter_base := ut_coverage_html_reporter(); +-- begin +-- l_reporter.set_reporter_id(:html_reporter_id); +-- l_reporter.lines_to_dbms_output(a_initial_timeout=>1, a_timeout_sec=>1); +-- end; +-- / +-- spool off set termout on spool stats.log diff --git a/old_tests/ut_suite_manager/ut_suite_manager.CacheInvalidaesOnPackageDrop.sql b/old_tests/ut_suite_manager/ut_suite_manager.CacheInvalidaesOnPackageDrop.sql deleted file mode 100644 index 9715eae8b..000000000 --- a/old_tests/ut_suite_manager/ut_suite_manager.CacheInvalidaesOnPackageDrop.sql +++ /dev/null @@ -1,50 +0,0 @@ -set termout off -create or replace package tst_package_to_be_dropped as - --%suite - - --%test - procedure test1; -end; -/ - -create or replace package body tst_package_to_be_dropped as - procedure test1 is begin ut.expect(1).to_equal(1); end; - procedure test2 is begin ut.expect(1).to_equal(1); end; -end; -/ - -set termout on - -declare - l_test_report ut_varchar2_list; -begin - select * bulk collect into l_test_report from table(ut.run(USER||'.tst_package_to_be_dropped')); -end; -/ - -set termout off -drop package tst_package_to_be_dropped -/ -set termout on - -declare - l_test_report ut_varchar2_list; - l_error_message varchar2(4000); - l_expected varchar2(4000); -begin - l_expected := '%tst_package_to_be_dropped%does not exist%'; - begin - select * bulk collect into l_test_report from table(ut.run(user || '.tst_package_to_be_dropped')); - exception - when others then - l_error_message := sqlerrm; - if l_error_message like l_expected then - :test_result := ut_utils.gc_success; - end if; - end; - if :test_result != ut_utils.gc_success or :test_result is null then - dbms_output.put_line('Failed: Expected exception with text like '''||l_expected||''' but got:''' || - l_error_message || ''''); - end if; -end; -/ diff --git a/old_tests/ut_suite_manager/ut_suite_manager.emptySuitePath.sql b/old_tests/ut_suite_manager/ut_suite_manager.emptySuitePath.sql deleted file mode 100644 index a957f7873..000000000 --- a/old_tests/ut_suite_manager/ut_suite_manager.emptySuitePath.sql +++ /dev/null @@ -1,41 +0,0 @@ -set termout off -create or replace package tst_empty_suite_path as - --%suite - --%suitepath - - --%test - procedure test1; -end; -/ - -create or replace package body tst_empty_suite_path as - procedure test1 is begin ut.expect(1).to_equal(1); end; -end; -/ - -set termout on - -declare - l_objects_to_run ut_suite_items; - l_suite ut_suite; -begin - - --act - l_objects_to_run := ut_suite_manager.configure_execution_by_path(ut_varchar2_list('tst_empty_suite_path')); - - --Assert - ut.expect(l_objects_to_run.count).to_equal(1); - - l_suite := treat(l_objects_to_run(1) as ut_suite); - - ut.expect(l_suite.name).to_equal('tst_empty_suite_path'); - - if ut_expectation_processor.get_status = ut_utils.gc_success then - :test_result := ut_utils.gc_success; - end if; - -end; -/ - -drop package tst_empty_suite_path -/ diff --git a/old_tests/ut_test/ut_test.AfterEachExecuted.sql b/old_tests/ut_test/ut_test.AfterEachExecuted.sql deleted file mode 100644 index 5711c38e9..000000000 --- a/old_tests/ut_test/ut_test.AfterEachExecuted.sql +++ /dev/null @@ -1,20 +0,0 @@ -PROMPT Invoke aftereach procedure - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests', - a_name => 'ut_passing_test', - a_line_no => null - ); -begin - simple_test.after_each_list := ut_executables(ut_executable(user, 'ut_example_tests', 'aftereach', ut_utils.gc_after_each)); ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_success and ut_example_tests.g_char2 = 'F' then - :test_result := ut_utils.gc_success; - end if; -end; -/ - diff --git a/old_tests/ut_test/ut_test.AfterEachProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.AfterEachProcedureNameInvalid.sql deleted file mode 100644 index 15765a811..000000000 --- a/old_tests/ut_test/ut_test.AfterEachProcedureNameInvalid.sql +++ /dev/null @@ -1,21 +0,0 @@ -PROMPT Does not execute test and reports error when test aftereach procedure name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests', - a_name => 'ut_exampletest', - a_line_no => null - ); -begin - simple_test.after_each_list := ut_executables(ut_executable(user, 'ut_example_tests', 'invalid setup name', ut_utils.gc_after_each)); - ut_example_tests.g_char := 'x'; - ut_example_tests.g_char2 := 'x'; ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_char2 = 'x' and simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.AfterEachProcedureNameNull.sql b/old_tests/ut_test/ut_test.AfterEachProcedureNameNull.sql deleted file mode 100644 index f40ee8c04..000000000 --- a/old_tests/ut_test/ut_test.AfterEachProcedureNameNull.sql +++ /dev/null @@ -1,21 +0,0 @@ -PROMPT Does not invoke aftereach procedure when aftereach procedure name for a test is null - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests', - a_name => 'ut_passing_test', - a_line_no => null - ); -begin - simple_test.after_each_list := ut_executables(ut_executable(user, 'ut_example_tests', '', ut_utils.gc_after_each)); ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_char2 = 'a' then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('expected: ut_example_tests.g_char = ''a'', got: '||ut_example_tests.g_char2 ); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.ApplicationInfoOnExecution.sql b/old_tests/ut_test/ut_test.ApplicationInfoOnExecution.sql deleted file mode 100644 index 1ffa7fc11..000000000 --- a/old_tests/ut_test/ut_test.ApplicationInfoOnExecution.sql +++ /dev/null @@ -1,149 +0,0 @@ -create or replace package ut_output_tests -as - --%suite - - gv_before_all_client_info varchar2(200); - gv_before_each_client_info varchar2(200); - gv_before_test_client_info varchar2(200); - gv_after_test_client_info varchar2(200); - gv_after_each_client_info varchar2(200); - gv_after_all_client_info varchar2(200); - - --%test - --%beforetest(before_test) - --%aftertest(after_test) - procedure the_test; - - --%beforeall - procedure beforeall; - - --%beforeeach - procedure beforeeach; - - procedure before_test; - procedure after_test; - - --%aftereach - procedure aftereach; - - --%afterall - procedure afterall; - -end; -/ - -create or replace package body ut_output_tests -as - - procedure the_test - as - l_module_name varchar2(4000); - l_action_name varchar2(4000); - l_client_info varchar2(4000); - begin - --Generate empty output - dbms_output.put_line(''); - ut.expect(1,'Test 1 Should Pass').to_equal(1); - dbms_application_info.read_module(module_name => l_module_name, action_name => l_action_name); - dbms_application_info.read_client_info(l_client_info); - ut.expect(l_module_name).to_equal('utPLSQL'); - ut.expect(l_action_name).to_be_like('ut_output_tests'); - ut.expect(l_client_info).to_be_like('the_test'); - end; - - procedure beforeall is - begin - dbms_application_info.read_client_info(gv_before_all_client_info); - end; - - procedure beforeeach is - begin - dbms_application_info.read_client_info(gv_before_each_client_info); - end; - - procedure before_test is - begin - dbms_application_info.read_client_info(gv_before_test_client_info); - end; - procedure after_test is - begin - dbms_application_info.read_client_info(gv_after_test_client_info); - end; - - procedure aftereach is - begin - dbms_application_info.read_client_info(gv_after_each_client_info); - end; - - procedure afterall is - begin - dbms_application_info.read_client_info(gv_after_all_client_info); - end; - -end; -/ - -declare - l_output_data dbms_output.chararr; - l_num_lines integer := 100000; - l_output clob; - l_result boolean := true; - l_client_info varchar2(4000); -begin - --act - ut.run('ut_output_tests'); - - --assert - dbms_output.get_lines( l_output_data, l_num_lines); - dbms_lob.createtemporary(l_output,true); - for i in 1 .. l_num_lines loop - dbms_lob.append(l_output,l_output_data(i)); - end loop; - - execute immediate 'begin :i := ut_output_tests.gv_before_all_client_info; end;' using out l_client_info; - if not nvl(l_client_info = 'beforeall', false) then - dbms_output.put_line('Wrong before all text: '||l_client_info); - l_result := false; - end if; - execute immediate 'begin :i := ut_output_tests.gv_before_each_client_info; end;' using out l_client_info; - if not nvl(l_client_info = 'beforeeach', false) then - dbms_output.put_line('Wrong before each text: '||l_client_info); - l_result := false; - end if; - execute immediate 'begin :i := ut_output_tests.gv_before_test_client_info; end;' using out l_client_info; - if not nvl(l_client_info = 'before_test', false) then - dbms_output.put_line('Wrong before test text: '||l_client_info); - l_result := false; - end if; - execute immediate 'begin :i := ut_output_tests.gv_after_test_client_info; end;' using out l_client_info; - if not nvl(l_client_info = 'after_test', false) then - dbms_output.put_line('Wrong after test text: '||l_client_info); - l_result := false; - end if; - execute immediate 'begin :i := ut_output_tests.gv_after_each_client_info; end;' using out l_client_info; - if not nvl(l_client_info = 'aftereach', false) then - dbms_output.put_line('Wrong after each text: '||l_client_info); - l_result := false; - end if; - execute immediate 'begin :i := ut_output_tests.gv_after_all_client_info; end;' using out l_client_info; - if not nvl(l_client_info = 'afterall', false) then - dbms_output.put_line('Wrong after all text: '||l_client_info); - l_result := false; - end if; - - if not nvl(l_output like '%0 failed, 0 errored, 0 disabled, 0 warning(s)%',false) then - l_result := false; - for i in 1 .. l_num_lines loop - dbms_output.put_line(l_output_data(i)); - end loop; - dbms_output.put_line('Failed: Wrong output'); - end if; - if l_result then - :test_result := ut_utils.gc_success; - end if; -end; -/ - -drop package ut_output_tests -/ - diff --git a/old_tests/ut_test/ut_test.BeforeEachExecuted.sql b/old_tests/ut_test/ut_test.BeforeEachExecuted.sql deleted file mode 100644 index 9d40441ac..000000000 --- a/old_tests/ut_test/ut_test.BeforeEachExecuted.sql +++ /dev/null @@ -1,21 +0,0 @@ -PROMPT Invoke beforeeach procedure - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests', - a_name => 'ut_passing_test', - a_line_no => null - ); -begin - simple_test.before_each_list := ut_executables(ut_executable(user, 'ut_example_tests', 'beforeeach', ut_utils.gc_before_each)); - ut_example_tests.g_number2 := null; ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_number2 = 1 then - :test_result := ut_utils.gc_success; - end if; -end; -/ - diff --git a/old_tests/ut_test/ut_test.BeforeEachProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.BeforeEachProcedureNameInvalid.sql deleted file mode 100644 index 5a9d40a58..000000000 --- a/old_tests/ut_test/ut_test.BeforeEachProcedureNameInvalid.sql +++ /dev/null @@ -1,20 +0,0 @@ -PROMPT Does not execute test and reports error when test beforeeach procedure name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests', - a_name => 'ut_exampletest', - a_line_no => null - ); -begin - simple_test.before_each_list := ut_executables(ut_executable(user, 'ut_example_tests', 'invalid setup name', ut_utils.gc_before_each)); - ut_example_tests.g_char2 := null; ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error and ut_example_tests.g_char2 is null then - :test_result := ut_utils.gc_success; - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.BeforeEachProcedureNameNull.sql b/old_tests/ut_test/ut_test.BeforeEachProcedureNameNull.sql deleted file mode 100644 index 66107c462..000000000 --- a/old_tests/ut_test/ut_test.BeforeEachProcedureNameNull.sql +++ /dev/null @@ -1,22 +0,0 @@ -PROMPT Does not invoke setup procedure when beforeeach procedure name for a test is null - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests', - a_name => 'ut_passing_test', - a_line_no => null - ); -begin - simple_test.before_each_list := ut_executables(ut_executable(user, 'ut_example_tests', '', ut_utils.gc_before_each)); - ut_example_tests.g_number2 := null; ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_number2 is null then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('expected: ut_example_tests.g_number is null, got: '||ut_example_tests.g_number2 ); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.IgnoreTollbackToSavepointException.sql b/old_tests/ut_test/ut_test.IgnoreTollbackToSavepointException.sql deleted file mode 100644 index 3e3c1a814..000000000 --- a/old_tests/ut_test/ut_test.IgnoreTollbackToSavepointException.sql +++ /dev/null @@ -1,17 +0,0 @@ -PROMPT Checks that rollback exception does not make run to fail - ---Arrange -declare - simple_test ut_test := ut_test(a_object_name => 'ut_example_tests', a_name => 'ut_commit_test', a_line_no => null); -begin - simple_test.rollback_type := ut_utils.gc_rollback_auto; ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_success then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.OwnerNameInvalid.sql b/old_tests/ut_test/ut_test.OwnerNameInvalid.sql deleted file mode 100644 index 5207af574..000000000 --- a/old_tests/ut_test/ut_test.OwnerNameInvalid.sql +++ /dev/null @@ -1,21 +0,0 @@ -PROMPT Reports error when test owner name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_owner => 'invalid owner name', - a_object_name => 'ut_example_tests', - a_name => 'ut_passing_test', - a_line_no => null); -begin ---Act - simple_test.do_execute(); - ---Assert - if simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.OwnerNameNull.sql b/old_tests/ut_test/ut_test.OwnerNameNull.sql deleted file mode 100644 index f57aebf92..000000000 --- a/old_tests/ut_test/ut_test.OwnerNameNull.sql +++ /dev/null @@ -1,18 +0,0 @@ -PROMPT Executes test in current schema when test owner name for a test is null - ---Arrange -declare - simple_test ut_test:= ut_test( - a_object_owner => null, - a_object_name => 'ut_example_tests', - a_name => 'ut_passing_test', - a_line_no => null); -begin ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_char = 'a' then - :test_result := simple_test.result; - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.PackageInInvalidState.sql b/old_tests/ut_test/ut_test.PackageInInvalidState.sql deleted file mode 100644 index 0b87a13d6..000000000 --- a/old_tests/ut_test/ut_test.PackageInInvalidState.sql +++ /dev/null @@ -1,27 +0,0 @@ -set termout off ---Arrange -create or replace package invalid_package is - v_variable non_existing_type; - procedure ut_exampletest; -end; -/ -set termout on - -declare - simple_test ut_test := ut_test(a_object_name => 'invalid_package', a_name => 'ut_exampletest', a_line_no => null); -begin ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ - -set termout off ---Cleanup -drop package invalid_package; -set termout off diff --git a/old_tests/ut_test/ut_test.PackageNameInvalid.sql b/old_tests/ut_test/ut_test.PackageNameInvalid.sql deleted file mode 100644 index b615e7589..000000000 --- a/old_tests/ut_test/ut_test.PackageNameInvalid.sql +++ /dev/null @@ -1,16 +0,0 @@ -PROMPT Reports error when unit test package name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test(a_object_name => 'invalid test package name', a_name => 'ut_passing_test', a_line_no => null); -begin ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.PackageNameNull.sql b/old_tests/ut_test/ut_test.PackageNameNull.sql deleted file mode 100644 index 59612fa3d..000000000 --- a/old_tests/ut_test/ut_test.PackageNameNull.sql +++ /dev/null @@ -1,16 +0,0 @@ -PROMPT Reports error when unit test package name for a test is null - ---Arrange -declare - simple_test ut_test := ut_test(a_object_name => null, a_name => 'ut_passing_test', a_line_no => null); -begin ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.ProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.ProcedureNameInvalid.sql deleted file mode 100644 index 2a8e80a9e..000000000 --- a/old_tests/ut_test/ut_test.ProcedureNameInvalid.sql +++ /dev/null @@ -1,16 +0,0 @@ -PROMPT Reports error when test procedure name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test(a_object_name => 'ut_example_tests' ,a_name => 'invalid procedure name', a_line_no => null); -begin ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.ProcedureNameNull.sql b/old_tests/ut_test/ut_test.ProcedureNameNull.sql deleted file mode 100644 index df4f0e593..000000000 --- a/old_tests/ut_test/ut_test.ProcedureNameNull.sql +++ /dev/null @@ -1,16 +0,0 @@ -PROMPT Reports error when test procedure name for a test is null - ---Arrange -declare - simple_test ut_test := ut_test(a_object_name => 'ut_example_tests', a_name => null, a_line_no => null); -begin ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('simple_test.result = '||ut_utils.test_result_to_char(simple_test.result)); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.ReportWarningOnRollbackFailed.sql b/old_tests/ut_test/ut_test.ReportWarningOnRollbackFailed.sql deleted file mode 100644 index 0e54d401c..000000000 --- a/old_tests/ut_test/ut_test.ReportWarningOnRollbackFailed.sql +++ /dev/null @@ -1,58 +0,0 @@ -create or replace package ut_output_test_rollback -as - --%suite - - --%test - procedure tt; - -end; -/ - -create or replace package body ut_output_test_rollback -as - - procedure tt is - begin - commit; - end; - -end; -/ - -declare - l_lines ut_varchar2_list; - l_results clob; -begin - --act - select * bulk collect into l_lines from table(ut.run('ut_output_test_rollback')); - - l_results := ut_utils.table_to_clob(l_lines); - - --assert - if l_results like q'[%Warnings: -% - 1) ut_output_test_rollback.tt - Unable to perform automatic rollback after test. An implicit or explicit commit/rollback occurred in procedures: - ut3.ut_output_test_rollback.tt - Use the "--%rollback(manual)" annotation or remove commit/rollback/ddl statements that are causing the issue. -% - 2) ut_output_test_rollback - Unable to perform automatic rollback after test suite. An implicit or explicit commit/rollback occurred in procedures: - ut3.ut_output_test_rollback.tt - Use the "--%rollback(manual)" annotation or remove commit/rollback/ddl statements that are causing the issue. -% -Finished in % seconds -1 tests, 0 failed, 0 errored, 0 disabled, 2 warning(s)%]' then - :test_result := ut_utils.gc_success; - else - for i in 1 .. l_lines.count loop - dbms_output.put_line(l_lines(i)); - end loop; - dbms_output.put_line('Failed: Wrong output'); - end if; -end; -/ - -drop package ut_output_test_rollback -/ - diff --git a/old_tests/ut_test/ut_test.SetupExecutedBeforeTest.sql b/old_tests/ut_test/ut_test.SetupExecutedBeforeTest.sql deleted file mode 100644 index 2a80cf586..000000000 --- a/old_tests/ut_test/ut_test.SetupExecutedBeforeTest.sql +++ /dev/null @@ -1,21 +0,0 @@ -PROMPT Invoke setup procedure before test when setup procedure name is defined - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests', - a_name => 'ut_passing_test', - a_line_no => null - ); -begin - simple_test.before_test_list := ut_executables(ut_executable(user, 'ut_example_tests', 'setup', ut_utils.gc_before_test)); - ut_example_tests.g_number := null; ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_number = 1 then - :test_result := ut_utils.gc_success; - end if; -end; -/ - diff --git a/old_tests/ut_test/ut_test.SetupProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.SetupProcedureNameInvalid.sql deleted file mode 100644 index d81141031..000000000 --- a/old_tests/ut_test/ut_test.SetupProcedureNameInvalid.sql +++ /dev/null @@ -1,20 +0,0 @@ -PROMPT Does not execute test and reports error when test setup procedure name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests', - a_name => 'ut_exampletest', - a_line_no => null - ); -begin - simple_test.before_test_list := ut_executables(ut_executable(user, 'ut_example_tests', 'invalid setup name', ut_utils.gc_before_test)); - ut_example_tests.g_char := null; ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_error and ut_example_tests.g_char is null then - :test_result := ut_utils.gc_success; - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.SetupProcedureNameNull.sql b/old_tests/ut_test/ut_test.SetupProcedureNameNull.sql deleted file mode 100644 index 9269fdd92..000000000 --- a/old_tests/ut_test/ut_test.SetupProcedureNameNull.sql +++ /dev/null @@ -1,22 +0,0 @@ -PROMPT Does not invoke setup procedure when setup procedure name for a test is null - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests', - a_name => 'ut_passing_test', - a_line_no => null - ); -begin - simple_test.before_test_list := ut_executables(ut_executable(user, 'ut_example_tests', null, ut_utils.gc_before_test)); - ut_example_tests.g_number := null; ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_number is null then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('expected: ut_example_tests.g_number is null, got: '||ut_example_tests.g_number ); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.TeardownExecutedAfterTest.sql b/old_tests/ut_test/ut_test.TeardownExecutedAfterTest.sql deleted file mode 100644 index bc733614b..000000000 --- a/old_tests/ut_test/ut_test.TeardownExecutedAfterTest.sql +++ /dev/null @@ -1,20 +0,0 @@ -PROMPT Invoke teardown procedure after test when teardown procedure name is defined - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests', - a_name => 'ut_passing_test', - a_line_no => null - ); -begin - simple_test.after_test_list := ut_executables(ut_executable(user, 'ut_example_tests', 'teardown', ut_utils.gc_after_test)); ---Act - simple_test.do_execute(); ---Assert - if simple_test.result = ut_utils.gc_success and ut_example_tests.g_char is null then - :test_result := ut_utils.gc_success; - end if; -end; -/ - diff --git a/old_tests/ut_test/ut_test.TeardownProcedureNameInvalid.sql b/old_tests/ut_test/ut_test.TeardownProcedureNameInvalid.sql deleted file mode 100644 index 5ae61cc13..000000000 --- a/old_tests/ut_test/ut_test.TeardownProcedureNameInvalid.sql +++ /dev/null @@ -1,20 +0,0 @@ -PROMPT Does not execute test and reports error when test teardown procedure name for a test is invalid - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests', - a_name => 'ut_exampletest', - a_line_no => null - ); -begin - simple_test.after_test_list := ut_executables(ut_executable(user, 'ut_example_tests', 'invalid setup name', ut_utils.gc_after_test)); - ut_example_tests.g_char := 'x'; ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_char = 'x' and simple_test.result = ut_utils.gc_error then - :test_result := ut_utils.gc_success; - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.TeardownProcedureNameNull.sql b/old_tests/ut_test/ut_test.TeardownProcedureNameNull.sql deleted file mode 100644 index 7460ca788..000000000 --- a/old_tests/ut_test/ut_test.TeardownProcedureNameNull.sql +++ /dev/null @@ -1,21 +0,0 @@ -PROMPT Does not invoke teardown procedure when teardown procedure name for a test is null - ---Arrange -declare - simple_test ut_test := ut_test( - a_object_name => 'ut_example_tests', - a_name => 'ut_passing_test', - a_line_no => null - ); -begin - simple_test.after_test_list := ut_executables(ut_executable(user, 'ut_example_tests', null, ut_utils.gc_after_test)); ---Act - simple_test.do_execute(); ---Assert - if ut_example_tests.g_char = 'a' then - :test_result := ut_utils.gc_success; - else - dbms_output.put_line('expected: ut_example_tests.g_char = ''a'', got: '''||ut_example_tests.g_char||'''' ); - end if; -end; -/ diff --git a/old_tests/ut_test/ut_test.TestOutputGathering.sql b/old_tests/ut_test/ut_test.TestOutputGathering.sql deleted file mode 100644 index 14181a4b0..000000000 --- a/old_tests/ut_test/ut_test.TestOutputGathering.sql +++ /dev/null @@ -1,103 +0,0 @@ -create or replace package ut_output_tests -as - --%suite - - --%beforeeach - procedure beforeeach; - - --%aftereach - procedure aftereach; - - --%test - --%beforetest(beforetest) - --%aftertest(aftertest) - procedure ut_passing_test; - - procedure beforetest; - - procedure aftertest; - - --%beforeall - procedure beforeall; - --%afterall - procedure afterall; - -end; -/ - -create or replace package body ut_output_tests -as - - procedure beforetest as - begin - dbms_output.put_line(''); - end; - - procedure aftertest - as - begin - dbms_output.put_line(''); - end; - - procedure beforeeach as - begin - dbms_output.put_line(''); - end; - - procedure aftereach - as - begin - dbms_output.put_line(''); - end; - - procedure ut_passing_test - as - begin - dbms_output.put_line(''); - ut.expect(1,'Test 1 Should Pass').to_equal(1); - end; - - procedure beforeall is - begin - dbms_output.put_line(''); - end; - - procedure afterall is - begin - dbms_output.put_line(''); - end; - -end; -/ - -declare - l_output_data dbms_output.chararr; - l_num_lines integer := 100000; - l_output clob; -begin - --act - ut.run('ut_output_tests'); - - --assert - dbms_output.get_lines( l_output_data, l_num_lines); - dbms_lob.createtemporary(l_output,true); - for i in 1 .. l_num_lines loop - dbms_lob.append(l_output,l_output_data(i)); - end loop; - - if l_output like '%%%%%%%%1 tests, 0 failed, 0 errored%' then - :test_result := ut_utils.gc_success; - end if; - - if :test_result != ut_utils.gc_success or :test_result is null then - for i in 1 .. l_num_lines loop - dbms_output.put_line(l_output_data(i)); - end loop; - dbms_output.put_line('Failed: Wrong output'); - end if; -end; -/ - -drop package ut_output_tests -/ - diff --git a/old_tests/ut_test/ut_test.TestOutputGatheringWhenEmpty.sql b/old_tests/ut_test/ut_test.TestOutputGatheringWhenEmpty.sql deleted file mode 100644 index dcd82fbad..000000000 --- a/old_tests/ut_test/ut_test.TestOutputGatheringWhenEmpty.sql +++ /dev/null @@ -1,55 +0,0 @@ -create or replace package ut_output_tests -as - --%suite - - --%test - procedure ut_passing_test; - -end; -/ - -create or replace package body ut_output_tests -as - - procedure ut_passing_test - as - begin - --Generate empty output - dbms_output.put_line(''); - ut.expect(1,'Test 1 Should Pass').to_equal(1); - end; - -end; -/ - -declare - l_output_data dbms_output.chararr; - l_num_lines integer := 100000; - l_output clob; -begin - --act - ut.run('ut_output_tests'); - - --assert - dbms_output.get_lines( l_output_data, l_num_lines); - dbms_lob.createtemporary(l_output,true); - for i in 1 .. l_num_lines loop - dbms_lob.append(l_output,l_output_data(i)); - end loop; - - if l_output like '%0 failed, 0 errored, 0 disabled, 0 warning(s)%' then - :test_result := ut_utils.gc_success; - end if; - - if :test_result != ut_utils.gc_success or :test_result is null then - for i in 1 .. l_num_lines loop - dbms_output.put_line(l_output_data(i)); - end loop; - dbms_output.put_line('Failed: Wrong output'); - end if; -end; -/ - -drop package ut_output_tests -/ - diff --git a/sonar-project.properties b/sonar-project.properties index a1fabbede..e13de646b 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -9,7 +9,7 @@ sonar.projectVersion=v3.1.3-develop # If not set, SonarQube starts looking for source code from the directory containing # the sonar-project.properties file. sonar.sources=./source -sonar.coverageReportPaths=./old_tests/coverage.xml,coverage.xml +sonar.coverageReportPaths=coverage.xml sonar.tests=./test sonar.testExecutionReportPaths=./test_results.xml sonar.links.issue=https://github.com/utPLSQL/utPLSQL/issues diff --git a/test/core/test_ut_test.pkb b/test/core/test_ut_test.pkb index 5b401463c..b521d6841 100644 --- a/test/core/test_ut_test.pkb +++ b/test/core/test_ut_test.pkb @@ -137,5 +137,561 @@ create or replace package body test_ut_test is ut.expect(l_suite.results_count.errored_count).to_equal(1); end; + procedure after_each_executed is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_each_list := ut3.ut_executables(ut3.ut_executable(user, 'ut_example_tests', 'add_1_to_g_number', ut3.ut_utils.gc_after_each)); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_success); + ut.expect(ut_example_tests.g_number).to_equal(1); + end; + + procedure after_each_proc_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_each_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', 'invalid setup name', ut3.ut_utils.gc_after_each) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_equal(0); + end; + + procedure after_each_procedure_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_each_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', null, ut3.ut_utils.gc_after_each) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_equal(0); + end; + + procedure create_app_info_package is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ut_output_tests + as + --%suite + + gv_before_all_client_info varchar2(200); + gv_before_each_client_info varchar2(200); + gv_before_test_client_info varchar2(200); + gv_after_test_client_info varchar2(200); + gv_after_each_client_info varchar2(200); + gv_after_all_client_info varchar2(200); + + --%test + --%beforetest(before_test) + --%aftertest(after_test) + procedure the_test; + + --%beforeall + procedure beforeall; + + --%beforeeach + procedure beforeeach; + + procedure before_test; + procedure after_test; + + --%aftereach + procedure aftereach; + + --%afterall + procedure afterall; + + end;]'; + execute immediate q'[create or replace package body ut_output_tests + as + + procedure the_test + as + l_module_name varchar2(4000); + l_action_name varchar2(4000); + l_client_info varchar2(4000); + begin + --Generate empty output + dbms_output.put_line(''); + ut.expect(1,'Test 1 Should Pass').to_equal(1); + dbms_application_info.read_module(module_name => l_module_name, action_name => l_action_name); + dbms_application_info.read_client_info(l_client_info); + ut.expect(l_module_name).to_equal('utPLSQL'); + ut.expect(l_action_name).to_be_like('ut_output_tests'); + ut.expect(l_client_info).to_be_like('the_test'); + end; + + procedure beforeall is + begin + dbms_application_info.read_client_info(gv_before_all_client_info); + end; + + procedure beforeeach is + begin + dbms_application_info.read_client_info(gv_before_each_client_info); + end; + + procedure before_test is + begin + dbms_application_info.read_client_info(gv_before_test_client_info); + end; + procedure after_test is + begin + dbms_application_info.read_client_info(gv_after_test_client_info); + end; + + procedure aftereach is + begin + dbms_application_info.read_client_info(gv_after_each_client_info); + end; + + procedure afterall is + begin + dbms_application_info.read_client_info(gv_after_all_client_info); + end; + + end;]'; + end; + + procedure drop_app_info_package is + pragma autonomous_transaction; + begin + execute immediate q'[drop package ut_output_tests]'; + end; + + procedure application_info_on_execution is + l_output_data ut3.ut_varchar2_list; + l_output clob; + function get_test_value(a_variable_name varchar2) return varchar2 is + l_result varchar2(4000); + begin + execute immediate 'begin :i := ut_output_tests.'||a_variable_name||'; end;' using out l_result; + return l_result; + end; + begin + --act + select * bulk collect into l_output_data + from table(ut3.ut.run('ut_output_tests')); + l_output := ut3.ut_utils.table_to_clob(l_output_data); + --assert + + ut.expect(get_test_value('gv_before_all_client_info')).to_equal('beforeall'); + ut.expect(get_test_value('gv_before_each_client_info')).to_equal('beforeeach'); + ut.expect(get_test_value('gv_before_test_client_info')).to_equal('before_test'); + ut.expect(get_test_value('gv_after_test_client_info')).to_equal('after_test'); + ut.expect(get_test_value('gv_after_each_client_info')).to_equal('aftereach'); + ut.expect(get_test_value('gv_after_all_client_info')).to_equal('afterall'); + ut.expect(l_output).to_be_like('%0 failed, 0 errored, 0 disabled, 0 warning(s)%'); + end; + + procedure before_each_executed is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'add_1_to_g_number', + a_line_no => null + ); + begin + l_test.before_each_list := ut3.ut_executables(ut3.ut_executable(user, 'ut_example_tests', 'set_g_number_0', ut3.ut_utils.gc_before_each)); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_success); + ut.expect(ut_example_tests.g_number).to_equal(1); + end; + + + procedure before_each_proc_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.before_each_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', 'invalid setup name', ut3.ut_utils.gc_before_each) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_be_null; + end; + + procedure before_each_proc_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.before_each_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', null, ut3.ut_utils.gc_before_each) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_be_null; + end; + + procedure ignore_savepoint_exception is + pragma autonomous_transaction; + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'ut_commit_test', + a_line_no => null + ); + begin + l_test.rollback_type := ut3.ut_utils.gc_rollback_auto; + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_success); + end; + + procedure owner_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_owner => 'invalid owner name', + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + end; + + procedure owner_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_owner => null, + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_success); + ut.expect(ut_example_tests.g_number).to_equal(0); + end; + + + procedure create_invalid_package is + pragma autonomous_transaction; + begin + execute immediate 'create or replace package invalid_package is + v_variable non_existing_type; + procedure ut_exampletest; + end;'; + exception when others then + null; + end; + + procedure drop_invalid_package is + pragma autonomous_transaction; + begin + execute immediate 'drop package invalid_package'; + exception when others then + null; + end; + + procedure package_in_invalid_state is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'invalid_package', + a_name => 'ut_exampletest', + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + end; + + procedure package_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'invalid package name', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + end; + + procedure package_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => null, + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + end; + + procedure procedure_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'invalid procedure name', + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + end; + + procedure procedure_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => null, + a_line_no => null + ); + begin + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + end; + + procedure before_test_executed is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'add_1_to_g_number', + a_line_no => null + ); + begin + l_test.before_test_list := ut3.ut_executables(ut3.ut_executable(user, 'ut_example_tests', 'set_g_number_0', ut3.ut_utils.gc_before_test)); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_success); + ut.expect(ut_example_tests.g_number).to_equal(1); + end; + + procedure before_test_proc_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.before_test_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', 'invalid setup name', ut3.ut_utils.gc_before_test) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_be_null; + end; + + procedure before_test_proc_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.before_test_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', null, ut3.ut_utils.gc_before_test) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_be_null; + end; + + procedure after_test_executed is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_test_list := ut3.ut_executables(ut3.ut_executable(user, 'ut_example_tests', 'add_1_to_g_number', ut3.ut_utils.gc_after_test)); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_success); + ut.expect(ut_example_tests.g_number).to_equal(1); + end; + + procedure after_test_proce_name_invalid is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_test_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', 'invalid procedure name', ut3.ut_utils.gc_after_test) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_equal(0); + end; + + procedure after_test_proc_name_null is + --Arrange + l_test ut3.ut_test := ut3.ut_test( + a_object_name => 'ut_example_tests', + a_name => 'set_g_number_0', + a_line_no => null + ); + begin + l_test.after_test_list := ut3.ut_executables( + ut3.ut_executable(user, 'ut_example_tests', null, ut3.ut_utils.gc_after_test) + ); + --Act + l_test.do_execute(); + --Assert + ut.expect(l_test.result).to_equal(ut3.ut_utils.gc_error); + ut.expect(ut_example_tests.g_number).to_equal(0); + end; + + procedure create_output_package is + pragma autonomous_transaction; + begin + execute immediate q'[create or replace package ut_output_tests + as + --%suite + + --%beforeeach + procedure beforeeach; + + --%aftereach + procedure aftereach; + + --%test + --%beforetest(beforetest) + --%aftertest(aftertest) + procedure ut_passing_test; + + procedure beforetest; + + procedure aftertest; + + --%beforeall + procedure beforeall; + --%afterall + procedure afterall; + + end;]'; + execute immediate q'[create or replace package body ut_output_tests + as + + procedure beforetest is + begin + dbms_output.put_line(''); + end; + + procedure aftertest is + begin + dbms_output.put_line(''); + end; + + procedure beforeeach is + begin + dbms_output.put_line(''); + end; + + procedure aftereach is + begin + dbms_output.put_line(''); + end; + + procedure ut_passing_test is + begin + dbms_output.put_line(''); + ut.expect(1,'Test 1 Should Pass').to_equal(1); + end; + + procedure beforeall is + begin + dbms_output.put_line(''); + end; + + procedure afterall is + begin + dbms_output.put_line(''); + end; + + end;]'; + exception when others then + null; + end; + + procedure drop_output_package is + pragma autonomous_transaction; + begin + execute immediate 'drop package ut_output_tests'; + exception when others then + null; + end; + + procedure test_output_gathering is + l_output_data ut3.ut_varchar2_list; + l_output clob; + begin + select * bulk collect into l_output_data + from table(ut3.ut.run('ut_output_tests')); + l_output := ut3.ut_utils.table_to_clob(l_output_data); + ut.expect(l_output).to_be_like( + '%%%%%%%%1 tests, 0 failed, 0 errored%' + ); + end; + + end; / diff --git a/test/core/test_ut_test.pks b/test/core/test_ut_test.pks index de6107326..5ee6e35ce 100644 --- a/test/core/test_ut_test.pks +++ b/test/core/test_ut_test.pks @@ -22,5 +22,71 @@ create or replace package test_ut_test is procedure beforeeach_errors; + --%context(executables in test) + + --%test(Executes aftereach procedure) + procedure after_each_executed; + + --%test(Fails test when aftereach procedure name invalid) + procedure after_each_proc_name_invalid; + --%test(Tails test when aftereach procedure name null) + procedure after_each_procedure_name_null; + + procedure create_app_info_package; + procedure drop_app_info_package; + --%beforetest(create_app_info_package) + --%aftertest(drop_app_info_package) + --%test(Sets application_info on execution of individual items) + procedure application_info_on_execution; + + --%test(Executes beforeeach procedure) + procedure before_each_executed; + --%test(Fails test when beforeeach procedure name invalid) + procedure before_each_proc_name_invalid; + --%test(Fails test when beforeeach procedure name null) + procedure before_each_proc_name_null; + --%test(Does not raise exception when rollback to savepoint fails) + procedure ignore_savepoint_exception; + --%test(Fails when owner name invalid) + procedure owner_name_invalid; + --%test(Runs test as current schema when owner name null) + procedure owner_name_null; + + procedure create_invalid_package; + procedure drop_invalid_package; + --%beforetest(create_app_info_package) + --%aftertest(drop_app_info_package) + --%test(Fails the test that references package with compilation errors) + procedure package_in_invalid_state; + --%test(Fails the test when package name is invalid) + procedure package_name_invalid; + --%test(Fails the test when package name is null) + procedure package_name_null; + --%test(Fails the test when procedure name invalid) + procedure procedure_name_invalid; + --%test(Fails the test when procedure name null) + procedure procedure_name_null; + + + --%test(Executes befroretest procedure) + procedure before_test_executed; + --%test(Fails test when befroretest procedure name invalid) + procedure before_test_proc_name_invalid; + --%test(Fails test when befroretest procedure name is null) + procedure before_test_proc_name_null; + --%test(Executes aftertest procedure) + procedure after_test_executed; + --%test(Fails test when aftertest procedure name invalid) + procedure after_test_proce_name_invalid; + --%test(Fails test when aftertest procedure name is null) + procedure after_test_proc_name_null; + + procedure create_output_package; + procedure drop_output_package; + --%beforetest(create_output_package) + --%aftertest(drop_output_package) + --%test(Test output gathering) + procedure test_output_gathering; + end; / diff --git a/test/helpers/ut_example_tests.pkb b/test/helpers/ut_example_tests.pkb index 5059103b6..d8afd592a 100644 --- a/test/helpers/ut_example_tests.pkb +++ b/test/helpers/ut_example_tests.pkb @@ -16,5 +16,9 @@ as g_number := 1 / 0; end; + procedure ut_commit_test is + begin + commit; + end; end; / diff --git a/test/helpers/ut_example_tests.pks b/test/helpers/ut_example_tests.pks index 7ff75ce12..428d55743 100644 --- a/test/helpers/ut_example_tests.pks +++ b/test/helpers/ut_example_tests.pks @@ -1,8 +1,8 @@ -create or replace package ut_example_tests -as - g_number number; - procedure set_g_number_0; - procedure add_1_to_g_number; - procedure failing_procedure; +create or replace package ut_example_tests as + g_number number; + procedure set_g_number_0; + procedure add_1_to_g_number; + procedure failing_procedure; + procedure ut_commit_test; end; / From 0ee3ce26f5c4567581869d80e73929dcbba5cbac Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 18 Nov 2018 18:42:18 +0000 Subject: [PATCH 31/33] Added missing endcontext in `test_ut_test` --- test/core/test_ut_test.pks | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/core/test_ut_test.pks b/test/core/test_ut_test.pks index 5ee6e35ce..ee888ecd3 100644 --- a/test/core/test_ut_test.pks +++ b/test/core/test_ut_test.pks @@ -88,5 +88,7 @@ create or replace package test_ut_test is --%test(Test output gathering) procedure test_output_gathering; + --%endcontext + end; / From 48aa33819d94636b4286c6ca9f589c90ae88bff2 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 18 Nov 2018 19:04:05 +0000 Subject: [PATCH 32/33] Removed unused constants. --- source/reporters/ut_ansiconsole_helper.pkb | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/reporters/ut_ansiconsole_helper.pkb b/source/reporters/ut_ansiconsole_helper.pkb index d9c0617e0..07d9ee9a7 100644 --- a/source/reporters/ut_ansiconsole_helper.pkb +++ b/source/reporters/ut_ansiconsole_helper.pkb @@ -18,8 +18,6 @@ create or replace package body ut_ansiconsole_helper as gc_red constant varchar2(7) := chr(27) || '[31m'; gc_green constant varchar2(7) := chr(27) || '[32m'; gc_yellow constant varchar2(7) := chr(27) || '[33m'; - gc_blue constant varchar2(7) := chr(27) || '[34m'; - gc_magenta constant varchar2(7) := chr(27) || '[35m'; gc_cyan constant varchar2(7) := chr(27) || '[36m'; gc_reset constant varchar2(7) := chr(27) || '[0m'; g_enabled boolean := false; From b33aaaee70db13038760f8401c101767b80e2309 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 18 Nov 2018 20:41:28 +0000 Subject: [PATCH 33/33] Added additional test for display of parser warnings. Fixed issue with warnings not getting shown. --- source/core/ut_suite_manager.pkb | 201 ++++++++++++++++--------------- test/api/test_ut_run.pkb | 42 ++++++- test/api/test_ut_run.pks | 6 + 3 files changed, 148 insertions(+), 101 deletions(-) diff --git a/source/core/ut_suite_manager.pkb b/source/core/ut_suite_manager.pkb index 19862992d..3c2c713eb 100644 --- a/source/core/ut_suite_manager.pkb +++ b/source/core/ut_suite_manager.pkb @@ -174,91 +174,112 @@ create or replace package body ut_suite_manager is a_level pls_integer, a_prev_level pls_integer, a_items_at_level t_item_levels - ) return ut_logical_suite is + ) return ut_suite_item is + l_result ut_suite_item; begin - return case a_rows( a_idx ).self_type when 'UT_SUITE' then - case when a_prev_level > a_level then - ut_suite( - self_type => a_rows( a_idx ).self_type, - object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), - name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, - rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, - line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, - start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => a_items_at_level(a_prev_level), - before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( - a_rows( a_idx ).after_all_list) - ) - else - ut_suite( - self_type => a_rows( a_idx ).self_type, - object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), - name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, - rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, - line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, - start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => ut_suite_items(), - before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( - a_rows( a_idx ).after_all_list) - ) - end + l_result := + case when a_prev_level > a_level then + ut_suite( + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => a_items_at_level(a_prev_level), + before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( + a_rows( a_idx ).after_all_list) + ) + else + ut_suite( + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items(), + before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( + a_rows( a_idx ).after_all_list) + ) + end; when 'UT_SUITE_CONTEXT' then - case when a_prev_level > a_level then - ut_suite_context( - self_type => a_rows( a_idx ).self_type, - object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), - name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, - rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, - line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, - start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => a_items_at_level(a_prev_level), - before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( - a_rows( a_idx ).after_all_list) - ) - else - ut_suite_context( - self_type => a_rows( a_idx ).self_type, - object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), - name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, - rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, - line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, - start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => ut_suite_items(), - before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( - a_rows( a_idx ).after_all_list) - ) - end + l_result := + case when a_prev_level > a_level then + ut_suite_context( + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => a_items_at_level(a_prev_level), + before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( + a_rows( a_idx ).after_all_list) + ) + else + ut_suite_context( + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items(), + before_all_list => sort_by_seq_no( a_rows( a_idx ).before_all_list), after_all_list => sort_by_seq_no( + a_rows( a_idx ).after_all_list) + ) + end; when 'UT_LOGICAL_SUITE' then - case when a_prev_level > a_level then - ut_logical_suite( - self_type => a_rows( a_idx ).self_type, - object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), - name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, - rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, - line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, - start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => a_items_at_level(a_prev_level) - ) - else - ut_logical_suite( - self_type => a_rows( a_idx ).self_type, - object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), - name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, - rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, - line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, - start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, + l_result := + case when a_prev_level > a_level then + ut_logical_suite( + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => a_items_at_level(a_prev_level) + ) + else + ut_logical_suite( + self_type => a_rows( a_idx ).self_type, + object_owner => a_rows( a_idx ).object_owner, object_name => lower( a_rows( a_idx ).object_name), + name => lower( a_rows( a_idx ).name), description => a_rows( a_idx ).description, path => a_rows( a_idx ).path, + rollback_type => a_rows( a_idx ).rollback_type, disabled_flag => a_rows( a_idx ).disabled_flag, + line_no => a_rows( a_idx ).line_no, parse_time => a_rows( a_idx ).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows( a_idx ).warnings, + results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), + items => ut_suite_items() + ) + end; + when 'UT_TEST' then + l_result := + ut_test( + self_type => a_rows(a_idx).self_type, + object_owner => a_rows(a_idx).object_owner, object_name => lower(a_rows(a_idx).object_name), + name => lower(a_rows(a_idx).name), description => a_rows(a_idx).description, path => a_rows(a_idx).path, + rollback_type => a_rows(a_idx).rollback_type, disabled_flag => a_rows(a_idx).disabled_flag, + line_no => a_rows(a_idx).line_no, parse_time => a_rows(a_idx).parse_time, + start_time => null, end_time => null, result => null, warnings => a_rows(a_idx).warnings, results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - items => ut_suite_items() - ) - end - end; + before_each_list => sort_by_seq_no(a_rows(a_idx).before_each_list), before_test_list => sort_by_seq_no(a_rows(a_idx).before_test_list), + item => a_rows(a_idx).item, + after_test_list => sort_by_seq_no(a_rows(a_idx).after_test_list), after_each_list => sort_by_seq_no(a_rows(a_idx).after_each_list), + all_expectations => ut_expectation_results(), failed_expectations => ut_expectation_results(), + parent_error_stack_trace => null, expected_error_codes => a_rows(a_idx).expected_error_codes + ); + end case; + l_result.results_count.warnings_count := l_result.warnings.count; + return l_result; end; procedure reconstruct_from_cache( @@ -283,26 +304,8 @@ create or replace package body ut_suite_manager is l_items_at_level(l_level) := ut_suite_items(); end if; l_items_at_level(l_level).extend; - if l_rows(l_idx).self_type = 'UT_TEST' then - l_items_at_level(l_level)(l_items_at_level(l_level).last) := - ut_test( - self_type => l_rows(l_idx).self_type, - object_owner => l_rows(l_idx).object_owner, object_name => lower(l_rows(l_idx).object_name), - name => lower(l_rows(l_idx).name), description => l_rows(l_idx).description, path => l_rows(l_idx).path, - rollback_type => l_rows(l_idx).rollback_type, disabled_flag => l_rows(l_idx).disabled_flag, - line_no => l_rows(l_idx).line_no, parse_time => l_rows(l_idx).parse_time, - start_time => null, end_time => null, result => null, warnings => l_rows(l_idx).warnings, - results_count => ut_results_counter(), transaction_invalidators => ut_varchar2_list(), - before_each_list => sort_by_seq_no(l_rows(l_idx).before_each_list), before_test_list => sort_by_seq_no(l_rows(l_idx).before_test_list), - item => l_rows(l_idx).item, - after_test_list => sort_by_seq_no(l_rows(l_idx).after_test_list), after_each_list => sort_by_seq_no(l_rows(l_idx).after_each_list), - all_expectations => ut_expectation_results(), failed_expectations => ut_expectation_results(), - parent_error_stack_trace => null, expected_error_codes => l_rows(l_idx).expected_error_codes - ); - else - pragma inline(get_logical_suite, 'YES'); - l_items_at_level(l_level)(l_items_at_level(l_level).last) := get_logical_suite(l_rows, l_idx, l_level,l_prev_level, l_items_at_level ); - end if; + pragma inline(get_logical_suite, 'YES'); + l_items_at_level(l_level)(l_items_at_level(l_level).last) := get_logical_suite(l_rows, l_idx, l_level,l_prev_level, l_items_at_level ); else a_suites.extend; pragma inline(get_logical_suite, 'YES'); diff --git a/test/api/test_ut_run.pkb b/test/api/test_ut_run.pkb index ecf123d5e..c52551b33 100644 --- a/test/api/test_ut_run.pkb +++ b/test/api/test_ut_run.pkb @@ -806,7 +806,45 @@ Failures:% begin execute immediate 'drop package invalid_pckag_that_revalidates'; execute immediate 'drop package parent_specs'; - end; - + end; + + procedure run_and_report_warnings is + l_results ut3.ut_varchar2_list; + l_actual clob; + begin + + select * bulk collect into l_results from table(ut3.ut.run('bad_annotations')); + l_actual := ut3.ut_utils.table_to_clob(l_results); + + ut.expect(l_actual).to_be_like('%Invalid annotation "--%context". Cannot find following "--%endcontext". Annotation ignored.% +%1 tests, 0 failed, 0 errored, 0 disabled, 1 warning(s)%'); + + end; + + procedure create_bad_annot is + pragma autonomous_transaction; + begin + execute immediate q'[ + create or replace package bad_annotations as + --%suite + + --%context + + --%test(invalidspecs) + procedure test1; + + end;]'; + + execute immediate q'[ + create or replace package body bad_annotations as + procedure test1 is begin ut.expect(1).to_equal(1); end; + end;]'; + + end; + procedure drop_bad_annot is + pragma autonomous_transaction; + begin + execute immediate 'drop package bad_annotations'; + end; end; / diff --git a/test/api/test_ut_run.pks b/test/api/test_ut_run.pks index 81eb801a3..2ed325b86 100644 --- a/test/api/test_ut_run.pks +++ b/test/api/test_ut_run.pks @@ -114,6 +114,12 @@ create or replace package test_ut_run is procedure generate_invalid_spec; procedure drop_invalid_spec; + --%test(Provides warnings on invalid annotations) + --%beforetest(create_bad_annot) + --%aftertest(drop_bad_annot) + procedure run_and_report_warnings; + procedure create_bad_annot; + procedure drop_bad_annot; --%endcontext end;