初始化
This commit is contained in:
2
tests/Pest.php
Normal file
2
tests/Pest.php
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
define('STUB_DIR', realpath(__DIR__ . '/stub'));
|
||||
153
tests/feature/HttpTest.php
Normal file
153
tests/feature/HttpTest.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
$process = null;
|
||||
beforeAll(function () use (&$process) {
|
||||
$process = new Process(['php', 'think', 'worker'], STUB_DIR, [
|
||||
'PHP_WEBSOCKET_ENABLE' => 'false',
|
||||
'PHP_QUEUE_ENABLE' => 'false',
|
||||
]);
|
||||
$process->start();
|
||||
$wait = 0;
|
||||
|
||||
while (!$process->getOutput()) {
|
||||
$wait++;
|
||||
if ($wait > 30) {
|
||||
throw new Exception('server start failed');
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(function () use (&$process) {
|
||||
echo $process->getOutput();
|
||||
$process->stop();
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
$this->httpClient = new Client([
|
||||
'base_uri' => 'http://127.0.0.1:8080',
|
||||
'cookies' => true,
|
||||
'http_errors' => false,
|
||||
'timeout' => 1,
|
||||
]);
|
||||
});
|
||||
|
||||
it('callback route', function () {
|
||||
$response = $this->httpClient->get('/');
|
||||
|
||||
expect($response->getStatusCode())
|
||||
->toBe(200)
|
||||
->and($response->getBody()->getContents())
|
||||
->toBe('hello world');
|
||||
});
|
||||
|
||||
it('controller route', function () {
|
||||
$jar = new CookieJar();
|
||||
|
||||
$response = $this->httpClient->get('/test', ['cookies' => $jar]);
|
||||
|
||||
expect($response->getStatusCode())
|
||||
->toBe(200)
|
||||
->and($response->getBody()->getContents())
|
||||
->toBe('test')
|
||||
->and($jar->getCookieByName('name')->getValue())
|
||||
->toBe('think');
|
||||
});
|
||||
|
||||
it('json post', function () {
|
||||
|
||||
$data = [
|
||||
'name' => 'think',
|
||||
];
|
||||
$response = $this->httpClient->post('/json', [
|
||||
'json' => $data,
|
||||
]);
|
||||
|
||||
expect($response->getStatusCode())
|
||||
->toBe(200)
|
||||
->and($response->getBody()->getContents())
|
||||
->toBe(json_encode($data));
|
||||
});
|
||||
|
||||
it('put and delete request', function () {
|
||||
$response = $this->httpClient->put('/');
|
||||
|
||||
expect($response->getStatusCode())
|
||||
->toBe(200)
|
||||
->and($response->getBody()->getContents())
|
||||
->toBe('put');
|
||||
|
||||
$response = $this->httpClient->delete('/');
|
||||
|
||||
expect($response->getStatusCode())
|
||||
->toBe(200)
|
||||
->and($response->getBody()->getContents())
|
||||
->toBe('delete');
|
||||
});
|
||||
|
||||
it('file response', function () {
|
||||
$response = $this->httpClient->get('/static/asset.txt');
|
||||
|
||||
expect($response->getStatusCode())
|
||||
->toBe(200)
|
||||
->and($response->getBody()->getContents())
|
||||
->toBe(file_get_contents(STUB_DIR . '/public/asset.txt'));
|
||||
});
|
||||
|
||||
it('sse', function () {
|
||||
$response = $this->httpClient->get('/sse', [
|
||||
'stream' => true,
|
||||
'timeout' => 3,
|
||||
]);
|
||||
|
||||
$body = $response->getBody();
|
||||
|
||||
$buffer = '';
|
||||
while (!$body->eof()) {
|
||||
$text = $body->read(1);
|
||||
if ($text == "\r") {
|
||||
continue;
|
||||
}
|
||||
$buffer .= $text;
|
||||
if ($text == "\n") {
|
||||
if ($buffer != "\n") {
|
||||
expect($buffer)->toStartWith('data: ');
|
||||
}
|
||||
$buffer = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('hot update', function () {
|
||||
$response = $this->httpClient->get('/hot');
|
||||
|
||||
expect($response->getStatusCode())
|
||||
->toBe(404);
|
||||
|
||||
$route = <<<PHP
|
||||
<?php
|
||||
|
||||
use think\\facade\\Route;
|
||||
|
||||
Route::get('/hot', function () {
|
||||
return 'hot';
|
||||
});
|
||||
PHP;
|
||||
|
||||
file_put_contents(STUB_DIR . '/route/hot.php', $route);
|
||||
|
||||
sleep(2);
|
||||
|
||||
$response = $this->httpClient->get('/hot');
|
||||
|
||||
expect($response->getStatusCode())
|
||||
->toBe(200)
|
||||
->and($response->getBody()->getContents())
|
||||
->toBe('hot');
|
||||
})->after(function () {
|
||||
@unlink(STUB_DIR . '/route/hot.php');
|
||||
})->skipOnWindows();
|
||||
5
tests/feature/QueueTest.php
Normal file
5
tests/feature/QueueTest.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
it('queue', function () {
|
||||
|
||||
});
|
||||
77
tests/feature/WebsocketTest.php
Normal file
77
tests/feature/WebsocketTest.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use React\EventLoop\Loop;
|
||||
use Symfony\Component\Process\Process;
|
||||
use function Ratchet\Client\connect;
|
||||
|
||||
$process = null;
|
||||
beforeAll(function () use (&$process) {
|
||||
$process = new Process(['php', 'think', 'worker'], STUB_DIR, [
|
||||
'PHP_WEBSOCKET_ENABLE' => 'true',
|
||||
'PHP_QUEUE_ENABLE' => 'false',
|
||||
'PHP_HOT_ENABLE' => 'false',
|
||||
]);
|
||||
$process->start();
|
||||
$wait = 0;
|
||||
|
||||
while (!$process->getOutput()) {
|
||||
$wait++;
|
||||
if ($wait > 30) {
|
||||
throw new Exception('server start failed');
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(function () use (&$process) {
|
||||
echo $process->getOutput();
|
||||
$process->stop();
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
$this->httpClient = new Client([
|
||||
'base_uri' => 'http://127.0.0.1:8080',
|
||||
'cookies' => true,
|
||||
'http_errors' => false,
|
||||
'timeout' => 1,
|
||||
]);
|
||||
});
|
||||
|
||||
it('http', function () {
|
||||
$response = $this->httpClient->get('/');
|
||||
|
||||
expect($response->getStatusCode())
|
||||
->toBe(200)
|
||||
->and($response->getBody()->getContents())
|
||||
->toBe('hello world');
|
||||
});
|
||||
|
||||
it('websocket', function () {
|
||||
$connected = 0;
|
||||
$messages = [];
|
||||
connect('ws://127.0.0.1:8080/websocket')
|
||||
->then(function (\Ratchet\Client\WebSocket $conn) use (&$connected, &$messages) {
|
||||
$connected++;
|
||||
$conn->on('message', function ($msg) use ($conn, &$messages) {
|
||||
$messages[] = (string) $msg;
|
||||
$conn->close();
|
||||
});
|
||||
});
|
||||
|
||||
connect('ws://127.0.0.1:8080/websocket')
|
||||
->then(function (\Ratchet\Client\WebSocket $conn) use (&$connected, &$messages) {
|
||||
$connected++;
|
||||
$conn->on('message', function ($msg) use ($conn, &$messages) {
|
||||
$messages[] = (string) $msg;
|
||||
$conn->close();
|
||||
});
|
||||
|
||||
$conn->send('hello');
|
||||
});
|
||||
|
||||
Loop::get()->run();
|
||||
|
||||
expect($connected)->toBe(2);
|
||||
expect($messages)->toBe(['hello', 'hello']);
|
||||
});
|
||||
1
tests/stub/.env
Normal file
1
tests/stub/.env
Normal file
@@ -0,0 +1 @@
|
||||
APP_DEBUG=true
|
||||
20
tests/stub/app/controller/Index.php
Normal file
20
tests/stub/app/controller/Index.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use think\facade\Cookie;
|
||||
use think\Request;
|
||||
|
||||
class Index
|
||||
{
|
||||
public function test()
|
||||
{
|
||||
Cookie::set('name', 'think');
|
||||
return 'test';
|
||||
}
|
||||
|
||||
public function json(Request $request)
|
||||
{
|
||||
return json($request->post());
|
||||
}
|
||||
}
|
||||
4
tests/stub/config/app.php
Normal file
4
tests/stub/config/app.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
return [
|
||||
'error_message' => 'error',
|
||||
];
|
||||
9
tests/stub/config/cache.php
Normal file
9
tests/stub/config/cache.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
return [
|
||||
'default' => 'file',
|
||||
'stores' => [
|
||||
'file' => [
|
||||
'type' => 'File',
|
||||
],
|
||||
]
|
||||
];
|
||||
40
tests/stub/config/queue.php
Normal file
40
tests/stub/config/queue.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
'default' => 'redis',
|
||||
'connections' => [
|
||||
'sync' => [
|
||||
'type' => 'sync',
|
||||
],
|
||||
'database' => [
|
||||
'type' => 'database',
|
||||
'queue' => 'default',
|
||||
'table' => 'jobs',
|
||||
'connection' => null,
|
||||
],
|
||||
'redis' => [
|
||||
'type' => 'redis',
|
||||
'queue' => 'default',
|
||||
'host' => env('REDIS_HOST', 'redis'),
|
||||
'port' => env('REDIS_PORT', 6379),
|
||||
'password' => '',
|
||||
'select' => 0,
|
||||
'timeout' => 0,
|
||||
'persistent' => true,
|
||||
'retry_after' => 600,
|
||||
],
|
||||
],
|
||||
'failed' => [
|
||||
'type' => 'none',
|
||||
'table' => 'failed_jobs',
|
||||
],
|
||||
];
|
||||
45
tests/stub/config/worker.php
Normal file
45
tests/stub/config/worker.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
use think\worker\websocket\Handler;
|
||||
|
||||
return [
|
||||
'http' => [
|
||||
'enable' => env('HTTP_ENABLE', true),
|
||||
'host' => '0.0.0.0',
|
||||
'port' => 8080,
|
||||
'worker_num' => 2,
|
||||
'options' => [],
|
||||
],
|
||||
'websocket' => [
|
||||
'enable' => env('WEBSOCKET_ENABLE', true),
|
||||
'handler' => Handler::class,
|
||||
'ping_interval' => 25000,
|
||||
'ping_timeout' => 60000,
|
||||
],
|
||||
//队列
|
||||
'queue' => [
|
||||
'enable' => env('QUEUE_ENABLE', true),
|
||||
'workers' => [
|
||||
'default' => [],
|
||||
],
|
||||
],
|
||||
//共享数据
|
||||
'conduit' => [
|
||||
'type' => 'socket',
|
||||
],
|
||||
'hot_update' => [
|
||||
'enable' => env('HOT_ENABLE', true),
|
||||
'name' => ['*.php'],
|
||||
'include' => [app_path(), config_path(), root_path('route')],
|
||||
'exclude' => [],
|
||||
],
|
||||
];
|
||||
1
tests/stub/public/asset.txt
Normal file
1
tests/stub/public/asset.txt
Normal file
@@ -0,0 +1 @@
|
||||
Asset
|
||||
51
tests/stub/route/app.php
Normal file
51
tests/stub/route/app.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
use think\facade\Route;
|
||||
|
||||
Route::get('/', function () {
|
||||
return 'hello world';
|
||||
});
|
||||
|
||||
Route::put('/', function () {
|
||||
return 'put';
|
||||
});
|
||||
|
||||
Route::delete('/', function () {
|
||||
return 'delete';
|
||||
});
|
||||
|
||||
Route::get('/sse', function () {
|
||||
|
||||
$generator = function () {
|
||||
foreach (range(0, 9) as $event) {
|
||||
yield 'data: ' . json_encode($event) . "\n\n";
|
||||
}
|
||||
|
||||
yield "data: [DONE]\n\n";
|
||||
};
|
||||
|
||||
$response = new \think\worker\response\Iterator($generator());
|
||||
|
||||
return $response->header([
|
||||
'Content-Type' => 'text/event-stream',
|
||||
'Cache-Control' => 'no-cache, must-revalidate',
|
||||
]);
|
||||
});
|
||||
|
||||
Route::get('/websocket', function () {
|
||||
return (new \think\worker\response\Websocket())
|
||||
->onOpen(function (\think\worker\Websocket $websocket) {
|
||||
$websocket->join('foo');
|
||||
})
|
||||
->onMessage(function (\think\worker\Websocket $websocket, \think\worker\websocket\Frame $frame) {
|
||||
$websocket->to('foo')->push($frame->data);
|
||||
});
|
||||
});
|
||||
|
||||
Route::get('test', 'index/test');
|
||||
Route::post('json', 'index/json');
|
||||
|
||||
Route::get('static/:path', function (string $path) {
|
||||
$filename = public_path() . $path;
|
||||
return new \think\worker\response\File($filename);
|
||||
})->pattern(['path' => '.*\.\w+$']);
|
||||
2
tests/stub/runtime/.gitignore
vendored
Normal file
2
tests/stub/runtime/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
12
tests/stub/think
Normal file
12
tests/stub/think
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use think\App;
|
||||
|
||||
require __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
$app = new App(__DIR__);
|
||||
|
||||
$app->console->addCommands([\think\worker\command\Server::class]);
|
||||
|
||||
$app->console->run();
|
||||
Reference in New Issue
Block a user