Report Tester Copy link

Description
Category: Testing and Tuning
Plugin: Blitz Report Development (report-tester)
Works with: Claude Code

Test a Blitz Report by running the original Oracle standard report and the Blitz version with the same parameters, then comparing output.

When to use it

  • Use after converting an RDF or BI Publisher report to Blitz.
Install

Claude Code

  1. Add the Enginatics marketplace in Claude Code.
    /plugin marketplace add enginatics/ai-skills
  2. Install the plugin.
    /plugin install blitz-report-ai-skills@enginatics
  3. Run the environment setup once; it describes your EBS development instance (never production).
    /blitz-report-ai-skills:blitz-environment-setup
  4. Run the skill, or just describe the task and Claude picks it up.
    /blitz-report-ai-skills:report-tester
  5. Keep it current: enable auto-update for the enginatics marketplace, or update manually.
    /plugin marketplace update enginatics

Requirements: Blitz Report installed on your Oracle EBS development instance, and database access from Claude Code to that instance (Oracle SQLcl MCP server, SQLcl or SQL*Plus). Never point the skills at production.

Validates a converted Blitz Report by running both the original Oracle standard report and the new Blitz Report with identical parameters, then comparing the output. This catches SQL errors, missing columns, wrong joins, and data discrepancies.

When to Use

  • After converting an Oracle Report (.rdf) or BI Publisher report to Blitz
  • When user asks to test or validate a converted report
  • As the final quality gate before delivering a report conversion

Arguments

$ARGUMENTS should contain the Blitz Report name (e.g., "FA Tax Reserve Ledger") and optionally the original concurrent program name.

Phase 1: Find Test Data

The biggest challenge is finding parameter combinations that produce output. Many Vision demo reports return zero rows with default parameters.

1.1 Identify the Original Concurrent Program
select
fcp.concurrent_program_name,
fcp.user_concurrent_program_name,
fe.execution_file_name,
fa.application_short_name
from
fnd_concurrent_programs fcp,
fnd_executables fe,
fnd_application fa
where
fcp.executable_id=fe.executable_id and
fcp.executable_application_id=fe.application_id and
fcp.application_id=fa.application_id and
fcp.user_concurrent_program_name like '%'||:keyword||'%'
1.2 Find Previous Successful Runs

Check if the report has been run before with data-producing parameters:

-- Find previous runs that produced output
select
fcr.request_id,
fcr.actual_start_date,
fcr.phase_code,
fcr.status_code,
fcr.argument_text,
fcr.outfile_name
from
fnd_concurrent_requests fcr,
fnd_concurrent_programs fcp
where
fcr.concurrent_program_id=fcp.concurrent_program_id and
fcp.concurrent_program_name=:program_name and
fcr.phase_code='C' and
fcr.status_code='C'
order by
fcr.request_id desc
fetch first 10 rows only

If previous runs exist, reuse their parameter values.

1.3 Find Valid Parameter Values

When no previous runs exist, query the data to find values that produce rows:

-- Example: find books with assets (for FA reports)
select fb.book_type_code, count(*)
from fa_books fb
where fb.transaction_header_id_out is null
group by fb.book_type_code
order by count(*) desc;
-- Example: find periods with transactions (for GL reports)
select gjh.period_name, count(*)
from gl_je_headers gjh
where gjh.ledger_id=1
group by gjh.period_name
order by count(*) desc;
-- Example: find operating units with invoices (for AP reports)
select haouv.name, count(*)
from ap_invoices_all aia, hr_all_organization_units_vl haouv
where aia.org_id=haouv.organization_id
group by haouv.name
order by count(*) desc;
1.4 Map Concurrent Program Parameters to Blitz Parameters
-- Get concurrent program parameter definitions
select
fdfcuv.column_seq_num,
fdfcuv.end_user_column_name,
fdfcuv.form_left_prompt,
fdfcuv.default_value,
fdfcuv.required_flag,
ffvs.flex_value_set_name
from
fnd_descr_flex_col_usage_vl fdfcuv,
fnd_flex_value_sets ffvs
where
fdfcuv.application_id=:app_id and
fdfcuv.descriptive_flexfield_name='$SRS$.'||:program_name and
fdfcuv.descriptive_flex_context_code='Global Data Elements' and
fdfcuv.flex_value_set_id=ffvs.flex_value_set_id(+)
order by
fdfcuv.column_seq_num

Match each concurrent program parameter to the corresponding Blitz Report parameter by name or prompt.

