- add ability to search for recently added or updated testcases
This commit is contained in:
ccooper%deadsquid.com 2006-06-28 19:03:45 +00:00
parent 1ae2c9bdc0
commit 8c88a62bbe
7 changed files with 171 additions and 95 deletions

View File

@ -57,7 +57,7 @@ my $cookie_expire_days = 7;
my $curSession;
# Given a username and password, validate the login. Returns the
# Lutmus::DB::User object associated with the username if the login
# Litmus::DB::User object associated with the username if the login
# is sucuessful. Returns false otherwise.
sub validate_login($$) {
my $username = shift;
@ -488,7 +488,7 @@ sub setCookie {
my $user_id = 0;
if ($user) {
$user_id = $user->userid();
$user_id = $user->user_id();
}
if (!$expires or $expires eq '') {

View File

@ -42,6 +42,7 @@ use Litmus::Error;
our $default_relevance_threshold = 1.0;
our $default_match_limit = 25;
our $default_num_days = 7;
Litmus::DB::Testcase->table('testcases');
@ -69,8 +70,8 @@ __PACKAGE__->set_sql(EnabledBySubgroup => qq{
__PACKAGE__->set_sql(CommunityEnabledBySubgroup => qq{
SELECT t.*
FROM testcases t, testcase_subgroups tsg
WHERE tsg.subgroup_id=? AND tsg.testcase_id=t.testcase_id AND t.enabled=1 AND t.community_enabled=1
FROM testcases t, testcase_subgroups tsg
WHERE tsg.subgroup_id=? AND tsg.testcase_id=t.testcase_id AND t.enabled=1 AND t.community_enabled=1
ORDER BY tsg.sort_order ASC
});
@ -97,7 +98,7 @@ sub is_completed {
$build_id,
$locale->{'abbrev'},
$platform->{'platform_id'},
$user->{'user_id'},
$user->{'user_id'},
);
} else {
@results = Litmus::DB::Testresult->search_Completed(
@ -107,8 +108,8 @@ sub is_completed {
$platform->{'platform_id'},
);
}
return @results;
return @results;
}
#########################################################################
@ -117,28 +118,80 @@ sub getFullTextMatches() {
my $text_snippet = shift;
my $match_limit = shift;
my $relevance_threshold = shift;
if (!$match_limit) {
$match_limit = $default_match_limit;
}
if (!$relevance_threshold) {
$relevance_threshold = $default_relevance_threshold
}
__PACKAGE__->set_sql(FullTextMatches => qq{
SELECT testcase_id, summary, MATCH (summary,steps,expected_results) AGAINST (?) AS relevance
FROM testcases
WHERE MATCH (summary,steps,expected_results) AGAINST (?) HAVING relevance > ?
ORDER BY relevance DESC, summary ASC
LIMIT $match_limit
SELECT testcase_id, summary, creation_date, last_updated, MATCH (summary,steps,expected_results) AGAINST (?) AS relevance
FROM testcases
WHERE MATCH (summary,steps,expected_results) AGAINST (?) HAVING relevance > ?
ORDER BY relevance DESC, summary ASC
LIMIT $match_limit
});
return $self->search_FullTextMatches(
$text_snippet,
$text_snippet,
$relevance_threshold
);
);
}
#########################################################################
sub getNewTestcases() {
my $self = shift;
my $num_days = shift;
my $match_limit = shift;
if (!$num_days) {
$num_days = $default_num_days;
}
if (!$match_limit) {
$match_limit = $default_match_limit;
}
__PACKAGE__->set_sql(NewTestcases => qq{
SELECT testcase_id, summary, creation_date, last_updated
FROM testcases
WHERE creation_date>=?
LIMIT $match_limit
});
my $err;
my $new_datestamp=&UnixDate(DateCalc("now","- $num_days days"),"%q");
return $self->search_NewTestcases($new_datestamp);
}
#########################################################################
sub getRecentlyUpdated() {
my $self = shift;
my $num_days = shift;
my $match_limit = shift;
if (!$num_days) {
$num_days = $default_num_days;
}
if (!$match_limit) {
$match_limit = $default_match_limit;
}
__PACKAGE__->set_sql(RecentlyUpdated => qq{
SELECT testcase_id, summary, creation_date, last_updated
FROM testcases
WHERE last_updated>=? AND last_updated>creation_date
LIMIT $match_limit
});
my $err;
my $new_datestamp=&UnixDate(DateCalc("now","- $num_days days"),"%q");
return $self->search_RecentlyUpdated($new_datestamp);
}
#########################################################################
@ -151,46 +204,51 @@ sub getDefaultRelevanceThreshold() {
return $default_relevance_threshold;
}
#########################################################################
sub getDefaultNumDays() {
return $default_num_days;
}
#########################################################################
sub clone() {
my $self = shift;
my $new_testcase = $self->copy;
if (!$new_testcase) {
if (!$new_testcase) {
return undef;
}
# Update dates to now.
my $now = &UnixDate("today","%q");
$new_testcase->creation_date($now);
$new_testcase->last_updated($now);
$new_testcase->update();
# Propagate subgroup membership;
my $dbh = __PACKAGE__->db_Main();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testcase_subgroups (testcase_id,subgroup_id,sort_order) SELECT ?,subgroup_id,sort_order FROM testcase_subgroups WHERE testcase_id=?";
my $rows = $dbh->do($sql,
my $rows = $dbh->do($sql,
undef,
$new_testcase->testcase_id,
$self->testcase_id
);
if (! $rows) {
# XXX: Do we need to throw a warning here?
# What happens when we clone a testcase that doesn't belong to
# What happens when we clone a testcase that doesn't belong to
# any subgroups?
}
}
$sql = "INSERT INTO related_testcases (testcase_id, related_testcase_id) VALUES (?,?)";
$rows = $dbh->do($sql,
undef,
$self->testcase_id,
$new_testcase->testcase_id
);
undef,
$self->testcase_id,
$new_testcase->testcase_id
);
if (! $rows) {
# XXX: Do we need to throw a warning here?
}
}
return $new_testcase;
}
@ -198,7 +256,7 @@ sub clone() {
sub delete_from_subgroups() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from testcase_subgroups WHERE testcase_id=?";
my $rows = $dbh->do($sql,
undef,
@ -209,8 +267,8 @@ sub delete_from_subgroups() {
#########################################################################
sub delete_from_related() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from related_testcases WHERE testcase_id=? OR related_testcase_id=?";
my $rows = $dbh->do($sql,
undef,
@ -235,7 +293,7 @@ sub update_subgroups() {
if (scalar @$new_subgroup_ids) {
# Failing to delete subgroups is _not_ fatal when adding a new testcase.
my $rv = $self->delete_from_subgroups();
my $dbh = __PACKAGE__->db_Main();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testcase_subgroups (testcase_id,subgroup_id,sort_order) VALUES (?,?,1)";
foreach my $new_subgroup_id (@$new_subgroup_ids) {
my $rows = $dbh->do($sql,

View File

@ -1232,9 +1232,29 @@ table.testcase-search th, table.test-runs th {
border: 0;
}
table.testcases th, table.testcases td.headerleft {
vertical-align: middle;
font-weight: bold;
text-transform: lowercase;
color: #666666;
padding: 0px 5px 0px 5px;
border: 0;
}
table.testcases td.headerleft {
text-align: left;
}
table.testcases tr {
border: solid #bbbbbb 1px;
}
div.testcase-search {
margin: 5px;
background-color: #efefef;
padding: 10px;
border: solid #bbbbbb 1px;
}

View File

@ -47,6 +47,7 @@ $vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
$vars->{'default_match_limit'} = Litmus::DB::Testcase->getDefaultMatchLimit();
$vars->{'default_num_days'} = Litmus::DB::Testcase->getDefaultNumDays();
$vars->{'default_relevance_threshold'} = Litmus::DB::Testcase->getDefaultRelevanceThreshold();
if (! $c->param) {
@ -116,7 +117,7 @@ if ($c->param("id")) {
$vars->{'onload'} = "toggleMessage('$status','$message');";
}
} elsif ($c->param("editingTestcases") &&
! Litmus::Auth::canEdit(Litmus::Auth::getCookie())) {
! Litmus::Auth::canEdit(Litmus::Auth::getCookie())) {
invalidInputError("You do not have permissions to edit testcases. ");
}
@ -162,8 +163,29 @@ if ($c->param("text_snippet")) {
$relevance_threshold);
$vars->{'testcases'} = \@testcases;
$vars->{'search_string_for_display'} = "Full-Text Search: \"$text_snippet\"";
$vars->{'fulltext'} = 1;
} elsif ($c->param("recently")) {
my $recently = $c->param("recently");
my $match_limit = $c->param("match_limit");
my $num_days = $c->param("num_days") || Litmus::DB::Testcase->getDefaultNumDays();
my @testcases;
my $search_string_for_display;
if ($recently eq 'added') {
@testcases = Litmus::DB::Testcase->getNewTestcases(
$num_days,
$match_limit
);
$search_string_for_display = "Testcases added in the last $num_days days";
} elsif ($recently eq 'changed') {
@testcases = Litmus::DB::Testcase->getRecentlyUpdated(
$num_days,
$match_limit
);
$search_string_for_display = "Testcases changed in the last $num_days days";
}
$vars->{'testcases'} = \@testcases;
$vars->{'search_string_for_display'} = $search_string_for_display;
}
Litmus->template()->process("show/search_for_testcases.tmpl", $vars) ||
internalError(Litmus->template()->error());

View File

@ -26,7 +26,7 @@
#%]
<div id="footer">
Search: <a href="search_results.cgi?order_by_created=DESC&amp;timespan=all&amp;result_status=fail&amp;limit=50">Recent Failures</a> | <a href="common_results.cgi?status=fail">Most Common Failures</a> | <a href="common_results.cgi?status=unclear">Testcases Most Frequently Marked As Unclear</a> | Test Runs In Progress
Search test results: <a href="search_results.cgi?order_by_created=DESC&amp;timespan=all&amp;result_status=fail&amp;limit=50">Recent Failures</a> | <a href="common_results.cgi?status=fail">Most Common Failures</a> | <a href="common_results.cgi?status=unclear">Testcases Most Frequently Marked As Unclear</a> | Test Runs In Progress<br/>Search testcases: <a href="show_test.cgi?recently=added">Recently Added</a> | <a href="show_test.cgi?recently=changed">Recently Changed</a>
</div>
</div>

View File

@ -32,15 +32,20 @@
[% title="View Testcase" %]
[% INCLUDE global/html_header.tmpl %]
[% INCLUDE global/html_header.tmpl js_files=['js/Help.js'] %]
[% INCLUDE global/litmus_header.tmpl %]
<script type="text/javascript">
function init()
{
FormInit(document.forms['search_by_testcase_id'], document.location.search);
FormInit(document.forms['search_fulltext'], document.location.search);
FormInit(document.forms['testcase_search_by_id'], document.location.search);
FormInit(document.forms['testcase_fulltext_search'], document.location.search);
FormInit(document.forms['testcase_search_recent'], document.location.search);
}
var relevanceHelpTitle = 'What is relevance?';
var relevanceHelpText = '<p>Relevance values are non-negative floating-point numbers. Zero relevance means no similarity. Relevance is computed based on the number of words in the row, the number of unique words in that row, the total number of words in the collection, and the number of documents (rows) that contain a particular word.</p><p><a target="external_link" href="http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html">More information on full-text searching can be found here.</a></p>';
</script>
<div id="page">
@ -51,56 +56,23 @@ function init()
<h1 class="firstHeading">[% title | html %]</h1>
<div class="section-full">
<div class="section-full">
<div class="section-header">
Search by Testcase ID #
<table class="testcase-search">
<tr>
<th>By Testcase ID#</th>
<th>By Full-text Search</th>
<th>By Recently Added/Changed</th>
</tr>
<tr>
<td valign="top" width="33%"><div class="testcase-search">Testcase ID#:<br/><form action="show_test.cgi" method="get" name="testcase_search_by_id" id="testcase_search_by_id"><input type="text" id="id" name="id" size="25" /><br/><input class="button" type="submit" value="Search By ID"></form></td></div></td>
<td valign="top" width="33%"><div class="testcase-search">String to match:<br/><form action="show_test.cgi" method="get" name="testcase_fulltext_search" id="testcase_fulltext_search"><input type="text" id="text_snippet" name="text_snippet" size="25" /><br/>Minimum Relevance Score:<br/><input type="text" name="relevance_threshold" id="relevance_threshold" value="[% default_relevance_threshold %]" size="5" />&nbsp;&lArr;&nbsp;<a name="relevance_help" onclick="toggleHelp(relevanceHelpTitle,relevanceHelpText);">What is relevance?</a><br/># of Matches:<br/><input type="text" name="match_limit" id="match_limit" value="[% default_match_limit %]" size="5" /><br/><input class="button" type="submit" value="Fulltext Search"></form>
</div></td>
<td valign="top"><div class="testcase-search"><form action="show_test.cgi" method="get" name="testcase_search_recent" id="testcase_search_recent"><input type="radio" id="recently" name="recently" value="added" checked/>&nbsp;Added<br/><input type="radio" id="recently" name="recently" value="changed" />&nbsp;Changed<br/>Within the last <input type="text" name="num_days" value="[% default_num_days %]" size="3"> days<br/># of Matches:<br/><input type="text" name="match_limit" id="match_limit" value="[% default_match_limit %]" size="5" /><br/><input class="button" type="submit" value="Search Recent"></div></td>
</tr>
</table>
</div>
<div class="section-content">
<form action="show_test.cgi" method="get" name="search_by_testcase_id" id="search_by_testcase_id">
<table border="0" celpadding="5" cellspacing="5">
<tr>
<td>Testcase ID#:</td><td><input type="text" id="id" name="id" size="25" /></td>
</tr>
<tr>
<td colspan="2" align="right"><input type="submit" value="Submit"></td>
</tr>
</table>
</form>
</div>
<div class="or">OR</div>
<div class="section-header">
Full-text Search
</div>
<div class="section-content">
<form action="show_test.cgi" method="get" name="search_fulltext" id="search_fulltext">
<table border="0" celpadding="5" cellspacing="5">
<tr>
<td>String to match:</td><td><input type="text" id="text_snippet" name="text_snippet" size="25" /></td>
</tr>
<tr>
<td># of Matches:</td><td><input type="text" name="match_limit" id="match_limit" value="[% default_match_limit %]" size="5" /></td>
</tr>
<tr>
<td>Minimum Relevance Score:</td><td><input type="text" name="relevance_threshold" id="relevance_threshold" value="[% default_relevance_threshold %]" size="5" /></td>
</tr>
<tr>
<td colspan="2" align="right"><input type="submit" value="Submit"></td>
</tr>
</table>
</form>
</div>
</div>
[% IF testcases %]
<h1 class="firstHeading">Matching Testcases[% IF search_string_for_display %] - [% search_string_for_display | html %][% END %]</h1>
@ -119,4 +91,4 @@ Full-text Search
</div> <!--END page-->
[% INCLUDE global/litmus_footer.tmpl %]
[% INCLUDE global/html_footer.tmpl %]
[% INCLUDE global/html_footer.tmpl %]

View File

@ -31,14 +31,16 @@
<table class="testcases">
<tr>
<th width="5%">Relevance</th>
[% IF fulltext %]<th width="5%">Relevance</th>[% END %]
<th width="5%">Testcase ID#</th>
<td class="headerleft">Name</td>
<th>Creation Date</th>
<th>Last Updated</th>
</tr>
[% IF testcases.size==0 %]
<tr>
<td class="no-results" colspan="3">No matching testcases were found.</td>
<td class="no-results" colspan="[% IF fulltext %]5[% ELSE %]4[% END %]">No matching testcases were found.</td>
</tr>
[% ELSE %]
[% FOREACH testcase=testcases %]
@ -48,11 +50,13 @@
[% rowstyle = 'odd' %]
[% END %]
<tr class="[% rowstyle %]">
<td align="center">[% testcase.relevance | html | format('%.2f') %]</td>
[% IF fulltext %]<td align="center">[% testcase.relevance | html | format('%.2f') %]</td>[% END %]
<td align="center"><a href="show_test.cgi?id=[% testcase.testcase_id | html | uri %]">[% testcase.testcase_id | html %]</a></td>
<td align="left">[% testcase.summary | html %]</td>
<td align="center">[% testcase.creation_date | html %]</td>
<td align="center">[% testcase.last_updated | html %]</td>
</tr>
[% END %]
[% END %]
</table>
</table>