//
// aegis - project change supervisor
// Copyright (C) 2000-2008, 2011, 2012, 2014 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
batch_result_list_ty *
change_test_batch(change::pointer cp, string_list_ty *wlp, user_ty::pointer up,
bool baseline_flag, int current, int total,
const nstring_list &variable_assignments, const long *remaining)
{
int flags;
batch_result_list_ty *result;
tstrslt_ty *tstrslt_data;
string_ty *the_command;
string_ty *s;
string_ty *output_file_name;
pconf_ty *pconf_data;
size_t j;
size_t k;
string_ty *dir;
trace(("change_test_batch(cp = %p, wlp = %p, up = %p, "
"baseline_flag = %d, current = %d, total = %d)\n{\n", cp.get(),
wlp, up.get(), baseline_flag, current, total));
pconf_data = change_pconf_get(cp, 1);
the_command = pconf_data->batch_test_command;
assert(the_command);
//
// resolve the file names
//
string_list_ty wl2;
for (j = 0; j < wlp->size(); ++j)
{
string_ty *fn;
string_ty *fn_abs;
fstate_src_ty *src_data;
fn = (*wlp)[j];
src_data = cp->file_find(nstring(fn), view_path_first);
if (src_data)
{
fn_abs = cp->file_path(fn);
}
else
{
src_data = cp->project_get()->file_find(fn, view_path_simple);
assert(src_data);
fn_abs = project_file_path(cp->project_get(), fn);
}
assert(fn_abs);
wl2.push_back(fn_abs);
str_free(fn_abs);
}
assert(cp->valid());
s = wl2.unsplit();
sub_context_ty sc;
sc.var_set_string("File_Names", s);
str_free(s);
output_file_name = os_edit_filename(0);
sc.var_set_string("Output", output_file_name);
if (baseline_flag && !cp->is_bogus())
{
nstring_list spbl;
cp->project_get()->search_path_get(spbl, false);
nstring s2 = spbl.unsplit(":");
sc.var_set_string("Search_Path_Executable", s2);
sc.var_override("Search_Path_Executable");
sc.var_optional("Search_Path_Executable");
}
sc.var_set_long("Current", current);
sc.var_optional("Current");
sc.var_set_long("Total", total);
sc.var_optional("Total");
sc.var_set_string("REMaining", format_elapsed(remaining[0]));
sc.var_optional("REMaining");
// Quote the variable assignments
nstring_list var;
for (size_t jj = 0; jj < variable_assignments.size(); ++jj)
var.push_back(variable_assignments[jj].quote_shell());
sc.var_set_string("VARiables", var.unsplit());
sc.var_append_if_unused("VARiables");
up->become_begin();
undo_unlink_errok(output_file_name);
up->become_end();
the_command = sc.substitute(cp, the_command);
//
// we need input if any of the tests are manual
//
flags = OS_EXEC_FLAG_NO_INPUT;
for (j = 0; j < wlp->size(); ++j)
{
string_ty *file_name;
fstate_src_ty *src_data;
file_name = (*wlp)[j];
src_data = cp->file_find(nstring(file_name), view_path_first);
if (!src_data)
{
src_data =
cp->project_get()->file_find(file_name, view_path_simple);
}
assert(src_data);
if (!src_data)
continue;
switch (src_data->usage)
{
case file_usage_source:
case file_usage_config:
case file_usage_build:
case file_usage_test:
#ifndef DEBUG
default:
#endif
continue;
case file_usage_manual_test:
flags = OS_EXEC_FLAG_INPUT;
break;
}
break;
}
//
// directory depends on the state of the change
//
// During long tests the automounter can unmount the
// directory referenced by the "dir" variable.
// To minimize this, it is essential that they are
// unresolved, and thus always trigger the automounter.
//
dir = cp->project_get()->baseline_path_get();
trace_string(dir);
if (!baseline_flag && !cp->is_bogus())
{
cstate_ty *cstate_data;
cstate_data = cp->cstate_get();
switch (cstate_data->state)
{
case cstate_state_awaiting_development:
assert(0);
case cstate_state_completed:
break;
case cstate_state_being_integrated:
dir = cp->integration_directory_get(false);
trace_string(dir);
break;
case cstate_state_being_developed:
case cstate_state_awaiting_review:
case cstate_state_being_reviewed:
case cstate_state_awaiting_integration:
dir = cp->development_directory_get(0);
trace_string(dir);
break;
}
}
//
// display progress message if requested
//
if (total > 0)
{
sc.var_set_long("Current", current + 1);
sc.var_set_long("Total", total);
if (wlp->size() == 1)
change_error(cp, &sc, i18n("test $current of $total"));
else
{
sc.var_set_long("Last", current + wlp->size());
change_error
(
cp,
&sc,
i18n("batch test from $current to $last of $total")
);
}
}
//
// run the command
// This tests all of the files at once.
//
// we average the elapsed time over all tests
//
change_env_set(cp, 1);
up->become_begin();
double t_begin = dtime();
os_execute(the_command, flags, dir);
double t_end = dtime();
str_free(the_command);
double elapsed = t_end - t_begin;
elapsed /= wlp->size();
trace(("elapsed = %g\n", elapsed));
//
// read the output
//
tstrslt_data = tstrslt_read_file(output_file_name);
os_unlink_errok(output_file_name);
up->become_end();
if (!tstrslt_data->test_result)
{
tstrslt_data->test_result =
(tstrslt_test_result_list_ty *)
tstrslt_test_result_list_type.alloc();
}
//
// transcribe the result structure
//
result = batch_result_list_new();
for (j = 0; j < tstrslt_data->test_result->length; ++j)
{
tstrslt_test_result_ty *p;
//
// perform sanity checks
//
p = tstrslt_data->test_result->list[j];
if (!p->file_name)
{
sc.var_set_string("File_Name", output_file_name);
sc.var_set_charstar("FieLD_Name", "test_result.file_name");
sc.var_set_charstar("REASON", " (no file_name field)");
sc.var_append_if_unused("REASON");
change_fatal
(
cp,
&sc,
i18n("$filename: corrupted \"$field_name\" field")
);
// NOTREACHED
}
for (k = 0; k < wlp->size(); ++k)
{
if (str_equal(p->file_name, wl2[k]))
{
//
// map abs name to relative name
//
str_free(p->file_name);
p->file_name = str_copy((*wlp)[k]);
break;
}
}
if (!wlp->member(p->file_name))
{
sc.var_set_string("File_Name", output_file_name);
sc.var_set_charstar("FieLD_Name", "test_result.file_name");
sc.var_set_string
(
"REASON",
" (filename \"" + nstring(p->file_name) + "\" not in the list)"
);
sc.var_append_if_unused("REASON");
change_fatal
(
cp,
&sc,
i18n("$filename: corrupted \"$field_name\" field")
);
// NOTREACHED
}
if (batch_result_list_member(result, p->file_name, p->architecture))
{
sc.var_set_string("File_Name", output_file_name);
sc.var_set_charstar("FieLD_Name", "test_result.file_name");
sc.var_set_string
(
"REASON",
(
" (filename \""
+
nstring(p->file_name)
+
"\" named more than once)"
)
);
sc.var_append_if_unused("REASON");
change_fatal
(
cp,
&sc,
i18n("$filename: corrupted \"$field_name\" field")
);
// NOTREACHED
}
//
// add result to list
//
batch_result_list_append
(
result,
p->file_name,
p->exit_status,
p->architecture,
elapsed
);
//
// emit verbose messages
//
switch (p->exit_status)
{
case 1:
if (baseline_flag)
{
sc.var_set_string("File_Name", p->file_name);
if (p->architecture)
{
sc.var_set_string("ARCHitecture", p->architecture);
sc.var_override("ARCHitecture");
change_verbose
(
cp,
&sc,
i18n
(
"$filename baseline fail, architecture $architecture, good"
)
);
}
else
{
change_verbose
(
cp,
&sc,
i18n("$filename baseline fail, good")
);
}
result->pass_count++;
}
else
{
sc.var_set_string("File_Name", p->file_name);
if (p->architecture)
{
sc.var_set_string("ARCHitecture", p->architecture);
sc.var_override("ARCHitecture");
change_verbose
(
cp,
&sc,
i18n("$filename fail, architecture $architecture")
);
}
else
change_verbose(cp, &sc, i18n("$filename fail"));
result->fail_count++;
}
break;
case 0:
if (baseline_flag)
{
sc.var_set_string("File_Name", p->file_name);
if (p->architecture)
{
sc.var_set_string("ARCHitecture", p->architecture);
sc.var_override("ARCHitecture");
change_verbose
(
cp,
&sc,
i18n
(
"$filename baseline pass, architecture $architecture, not good"
)
);
}
else
{
change_verbose
(
cp,
&sc,
i18n("$filename baseline pass, not good")
);
}
result->fail_count++;
}
else
{
sc.var_set_string("File_Name", p->file_name);
if (p->architecture)
{
sc.var_set_string("ARCHitecture", p->architecture);
sc.var_override("ARCHitecture");
change_verbose
(
cp,
&sc,
i18n("$filename pass, architecture $architecture")
);
}
else
change_verbose(cp, &sc, i18n("$filename pass"));
result->pass_count++;
}
break;
case 77:
{
// Note: the value 77 was chosen to be compatible with
// other test systems.
sc.var_set_string("File_Name", p->file_name);
if (p->architecture)
{
sc.var_set_string("ARCHitecture", p->architecture);
sc.var_override("ARCHitecture");
change_verbose
(
cp,
&sc,
i18n("$filename skipped, architecture $architecture")
);
}
else
change_verbose(cp, &sc, i18n("$filename skipped"));
result->skip_count++;
}
break;
default:
{
sc.var_set_string("File_Name", p->file_name);
if (p->architecture)
{
sc.var_set_string("ARCHitecture", p->architecture);
sc.var_override("ARCHitecture");
change_verbose
(
cp,
&sc,
i18n("$filename no result, architecture $architecture")
);
}
else
change_verbose(cp, &sc, i18n("$filename no result"));
result->no_result_count++;
}
break;
}
}
tstrslt_type.free(tstrslt_data);
str_free(output_file_name);
//
// all done
//
trace(("return %p;\n", result));
trace(("}\n"));
return result;
}
// vim: set ts=8 sw=4 et :