summaryrefslogtreecommitdiffstats
path: root/src/VBox/ValidationKit/testmanager/db/TestManagerDatabaseInit.pgsql
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/ValidationKit/testmanager/db/TestManagerDatabaseInit.pgsql')
-rw-r--r--src/VBox/ValidationKit/testmanager/db/TestManagerDatabaseInit.pgsql1950
1 files changed, 1950 insertions, 0 deletions
diff --git a/src/VBox/ValidationKit/testmanager/db/TestManagerDatabaseInit.pgsql b/src/VBox/ValidationKit/testmanager/db/TestManagerDatabaseInit.pgsql
new file mode 100644
index 00000000..10e93ff2
--- /dev/null
+++ b/src/VBox/ValidationKit/testmanager/db/TestManagerDatabaseInit.pgsql
@@ -0,0 +1,1950 @@
+-- $Id: TestManagerDatabaseInit.pgsql $
+--- @file
+-- VBox Test Manager Database Creation script.
+--
+
+--
+-- Copyright (C) 2012-2023 Oracle and/or its affiliates.
+--
+-- This file is part of VirtualBox base platform packages, as
+-- available from https://www.virtualbox.org.
+--
+-- 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, in version 3 of the
+-- License.
+--
+-- 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 <https://www.gnu.org/licenses>.
+--
+-- The contents of this file may alternatively be used under the terms
+-- of the Common Development and Distribution License Version 1.0
+-- (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+-- in the VirtualBox distribution, in which case the provisions of the
+-- CDDL are applicable instead of those of the GPL.
+--
+-- You may elect to license modified versions of this file under the
+-- terms and conditions of either the GPL or the CDDL or both.
+--
+-- SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+--
+
+--
+-- Declaimer:
+--
+-- The guys working on this design are not database experts, web
+-- programming experts or similar, rather we are low level guys
+-- who's main job is x86 & AMD64 virtualization. So, please don't
+-- be too hard on us. :-)
+--
+--
+
+
+-- D R O P D A T A B A S E t e s t m a n a g e r - - you do this now.
+\set ON_ERROR_STOP 1
+CREATE DATABASE testmanager;
+\connect testmanager;
+
+
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- S y s t e m
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+
+---
+-- Log table for a few important events.
+--
+-- Currently, two events are planned to be logged:
+-- - Sign on of an unknown testbox, including the IP and System UUID.
+-- This will be restricted to one entry per 24h or something like that:
+-- SELECT COUNT(*)
+-- FROM SystemLog
+-- WHERE tsCreated >= (current_timestamp - interval '24 hours')
+-- AND sEvent = 'TBoxUnkn'
+-- AND sLogText = :sNewLogText;
+-- - When cleaning up an abandoned testcase (scenario #9), log which
+-- testbox abandoned which testset.
+--
+-- The Web UI will have some way of displaying the log.
+--
+-- A batch job should regularly clean out old log messages, like for instance
+-- > 64 days.
+--
+CREATE TABLE SystemLog (
+ --- When this was logged.
+ tsCreated TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- The event type.
+ -- This is a 8 character string identifier so that we don't need to change
+ -- some enum type everytime we introduce a new event type.
+ sEvent CHAR(8) NOT NULL,
+ --- The log text.
+ sLogText text NOT NULL,
+
+ PRIMARY KEY (tsCreated, sEvent)
+);
+
+
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- C o n f i g u r a t i o n
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+
+--- @table Users
+-- Test manager users.
+--
+-- This is mainly for doing simple access checks before permitting access to
+-- the test manager. This needs to be coordinated with
+-- apache/ldap/Oracle-Single-Sign-On.
+--
+-- The main purpose, though, is for tracing who changed the test config and
+-- analysis data.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp.
+--
+CREATE SEQUENCE UserIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE Users (
+ --- The user id.
+ uid INTEGER DEFAULT NEXTVAL('UserIdSeq') NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER DEFAULT NULL,
+ --- User name.
+ sUsername text NOT NULL,
+ --- The email address of the user.
+ sEmail text NOT NULL,
+ --- The full name.
+ sFullName text NOT NULL,
+ --- The login name used by apache.
+ sLoginName text NOT NULL,
+ --- Read access only.
+ fReadOnly BOOLEAN NOT NULL DEFAULT FALSE,
+
+ PRIMARY KEY (uid, tsExpire)
+);
+CREATE INDEX UsersLoginNameIdx ON Users (sLoginName, tsExpire DESC);
+
+
+--- @table GlobalResources
+-- Global resource configuration.
+--
+-- For example an iSCSI target.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp.
+--
+CREATE SEQUENCE GlobalResourceIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE GlobalResources (
+ --- The global resource ID.
+ -- This stays the same thru updates.
+ idGlobalRsrc INTEGER DEFAULT NEXTVAL('GlobalResourceIdSeq') NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+ --- The name of the resource.
+ sName text NOT NULL,
+ --- Optional resource description.
+ sDescription text,
+ --- Indicates whether this resource is currently enabled (online).
+ fEnabled boolean DEFAULT FALSE NOT NULL,
+
+ PRIMARY KEY (idGlobalRsrc, tsExpire)
+);
+
+
+--- @table BuildSources
+-- Build sources.
+--
+-- This is used by a scheduling group to select builds and the default
+-- Validation Kit from the Builds table.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp.
+--
+-- @todo Any better way of representing this so we could more easily
+-- join/whatever when searching for builds?
+--
+CREATE SEQUENCE BuildSourceIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE BuildSources (
+ --- The build source identifier.
+ -- This stays constant over time.
+ idBuildSrc INTEGER DEFAULT NEXTVAL('BuildSourceIdSeq') NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+
+ --- The name of the build source.
+ sName TEXT NOT NULL,
+ --- Description.
+ sDescription TEXT DEFAULT NULL,
+
+ --- Which product.
+ -- ASSUME that it is okay to limit a build source to a single product.
+ sProduct text NOT NULL,
+ --- Which branch.
+ -- ASSUME that it is okay to limit a build source to a branch.
+ sBranch text NOT NULL,
+
+ --- Build types to include, all matches if NULL.
+ -- @todo Weighting the types would be nice in a later version.
+ asTypes text ARRAY DEFAULT NULL,
+ --- Array of the 'sOs.sCpuArch' to match, all matches if NULL.
+ -- See KBUILD_OSES in kBuild for a list of standard target OSes, and
+ -- KBUILD_ARCHES for a list of standard architectures.
+ --
+ -- @remarks See marks on 'os-agnostic' and 'noarch' in BuildCategories.
+ asOsArches text ARRAY DEFAULT NULL,
+
+ --- The first subversion tree revision to match, no lower limit if NULL.
+ iFirstRevision INTEGER DEFAULT NULL,
+ --- The last subversion tree revision to match, no upper limit if NULL.
+ iLastRevision INTEGER DEFAULT NULL,
+
+ --- The maximum age of the builds in seconds, unlimited if NULL.
+ cSecMaxAge INTEGER DEFAULT NULL,
+
+ PRIMARY KEY (idBuildSrc, tsExpire)
+);
+
+
+--- @table TestCases
+-- Test case configuration.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp.
+--
+CREATE SEQUENCE TestCaseIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE SEQUENCE TestCaseGenIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE TestCases (
+ --- The fixed test case ID.
+ -- This is assigned when the test case is created and will never change.
+ idTestCase INTEGER DEFAULT NEXTVAL('TestCaseIdSeq') NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+ --- Generation ID for this row, a truly unique identifier.
+ -- This is primarily for referencing by TestSets.
+ idGenTestCase INTEGER UNIQUE DEFAULT NEXTVAL('TestCaseGenIdSeq') NOT NULL,
+
+ --- The name of the test case.
+ sName TEXT NOT NULL,
+ --- Optional test case description.
+ sDescription TEXT DEFAULT NULL,
+ --- Indicates whether this test case is currently enabled.
+ fEnabled BOOLEAN DEFAULT FALSE NOT NULL,
+ --- Default test case timeout given in seconds.
+ cSecTimeout INTEGER NOT NULL CHECK (cSecTimeout > 0),
+ --- Default TestBox requirement expression (python boolean expression).
+ -- All the scheduler properties are available for use with the same names
+ -- as in that table.
+ -- If NULL everything matches.
+ sTestBoxReqExpr TEXT DEFAULT NULL,
+ --- Default build requirement expression (python boolean expression).
+ -- The following build properties are available: sProduct, sBranch,
+ -- sType, asOsArches, sVersion, iRevision, uidAuthor and idBuild.
+ -- If NULL everything matches.
+ sBuildReqExpr TEXT DEFAULT NULL,
+
+ --- The base command.
+ -- String suitable for executing in bourne shell with space as separator
+ -- (IFS). References to @BUILD_BINARIES@ will be replaced WITH the content
+ -- of the Builds(sBinaries) field.
+ sBaseCmd TEXT NOT NULL,
+
+ --- Comma separated list of test suite zips (or tars) that the testbox will
+ -- need to download and expand prior to testing.
+ -- If NULL the current test suite of the scheduling group will be used (the
+ -- scheduling group will have an optional test suite build queue associated
+ -- with it). The current test suite can also be referenced by
+ -- @VALIDATIONKIT_ZIP@ in case more downloads are required. Files may also be
+ -- uploaded to the test manager download area, in which case the
+ -- @DOWNLOAD_BASE_URL@ prefix can be used to refer to this area.
+ sTestSuiteZips TEXT DEFAULT NULL,
+
+ -- Comment regarding a change or something.
+ sComment TEXT DEFAULT NULL,
+
+ PRIMARY KEY (idTestCase, tsExpire)
+);
+
+
+--- @table TestCaseArgs
+-- Test case argument list variations.
+--
+-- For example, we have a test case that does a set of tests on a virtual
+-- machine. To get better code/feature coverage of this testcase we wish to
+-- run it with different guest hardware configuration. The test case may do
+-- the same stuff, but the guest OS as well as the VMM may react differently to
+-- the hardware configurations and uncover issues in the VMM, device emulation
+-- or other places.
+--
+-- Typical hardware variations are:
+-- - guest memory size (RAM),
+-- - guest video memory size (VRAM),
+-- - virtual CPUs / cores / threads,
+-- - virtual chipset
+-- - virtual network interface card (NIC)
+-- - USB 1.1, USB 2.0, no USB
+--
+-- The TM web UI will help the user create a reasonable set of permutations
+-- of these parameters, the user specifies a maximum and the TM uses certain
+-- rules together with random selection to generate the desired number. The
+-- UI will also help suggest fitting testbox requirements according to the
+-- RAM/VRAM sizes and the virtual CPU counts. The user may then make
+-- adjustments to the suggestions before commit them.
+--
+-- Alternatively, the user may also enter all the permutations without any
+-- help from the UI.
+--
+-- Note! All test cases has at least one entry in this table, even if it is
+-- empty, because testbox requirements are specified thru this.
+--
+-- Querying the valid parameter lists for a testase this way:
+-- SELECT * ... WHERE idTestCase = TestCases.idTestCase
+-- AND tsExpire > <when>
+-- AND tsEffective <= <when>;
+--
+-- Querying the valid parameter list for the latest generation can be
+-- simplified by just checking tsExpire date:
+-- SELECT * ... WHERE idTestCase = TestCases.idTestCase
+-- AND tsExpire == TIMESTAMP WITH TIME ZONE 'infinity';
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp.
+--
+CREATE SEQUENCE TestCaseArgsIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE SEQUENCE TestCaseArgsGenIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE TestCaseArgs (
+ --- The test case ID.
+ -- Non-unique foreign key: TestCases(idTestCase).
+ idTestCase INTEGER NOT NULL,
+ --- The testcase argument variation ID (fixed).
+ -- This is primarily for TestGroupMembers.aidTestCaseArgs.
+ idTestCaseArgs INTEGER DEFAULT NEXTVAL('TestCaseArgsIdSeq') NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+ --- Generation ID for this row.
+ -- This is primarily for efficient referencing by TestSets and SchedQueues.
+ idGenTestCaseArgs INTEGER UNIQUE DEFAULT NEXTVAL('TestCaseArgsGenIdSeq') NOT NULL,
+
+ --- The additional arguments.
+ -- String suitable for bourne shell style argument parsing with space as
+ -- separator (IFS). References to @BUILD_BINARIES@ will be replaced with
+ -- the content of the Builds(sBinaries) field.
+ sArgs TEXT NOT NULL,
+ --- Optional test case timeout given in seconds.
+ -- If NULL, the TestCases.cSecTimeout field is used instead.
+ cSecTimeout INTEGER DEFAULT NULL CHECK (cSecTimeout IS NULL OR cSecTimeout > 0),
+ --- Additional TestBox requirement expression (python boolean expression).
+ -- All the scheduler properties are available for use with the same names
+ -- as in that table. This is checked after first checking the requirements
+ -- in the TestCases.sTestBoxReqExpr field.
+ sTestBoxReqExpr TEXT DEFAULT NULL,
+ --- Additional build requirement expression (python boolean expression).
+ -- The following build properties are available: sProduct, sBranch,
+ -- sType, asOsArches, sVersion, iRevision, uidAuthor and idBuild. This is
+ -- checked after first checking the requirements in the
+ -- TestCases.sBuildReqExpr field.
+ sBuildReqExpr TEXT DEFAULT NULL,
+ --- Number of testboxes required (gang scheduling).
+ cGangMembers SMALLINT DEFAULT 1 NOT NULL CHECK (cGangMembers > 0 AND cGangMembers < 1024),
+ --- Optional variation sub-name.
+ sSubName TEXT DEFAULT NULL,
+
+ --- The arguments are part of the primary key for several reasons.
+ -- No duplicate argument lists (makes no sense - if you want to prioritize
+ -- argument lists, we add that explicitly). This may hopefully enable us
+ -- to more easily check coverage later on, even when the test case is
+ -- reconfigured with more/less permutations.
+ PRIMARY KEY (idTestCase, tsExpire, sArgs)
+);
+CREATE INDEX TestCaseArgsLookupIdx ON TestCaseArgs (idTestCase, tsExpire DESC, tsEffective ASC);
+
+
+--- @table TestCaseDeps
+-- Test case dependencies (N:M)
+--
+-- This effect build selection. The build must have passed all runs of the
+-- given prerequisite testcase (idTestCasePreReq) and executed at a minimum one
+-- argument list variation.
+--
+-- This should also affect scheduling order, if possible at least one
+-- prerequisite testcase variation should be place before the specific testcase
+-- in the scheduling queue.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp. To select the currently valid entries use
+-- tsExpire = TIMESTAMP WITH TIME ZONE 'infinity'.
+--
+CREATE TABLE TestCaseDeps (
+ --- The test case that depends on someone.
+ -- Non-unique foreign key: TestCases(idTestCase).
+ idTestCase INTEGER NOT NULL,
+ --- The prerequisite test case ID.
+ -- Non-unique foreign key: TestCases(idTestCase).
+ idTestCasePreReq INTEGER NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+
+ PRIMARY KEY (idTestCase, idTestCasePreReq, tsExpire)
+);
+
+
+--- @table TestCaseGlobalRsrcDeps
+-- Test case dependencies on global resources (N:M)
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp. To select the currently valid entries use
+-- tsExpire = TIMESTAMP WITH TIME ZONE 'infinity'.
+--
+CREATE TABLE TestCaseGlobalRsrcDeps (
+ --- The test case that depends on someone.
+ -- Non-unique foreign key: TestCases(idTestCase).
+ idTestCase INTEGER NOT NULL,
+ --- The prerequisite resource ID.
+ -- Non-unique foreign key: GlobalResources(idGlobalRsrc).
+ idGlobalRsrc INTEGER NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+
+ PRIMARY KEY (idTestCase, idGlobalRsrc, tsExpire)
+);
+
+
+--- @table TestGroups
+-- Test Group - A collection of test cases.
+--
+-- This is for simplifying test configuration by working with a few groups
+-- instead of a herd of individual testcases. It may also be used for creating
+-- test suites for certain areas (like guest additions) or tasks (like
+-- performance measurements).
+--
+-- A test case can be member of any number of test groups.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp. To select the currently valid entries use
+-- tsExpire = TIMESTAMP WITH TIME ZONE 'infinity'.
+--
+CREATE SEQUENCE TestGroupIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE TestGroups (
+ --- The fixed scheduling group ID.
+ -- This is assigned when the group is created and will never change.
+ idTestGroup INTEGER DEFAULT NEXTVAL('TestGroupIdSeq') NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+
+ --- The name of the scheduling group.
+ sName TEXT NOT NULL,
+ --- Optional group description.
+ sDescription TEXT,
+ -- Comment regarding a change or something.
+ sComment TEXT DEFAULT NULL,
+
+ PRIMARY KEY (idTestGroup, tsExpire)
+);
+CREATE INDEX TestGroups_id_index ON TestGroups (idTestGroup, tsExpire DESC, tsEffective ASC);
+
+
+--- @table TestGroupMembers
+-- The N:M relationship between test case configurations and test groups.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp. To select the currently valid entries use
+-- tsExpire = TIMESTAMP WITH TIME ZONE 'infinity'.
+--
+CREATE TABLE TestGroupMembers (
+ --- The group ID.
+ -- Non-unique foreign key: TestGroups(idTestGroup).
+ idTestGroup INTEGER NOT NULL,
+ --- The test case ID.
+ -- Non-unique foreign key: TestCases(idTestCase).
+ idTestCase INTEGER NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+
+ --- Test case scheduling priority.
+ -- Higher number causes the test case to be run more frequently.
+ -- @sa SchedGroupMembers.iSchedPriority, TestBoxesInSchedGroups.iSchedPriority
+ -- @todo Not sure we want to keep this...
+ iSchedPriority INTEGER DEFAULT 16 CHECK (iSchedPriority >= 0 AND iSchedPriority < 32) NOT NULL,
+
+ --- Limit the memberships to the given argument variations.
+ -- Non-unique foreign key: TestCaseArgs(idTestCase, idTestCaseArgs).
+ aidTestCaseArgs INTEGER ARRAY DEFAULT NULL,
+
+ PRIMARY KEY (idTestGroup, idTestCase, tsExpire)
+);
+
+
+--- @table SchedGroups
+-- Scheduling group (aka. testbox partitioning) configuration.
+--
+-- A testbox is associated with exactly one scheduling group. This association
+-- can be changed, of course. If we (want to) retire a group which still has
+-- testboxes associated with it, these will be moved to the 'default' group.
+--
+-- The TM web UI will make sure that a testbox is always in a group and that
+-- the default group cannot be deleted.
+--
+-- A scheduling group combines several things:
+-- - A selection of builds to test (via idBuildSrc).
+-- - A collection of test groups to test with (via SchedGroupMembers).
+-- - A set of testboxes to test on (via TestBoxes.idSchedGroup).
+--
+-- In additions there is an optional source of fresh test suite builds (think
+-- VBoxTestSuite) as well as scheduling options.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp. To select the currently valid entries use
+-- tsExpire = TIMESTAMP WITH TIME ZONE 'infinity'.
+--
+CREATE TYPE Scheduler_T AS ENUM (
+ 'bestEffortContinousItegration',
+ 'reserved'
+);
+CREATE SEQUENCE SchedGroupIdSeq
+ START 2
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE SchedGroups (
+ --- The fixed scheduling group ID.
+ -- This is assigned when the group is created and will never change.
+ idSchedGroup INTEGER DEFAULT NEXTVAL('SchedGroupIdSeq') NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ -- @note This is NULL for the default group.
+ uidAuthor INTEGER DEFAULT NULL,
+
+ --- The name of the scheduling group.
+ sName TEXT NOT NULL,
+ --- Optional group description.
+ sDescription TEXT,
+ --- Indicates whether this group is currently enabled.
+ fEnabled boolean NOT NULL,
+ --- The scheduler to use.
+ -- This is for when we later desire different scheduling that the best
+ -- effort stuff provided by the initial implementation.
+ enmScheduler Scheduler_T DEFAULT 'bestEffortContinousItegration'::Scheduler_T NOT NULL,
+ --- The build source.
+ -- Non-unique foreign key: BuildSources(idBuildSrc)
+ idBuildSrc INTEGER DEFAULT NULL,
+ --- The Validation Kit build source (@VALIDATIONKIT_ZIP@).
+ -- Non-unique foreign key: BuildSources(idBuildSrc)
+ idBuildSrcTestSuite INTEGER DEFAULT NULL,
+ -- Comment regarding a change or something.
+ sComment TEXT DEFAULT NULL,
+
+ PRIMARY KEY (idSchedGroup, tsExpire)
+);
+
+-- Special default group.
+INSERT INTO SchedGroups (idSchedGroup, tsEffective, tsExpire, sName, sDescription, fEnabled)
+ VALUES (1, TIMESTAMP WITH TIME ZONE 'epoch', TIMESTAMP WITH TIME ZONE 'infinity', 'default', 'default group', FALSE);
+
+
+--- @table SchedGroupMembers
+-- N:M relationship between scheduling groups and test groups.
+--
+-- Several scheduling parameters are associated with this relationship.
+--
+-- The test group dependency (idTestGroupPreReq) can be used in the same way as
+-- TestCaseDeps.idTestCasePreReq, only here on test group level. This means it
+-- affects the build selection. The builds needs to have passed all test runs
+-- the prerequisite test group and done at least one argument variation of each
+-- test case in it.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp. To select the currently valid entries use
+-- tsExpire = TIMESTAMP WITH TIME ZONE 'infinity'.
+--
+CREATE TABLE SchedGroupMembers (
+ --- Scheduling ID.
+ -- Non-unique foreign key: SchedGroups(idSchedGroup).
+ idSchedGroup INTEGER NOT NULL,
+ --- Testgroup ID.
+ -- Non-unique foreign key: TestGroups(idTestGroup).
+ idTestGroup INTEGER NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+
+ --- The scheduling priority of the test group.
+ -- Higher number causes the test case to be run more frequently.
+ -- @sa TestGroupMembers.iSchedPriority, TestBoxesInSchedGroups.iSchedPriority
+ iSchedPriority INTEGER DEFAULT 16 CHECK (iSchedPriority >= 0 AND iSchedPriority < 32) NOT NULL,
+ --- When during the week this group is allowed to start running, NULL means
+ -- there are no constraints.
+ -- Each bit in the bitstring represents one hour, with bit 0 indicating the
+ -- midnight hour on a monday.
+ bmHourlySchedule bit(168) DEFAULT NULL,
+ --- Optional test group dependency.
+ -- Non-unique foreign key: TestGroups(idTestGroup).
+ -- This is for requiring that a build has been subject to smoke tests
+ -- before bothering to subject it to longer tests.
+ -- @todo Not entirely sure this should be here, but I'm not so keen on yet
+ -- another table as the only use case is smoketests.
+ idTestGroupPreReq INTEGER DEFAULT NULL,
+
+ PRIMARY KEY (idSchedGroup, idTestGroup, tsExpire)
+);
+
+
+--- @table TestBoxStrTab
+-- String table for the test boxes.
+--
+-- This is a string cache for all string members in TestBoxes except the name.
+-- The rational is to avoid duplicating large strings like sReport when the
+-- testbox reports a new cMbScratch value or the box when the test sheriff
+-- sends a reboot command or similar.
+--
+-- At the time this table was introduced, we had 400558 TestBoxes rows, where
+-- the SUM(LENGTH(sReport)) was 993MB. There were really just 1066 distinct
+-- sReport values, with a total length of 0x3 MB.
+--
+-- Nothing is ever deleted from this table.
+--
+-- @note Should use a stored procedure to query/insert a string.
+--
+--
+-- TestBox stats prior to conversion:
+-- SELECT COUNT(*) FROM TestBoxes: 400558 rows
+-- SELECT pg_total_relation_size('TestBoxes'): 740794368 bytes (706 MB)
+-- Average row cost: 740794368 / 400558 = 1849 bytes/row
+--
+-- After conversion:
+-- SELECT COUNT(*) FROM TestBoxes: 400558 rows
+-- SELECT pg_total_relation_size('TestBoxes'): 144375808 bytes (138 MB)
+-- SELECT COUNT(idStr) FROM TestBoxStrTab: 1292 rows
+-- SELECT pg_total_relation_size('TestBoxStrTab'): 5709824 bytes (5.5 MB)
+-- (144375808 + 5709824) / 740794368 = 20 %
+-- Average row cost boxes: 144375808 / 400558 = 360 bytes/row
+-- Average row cost strings: 5709824 / 1292 = 4420 bytes/row
+--
+CREATE SEQUENCE TestBoxStrTabIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE TestBoxStrTab (
+ --- The ID of this string.
+ idStr INTEGER PRIMARY KEY DEFAULT NEXTVAL('TestBoxStrTabIdSeq'),
+ --- The string value.
+ sValue text NOT NULL,
+ --- Creation time stamp.
+ tsCreated TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL
+);
+-- Note! Must use hash index as the sReport strings are too long for regular indexing.
+CREATE INDEX TestBoxStrTabNameIdx ON TestBoxStrTab USING hash (sValue);
+
+--- Empty string with ID 0.
+INSERT INTO TestBoxStrTab (idStr, sValue) VALUES (0, '');
+
+
+--- @type TestBoxCmd_T
+-- Testbox commands.
+CREATE TYPE TestBoxCmd_T AS ENUM (
+ 'none',
+ 'abort',
+ 'reboot', --< This implies abort. Status changes when reaching 'idle'.
+ 'upgrade', --< This is only handled when asking for work.
+ 'upgrade-and-reboot', --< Ditto.
+ 'special' --< Similar to upgrade, reserved for the future.
+);
+
+
+--- @type LomKind_T
+-- The kind of lights out management on a testbox.
+CREATE TYPE LomKind_T AS ENUM (
+ 'none',
+ 'ilom',
+ 'elom',
+ 'apple-xserve-lom'
+);
+
+
+--- @table TestBoxes
+-- Testbox configurations.
+--
+-- The testboxes are identified by IP and the system UUID if available. Should
+-- the IP change, the testbox will be refused at sign on and the testbox
+-- sheriff will have to update it's IP.
+--
+-- @todo Implement the UUID stuff. Get it from DMI, UEFI or whereever.
+-- Mismatching needs to be logged somewhere...
+--
+-- To query the currently valid configuration:
+-- SELECT ... WHERE id = idTestBox AND tsExpire = TIMESTAMP WITH TIME ZONE 'infinity';
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp. To select the currently valid entries use
+-- tsExpire = TIMESTAMP WITH TIME ZONE 'infinity'.
+--
+CREATE SEQUENCE TestBoxIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE SEQUENCE TestBoxGenIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE TestBoxes (
+ --- The fixed testbox ID.
+ -- This is assigned when the testbox is created and will never change.
+ idTestBox INTEGER DEFAULT NEXTVAL('TestBoxIdSeq') NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- When modified automatically by the testbox, NULL is used.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER DEFAULT NULL,
+ --- Generation ID for this row.
+ -- This is primarily for referencing by TestSets.
+ idGenTestBox INTEGER UNIQUE DEFAULT NEXTVAL('TestBoxGenIdSeq') NOT NULL,
+
+ --- The testbox IP.
+ -- This is from the webserver point of view and automatically updated on
+ -- SIGNON. The test setup doesn't permit for IP addresses to change while
+ -- the testbox is operational, because this will break gang tests.
+ ip inet NOT NULL,
+ --- The system or firmware UUID.
+ -- This uniquely identifies the testbox when talking to the server. After
+ -- SIGNON though, the testbox will also provide idTestBox and ip to
+ -- establish its identity beyond doubt.
+ uuidSystem uuid NOT NULL,
+ --- The testbox name.
+ -- Usually similar to the DNS name.
+ sName text NOT NULL,
+ --- Optional testbox description.
+ -- Intended for describing the box as well as making other relevant notes.
+ idStrDescription INTEGER REFERENCES TestBoxStrTab(idStr) DEFAULT NULL,
+
+ --- Indicates whether this testbox is enabled.
+ -- A testbox gets disabled when we're doing maintenance, debugging a issue
+ -- that happens only on that testbox, or some similar stuff. This is an
+ -- alternative to deleting the testbox.
+ fEnabled BOOLEAN DEFAULT NULL,
+
+ --- The kind of lights-out-management.
+ enmLomKind LomKind_T DEFAULT 'none'::LomKind_T NOT NULL,
+ --- The IP adress of the lights-out-management.
+ -- This can be NULL if enmLomKind is 'none', otherwise it must contain a valid address.
+ ipLom inet DEFAULT NULL,
+
+ --- Timeout scale factor, given as a percent.
+ -- This is a crude adjustment of the test case timeout for slower hardware.
+ pctScaleTimeout smallint DEFAULT 100 NOT NULL CHECK (pctScaleTimeout > 10 AND pctScaleTimeout < 20000),
+
+ --- Change comment or similar.
+ idStrComment INTEGER REFERENCES TestBoxStrTab(idStr) DEFAULT NULL,
+
+ --- @name Scheduling properties (reported by testbox script).
+ -- @{
+ --- Same abbrieviations as kBuild, see KBUILD_OSES.
+ idStrOs INTEGER REFERENCES TestBoxStrTab(idStr) DEFAULT NULL,
+ --- Informational, no fixed format.
+ idStrOsVersion INTEGER REFERENCES TestBoxStrTab(idStr) DEFAULT NULL,
+ --- Same as CPUID reports (GenuineIntel, AuthenticAMD, CentaurHauls, ...).
+ idStrCpuVendor INTEGER REFERENCES TestBoxStrTab(idStr) DEFAULT NULL,
+ --- Same as kBuild - x86, amd64, ... See KBUILD_ARCHES.
+ idStrCpuArch INTEGER REFERENCES TestBoxStrTab(idStr) DEFAULT NULL,
+ --- The CPU name if available.
+ idStrCpuName INTEGER REFERENCES TestBoxStrTab(idStr) DEFAULT NULL,
+ --- Number identifying the CPU family/model/stepping/whatever.
+ -- For x86 and AMD64 type CPUs, this will on the following format:
+ -- (EffFamily << 24) | (EffModel << 8) | Stepping.
+ lCpuRevision bigint DEFAULT NULL,
+ --- Number of CPUs, CPU cores and CPU threads.
+ cCpus smallint DEFAULT NULL CHECK (cCpus IS NULL OR cCpus > 0),
+ --- Set if capable of hardware virtualization.
+ fCpuHwVirt boolean DEFAULT NULL,
+ --- Set if capable of nested paging.
+ fCpuNestedPaging boolean DEFAULT NULL,
+ --- Set if CPU capable of 64-bit (VBox) guests.
+ fCpu64BitGuest boolean DEFAULT NULL,
+ --- Set if chipset with usable IOMMU (VT-d / AMD-Vi).
+ fChipsetIoMmu boolean DEFAULT NULL,
+ --- Set if the test box does raw-mode tests.
+ fRawMode boolean DEFAULT NULL,
+ --- The (approximate) memory size in megabytes (rounded down to nearest 4 MB).
+ cMbMemory bigint DEFAULT NULL CHECK (cMbMemory IS NULL OR cMbMemory > 0),
+ --- The amount of scratch space in megabytes (rounded down to nearest 64 MB).
+ cMbScratch bigint DEFAULT NULL CHECK (cMbScratch IS NULL OR cMbScratch >= 0),
+ --- Free form hardware and software report field.
+ idStrReport INTEGER REFERENCES TestBoxStrTab(idStr) DEFAULT NULL,
+ --- @}
+
+ --- The testbox script revision number, serves the purpose of a version number.
+ -- Probably good to have when scheduling upgrades as well for status purposes.
+ iTestBoxScriptRev INTEGER DEFAULT 0 NOT NULL,
+ --- The python sys.hexversion (layed out as of 2.7).
+ -- Good to know which python versions we need to support.
+ iPythonHexVersion INTEGER DEFAULT NULL,
+
+ --- Pending command.
+ -- @note We put it here instead of in TestBoxStatuses to get history.
+ enmPendingCmd TestBoxCmd_T DEFAULT 'none'::TestBoxCmd_T NOT NULL,
+
+ PRIMARY KEY (idTestBox, tsExpire),
+
+ --- Nested paging requires hardware virtualization.
+ CHECK (fCpuNestedPaging IS NULL OR (fCpuNestedPaging <> TRUE OR fCpuHwVirt = TRUE))
+);
+CREATE UNIQUE INDEX TestBoxesUuidIdx ON TestBoxes (uuidSystem, tsExpire DESC);
+CREATE INDEX TestBoxesExpireEffectiveIdx ON TestBoxes (tsExpire DESC, tsEffective ASC);
+
+
+--
+-- Create a view for TestBoxes where the strings are resolved.
+--
+CREATE VIEW TestBoxesWithStrings AS
+ SELECT TestBoxes.*,
+ Str1.sValue AS sDescription,
+ Str2.sValue AS sComment,
+ Str3.sValue AS sOs,
+ Str4.sValue AS sOsVersion,
+ Str5.sValue AS sCpuVendor,
+ Str6.sValue AS sCpuArch,
+ Str7.sValue AS sCpuName,
+ Str8.sValue AS sReport
+ FROM TestBoxes
+ LEFT OUTER JOIN TestBoxStrTab Str1 ON idStrDescription = Str1.idStr
+ LEFT OUTER JOIN TestBoxStrTab Str2 ON idStrComment = Str2.idStr
+ LEFT OUTER JOIN TestBoxStrTab Str3 ON idStrOs = Str3.idStr
+ LEFT OUTER JOIN TestBoxStrTab Str4 ON idStrOsVersion = Str4.idStr
+ LEFT OUTER JOIN TestBoxStrTab Str5 ON idStrCpuVendor = Str5.idStr
+ LEFT OUTER JOIN TestBoxStrTab Str6 ON idStrCpuArch = Str6.idStr
+ LEFT OUTER JOIN TestBoxStrTab Str7 ON idStrCpuName = Str7.idStr
+ LEFT OUTER JOIN TestBoxStrTab Str8 ON idStrReport = Str8.idStr;
+
+
+--- @table TestBoxesInSchedGroups
+-- N:M relationship between test boxes and scheduling groups.
+--
+-- We associate a priority with this relationship.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp. To select the currently valid entries use
+-- tsExpire = TIMESTAMP WITH TIME ZONE 'infinity'.
+--
+CREATE TABLE TestBoxesInSchedGroups (
+ --- TestBox ID.
+ -- Non-unique foreign key: TestBoxes(idTestBox).
+ idTestBox INTEGER NOT NULL,
+ --- Scheduling ID.
+ -- Non-unique foreign key: SchedGroups(idSchedGroup).
+ idSchedGroup INTEGER NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+
+ --- The scheduling priority of the scheduling group for the test box.
+ -- Higher number causes the scheduling group to be serviced more frequently.
+ -- @sa TestGroupMembers.iSchedPriority, SchedGroups.iSchedPriority
+ iSchedPriority INTEGER DEFAULT 16 CHECK (iSchedPriority >= 0 AND iSchedPriority < 32) NOT NULL,
+
+ PRIMARY KEY (idTestBox, idSchedGroup, tsExpire)
+);
+
+
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- F a i l u r e T r a c k i n g
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+
+
+--- @table FailureCategories
+-- Failure categories.
+--
+-- This is for organizing the failure reasons.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp. To select the currently valid entries use
+-- tsExpire = TIMESTAMP WITH TIME ZONE 'infinity'.
+--
+CREATE SEQUENCE FailureCategoryIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE FailureCategories (
+ --- The identifier of this failure category (once assigned, it will never change).
+ idFailureCategory INTEGER DEFAULT NEXTVAL('FailureCategoryIdSeq') NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+ --- The short category description.
+ -- For combo boxes and other selection lists.
+ sShort text NOT NULL,
+ --- Full description
+ -- For cursor-over-poppups for instance.
+ sFull text NOT NULL,
+
+ PRIMARY KEY (idFailureCategory, tsExpire)
+);
+
+
+--- @table FailureReasons
+-- Failure reasons.
+--
+-- When analysing a test failure, the testbox sheriff will try assign a fitting
+-- reason for the failure. This table is here to help the sheriff in his/hers
+-- job as well as developers looking checking if their changes affected the
+-- test results in any way.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp. To select the currently valid entries use
+-- tsExpire = TIMESTAMP WITH TIME ZONE 'infinity'.
+--
+CREATE SEQUENCE FailureReasonIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE FailureReasons (
+ --- The identifier of this failure reason (once assigned, it will never change).
+ idFailureReason INTEGER DEFAULT NEXTVAL('FailureReasonIdSeq') NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+
+ --- The failure category this reason belongs to.
+ -- Non-unique foreign key: FailureCategories(idFailureCategory)
+ idFailureCategory INTEGER NOT NULL,
+ --- The short failure description.
+ -- For combo boxes and other selection lists.
+ sShort text NOT NULL,
+ --- Full failure description.
+ sFull text NOT NULL,
+ --- Ticket number in the primary bugtracker.
+ iTicket INTEGER DEFAULT NULL,
+ --- Other URLs to reports or discussions of the observed symptoms.
+ asUrls text ARRAY DEFAULT NULL,
+
+ PRIMARY KEY (idFailureReason, tsExpire)
+);
+CREATE INDEX FailureReasonsCategoryIdx ON FailureReasons (idFailureCategory, idFailureReason);
+
+
+
+--- @table TestResultFailures
+-- This is for tracking/discussing test result failures.
+--
+-- The rational for putting this is a separate table is that we need history on
+-- this while TestResults does not.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp. To select the currently valid entries use
+-- tsExpire = TIMESTAMP WITH TIME ZONE 'infinity'.
+--
+CREATE TABLE TestResultFailures (
+ --- The test result we're disucssing.
+ -- @note The foreign key is declared after TestResults (further down).
+ idTestResult INTEGER NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+ --- The testsest this result is a part of.
+ -- This is mainly an aid for bypassing the enormous TestResults table.
+ -- Note! This is a foreign key, but we have to add it after TestSets has
+ -- been created, see further down.
+ idTestSet INTEGER NOT NULL,
+
+ --- The suggested failure reason.
+ -- Non-unique foreign key: FailureReasons(idFailureReason)
+ idFailureReason INTEGER NOT NULL,
+ --- Optional comment.
+ sComment text DEFAULT NULL,
+
+ PRIMARY KEY (idTestResult, tsExpire)
+);
+CREATE INDEX TestResultFailureIdx ON TestResultFailures (idTestSet, tsExpire DESC, tsEffective ASC);
+CREATE INDEX TestResultFailureIdx2 ON TestResultFailures (idTestResult, tsExpire DESC, tsEffective ASC);
+CREATE INDEX TestResultFailureIdx3 ON TestResultFailures (idFailureReason, idTestResult, tsExpire DESC, tsEffective ASC);
+
+
+
+
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- T e s t I n p u t
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+
+
+--- @table BuildBlacklist
+-- Table used to blacklist sets of builds.
+--
+-- The best usage example is a VMM developer realizing that a change causes the
+-- host to panic, hang, or otherwise misbehave. To prevent the testbox sheriff
+-- from repeatedly having to reboot testboxes, the builds gets blacklisted
+-- until there is a working build again. This may mean adding an open ended
+-- blacklist spec and then updating it with the final revision number once the
+-- fix has been committed.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp. To select the currently valid entries use
+-- tsExpire = TIMESTAMP WITH TIME ZONE 'infinity'.
+--
+-- @todo Would be nice if we could replace the text strings below with a set of
+-- BuildCategories, or sore it in any other way which would enable us to
+-- do a negative join with build category... The way it is specified
+-- now, it looks like we have to open a cursor of prospecitve builds and
+-- filter then thru this table one by one.
+--
+-- Any better representation is welcome, but this is low prioirty for
+-- now, as it's relatively easy to change this later one.
+--
+CREATE SEQUENCE BuildBlacklistIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE BuildBlacklist (
+ --- The blacklist entry id.
+ -- This stays constant over time.
+ idBlacklisting INTEGER DEFAULT NEXTVAL('BuildBlacklistIdSeq') NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ uidAuthor INTEGER NOT NULL,
+
+ --- The reason for the blacklisting.
+ -- Non-unique foreign key: FailureReasons(idFailureReason)
+ idFailureReason INTEGER NOT NULL,
+
+ --- Which product.
+ -- ASSUME that it is okay to limit a blacklisting to a single product.
+ sProduct text NOT NULL,
+ --- Which branch.
+ -- ASSUME that it is okay to limit a blacklisting to a branch.
+ sBranch text NOT NULL,
+
+ --- Build types to include, all matches if NULL.
+ asTypes text ARRAY DEFAULT NULL,
+ --- Array of the 'sOs.sCpuArch' to match, all matches if NULL.
+ -- See KBUILD_OSES in kBuild for a list of standard target OSes, and
+ -- KBUILD_ARCHES for a list of standard architectures.
+ --
+ -- @remarks See marks on 'os-agnostic' and 'noarch' in BuildCategories.
+ asOsArches text ARRAY DEFAULT NULL,
+
+ --- The first subversion tree revision to blacklist.
+ iFirstRevision INTEGER NOT NULL,
+ --- The last subversion tree revision to blacklist, no upper limit if NULL.
+ iLastRevision INTEGER NOT NULL,
+
+ PRIMARY KEY (idBlacklisting, tsExpire)
+);
+CREATE INDEX BuildBlacklistIdx ON BuildBlacklist (iLastRevision DESC, iFirstRevision ASC, sProduct, sBranch,
+ tsExpire DESC, tsEffective ASC);
+
+--- @table BuildCategories
+-- Build categories.
+--
+-- The purpose of this table is saving space in the Builds table and hopefully
+-- speed things up when selecting builds as well (compared to selecting on 4
+-- text fields in the much larger Builds table).
+--
+-- Insert only table, no update, no delete. History is not needed.
+--
+CREATE SEQUENCE BuildCategoryIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE BuildCategories (
+ --- The build type identifier.
+ idBuildCategory INTEGER PRIMARY KEY DEFAULT NEXTVAL('BuildCategoryIdSeq') NOT NULL,
+ --- Product.
+ -- The product name. For instance 'VBox' or 'VBoxTestSuite'.
+ sProduct TEXT NOT NULL,
+ --- The version control repository name.
+ sRepository TEXT NOT NULL,
+ --- The branch name (in the version control system).
+ sBranch TEXT NOT NULL,
+ --- The build type.
+ -- See KBUILD_BLD_TYPES in kBuild for a list of standard build types.
+ sType TEXT NOT NULL,
+ --- Array of the 'sOs.sCpuArch' supported by the build.
+ -- See KBUILD_OSES in kBuild for a list of standard target OSes, and
+ -- KBUILD_ARCHES for a list of standard architectures.
+ --
+ -- @remarks 'os-agnostic' is used if the build doesn't really target any
+ -- specific OS or if it targets all applicable OSes.
+ -- 'noarch' is used if the build is architecture independent or if
+ -- all applicable architectures are handled.
+ -- Thus, 'os-agnostic.noarch' will run on all build boxes.
+ --
+ -- @note The array shall be sorted ascendingly to prevent unnecessary duplicates!
+ --
+ asOsArches TEXT ARRAY NOT NULL,
+
+ UNIQUE (sProduct, sRepository, sBranch, sType, asOsArches)
+);
+
+
+--- @table Builds
+-- The builds table contains builds from the tinderboxes and oaccasionally from
+-- developers.
+--
+-- The tinderbox side could be fed by a batch job enumerating the build output
+-- directories every so often, looking for new builds. Or we could query them
+-- from the tinderbox database. Yet another alternative is making the
+-- tinderbox server or client side software inform us about all new builds.
+--
+-- The developer builds are entered manually thru the TM web UI. They are used
+-- for subjecting new code to some larger scale testing before commiting,
+-- enabling, or merging a private branch.
+--
+-- The builds are being selected from this table by the via the build source
+-- specification that SchedGroups.idBuildSrc and
+-- SchedGroups.idBuildSrcTestSuite links to.
+--
+-- @remarks This table stores history. Never update or delete anything. The
+-- equivalent of deleting is done by setting the 'tsExpire' field to
+-- current_timestamp. To select the currently valid entries use
+-- tsExpire = TIMESTAMP WITH TIME ZONE 'infinity'.
+--
+CREATE SEQUENCE BuildIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE Builds (
+ --- The build identifier.
+ -- This remains unchanged
+ idBuild INTEGER DEFAULT NEXTVAL('BuildIdSeq') NOT NULL,
+ --- When this build was created or entered into the database.
+ -- This remains unchanged
+ tsCreated TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row starts taking effect (inclusive).
+ tsEffective TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- When this row stops being tsEffective (exclusive).
+ tsExpire TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'infinity' NOT NULL,
+ --- The user id of the one who created/modified this entry.
+ -- Non-unique foreign key: Users(uid)
+ -- @note This is NULL if added by a batch job / tinderbox.
+ uidAuthor INTEGER DEFAULT NULL,
+ --- The build category.
+ idBuildCategory INTEGER REFERENCES BuildCategories(idBuildCategory) NOT NULL,
+ --- The subversion tree revision of the build.
+ iRevision INTEGER NOT NULL,
+ --- The product version number (suitable for RTStrVersionCompare).
+ sVersion TEXT NOT NULL,
+ --- The link to the tinderbox log of this build.
+ sLogUrl TEXT,
+ --- Comma separated list of binaries.
+ -- The binaries have paths relative to the TESTBOX_PATH_BUILDS or full URLs.
+ sBinaries TEXT NOT NULL,
+ --- Set when the binaries gets deleted by the build quota script.
+ fBinariesDeleted BOOLEAN DEFAULT FALSE NOT NULL,
+
+ UNIQUE (idBuild, tsExpire)
+);
+CREATE INDEX BuildsLookupIdx ON Builds (idBuildCategory, iRevision);
+
+
+--- @table VcsRevisions
+-- This table is for translating build revisions into commit details.
+--
+-- For graphs and test results, it would be useful to translate revisions into
+-- dates and maybe provide commit message and the committer.
+--
+-- Data is entered exclusively thru one or more batch jobs, so no internal
+-- authorship needed. Also, since we're mirroring data from external sources
+-- here, the batch job is allowed to update/replace existing records.
+--
+-- @todo We we could collect more info from the version control systems, if we
+-- believe it's useful and can be presented in a reasonable manner.
+-- Getting a list of affected files would be simple (requires
+-- a separate table with a M:1 relationship to this table), or try
+-- associate a commit to a branch.
+--
+CREATE TABLE VcsRevisions (
+ --- The version control tree name.
+ sRepository TEXT NOT NULL,
+ --- The version control tree revision number.
+ iRevision INTEGER NOT NULL,
+ --- When the revision was created (committed).
+ tsCreated TIMESTAMP WITH TIME ZONE NOT NULL,
+ --- The name of the committer.
+ -- @note Not to be confused with uidAuthor and test manager users.
+ sAuthor TEXT,
+ --- The commit message.
+ sMessage TEXT,
+
+ UNIQUE (sRepository, iRevision)
+);
+CREATE INDEX VcsRevisionsByDate ON VcsRevisions (tsCreated DESC);
+
+
+--- @table VcsBugReferences
+-- This is for relating commits to a bug and vice versa.
+--
+-- This feature isn't so much for the test manager as a cheap way of extending
+-- bug trackers without VCS integration. We just need to parse the commit
+-- messages when inserting them into the VcsRevisions table.
+--
+-- Same input, updating and history considerations as VcsRevisions.
+--
+CREATE TABLE VcsBugReferences (
+ --- The version control tree name.
+ sRepository TEXT NOT NULL,
+ --- The version control tree revision number.
+ iRevision INTEGER NOT NULL,
+ --- The bug tracker identifier - see g_kdBugTrackers in config.py.
+ sBugTracker CHAR(4) NOT NULL,
+ --- The bug number in the bug tracker.
+ lBugNo BIGINT NOT NULL,
+
+ UNIQUE (sRepository, iRevision, sBugTracker, lBugNo)
+);
+CREATE INDEX VcsBugReferencesLookupIdx ON VcsBugReferences (sBugTracker, lBugNo);
+
+
+
+
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- T e s t R e s u l t s
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+
+
+--- @table TestResultStrTab
+-- String table for the test results.
+--
+-- This is a string cache for value names, test names and possible more, that
+-- is frequently repated in the test results record for each test run. The
+-- purpose is not only to save space, but to make datamining queries faster by
+-- giving them integer fields to work on instead of text fields. There may
+-- possibly be some benefits on INSERT as well as there are only integer
+-- indexes.
+--
+-- Nothing is ever deleted from this table.
+--
+-- @note Should use a stored procedure to query/insert a string.
+--
+CREATE SEQUENCE TestResultStrTabIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE TestResultStrTab (
+ --- The ID of this string.
+ idStr INTEGER PRIMARY KEY DEFAULT NEXTVAL('TestResultStrTabIdSeq'),
+ --- The string value.
+ sValue text NOT NULL,
+ --- Creation time stamp.
+ tsCreated TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL
+);
+CREATE UNIQUE INDEX TestResultStrTabNameIdx ON TestResultStrTab (sValue);
+
+--- Empty string with ID 0.
+INSERT INTO TestResultStrTab (idStr, sValue) VALUES (0, '');
+
+
+--- @type TestStatus_T
+-- The status of a test (set / result).
+--
+CREATE TYPE TestStatus_T AS ENUM (
+ -- Initial status:
+ 'running',
+ -- Final statuses:
+ 'success',
+ -- Final status: Test didn't fail as such, it was something else.
+ 'skipped',
+ 'bad-testbox',
+ 'aborted',
+ -- Final status: Test failed.
+ 'failure',
+ 'timed-out',
+ 'rebooted'
+);
+
+
+--- @table TestResults
+-- Test results - a recursive bundle of joy!
+--
+-- A test case will be created when the testdriver calls reporter.testStart and
+-- concluded with reporter.testDone. The testdriver (or it subordinates) can
+-- use these methods to create nested test results. For IPRT based test cases,
+-- RTTestCreate, RTTestInitAndCreate and RTTestSub will both create new test
+-- result records, where as RTTestSubDone, RTTestSummaryAndDestroy and
+-- RTTestDestroy will conclude records.
+--
+-- By concluding is meant updating the status. When the test driver reports
+-- success, we check it against reported results. (paranoia strikes again!)
+--
+-- Nothing is ever deleted from this table.
+--
+-- @note As seen below, several other tables associate data with a
+-- test result, and the top most test result is referenced by the
+-- test set.
+--
+CREATE SEQUENCE TestResultIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE TestResults (
+ --- The ID of this test result.
+ idTestResult INTEGER PRIMARY KEY DEFAULT NEXTVAL('TestResultIdSeq'),
+ --- The parent test result.
+ -- This is NULL for the top test result.
+ idTestResultParent INTEGER REFERENCES TestResults(idTestResult),
+ --- The test set this result is a part of.
+ -- Note! This is a foreign key, but we have to add it after TestSets has
+ -- been created, see further down.
+ idTestSet INTEGER NOT NULL,
+ --- Creation time stamp. This may also be the timestamp of when the test started.
+ tsCreated TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- The elapsed time for this test.
+ -- This is either reported by the directly (with some sanity checking) or
+ -- calculated (current_timestamp - created_ts).
+ -- @todo maybe use a nanosecond field here, check with what
+ tsElapsed interval DEFAULT NULL,
+ --- The test name.
+ idStrName INTEGER REFERENCES TestResultStrTab(idStr) NOT NULL,
+ --- The error count.
+ cErrors INTEGER DEFAULT 0 NOT NULL,
+ --- The test status.
+ enmStatus TestStatus_T DEFAULT 'running'::TestStatus_T NOT NULL,
+ --- Nesting depth.
+ iNestingDepth smallint NOT NULL CHECK (iNestingDepth >= 0 AND iNestingDepth < 16),
+ -- Make sure errors and status match up.
+ CONSTRAINT CheckStatusMatchesErrors
+ CHECK ( (cErrors > 0 AND enmStatus IN ('running'::TestStatus_T,
+ 'failure'::TestStatus_T, 'timed-out'::TestStatus_T, 'rebooted'::TestStatus_T ))
+ OR (cErrors = 0 AND enmStatus IN ('running'::TestStatus_T, 'success'::TestStatus_T,
+ 'skipped'::TestStatus_T, 'aborted'::TestStatus_T, 'bad-testbox'::TestStatus_T))
+ ),
+ -- The following is for the TestResultFailures foreign key.
+ -- Note! This was added with the name TestResults_idTestResult_idTestSet_key in the tmdb-r16 update script.
+ UNIQUE (idTestResult, idTestSet)
+);
+
+CREATE INDEX TestResultsSetIdx ON TestResults (idTestSet, idStrName, idTestResult);
+CREATE INDEX TestResultsParentIdx ON TestResults (idTestResultParent);
+-- The TestResultsNameIdx and TestResultsNameIdx2 are for speeding up the result graph & reporting code.
+CREATE INDEX TestResultsNameIdx ON TestResults (idStrName, tsCreated DESC);
+CREATE INDEX TestResultsNameIdx2 ON TestResults (idTestResult, idStrName);
+
+ALTER TABLE TestResultFailures ADD CONSTRAINT TestResultFailures_idTestResult_idTestSet_fkey
+ FOREIGN KEY (idTestResult, idTestSet) REFERENCES TestResults(idTestResult, idTestSet) MATCH FULL;
+
+
+--- @table TestResultValues
+-- Test result values.
+--
+-- A testdriver or subordinate may report a test value via
+-- reporter.testValue(), while IPRT based test will use RTTestValue and
+-- associates.
+--
+-- This is an insert only table, no deletes, no updates.
+--
+CREATE SEQUENCE TestResultValueIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE TestResultValues (
+ --- The ID of this value.
+ idTestResultValue INTEGER PRIMARY KEY DEFAULT NEXTVAL('TestResultValueIdSeq'),
+ --- The test result it was reported within.
+ idTestResult INTEGER REFERENCES TestResults(idTestResult) NOT NULL,
+ --- The test set this value is a part of (for avoiding joining thru TestResults).
+ -- Note! This is a foreign key, but we have to add it after TestSets has
+ -- been created, see further down.
+ idTestSet INTEGER NOT NULL,
+ --- Creation time stamp.
+ tsCreated TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- The name.
+ idStrName INTEGER REFERENCES TestResultStrTab(idStr) NOT NULL,
+ --- The value.
+ lValue bigint NOT NULL,
+ --- The unit.
+ -- @todo This is currently not defined properly. Will fix/correlate this
+ -- with the other places we use unit (IPRT/testdriver/VMMDev).
+ iUnit smallint NOT NULL CHECK (iUnit >= 0 AND iUnit < 1024)
+);
+
+CREATE INDEX TestResultValuesIdx ON TestResultValues(idTestResult);
+-- The TestResultValuesGraphIdx is for speeding up the result graph & reporting code.
+CREATE INDEX TestResultValuesGraphIdx ON TestResultValues(idStrName, tsCreated);
+-- The TestResultValuesLogIdx is for speeding up the log viewer.
+CREATE INDEX TestResultValuesLogIdx ON TestResultValues(idTestSet, tsCreated);
+
+
+--- @table TestResultFiles
+-- Test result files.
+--
+-- A testdriver or subordinate may report a file by using
+-- reporter.addFile() or reporter.addLogFile().
+--
+-- The files stored here as well as the primary log file will be processed by a
+-- batch job and compressed if considered compressable. Thus, TM will look for
+-- files with a .gz/.bz2 suffix first and then without a suffix.
+--
+-- This is an insert only table, no deletes, no updates.
+--
+CREATE SEQUENCE TestResultFileId
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE TestResultFiles (
+ --- The ID of this file.
+ idTestResultFile INTEGER PRIMARY KEY DEFAULT NEXTVAL('TestResultFileId'),
+ --- The test result it was reported within.
+ idTestResult INTEGER REFERENCES TestResults(idTestResult) NOT NULL,
+ --- The test set this file is a part of (for avoiding joining thru TestResults).
+ -- Note! This is a foreign key, but we have to add it after TestSets has
+ -- been created, see further down.
+ idTestSet INTEGER NOT NULL,
+ --- Creation time stamp.
+ tsCreated TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- The filename relative to TestSets(sBaseFilename) + '-'.
+ -- The set of valid filename characters should be very limited so that no
+ -- file system issues can occure either on the TM side or the user when
+ -- loading the files. Tests trying to use other characters will fail.
+ -- Valid character regular expession: '^[a-zA-Z0-9_-(){}#@+,.=]*$'
+ idStrFile INTEGER REFERENCES TestResultStrTab(idStr) NOT NULL,
+ --- The description.
+ idStrDescription INTEGER REFERENCES TestResultStrTab(idStr) NOT NULL,
+ --- The kind of file.
+ -- For instance: 'log/release/vm',
+ -- 'screenshot/failure',
+ -- 'screencapture/failure',
+ -- 'xmllog/somestuff'
+ idStrKind INTEGER REFERENCES TestResultStrTab(idStr) NOT NULL,
+ --- The mime type for the file.
+ -- For instance: 'text/plain',
+ -- 'image/png',
+ -- 'video/webm',
+ -- 'text/xml'
+ idStrMime INTEGER REFERENCES TestResultStrTab(idStr) NOT NULL
+);
+
+CREATE INDEX TestResultFilesIdx ON TestResultFiles(idTestResult);
+CREATE INDEX TestResultFilesIdx2 ON TestResultFiles(idTestSet, tsCreated DESC);
+
+
+--- @table TestResultMsgs
+-- Test result message.
+--
+-- A testdriver or subordinate may report a message via the sDetails parameter
+-- of the reporter.testFailure() method, while IPRT test cases will use
+-- RTTestFailed, RTTestPrintf and their friends. For RTTestPrintf, we will
+-- ignore the more verbose message levels since these can also be found in one
+-- of the logs.
+--
+-- This is an insert only table, no deletes, no updates.
+--
+CREATE TYPE TestResultMsgLevel_T AS ENUM (
+ 'failure',
+ 'info'
+);
+CREATE SEQUENCE TestResultMsgIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE TestResultMsgs (
+ --- The ID of this file.
+ idTestResultMsg INTEGER PRIMARY KEY DEFAULT NEXTVAL('TestResultMsgIdSeq'),
+ --- The test result it was reported within.
+ idTestResult INTEGER REFERENCES TestResults(idTestResult) NOT NULL,
+ --- The test set this file is a part of (for avoiding joining thru TestResults).
+ -- Note! This is a foreign key, but we have to add it after TestSets has
+ -- been created, see further down.
+ idTestSet INTEGER NOT NULL,
+ --- Creation time stamp.
+ tsCreated TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- The message string.
+ idStrMsg INTEGER REFERENCES TestResultStrTab(idStr) NOT NULL,
+ --- The message level.
+ enmLevel TestResultMsgLevel_T NOT NULL
+);
+
+CREATE INDEX TestResultMsgsIdx ON TestResultMsgs(idTestResult);
+CREATE INDEX TestResultMsgsIdx2 ON TestResultMsgs(idTestSet, tsCreated DESC);
+
+
+--- @table TestSets
+-- Test sets / Test case runs.
+--
+-- This is where we collect data about test runs.
+--
+-- @todo Not entirely sure where the 'test set' term came from. Consider
+-- finding something more appropriate.
+--
+CREATE SEQUENCE TestSetIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE TestSets (
+ --- The ID of this test set.
+ idTestSet INTEGER PRIMARY KEY DEFAULT NEXTVAL('TestSetIdSeq') NOT NULL,
+
+ --- The test config timestamp, used when reading test config.
+ tsConfig TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ --- When this test set was scheduled.
+ -- idGenTestBox is valid at this point.
+ tsCreated TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ --- When this test completed, i.e. testing stopped. This should only be set once.
+ tsDone TIMESTAMP WITH TIME ZONE DEFAULT NULL,
+ --- The current status.
+ enmStatus TestStatus_T DEFAULT 'running'::TestStatus_T NOT NULL,
+
+ --- The build we're testing.
+ -- Non-unique foreign key: Builds(idBuild)
+ idBuild INTEGER NOT NULL,
+ --- The build category of idBuild when the test started.
+ -- This is for speeding up graph data collection, i.e. avoid idBuild
+ -- the WHERE part of the selection.
+ idBuildCategory INTEGER REFERENCES BuildCategories(idBuildCategory) NOT NULL,
+ --- The test suite build we're using to do the testing.
+ -- This is NULL if the test suite zip wasn't referred or if a test suite
+ -- build source wasn't configured.
+ -- Non-unique foreign key: Builds(idBuild)
+ idBuildTestSuite INTEGER DEFAULT NULL,
+
+ --- The exact testbox configuration.
+ idGenTestBox INTEGER REFERENCES TestBoxes(idGenTestBox) NOT NULL,
+ --- The testbox ID for joining with (valid: tsStarted).
+ -- Non-unique foreign key: TestBoxes(idTestBox)
+ idTestBox INTEGER NOT NULL,
+ --- The scheduling group ID the test was scheduled thru (valid: tsStarted).
+ -- Non-unique foreign key: SchedGroups(idSchedGroup)
+ idSchedGroup INTEGER NOT NULL,
+
+ --- The testgroup (valid: tsConfig).
+ -- Non-unique foreign key: TestBoxes(idTestGroup)
+ -- Note! This also gives the member ship entry, since a testcase can only
+ -- have one membership per test group.
+ idTestGroup INTEGER NOT NULL,
+
+ --- The exact test case config we executed in this test run.
+ idGenTestCase INTEGER REFERENCES TestCases(idGenTestCase) NOT NULL,
+ --- The test case ID for joining with (valid: tsConfig).
+ -- Non-unique foreign key: TestBoxes(idTestCase)
+ idTestCase INTEGER NOT NULL,
+
+ --- The arguments (and requirements++) we executed this test case with.
+ idGenTestCaseArgs INTEGER REFERENCES TestCaseArgs(idGenTestCaseArgs) NOT NULL,
+ --- The argument variation ID (valid: tsConfig).
+ -- Non-unique foreign key: TestCaseArgs(idTestCaseArgs)
+ idTestCaseArgs INTEGER NOT NULL,
+
+ --- The root of the test result tree.
+ -- @note This will only be NULL early in the transaction setting up the testset.
+ -- @note If the test reports more than one top level test result, we'll
+ -- fail the whole test run and let the test developer fix it.
+ idTestResult INTEGER REFERENCES TestResults(idTestResult) DEFAULT NULL,
+
+ --- The base filename used for storing files related to this test set.
+ -- This is a path relative to wherever TM is dumping log files. In order
+ -- to not become a file system test case, we will try not to put too many
+ -- hundred thousand files in a directory. A simple first approach would
+ -- be to just use the current date (tsCreated) like this:
+ -- TM_FILE_DIR/year/month/day/TestSets.idTestSet
+ --
+ -- The primary log file for the test is this name suffixed by '.log'.
+ --
+ -- The files in the testresultfile table gets their full names like this:
+ -- TM_FILE_DIR/sBaseFilename-testresultfile.id-TestResultStrTab(testresultfile.idStrFilename)
+ --
+ -- @remarks We store this explicitly in case we change the directly layout
+ -- at some later point.
+ sBaseFilename text UNIQUE NOT NULL,
+
+ --- The gang member number number, 0 is the leader.
+ iGangMemberNo SMALLINT DEFAULT 0 NOT NULL CHECK (iGangMemberNo >= 0 AND iGangMemberNo < 1024),
+ --- The test set of the gang leader, NULL if no gang involved.
+ -- @note This is set by the gang leader as well, so that we can find all
+ -- gang members by WHERE idTestSetGangLeader = :id.
+ idTestSetGangLeader INTEGER REFERENCES TestSets(idTestSet) DEFAULT NULL
+
+);
+CREATE INDEX TestSetsGangIdx ON TestSets (idTestSetGangLeader);
+CREATE INDEX TestSetsBoxIdx ON TestSets (idTestBox, idTestResult);
+CREATE INDEX TestSetsBuildIdx ON TestSets (idBuild, idTestResult);
+CREATE INDEX TestSetsTestCaseIdx ON TestSets (idTestCase, idTestResult);
+CREATE INDEX TestSetsTestVarIdx ON TestSets (idTestCaseArgs, idTestResult);
+--- The TestSetsDoneCreatedBuildCatIdx is for testbox results, graph options and such.
+CREATE INDEX TestSetsDoneCreatedBuildCatIdx ON TestSets (tsDone DESC NULLS FIRST, tsCreated ASC, idBuildCategory);
+--- For graphs.
+CREATE INDEX TestSetsGraphBoxIdx ON TestSets (idTestBox, tsCreated DESC, tsDone ASC NULLS LAST, idBuildCategory, idTestCase);
+
+ALTER TABLE TestResults ADD FOREIGN KEY (idTestSet) REFERENCES TestSets(idTestSet) MATCH FULL;
+ALTER TABLE TestResultValues ADD FOREIGN KEY (idTestSet) REFERENCES TestSets(idTestSet) MATCH FULL;
+ALTER TABLE TestResultFiles ADD FOREIGN KEY (idTestSet) REFERENCES TestSets(idTestSet) MATCH FULL;
+ALTER TABLE TestResultMsgs ADD FOREIGN KEY (idTestSet) REFERENCES TestSets(idTestSet) MATCH FULL;
+ALTER TABLE TestResultFailures ADD FOREIGN KEY (idTestSet) REFERENCES TestSets(idTestSet) MATCH FULL;
+
+
+
+
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- T e s t M a n g e r P e r s i s t e n t S t o r a g e
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+
+--- @type TestBoxState_T
+-- TestBox state.
+--
+-- @todo Consider drawing a state diagram for this.
+--
+CREATE TYPE TestBoxState_T AS ENUM (
+ --- Nothing to do.
+ -- Prev: testing, gang-cleanup, rebooting, upgrading,
+ -- upgrading-and-rebooting, doing-special-cmd.
+ -- Next: testing, gang-gathering, rebooting, upgrading,
+ -- upgrading-and-rebooting, doing-special-cmd.
+ 'idle',
+ --- Executing a test.
+ -- Prev: idle
+ -- Next: idle
+ 'testing',
+
+ -- Gang scheduling statuses:
+ --- The gathering of a gang.
+ -- Prev: idle
+ -- Next: gang-gathering-timedout, gang-testing
+ 'gang-gathering',
+ --- The gathering timed out, the testbox needs to cleanup and move on.
+ -- Prev: gang-gathering
+ -- Next: idle
+ -- This is set on all gathered members by the testbox who triggers the
+ -- timeout.
+ 'gang-gathering-timedout',
+ --- The gang scheduling equivalent of 'testing'.
+ -- Prev: gang-gathering
+ -- Next: gang-cleanup
+ 'gang-testing',
+ --- Waiting for the other gang members to stop testing so that cleanups
+ -- can be performed and members safely rescheduled.
+ -- Prev: gang-testing
+ -- Next: idle
+ --
+ -- There are two resource clean up issues being targeted here:
+ -- 1. Global resources will be allocated by the leader when he enters the
+ -- 'gang-gathering' state. If the leader quits and frees the resource
+ -- while someone is still using it, bad things will happen. Imagine a
+ -- global resource without any access checks and relies exclusivly on
+ -- the TM doing its job.
+ -- 2. TestBox resource accessed by other gang members may also be used in
+ -- other tests. Should a gang member leave early and embark on a
+ -- testcase using the same resources, bad things will happen. Example:
+ -- Live migration. One partner leaves early because it detected some
+ -- fatal failure, the other one is still trying to connect to him.
+ -- The testbox is scheduled again on the same live migration testcase,
+ -- only with different arguments (VM config), it will try migrate using
+ -- the same TCP ports. Confusion ensues.
+ --
+ -- To figure out whether to remain in this status because someone is
+ -- still testing:
+ -- SELECT COUNT(*) FROM TestBoxStatuses, TestSets
+ -- WHERE TestSets.idTestSetGangLeader = :idGangLeader
+ -- AND TestSets.idTestBox = TestBoxStatuses.idTestBox
+ -- AND TestSets.idTestSet = TestBoxStatuses.idTestSet
+ -- AND TestBoxStatuses.enmState = 'gang-testing'::TestBoxState_T;
+ 'gang-cleanup',
+
+ -- Command related statuses (all command status changes comes from 'idle'
+ -- and goes back to 'idle'):
+ 'rebooting',
+ 'upgrading',
+ 'upgrading-and-rebooting',
+ 'doing-special-cmd'
+);
+
+--- @table TestBoxStatuses
+-- Testbox status table.
+--
+-- History is not planned on this table.
+--
+CREATE TABLE TestBoxStatuses (
+ --- The testbox.
+ idTestBox INTEGER PRIMARY KEY NOT NULL,
+ --- The testbox generation ID.
+ idGenTestBox INTEGER REFERENCES TestBoxes(idGenTestBox) NOT NULL,
+ --- When this status was last updated.
+ -- This is updated everytime the testbox talks to the test manager, thus it
+ -- can easily be used to find testboxes which has stopped responding.
+ --
+ -- This is used for timeout calculation during gang-gathering, so in that
+ -- scenario it won't be updated until the gang is gathered or we time out.
+ tsUpdated TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
+ --- The current state.
+ enmState TestBoxState_T DEFAULT 'idle'::TestBoxState_T NOT NULL,
+ --- Reference to the test set
+ idTestSet INTEGER REFERENCES TestSets(idTestSet),
+ --- Interal work item number.
+ -- This is used to pick and prioritize between multiple scheduling groups.
+ iWorkItem INTEGER DEFAULT 0 NOT NULL
+);
+
+
+--- @table GlobalResourceStatuses
+-- Global resource status, tracks which test set resources are allocated by.
+--
+-- History is not planned on this table.
+--
+CREATE TABLE GlobalResourceStatuses (
+ --- The resource ID.
+ -- Non-unique foreign key: GlobalResources(idGlobalRsrc).
+ idGlobalRsrc INTEGER PRIMARY KEY NOT NULL,
+ --- The resource owner.
+ -- @note This is going thru testboxstatus to be able to use the testbox ID
+ -- as a foreign key.
+ idTestBox INTEGER REFERENCES TestBoxStatuses(idTestBox) NOT NULL,
+ --- When the allocation took place.
+ tsAllocated TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL
+);
+
+
+--- @table SchedQueues
+-- Scheduler queue.
+--
+-- The queues are currently associated with a scheduling group, it could
+-- alternative be changed to hook on to a testbox instead. It depends on what
+-- kind of scheduling method we prefer. The former method aims at test case
+-- thruput, making sacrifices in the hardware distribution area. The latter is
+-- more like the old buildbox style testing, making sure that each test case is
+-- executed on each testbox.
+--
+-- When there are configuration changes, TM will regenerate the scheduling
+-- queue for the affected scheduling groups. We do not concern ourselves with
+-- trying to continue at the approximately same queue position, we simply take
+-- it from the top.
+--
+-- When a testbox ask for work, we will open a cursor on the queue and take the
+-- first test in the queue that can be executed on that testbox. The test will
+-- be moved to the end of the queue (getting a new item_id).
+--
+-- If a test is manually changed to the head of the queue, the item will get a
+-- item_id which is 1 lower than the head of the queue. Unless someone does
+-- this a couple of billion times, we shouldn't have any trouble running out of
+-- number space. :-)
+--
+-- Manually moving a test to the end of the queue is easy, just get a new
+-- 'item_id'.
+--
+-- History is not planned on this table.
+--
+CREATE SEQUENCE SchedQueueItemIdSeq
+ START 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+CREATE TABLE SchedQueues (
+ --- The scheduling queue (one queue per scheduling group).
+ -- Non-unique foreign key: SchedGroups(idSchedGroup)
+ idSchedGroup INTEGER NOT NULL,
+ --- The scheduler queue entry ID.
+ -- Lower numbers means early queue position.
+ idItem INTEGER DEFAULT NEXTVAL('SchedQueueItemIdSeq') NOT NULL,
+ --- The queue offset.
+ -- This is used for repositining the queue when recreating it. It can also
+ -- be used to figure out how jumbled the queue gets after real life has had
+ -- it's effect on it.
+ offQueue INTEGER NOT NULL,
+ --- The test case argument variation to execute.
+ idGenTestCaseArgs INTEGER REFERENCES TestCaseArgs(idGenTestCaseArgs) NOT NULL,
+ --- The relevant testgroup.
+ -- Non-unique foreign key: TestGroups(idTestGroup).
+ idTestGroup INTEGER NOT NULL,
+ --- Aggregated test group dependencies (NULL if none).
+ -- Non-unique foreign key: TestGroups(idTestGroup).
+ -- See also comments on SchedGroupMembers.idTestGroupPreReq.
+ aidTestGroupPreReqs INTEGER ARRAY DEFAULT NULL,
+ --- The scheduling time constraints (see SchedGroupMembers.bmHourlySchedule).
+ bmHourlySchedule bit(168) DEFAULT NULL,
+ --- When the queue entry was created and for which config is valid.
+ -- This is the timestamp that should be used when reading config info.
+ tsConfig TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ --- When this status was last scheduled.
+ -- This is set to current_timestamp when moving the entry to the end of the
+ -- queue. It's initial value is unix-epoch. Not entirely sure if it's
+ -- useful beyond introspection and non-unique foreign key hacking.
+ tsLastScheduled TIMESTAMP WITH TIME ZONE DEFAULT TIMESTAMP WITH TIME ZONE 'epoch' NOT NULL,
+
+ --- This is used in gang scheduling.
+ idTestSetGangLeader INTEGER REFERENCES TestSets(idTestSet) DEFAULT NULL UNIQUE,
+ --- The number of gang members still missing.
+ --
+ -- This saves calculating the number of missing members via selects like:
+ -- SELECT COUNT(*) FROM TestSets WHERE idTestSetGangLeader = :idGang;
+ -- and
+ -- SELECT cGangMembers FROM TestCaseArgs WHERE idGenTestCaseArgs = :idTest;
+ -- to figure out whether to remain in 'gather-gang'::TestBoxState_T.
+ --
+ cMissingGangMembers smallint DEFAULT 1 NOT NULL,
+
+ --- @todo
+ --- The number of times this has been considered for scheduling.
+ -- cConsidered SMALLINT DEFAULT 0 NOT NULL,
+
+ PRIMARY KEY (idSchedGroup, idItem)
+);
+CREATE INDEX SchedQueuesItemIdx ON SchedQueues(idItem);
+CREATE INDEX SchedQueuesSchedGroupIdx ON SchedQueues(idSchedGroup);
+