Phase 2: Run the Oracle Standard Report

2.1 Submit via fnd_request.submit_request
declare
l_request_id number;
begin
fnd_global.apps_initialize(<user_id>, :resp_id, :app_id); --your own EBS user: select fu.user_id from fnd_user fu where fu.user_name='<YOUR_USER>'
mo_global.init('S');
l_request_id:=fnd_request.submit_request(
:app_short_name,    -- e.g., 'OFA', 'SQLAP', 'AR'
:program_name,      -- e.g., 'FADTXA'
null,               -- description
null,               -- start_time
false,              -- sub_request
:param1, :param2, :param3, :param4, :param5,
:param6, :param7, :param8, :param9, :param10,
chr(0)              -- end of params marker
);
commit;
dbms_output.put_line('request_id: '||l_request_id);
end;

Finding the right responsibility:

-- Find a responsibility that can run this program
select distinct
fr.responsibility_key,
fr.responsibility_id,
fa.application_id
from
fnd_responsibility fr,
fnd_application fa,
fnd_request_groups frg,
fnd_request_group_units frgu,
fnd_concurrent_programs fcp
where
fr.request_group_id=frg.request_group_id and
fr.application_id=fa.application_id and
frg.request_group_id=frgu.request_group_id and
fcp.concurrent_program_name=:program_name and
(frgu.unit_application_id=fcp.application_id and
 frgu.request_unit_id=fcp.concurrent_program_id and
 frgu.request_unit_type='P'
 or
 frgu.unit_application_id=fcp.application_id and
 frgu.request_unit_type='A')
fetch first 5 rows only
2.2 Wait for Completion
-- Check request status
select
fcr.phase_code, fcr.status_code,
fcr.completion_text,
fcr.outfile_name, fcr.logfile_name
from
fnd_concurrent_requests fcr
where
fcr.request_id=:request_id

Wait until phase_code='C' (Completed). If status_code<>'C' (not Normal), check the log file for errors.

2.3 Retrieve Output
# Output files are typically in:
# $APPLCSF/out/
# or the path from fcr.outfile_name
# Copy output to /tmp for analysis
cp /path/to/o<request_id>.out /tmp/oracle_report_output.txt
# For PDF/Excel output, may need to check fnd_lobs
-- Check for output in fnd_lobs (some reports store output here)
select fl.file_id, fl.file_name, dbms_lob.getlength(fl.file_data) file_size
from fnd_lobs fl
where fl.file_name like '%'||:request_id||'%'
order by fl.file_id desc;

Phase 3: Run the Blitz Report

3.1 Submit via xxen_api
declare
l_run_id number;
l_request_id number;
l_message varchar2(4000);
begin
fnd_global.apps_initialize(<user_id>, 50553, 101);
mo_global.init('S');
l_run_id:=xxen_api.create_run_id(:blitz_report_id);
-- Set parameters to match the Oracle report run
xxen_api.set_parameter_value_(
p_parameter_name=>'Book',
p_value=>:param_book,
p_report_name=>:blitz_report_name,
p_run_id=>l_run_id
);
-- Repeat for each parameter
l_message:=xxen_api.report_submit_concurrent(:blitz_report_id, l_run_id, x_request_id=>l_request_id);
commit;
dbms_output.put_line('request_id: '||l_request_id);
end;
3.2 Retrieve Blitz Output
-- Find the output XLSM in fnd_lobs
select fl.file_id, fl.file_name, dbms_lob.getlength(fl.file_data) file_size
from fnd_lobs fl, fnd_concurrent_requests fcr
where fcr.request_id=:blitz_request_id and
fl.file_id=fcr.output_file_id;

The Blitz output is an XLSM file. To compare, extract the data sheet.

Phase 4: Compare Outputs

4.1 Row Count Comparison

The simplest check — do both reports return the same number of rows?

-- Quick Blitz row count (from the SQL directly)
select count(*) from (<blitz_report_sql_with_params>);
-- Compare with Oracle report output line count
-- (parse the .out file or count data rows in XLSM)
4.2 Data Comparison Strategy

Since Oracle Reports output is typically formatted text/PDF and Blitz output is XLSM, exact byte comparison isn't possible. Instead:

Option A: SQL-level comparison (preferred, most reliable)

Run the Blitz SQL directly and compare against the Oracle report's source query:

