You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
I'm super happy with coverage provided by utPLSQL however my company uses testing framework written in java with additional code run with sqlplus for integration tests. Is there any way to manually start, stop and generate sonar report without wrapping every piece of code with utplsql?
It would be great as my PL/SQL code is fragmented and called from different places but I would love to be able to get the coverage. I found that this project uses dbms_profiler so it shouldn't be a problem. Is there any instruction how to do this?
Provide version info
utPLSQL 3.1.9
Oracle 12.2
Information about client software
Other, using jdbc
So there is a way to do this on single session? So I could wrap my main jdbc connection (it uses one session) and cover at least this. That is still huge for me as I just need coverage without wrapping everything into ut.run (as I would have to wrap every call into fake test procedure because it is run from java) which is also not perfect as I will end up with as many reports as calls.
Yes. In single-session mode, there is a way.
This way is however undocumented and you need to be aware that it might no longer work in next releases as you're hooking into internal parts of uPLSQL instead of using public API.
The below was tested to work on v3.1.9,
Add extra grants and synonyms to internal utPLSQL elements.
grant execute on ut_coverage to ...;
grant execute on ut_run to ...;
create or replace synonym ut_coverage for ut3.ut_coverage;
create or replace synonym ut_run for ut3.ut_run;
create or replace synonym ut_output_table_buffer for ut3.ut_output_table_buffer;
connect to DB.
call:
begin
ut_coverage.coverage_start();
ut_coverage.coverage_resume();
end;
/
execute your tested code:
begin
my_code;
end;
/
call:
declare
/* PROVIDE UNIQUE ID for this run - the ID needs to be used later*/
v_reporter_id raw(32) := 'd8a79e85915640a6a4e1698fdf90ba75'; --sys_guid();
/* PROVIDE TYPE OF REPORTER*/
v_reporter ut_coverage_html_reporter := ut_coverage_html_reporter();
begin
v_reporter.set_reporter_id( v_reporter_id );
v_reporter.after_calling_run(
ut_run(
a_items => null--, /* leave it as NULL - irrelevant*/
/*optional - LIST OF SCHEMAS TO GET COVERAGE FOR - if not provided - current-schema is used */
--a_schema_names => ut_varchar2_rows(user) --,
/* optional - you can provide list of objects that should be included in coverage reports*/
-- a_include_objects => null,
/* optional - you can provide list of objects that should be excluded from coverage reports*/
-- a_exclude_objects => null,
/* optional - you can provide DB-object - file map here using ut_file_mappings
that way your coverage will be limited to specified objects
*/
-- a_project_file_mappings => null
)
);
v_reporter.on_finalize(null);
end;
/
Run the below query to get report in reporter format specified above.
/* PROVIDE UNIQUE ID for the run - same as in above block*/
select *
from table(
ut_output_table_buffer('d8a79e85915640a6a4e1698fdf90ba75').get_lines(1,1)
);
The query works only once per run, as the data is consumed from buffer by query.
So select into something (save data into file).
Having all that said
I would rather have a public API for this in utPLSQL then have users hook into internal stuff.
Public API could be easier to use too.
Reacted by Philipp Salvisberg, Ksawery Karwacki and alesana-san
That would be pretty nice usable API I think.
With that API, we would open-up utPLSQL for coverage-usage outside of utPLSQL unit-test runs.
That change would also allow for multi-session runs therefore enabling utPLSQL itself for parallel test execution!
There are two options though to consider:
the coverage data gets fully consumed after reporting (data is cleaned-up)
the coverage data remains in DB after reporting
I would prefer the first option as it also takes care of cleaning-up profiler and coverage tables. This is something utPLSQL is not handling at the moment.
I must say - this feature work looks pretty exciting :)
Reacted by Ksawery Karwacki and Philipp Salvisberg
I agree on that approach as there is almost no reason why we should keep the data after report is generated. One possible scenario is when you want to generate multiple types of report from single run.
I see it's definitely doable from implementation side and probably not a huge change.
We would maintain backward-compatibility of API, so that whatever works today, would still work as it was.
The CLI should be extended to produce reports (e.g. using ut_coverage_sonar_reporter or ut_coverage_html_reporter or any other reporter) based on a given report ID without running utPLSQL tests.
The start/stop mechanism is flexible enough. It can be used explicitly during test runs or included in a logon/logoff trigger to further simplify the usage. That way everything executed under a defined user is covered and the profiling data is cleared after the completion of the report.
I like the feature, too. Will have to think about what that means for CLI and java-api. It sounds like it'll lead to more modularization, which is a great thing.
Is there any ETA for that as I am moving closer and closer to the point when I would love to introduce code coverage. I could of course use junky hack discussed above but if there is any chance for pre-release, bleeding edge alpha implementation then I'm all in ;)
No problem. I hope everything is fine for you now.
I finally tried the old janky workaround and it didn't work for me as reporting returns 0 lines covered even thou I run a procedure form my schema. But I tested that on latest version so it might no longer work.
Anyway I still can't wait to lay my hands on full api :)
I'm on vacation for past couple of weeks and I try to avoid coding :) I'll be back to my regular office routine in a week after that I'm going to prepare some tests and run it.
I tried to run the workaround approach from #1025 (comment) using java as described above but generated report was always empty. Due to lack of time to investigate this I just dropped it and was waiting for full implementation.
I'll get back to you as soon as I will get some results after my holiday break.
I've run some initial test and seems to work like a charm.
I had few doubts about configuration of reporter as documentation lists all parameters except coverage_run_id as optional so my assumption was that something like this:
should generate me report for all schemas where ut_runner.coverage_start/ut_runner.coverage_stop occurred. That didn't happened and I had to add schema to parameters which makes it not so optional ;)
Generally I'm pretty pumped about it, start/stop takes almost no time so overhead is minimal, the fact that we can generate multiple reports for different purposes is awesome.
One thing for consideration is to add option to remove data for specific run_id. Without auto cleanup after generation of report for multiple runs it may be just a lot of unused data clogging datafiles. Something like ut_runner.coverage_clean(a_coverage_run_id) might be useful especially if code coverage is generated over multiple run_ids and over many big schemas.
Overall 10/10, would recommend this to my family and friends ;)
@ksawerykarwacki
I'll look into the schema name issue.
Note however, that coverage reporting has a bit of inverse logic to what you described:
should generate me report for all schemas where ut_runner.coverage_start/ut_runner.coverage_stop occurred
Coverage is gathered on all schemas (regardless of connected user.
So if you connect as user X, enable coverage and run code in schema Y, the coverage on objects located in schema Y is gathered, not in schema X
When reporting, you need to specify which schemas or objects you're interested in for coverage reports.
If no schema is provided, the current schema of session where report is generated will be used.
For the mapping, you will need a clever regex, depends on your file names too.
Can you provide a more detailed example of what would be file names and extensions for given objects?
Also do your file path (filename or directory) include owner(schema) or are all sources deployed to one schema?
All of this decides on config for report.
If you will provide more details I can give you some help with that.
Have a look at this issue: utPLSQL/utPLSQL-cli#184
Activity
jgebal commentedon Nov 28, 2019
Hi @ksawerykarwacki
Currently, utPLSQL utilizes coverage internally.
All of the above is done in single-session mode.
To enable coverage gathering from outside, we would need do to some rework of internal code so that you could have one coverage for multiple sessions.
Most probably, when running your tests from outside of DB, you might be utilizing more than one session.
You might have:
So in essence you we would need to expose API that would allow an external program to:
ABCDEor some UUID)ABCDEABCDEWe've already had similar request in the past.
I think it's doable.
We would need:
ABCDwith list of coverage & profiler run_id'sI guess it could be few days - few weeks of work to get it done.
ksawerykarwacki commentedon Nov 29, 2019
So there is a way to do this on single session? So I could wrap my main jdbc connection (it uses one session) and cover at least this. That is still huge for me as I just need coverage without wrapping everything into ut.run (as I would have to wrap every call into fake test procedure because it is run from java) which is also not perfect as I will end up with as many reports as calls.
jgebal commentedon Nov 29, 2019
Yes. In single-session mode, there is a way.
This way is however undocumented and you need to be aware that it might no longer work in next releases as you're hooking into internal parts of uPLSQL instead of using public API.
The below was tested to work on v3.1.9,
connect to DB.
call:
The query works only once per run, as the data is consumed from buffer by query.
So select into something (save data into file).
Having all that said
I would rather have a public API for this in utPLSQL then have users hook into internal stuff.
Public API could be easier to use too.
ksawerykarwacki commentedon Nov 29, 2019
I agree that having official API is a way to go so this is still a enhancement request rather than question.
@jgebal Nevertheless thank you for giving me something to start with for now.
jgebal commentedon Nov 29, 2019
I think it's a good feature to add to API.
I mean adding ability to run utPLSQL coverage without invoking ut.run();
The API could be something like this:
use UUID on the APP side to generate a unique identifier for your application tests.
wrap each call to database code with coverage registration like:
Each test run can be executed in separate session.
Tests can be executed in parallel.
The
a_coverage_optionscould be optional.That would be pretty nice usable API I think.
With that API, we would open-up utPLSQL for coverage-usage outside of utPLSQL unit-test runs.
That change would also allow for multi-session runs therefore enabling utPLSQL itself for parallel test execution!
There are two options though to consider:
I would prefer the first option as it also takes care of cleaning-up profiler and coverage tables. This is something utPLSQL is not handling at the moment.
I must say - this feature work looks pretty exciting :)
ksawerykarwacki commentedon Nov 29, 2019
I agree on that approach as there is almost no reason why we should keep the data after report is generated. One possible scenario is when you want to generate multiple types of report from single run.
jgebal commentedon Mar 14, 2020
@pesse @PhilippSalvisberg @lwasylow
What do you think of the suggested change from usability perspective?
I see it's definitely doable from implementation side and probably not a huge change.
We would maintain backward-compatibility of API, so that whatever works today, would still work as it was.
PhilippSalvisberg commentedon Mar 15, 2020
I like the approach.
The CLI should be extended to produce reports (e.g. using
ut_coverage_sonar_reporterorut_coverage_html_reporteror any other reporter) based on a given report ID without running utPLSQL tests.The start/stop mechanism is flexible enough. It can be used explicitly during test runs or included in a logon/logoff trigger to further simplify the usage. That way everything executed under a defined user is covered and the profiling data is cleared after the completion of the report.
pesse commentedon Mar 20, 2020
I like the feature, too. Will have to think about what that means for CLI and java-api. It sounds like it'll lead to more modularization, which is a great thing.
ksawerykarwacki commentedon Apr 10, 2020
Is there any ETA for that as I am moving closer and closer to the point when I would love to introduce code coverage. I could of course use junky hack discussed above but if there is any chance for pre-release, bleeding edge alpha implementation then I'm all in ;)
jgebal commentedon Apr 10, 2020
HI @ksawerykarwacki
Long weekend is coming and with lockdown, there is a chance I might make good progress on it :)
jgebal commentedon Apr 13, 2020
@ksawerykarwacki - will need another weekend or two to get into this.
This long Easter weekend I have decided to actually get some rest.
ksawerykarwacki commentedon May 12, 2020
Is there some progress by any chance?
jgebal commentedon May 12, 2020
Sorry @ksawerykarwacki
I had some really serious personal matters to attend.
I've started looking into it just now.
ksawerykarwacki commentedon May 18, 2020
No problem. I hope everything is fine for you now.
I finally tried the old janky workaround and it didn't work for me as reporting returns 0 lines covered even thou I run a procedure form my schema. But I tested that on latest version so it might no longer work.
Anyway I still can't wait to lay my hands on full api :)
jgebal commentedon Jun 21, 2020
@ksawerykarwacki - did you get a chance to try the new coverage approach in #1079?
ksawerykarwacki commentedon Jun 21, 2020
I'm on vacation for past couple of weeks and I try to avoid coding :) I'll be back to my regular office routine in a week after that I'm going to prepare some tests and run it.
To give you some way how I will test it:
I will be using Java to call it as all my calls are run over NamedParameterJdbcTemplate using update method(https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.html#update-java.lang.String-java.util.Map-), inside I use call statement.
I tried to run the workaround approach from #1025 (comment) using java as described above but generated report was always empty. Due to lack of time to investigate this I just dropped it and was waiting for full implementation.
I'll get back to you as soon as I will get some results after my holiday break.
ksawerykarwacki commentedon Jun 30, 2020
I've run some initial test and seems to work like a charm.
I had few doubts about configuration of reporter as documentation lists all parameters except coverage_run_id as optional so my assumption was that something like this:
select * from table( ut_coverage_html_reporter().get_report( a_coverage_options => ut_coverage_options( coverage_run_id => 'A6AA5B7361251CE6E053020011ACA055' ) ) );should generate me report for all schemas where ut_runner.coverage_start/ut_runner.coverage_stop occurred. That didn't happened and I had to add schema to parameters which makes it not so optional ;)
Generally I'm pretty pumped about it, start/stop takes almost no time so overhead is minimal, the fact that we can generate multiple reports for different purposes is awesome.
One thing for consideration is to add option to remove data for specific run_id. Without auto cleanup after generation of report for multiple runs it may be just a lot of unused data clogging datafiles. Something like ut_runner.coverage_clean(a_coverage_run_id) might be useful especially if code coverage is generated over multiple run_ids and over many big schemas.
Overall 10/10, would recommend this to my family and friends ;)
ksawerykarwacki commentedon Jun 30, 2020
@jgebal I also struggle with some file mappings as my structure is a bit different. My folder structure looks like this:
I don't know how to do mapping if I have additional folder level for packages
jgebal commentedon Jul 1, 2020
@ksawerykarwacki
I'll look into the schema name issue.
Note however, that coverage reporting has a bit of inverse logic to what you described:
Coverage is gathered on all schemas (regardless of connected user.
So if you connect as user
X, enable coverage and run code in schemaY, the coverage on objects located in schemaYis gathered, not in schemaXWhen reporting, you need to specify which schemas or objects you're interested in for coverage reports.
If no schema is provided, the current schema of session where report is generated will be used.
jgebal commentedon Jul 1, 2020
For the mapping, you will need a clever regex, depends on your file names too.
Can you provide a more detailed example of what would be file names and extensions for given objects?
Also do your file path (filename or directory) include owner(schema) or are all sources deployed to one schema?
All of this decides on config for report.
If you will provide more details I can give you some help with that.
Have a look at this issue: utPLSQL/utPLSQL-cli#184