Line 95: | Line 95: | ||
REQUIRE_PLUGIN(plugin_name); # Ensure that a plugin is loaded and available in order to run the test case |
REQUIRE_PLUGIN(plugin_name); # Ensure that a plugin is loaded and available in order to run the test case |
||
− | == Function Test Case |
+ | == Function Test Case Result Format == |
The new results format will follow a more standard xUnit way of testing (asserting) expected results. Here is an example results file which would accompany the above test: |
The new results format will follow a more standard xUnit way of testing (asserting) expected results. Here is an example results file which would accompany the above test: |
Revision as of 18:45, 14 October 2008
Testing Scope
What do we need to test? Everything possible. The testing framework needs to be able to test countless configurations of plugins, engines, configuration variables, performance scenarious, and more. So, the framework needs to abstract away these variations so that the test-writer can focus on writing the test and not making the test specific to one plugin or engine.
Types of Tests
Types of tests:
- Functional/Use Case: test of a series of actions which should have a determinate behaviour
- For instance, test that a CREATE TABLE, followed by a DROP TABLE, followed by a TRUNCATE TABLE results in an error.
- Unit Test: a test of a code section or class. The test tests whether the publicly described interface works as described, and that inputs and outputs of the interface are correct
- For example, a unit test of the Lex class would test all public methods for proper input and output, and verify that state changes are consistent with the published API
- Bug Fix test: a test which verifies a bug's behaviour and demonstrates the correct behaviour.
- For example, if a bug is issued which says that GROUP_CONCAT() does not function as advertised, the test case is written to first verify the behaviour, and then, when the bug is fixed in the code, that the code fixes the bug.
- Performance test: a test which tracks the regression or increase in performance/scalability of the server over time
- Stress test: a test which attempts to overload the server or determine the breaking points of the server
Areas to Test
Which test suites should be built?
- Replication
- Client/Server Communication
- Transactions
- Information Schema
Test Automation Framework
For designing a framework, various elements need to be taken into consideration. Some of them are:
- What actions need to be commonly performed per test run
- Communication with additional automation tools
- Communicating between test client and various other clients and servers
- Logging of the test run
- How Errors and Warnings should be handled?
- Standardized input and output of tests
- How to deal with dependencies within tests?
Functional Test Case Input Format
The existing system of using separate files for tests and for results will be kept. After considering a single file approach, it was determined that testing multiple engines, plugins, and options would make the single file approach untenable, as too many differences would need to be tested in a single test file.
The test case format is proposed as follows:
aggregate_no_rows.test:
# Tests that COUNT(*), AVG(), MIN(), MAX() on a table # with no rows returns correct results SETUP () { EXECUTE_SQL("DROP TABLE IF EXISTS t1"); EXECUTE_SQL("CREATE TABLE t1 (id INT NOT NULL)"); } TEARDOWN () { EXECUTE_SQL("TRUNCATE t1"); } TEST (count) { EXECUTE_SQL("SELECT COUNT(*) FROM t1"); } TEST (max) { EXECUTE_SQL("SELECT MAX(id) FROM t1"); } TEST (min) { EXECUTE_SQL("SELECT MIN(id) FROM t1"); } TEST (avg) { EXECUTE_SQL("SELECT AVG(id) FROM t1"); }
Each test case file shall contain zero or one "SETUP() {}" section, containing test commands run before each test in the test case file is run. Similarly, zero or one "TEARDOWN() {}" section may be included that is run after each test in the test case file is run.
Comments are any line which begins with a # symbol
A "TEST(test_name) {}" section indicates a single test in the test case. Inside the parentheses, you should put a descriptive name for the single test. The name of the test will default to testN where N is the ordinal position of the test in the test case file.
Within each test in a test case file, you may place one or more test commands for the runner to execute in the test. Test commands include the following:
EXECUTE_SQL(sql_string); # Executes the statement inside the parentheses EXECUTE_SQL_FROM_FILE(filename); # Execute all statements in a supplied file
Other possible commands which may be issued in a test case:
REQUIRE_PLUGIN(plugin_name); # Ensure that a plugin is loaded and available in order to run the test case
Function Test Case Result Format
The new results format will follow a more standard xUnit way of testing (asserting) expected results. Here is an example results file which would accompany the above test:
aggregate_no_rows.result:
RESULT (count) { ASSERT_ROWS(1); ASSERT_DATA_EQUALS(0,0,0); } RESULT (max) { ASSERT_ROWS(1); ASSERT_DATA_ISNULL(0,0); } RESULT (min) { ASSERT_ROWS(1); ASSERT_DATA_ISNULL(0,0); } RESULT (avg) { ASSERT_ROWS(1); ASSERT_DATA_ISNULL(0,0); }
Required Actions of Test Runner
Framework development is facilitated using the same set of identified tools. Scripting language supported by the test automation tools is used to create the components. Tool extensibility utility/component can be developed using a different language. In addition to the re-usable components, driver scripts and worker scripts need to be created. The approach for developing re-usable utilities/components should include:
- Record/Replay
- Screen/Window/Transaction
- Action/Keyword
- Data Driven
Thoughts on a new Test Runner
Basically, the existing test runner (/tests/test-run.pl) is pretty good. A new test runner should built on its foundation and clean it up to make it more extensible. The existing framework does the following things, which should be kept/emulated:
- Spawn a pool of threads to run individual test cases
- Allow a developer to run a specific test or a suite of tests
New concepts for a new Test Runner
A "suite" is a collection of tests that check a related feature or functional unit. For instance, "replication" or "transactions"
A "config" is an input to the test runner which sets or unsets a variety of parameters in the test run.
A "type" is the type of test (functional, unit, stress, etc)
Calling the test runner in various formats
# Run the functional replication tests ./test-runner --suite=replication --type=functional
# Run the "slave-api" unit test in the replication suite ./test-runner --type=unit suite=replication slave-api
# Run all the functional tests ./test-runner --type=functional
# Run all functional tests for the "MyISAM" configuration ./test-runner --type=functional --config=MyISAM
Structure of the Testing Framework
/ # root source directory /tests # root testing directory /runner # location for the actual test runner and framework /functional # location of functional test /performance # location of performance tests /stress # location of stress tests /var # runtime location for test runner data and files
Thought: Unit tests should be in a /unit directory within each directory? For instance, server unit tests should be in /drizzled/unit ?
Existing Test Runner Options
Logging: ./dtr --help ./dtr [ OPTIONS ] [ TESTCASE ] Options to control what engine/variation to run compress Use the compressed protocol between client and server bench Run the benchmark suite small-bench Run the benchmarks with --small-tests --small-tables Options to control directories to use benchdir=DIR The directory where the benchmark suite is stored (default: ../../mysql-bench) tmpdir=DIR The directory where temporary files are stored (default: ./var/tmp). vardir=DIR The directory where files generated from the test run is stored (default: ./var). Specifying a ramdisk or tmpfs will speed up tests. mem Run testsuite in "memory" using tmpfs or ramdisk Attempts to find a suitable location using a builtin list of standard locations for tmpfs (/dev/shm) The option can also be set using environment variable MTR_MEM=[DIR] Options to control what test suites or cases to run force Continue to run the suite after failure do-test=PREFIX or REGEX Run test cases which name are prefixed with PREFIX or fulfills REGEX skip-test=PREFIX or REGEX Skip test cases which name are prefixed with PREFIX or fulfills REGEX start-from=PREFIX Run test cases starting from test prefixed with PREFIX suite[s]=NAME1,..,NAMEN Collect tests in suites from the comma separated list of suite names. The default is: "main,binlog,rpl" skip-rpl Skip the replication test cases. big-test Set the environment variable BIG_TEST, which can be checked from test cases. combination="ARG1 .. ARG2" Specify a set of "mysqld" arguments for one combination. skip-combination Skip any combination options and combinations files Options that specify ports master_port=PORT Specify the port number used by the first master slave_port=PORT Specify the port number used by the first slave mtr-build-thread=# Specify unique collection of ports. Can also be set by setting the environment variable MTR_BUILD_THREAD. Options for test case authoring record TESTNAME (Re)genereate the result file for TESTNAME check-testcases Check testcases for sideeffects mark-progress Log line number and elapsed time to <testname>.progress Options that pass on options mysqld=ARGS Specify additional arguments to "mysqld" Options to run test on running server extern Use running server for tests user=USER User for connection to extern server Options for debugging the product client-ddd Start drizzletest client in ddd client-debugger=NAME Start drizzletest in the selected debugger client-gdb Start drizzletest client in gdb ddd Start mysqld in ddd debug Dump trace output for all servers and client programs debugger=NAME Start mysqld in the selected debugger gdb Start the mysqld(s) in gdb manual-debug Let user manually start mysqld in debugger, before running test(s) manual-gdb Let user manually start mysqld in gdb, before running test(s) manual-ddd Let user manually start mysqld in ddd, before running test(s) master-binary=PATH Specify the master "mysqld" to use slave-binary=PATH Specify the slave "mysqld" to use strace-client Create strace output for drizzletest client max-save-core Limit the number of core files saved (to avoid filling up disks for heavily crashing server). Defaults to 5, set to 0 for no limit. Options for coverage, profiling etc gcov FIXME gprof See online documentation on how to use it. valgrind Run the "drizzletest" and "mysqld" executables using valgrind with default options valgrind-all Synonym for --valgrind valgrind-drizzletest Run the "drizzletest" and "drizzle_client_test" executable with valgrind valgrind-mysqld Run the "mysqld" executable with valgrind valgrind-options=ARGS Deprecated, use --valgrind-option valgrind-option=ARGS Option to give valgrind, replaces default option(s), can be specified more then once valgrind-path=[EXE] Path to the valgrind executable callgrind Instruct valgrind to use callgrind Misc options comment=STR Write STR to the output notimer Don't show test case execution time script-debug Debug this script itself verbose More verbose output start-and-exit Only initialize and start the servers, using the startup settings for the specified test case (if any) start-dirty Only start the servers (without initialization) for the specified test case (if any) fast Don't try to clean up from earlier runs reorder Reorder tests to get fewer server restarts help Get this help text testcase-timeout=MINUTES Max test case run time (default 15) suite-timeout=MINUTES Max test suite run time (default 180) warnings | log-warnings Pass --log-warnings to mysqld sleep=SECONDS Passed to drizzletest, will be used as fixed sleep time