-- Run Blitz SQL
select count(*), sum(amount), min(date_col), max(date_col)
from (<blitz_report_sql>)
where <parameter_conditions>;
-- Run original RDF SQL (from the RAD)
select count(*), sum(amount), min(date_col), max(date_col)
from (<original_rdf_sql>)
where <parameter_conditions>;

Compare: row counts, key aggregates (sums, counts), min/max values.

Option A only compares what the Blitz SQL and the original's query both contain. Formula columns, placeholders, package loop code that fills cursor literals, group filters and format triggers are outside that query. A conversion that dropped them passes Option A with identical counts and sums. Check those values with the formula port of migrate-custom-reports/references/value-fidelity.md, or against the program's own output.

Option B: Column-by-column comparison

For each column in the Blitz Report, verify it matches the original:

  1. Same column name/alias
  2. Same data on every row: join the two row sets on the key and count differences per column (sum(decode(o.col,n.col,0,1))); a spot check of a few rows misses the branch or edge case that differs
  3. Same aggregates (totals, subtotals)

Option C: Full data comparison (most thorough)

Export both datasets to a temp table and do a MINUS:

-- Create temp tables with both outputs
create global temporary table xx_oracle_output as <original_sql>;
create global temporary table xx_blitz_output as <blitz_sql>;
-- Find rows in Oracle but not in Blitz (missing rows)
select * from xx_oracle_output
minus
select * from xx_blitz_output;
-- Find rows in Blitz but not in Oracle (extra rows)
select * from xx_blitz_output
minus
select * from xx_oracle_output;
4.3 Common Discrepancies and Causes
DiscrepancyCommon CauseFix
Extra rows in BlitzMissing WHERE condition from BeforeReport lexicalAdd condition to Blitz SQL
Missing rows in BlitzExtra filter from Blitz parameterCheck parameter defaults
Different amountsFormula function not converted correctlyReview CF_ formulas
Different date formatFormat mask mismatchCheck to_char format
Missing columnsGroup summary not includedAdd analytic function
Different row orderORDER BY mismatchVerify sort columns
NULL vs blankNVL in original, missing in BlitzAdd NVL
Currency formattingSRW FORMAT_CURRENCY not replicatedUse to_char with format
4.4 Flexfield Comparison

If the original report uses FND FLEXSQL / FND FLEXIDVAL user exits:

  • Original: SRW.USER_EXIT('FND FLEXSQL CODE="GL#" ...) → flexfield segment values
  • Blitz: gcck.concatenated_segments or xxen_util.segments() or individual segment columns

Verify the same segments appear in the same format.

Phase 5: Report Results

Test Report Format
# Report Comparison Results
**Blitz Report:** <report name>
**Oracle Report:** <concurrent program name>
**Date:** <date>
## Parameters Used
| Parameter | Value |
|-----------|-------|
| Book | OPS CORP |
| Period | Jun-08 |
## Comparison Summary
| Check | Result | Details |
|-------|--------|---------|
| Oracle report runs successfully | Pass/Fail | request_id: NNN |
| Blitz report runs successfully | Pass/Fail | request_id: NNN |
| Row count matches | Pass/Fail | Oracle: N, Blitz: N |
| Key aggregates match | Pass/Fail | SUM(amount): Oracle=X, Blitz=X |
| All columns present | Pass/Fail | Missing: [list] |
| Column order matches | Pass/Fail | Differences: [list] |
| Data spot-check | Pass/Fail | Checked rows 1-5 and last 5 |
## Discrepancies Found
### [1] Missing condition in WHERE clause
- **Oracle SQL:** `AND fb.period_counter <= :P_END_PERIOD`
- **Blitz SQL:** condition missing
- **Impact:** Extra rows returned
- **Fix:** Add period filter
## Passed Checks
- Row count matches (both return 47 rows)
- SUM(cost) matches: 1,234,567.89
- ...

Tips

  1. Start with simple parameters — use a single book, one period, one org to minimize data volume
  2. Run Oracle report first — if it returns 0 rows, the parameters are wrong (no point running Blitz)
  3. Check BeforeReport trigger — it often builds dynamic WHERE clauses that the Blitz conversion must replicate
  4. Formula functions — some CF_ formulas do complex calculations that may need PL/SQL functions in Blitz
  5. Vision data periods — FA: Jun-08, GL/AP/AR: Dec-12, Manufacturing: Dec-2012
  6. Clean up temp tables — drop any global temporary tables created for comparison
  7. Save test parameters — document which parameters worked for future regression testing