diff options
-rw-r--r-- | application/config/config.php | 6 | ||||
-rw-r--r-- | application/controllers/tools.php | 37 | ||||
-rw-r--r-- | application/tests/Test.php | 98 | ||||
-rw-r--r-- | application/tests/test_api_v1.php | 118 | ||||
-rw-r--r-- | data/tests/small-file | 3 | ||||
-rwxr-xr-x | run-tests.sh | 59 |
6 files changed, 320 insertions, 1 deletions
diff --git a/application/config/config.php b/application/config/config.php index 2748e97c0..16f5af4bb 100644 --- a/application/config/config.php +++ b/application/config/config.php @@ -126,7 +126,11 @@ $config['subclass_prefix'] = 'MY_'; | DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!! | */ -$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-'; +if (php_sapi_name() == "cli") { + $config['permitted_uri_chars'] = ''; +} else { + $config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-'; +} /* diff --git a/application/controllers/tools.php b/application/controllers/tools.php index 8c0785409..f04f86224 100644 --- a/application/controllers/tools.php +++ b/application/controllers/tools.php @@ -42,4 +42,41 @@ class Tools extends MY_Controller { throw new \exceptions\ApiException("tools/update_database/migration-error", $this->migration->error_string()); } } + + function drop_all_tables_using_prefix() + { + $tables = $this->db->list_tables(); + $prefix = $this->db->dbprefix; + $tables_to_drop = array(); + + foreach ($tables as $table) { + if (strpos($table, $prefix) === 0) { + $tables_to_drop[] = $this->db->protect_identifiers($table); + } + } + + $this->db->query('SET FOREIGN_KEY_CHECKS = 0'); + $this->db->query('DROP TABLE '.implode(", ", $tables_to_drop)); + $this->db->query('SET FOREIGN_KEY_CHECKS = 1'); + } + + function test() + { + global $argv; + $url = $argv[3]; + $testcase = $argv[4]; + + $testclass = '\tests\\'.$testcase; + $test = new $testclass(); + $test->setServer($url); + + $refl = new ReflectionClass($test); + foreach ($refl->getMethods() as $method) { + if (strpos($method->name, "test_") === 0) { + $test->init(); + $test->{$method->name}(); + $test->cleanup(); + } + } + } } diff --git a/application/tests/Test.php b/application/tests/Test.php new file mode 100644 index 000000000..81225b312 --- /dev/null +++ b/application/tests/Test.php @@ -0,0 +1,98 @@ +<?php +/* + * Copyright 2015 Florian "Bluewind" Pritz <bluewind@server-speed.net> + * + * Licensed under AGPLv3 + * (see COPYING for full license text) + * + */ + +namespace tests; + +abstract class Test { + protected $t; + protected $server = ""; + + public function __construct() + { + require_once APPPATH."/third_party/test-more-php/Test-More-OO.php"; + $this->t = new \TestMore(); + $this->t->plan("no_plan"); + } + + public function setServer($server) + { + $this->server = $server; + } + + // Method: POST, PUT, GET etc + // Data: array("param" => "value") ==> index.php?param=value + // Source: http://stackoverflow.com/a/9802854/953022 + protected function CallAPI($method, $url, $data = false) + { + $curl = curl_init(); + + switch ($method) { + case "POST": + curl_setopt($curl, CURLOPT_POST, 1); + + if ($data) + curl_setopt($curl, CURLOPT_POSTFIELDS, $data); + break; + case "PUT": + curl_setopt($curl, CURLOPT_PUT, 1); + break; + default: + if ($data) + $url = sprintf("%s?%s", $url, http_build_query($data)); + } + + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_HTTPHEADER, array( + "Accept: application/json", + )); + + $result = curl_exec($curl); + + curl_close($curl); + + $json = json_decode($result, true); + if ($json === NULL) { + $this->t->fail("json decode"); + $this->diagReply($result); + } + + return $json; + } + + protected function expectSuccess($testname, $reply) + { + if (!isset($reply["status"]) || $reply["status"] != "success") { + $this->t->fail($testname); + $this->diagReply($reply); + } else { + $this->t->pass($testname); + } + return $reply; + } + + protected function diagReply($reply) + { + $this->t->diag("Request got unexpected response:"); + $this->t->diag(var_export($reply, true)); + } + + public function init() + { + } + + public function cleanup() + { + } + + public function __destruct() + { + $this->t->done_testing(); + } +} diff --git a/application/tests/test_api_v1.php b/application/tests/test_api_v1.php new file mode 100644 index 000000000..387e3fe6c --- /dev/null +++ b/application/tests/test_api_v1.php @@ -0,0 +1,118 @@ +<?php +/* + * Copyright 2015 Florian "Bluewind" Pritz <bluewind@server-speed.net> + * + * Licensed under AGPLv3 + * (see COPYING for full license text) + * + */ + +namespace tests; + +class test_api_v1 extends Test { + + private $apikeys = array(); + + public function __construct() + { + parent::__construct(); + + $CI =& get_instance(); + $CI->load->model("muser"); + $CI->load->model("mfile"); + + foreach (array(1,2,3,4,5) as $i) { + $CI->db->insert("users", array( + 'username' => "testuser-api_v1-$i", + 'password' => $CI->muser->hash_password("testpass$i"), + 'email' => "testuser$i@localhost.invalid", + 'referrer' => NULL + )); + $this->apikeys[$i] = \service\user::create_apikey($CI->db->insert_id(), "", "apikey"); + } + + } + + public function test_create_apikey_createNewKey() + { + $ret = $this->CallAPI("POST", "$this->server/api/1.0.0/user/create_apikey", array( + "username" => "testuser-api_v1-1", + "password" => "testpass1", + "access_level" => "apikey", + "comment" => "main api key", + )); + $this->expectSuccess("create-apikey", $ret); + + $this->t->isnt($ret["data"]["new_key"], "", "apikey not empty"); + } + + public function test_history_empty() + { + $ret = $this->CallAPI("POST", "$this->server/api/1.0.0/file/history", array( + "apikey" => $this->apikeys[1], + )); + $this->expectSuccess("get history", $ret); + + $this->t->ok(empty($ret["data"]["items"]), "items key exists and empty"); + $this->t->ok(empty($ret["data"]["multipaste_items"]), "multipaste_items key exists and empty"); + $this->t->is($ret["data"]["total_size"], 0, "total_size = 0 since no uploads"); + } + + public function test_get_config() + { + $ret = $this->CallAPI("POST", "$this->server/api/1.0.0/file/get_config", array( + )); + $this->expectSuccess("get_config", $ret); + + $this->t->like($ret["data"]["upload_max_size"], '/[0-9]+/', "upload_max_size is int"); + $this->t->like($ret["data"]["max_files_per_request"], '/[0-9]+/', "max_files_per_request is int"); + } + + public function test_upload_uploadFile() + { + $ret = $this->CallAPI("POST", "$this->server/api/1.0.0/file/upload", array( + "apikey" => $this->apikeys[2], + "file[1]" => curl_file_create("data/tests/small-file"), + )); + $this->expectSuccess("upload file", $ret); + + $this->t->ok(!empty($ret["data"]["ids"]), "got IDs"); + $this->t->ok(!empty($ret["data"]["urls"]), "got URLs"); + } + + public function test_history_notEmptyAfterUpload() + { + $ret = $this->CallAPI("POST", "$this->server/api/1.0.0/file/upload", array( + "apikey" => $this->apikeys[3], + "file[1]" => curl_file_create("data/tests/small-file"), + )); + $this->expectSuccess("upload file", $ret); + + $ret = $this->CallAPI("POST", "$this->server/api/1.0.0/file/history", array( + "apikey" => $this->apikeys[3], + )); + $this->expectSuccess("history not empty after upload", $ret); + + $this->t->ok(!empty($ret["data"]["items"]), "history not empty after upload (items)"); + $this->t->ok(empty($ret["data"]["multipaste_items"]), "didn't upload multipaste"); + $this->t->is($ret["data"]["total_size"], filesize("data/tests/small-file"), "total_size == uploaded file"); + } + + public function test_history_notSharedBetweenUsers() + { + $ret = $this->CallAPI("POST", "$this->server/api/1.0.0/file/upload", array( + "apikey" => $this->apikeys[4], + "file[1]" => curl_file_create("data/tests/small-file"), + )); + $this->expectSuccess("upload file", $ret); + + $ret = $this->CallAPI("POST", "$this->server/api/1.0.0/file/history", array( + "apikey" => $this->apikeys[5], + )); + $this->expectSuccess("get history", $ret); + + $this->t->ok(empty($ret["data"]["items"]), "items key exists and empty"); + $this->t->ok(empty($ret["data"]["multipaste_items"]), "multipaste_items key exists and empty"); + $this->t->is($ret["data"]["total_size"], 0, "total_size = 0 since no uploads"); + } +} diff --git a/data/tests/small-file b/data/tests/small-file new file mode 100644 index 000000000..9e730c42b --- /dev/null +++ b/data/tests/small-file @@ -0,0 +1,3 @@ +This is just a small test file. + +Yes, it's really just that. diff --git a/run-tests.sh b/run-tests.sh new file mode 100755 index 000000000..0b6cea761 --- /dev/null +++ b/run-tests.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# +# This runs the testsuite +# +# If you have a local webserver call this script with it's URL. Otherwise the +# php dev server is used and that slows down tests a lot. +# + +startdir="$(dirname "$0")" +url="" +use_php_dev_server=0 + +if (($#>0)); then + url="$1" +fi + + +if [[ -z "$url" ]]; then + port=23115 + url="http://127.0.0.1:$port/index.php" + use_php_dev_server=1 +fi + +cd "$startdir" + +test -d system || exit 1 +test -d application || exit 1 +test -f run-tests.sh || exit 1 + +# prepare +cat <<EOF >application/config/database-testsuite.php || exit 1 +<?php +\$db['default']['dbprefix'] = "testsuite-prefix-"; +EOF + +if ((use_php_dev_server)); then + php -S 127.0.0.1:$port & + server_pid=$! + + while ! curl -s "$url" >/dev/null; do + sleep 0.2; + done +fi + +testpath="application/tests" +tests=($testpath/test_*.php) +tests=(${tests[@]#$testpath\/}) +tests=(${tests[@]%.php}) + +# run tests +php index.php tools update_database +prove -ve "php index.php tools test $url" "${tests[@]}" +php index.php tools drop_all_tables_using_prefix + +# cleanup +if ((use_php_dev_server)); then + kill $server_pid +fi +rm -f $startdir/application/config/database-testsuite.php |