summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValery Piashchynski <[email protected]>2020-11-05 17:58:23 +0300
committerGitHub <[email protected]>2020-11-05 17:58:23 +0300
commit9fbe7726dd55cfedda724b7644e1b6bf7c1a6cb4 (patch)
treef2bf9b97d38103de51e2d140aa76666f9c6341c8
parentedc45b3e24afdb5e56e74ffbbbd50e0e3b04922b (diff)
parent73da7300fcc9b8b22faa1c91fc1faff22ab944ff (diff)
Merge pull request #388 from spiral/enhancement/testsv2.0.0-alpha15
Tests for the new plugins
-rw-r--r--.dockerignore10
-rwxr-xr-x.github/workflows/ci-build.yml21
-rwxr-xr-x.rr.yaml4
-rw-r--r--Dockerfile27
-rw-r--r--Makefile7
-rwxr-xr-xbors.toml13
-rwxr-xr-xcomposer.lock423
-rwxr-xr-xerrors/debug_cap.go10
-rwxr-xr-xerrors/debug_stack.go116
-rwxr-xr-xerrors/debug_test.go74
-rwxr-xr-xerrors/errors.go215
-rwxr-xr-xerrors/marshal.go102
-rwxr-xr-xgo.mod15
-rwxr-xr-xgo.sum55
-rw-r--r--log/interface.go16
-rw-r--r--log/zap_adapter.go56
-rw-r--r--phpstan.neon.dist5
-rwxr-xr-xpipe_factory.go47
-rw-r--r--plugins/app/plugin.go (renamed from plugins/app/app.go)33
-rw-r--r--plugins/app/tests/app_test.go358
-rw-r--r--plugins/app/tests/configs/.rr-no-app-section.yaml9
-rw-r--r--plugins/app/tests/configs/.rr-sockets.yaml9
-rw-r--r--plugins/app/tests/configs/.rr-tcp.yaml9
-rw-r--r--plugins/app/tests/configs/.rr-wrong-command.yaml (renamed from plugins/app/tests/.rr.yaml)4
-rw-r--r--plugins/app/tests/configs/.rr-wrong-relay.yaml9
-rw-r--r--plugins/app/tests/configs/.rr.yaml9
-rw-r--r--plugins/app/tests/hello.php1
-rw-r--r--plugins/app/tests/plugin_1.go55
-rw-r--r--plugins/app/tests/plugin_2.go88
-rw-r--r--plugins/app/tests/plugin_pipes.go130
-rw-r--r--plugins/app/tests/plugin_sockets.go111
-rw-r--r--plugins/app/tests/plugin_tcp.go111
-rw-r--r--plugins/app/tests/socket.php25
-rw-r--r--plugins/app/tests/tcp.php20
-rwxr-xr-xplugins/config/configurer.go (renamed from plugins/config/provider.go)4
-rwxr-xr-xplugins/config/plugin.go (renamed from plugins/config/viper.go)12
-rwxr-xr-xplugins/config/tests/.rr.yaml10
-rwxr-xr-xplugins/config/tests/config_test.go4
-rwxr-xr-xplugins/config/tests/plugin1.go4
-rw-r--r--plugins/logger/encoder.go2
-rw-r--r--plugins/logger/plugin.go (renamed from plugins/logger/zap_logger.go)31
-rw-r--r--plugins/logger/tests/.rr.yaml0
-rw-r--r--plugins/logger/tests/logger_test.go (renamed from plugins/app/tests/factory_test.go)20
-rw-r--r--plugins/logger/tests/plugin.go40
-rwxr-xr-xplugins/rpc/plugin.go (renamed from plugins/rpc/rpc.go)92
-rw-r--r--plugins/rpc/tests/.rr-rpc-disabled.yaml3
-rw-r--r--plugins/rpc/tests/.rr.yaml3
-rw-r--r--plugins/rpc/tests/plugin1.go42
-rw-r--r--plugins/rpc/tests/plugin2.go54
-rw-r--r--plugins/rpc/tests/rpc_test.go169
-rwxr-xr-xstatic_pool.go2
-rwxr-xr-xsupervisor_pool.go2
-rwxr-xr-xsync_worker.go2
-rwxr-xr-xworker_watcher.go2
54 files changed, 1532 insertions, 1163 deletions
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..bfa82a3d
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,10 @@
+.dockerignore
+.git
+.gitignore
+.editorconfig
+.github
+/src
+/tests
+/bin
+composer.json
+vendor_php \ No newline at end of file
diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml
index 94549c37..e3e09d88 100755
--- a/.github/workflows/ci-build.yml
+++ b/.github/workflows/ci-build.yml
@@ -1,6 +1,6 @@
name: CI
-on: [push, pull_request]
+on: [ push, pull_request ]
jobs:
build:
@@ -9,9 +9,9 @@ jobs:
strategy:
fail-fast: false
matrix:
- php: [7.2, 7.3, 7.4]
- go: [1.14, 1.15]
- os: [ubuntu-latest]
+ php: [ 7.4 ]
+ go: [ 1.14, 1.15 ]
+ os: [ ubuntu-latest ]
env:
GO111MODULE: on
steps:
@@ -65,8 +65,12 @@ jobs:
- name: Run golang tests
run: |
- composer update
- go test -v -coverprofile=lib.txt -covermode=atomic
+ go test -v -race . -tags=debug -coverprofile=lib.txt -covermode=atomic
+ go test -v -race ./plugins/rpc -tags=debug -coverprofile=rpc_config.txt -covermode=atomic
+ go test -v -race ./plugins/rpc/tests -tags=debug -coverprofile=rpc.txt -covermode=atomic
+ go test -v -race ./plugins/config/tests -tags=debug -coverprofile=plugin_config.txt -covermode=atomic
+ go test -v -race ./plugins/logger/tests -tags=debug -coverprofile=logger.txt -covermode=atomic
+ go test -v -race ./plugins/app/tests -tags=debug -coverprofile=app.txt -covermode=atomic
- name: Run code coverage
env:
@@ -76,6 +80,11 @@ jobs:
curl https://codecov.io/bash -o codecov-bash
chmod +x codecov-bash
./codecov-bash -f lib.txt
+ ./codecov-bash -f rpc_config.txt
+ ./codecov-bash -f rpc.txt
+ ./codecov-bash -f plugin_config.txt
+ ./codecov-bash -f logger.txt
+ ./codecov-bash -f app.txt
fi
golangci-check:
diff --git a/.rr.yaml b/.rr.yaml
index 30d23695..81e1b0c4 100755
--- a/.rr.yaml
+++ b/.rr.yaml
@@ -1,7 +1,7 @@
app:
commmand: "php app.php"
- user: user
- group: group
+ user: ""
+ group: ""
env:
DEBUG: true
APP_KEY: "..." \ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..09cf7933
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,27 @@
+FROM golang:latest as builder
+
+COPY . /src
+
+WORKDIR /src
+
+RUN set -x \
+ && apt-get update -y \
+ && apt-get install -y bash git \
+ && go version \
+ && bash ./build.sh \
+ && test -f ./.rr.yaml
+
+FROM alpine:latest
+
+LABEL \
+ org.opencontainers.image.title="roadrunner" \
+ org.opencontainers.image.description="High-performance PHP application server, load-balancer and process manager" \
+ org.opencontainers.image.url="https://github.com/spiral/roadrunner" \
+ org.opencontainers.image.source="https://github.com/spiral/roadrunner" \
+ org.opencontainers.image.vendor="SpiralScout" \
+ org.opencontainers.image.licenses="MIT"
+
+COPY --from=builder /src/rr /usr/bin/rr
+COPY --from=builder /src/.rr.yaml /etc/rr.yaml
+
+ENTRYPOINT ["/usr/bin/rr"] \ No newline at end of file
diff --git a/Makefile b/Makefile
index 128e2a5a..99ae9840 100644
--- a/Makefile
+++ b/Makefile
@@ -1,2 +1,7 @@
test:
- go test -v -race -tags=debug .
+ go test -v -race -cover . -tags=debug
+ go test -v -race -cover ./plugins/rpc -tags=debug
+ go test -v -race -cover ./plugins/rpc/tests -tags=debug
+ go test -v -race -cover ./plugins/config/tests -tags=debug
+ go test -v -race -cover ./plugins/app/tests -tags=debug
+ go test -v -race -cover ./plugins/logger/tests -tags=debug \ No newline at end of file
diff --git a/bors.toml b/bors.toml
index 6dbbcaee..17543f78 100755
--- a/bors.toml
+++ b/bors.toml
@@ -1,14 +1,9 @@
status = [
-'Build (PHP 7.2, Go 1.15, OS ubuntu-latest)',
-'Build (PHP 7.2, Go 1.14, OS ubuntu-latest)',
-'Build (PHP 7.3, Go 1.15, OS ubuntu-latest)',
-'Build (PHP 7.3, Go 1.14, OS ubuntu-latest)',
-'Build (PHP 7.4, Go 1.15, OS ubuntu-latest)',
-'Build (PHP 7.4, Go 1.14, OS ubuntu-latest)',
-'runner / golangci-lint',
-'Build docker image',]
+ 'Build (PHP 7.4, Go 1.15, OS ubuntu-latest)',
+ 'Build (PHP 7.4, Go 1.14, OS ubuntu-latest)',
+ 'runner / golangci-lint', ]
required_approvals = 1
delete_merged_branches = true
-timeout-sec = 1800 \ No newline at end of file
+timeout-sec = 600 \ No newline at end of file
diff --git a/composer.lock b/composer.lock
index 13e6af6b..183f9fef 100755
--- a/composer.lock
+++ b/composer.lock
@@ -4,168 +4,9 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "439018483d4d3a37c3d369d2587b8311",
+ "content-hash": "95535b37e4eb6476a2f89ea1b0f16e48",
"packages": [
{
- "name": "laminas/laminas-diactoros",
- "version": "2.4.1",
- "source": {
- "type": "git",
- "url": "https://github.com/laminas/laminas-diactoros.git",
- "reference": "36ef09b73e884135d2059cc498c938e90821bb57"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/36ef09b73e884135d2059cc498c938e90821bb57",
- "reference": "36ef09b73e884135d2059cc498c938e90821bb57",
- "shasum": ""
- },
- "require": {
- "laminas/laminas-zendframework-bridge": "^1.0",
- "php": "^7.1",
- "psr/http-factory": "^1.0",
- "psr/http-message": "^1.0"
- },
- "conflict": {
- "phpspec/prophecy": "<1.9.0"
- },
- "provide": {
- "psr/http-factory-implementation": "1.0",
- "psr/http-message-implementation": "1.0"
- },
- "replace": {
- "zendframework/zend-diactoros": "^2.2.1"
- },
- "require-dev": {
- "ext-curl": "*",
- "ext-dom": "*",
- "ext-gd": "*",
- "ext-libxml": "*",
- "http-interop/http-factory-tests": "^0.5.0",
- "laminas/laminas-coding-standard": "~1.0.0",
- "php-http/psr7-integration-tests": "^1.0",
- "phpunit/phpunit": "^7.5.18"
- },
- "type": "library",
- "extra": {
- "laminas": {
- "config-provider": "Laminas\\Diactoros\\ConfigProvider",
- "module": "Laminas\\Diactoros"
- }
- },
- "autoload": {
- "files": [
- "src/functions/create_uploaded_file.php",
- "src/functions/marshal_headers_from_sapi.php",
- "src/functions/marshal_method_from_sapi.php",
- "src/functions/marshal_protocol_version_from_sapi.php",
- "src/functions/marshal_uri_from_sapi.php",
- "src/functions/normalize_server.php",
- "src/functions/normalize_uploaded_files.php",
- "src/functions/parse_cookie_header.php",
- "src/functions/create_uploaded_file.legacy.php",
- "src/functions/marshal_headers_from_sapi.legacy.php",
- "src/functions/marshal_method_from_sapi.legacy.php",
- "src/functions/marshal_protocol_version_from_sapi.legacy.php",
- "src/functions/marshal_uri_from_sapi.legacy.php",
- "src/functions/normalize_server.legacy.php",
- "src/functions/normalize_uploaded_files.legacy.php",
- "src/functions/parse_cookie_header.legacy.php"
- ],
- "psr-4": {
- "Laminas\\Diactoros\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "description": "PSR HTTP Message implementations",
- "homepage": "https://laminas.dev",
- "keywords": [
- "http",
- "laminas",
- "psr",
- "psr-17",
- "psr-7"
- ],
- "support": {
- "chat": "https://laminas.dev/chat",
- "docs": "https://docs.laminas.dev/laminas-diactoros/",
- "forum": "https://discourse.laminas.dev",
- "issues": "https://github.com/laminas/laminas-diactoros/issues",
- "rss": "https://github.com/laminas/laminas-diactoros/releases.atom",
- "source": "https://github.com/laminas/laminas-diactoros"
- },
- "funding": [
- {
- "url": "https://funding.communitybridge.org/projects/laminas-project",
- "type": "community_bridge"
- }
- ],
- "time": "2020-09-03T14:29:41+00:00"
- },
- {
- "name": "laminas/laminas-zendframework-bridge",
- "version": "1.1.1",
- "source": {
- "type": "git",
- "url": "https://github.com/laminas/laminas-zendframework-bridge.git",
- "reference": "6ede70583e101030bcace4dcddd648f760ddf642"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6ede70583e101030bcace4dcddd648f760ddf642",
- "reference": "6ede70583e101030bcace4dcddd648f760ddf642",
- "shasum": ""
- },
- "require": {
- "php": "^5.6 || ^7.0 || ^8.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3",
- "squizlabs/php_codesniffer": "^3.5"
- },
- "type": "library",
- "extra": {
- "laminas": {
- "module": "Laminas\\ZendFrameworkBridge"
- }
- },
- "autoload": {
- "files": [
- "src/autoload.php"
- ],
- "psr-4": {
- "Laminas\\ZendFrameworkBridge\\": "src//"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "description": "Alias legacy ZF class names to Laminas Project equivalents.",
- "keywords": [
- "ZendFramework",
- "autoloading",
- "laminas",
- "zf"
- ],
- "support": {
- "forum": "https://discourse.laminas.dev/",
- "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues",
- "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom",
- "source": "https://github.com/laminas/laminas-zendframework-bridge"
- },
- "funding": [
- {
- "url": "https://funding.communitybridge.org/projects/laminas-project",
- "type": "community_bridge"
- }
- ],
- "time": "2020-09-14T14:23:00+00:00"
- },
- {
"name": "psr/container",
"version": "1.0.0",
"source": {
@@ -219,114 +60,6 @@
"time": "2017-02-14T16:28:37+00:00"
},
{
- "name": "psr/http-factory",
- "version": "1.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/http-factory.git",
- "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
- "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
- "shasum": ""
- },
- "require": {
- "php": ">=7.0.0",
- "psr/http-message": "^1.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psr\\Http\\Message\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
- }
- ],
- "description": "Common interfaces for PSR-7 HTTP message factories",
- "keywords": [
- "factory",
- "http",
- "message",
- "psr",
- "psr-17",
- "psr-7",
- "request",
- "response"
- ],
- "support": {
- "source": "https://github.com/php-fig/http-factory/tree/master"
- },
- "time": "2019-04-30T12:38:16+00:00"
- },
- {
- "name": "psr/http-message",
- "version": "1.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/http-message.git",
- "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
- "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psr\\Http\\Message\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
- }
- ],
- "description": "Common interface for HTTP messages",
- "homepage": "https://github.com/php-fig/http-message",
- "keywords": [
- "http",
- "http-message",
- "psr",
- "psr-7",
- "request",
- "response"
- ],
- "support": {
- "source": "https://github.com/php-fig/http-message/tree/master"
- },
- "time": "2016-08-06T14:39:51+00:00"
- },
- {
"name": "spiral/goridge",
"version": "v2.4.5",
"source": {
@@ -377,16 +110,16 @@
},
{
"name": "symfony/console",
- "version": "v5.1.7",
+ "version": "v5.1.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "ae789a8a2ad189ce7e8216942cdb9b77319f5eb8"
+ "reference": "e0b2c29c0fa6a69089209bbe8fcff4df2a313d0e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/ae789a8a2ad189ce7e8216942cdb9b77319f5eb8",
- "reference": "ae789a8a2ad189ce7e8216942cdb9b77319f5eb8",
+ "url": "https://api.github.com/repos/symfony/console/zipball/e0b2c29c0fa6a69089209bbe8fcff4df2a313d0e",
+ "reference": "e0b2c29c0fa6a69089209bbe8fcff4df2a313d0e",
"shasum": ""
},
"require": {
@@ -423,11 +156,6 @@
"symfony/process": ""
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.1-dev"
- }
- },
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
@@ -453,7 +181,7 @@
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/console/tree/v5.1.7"
+ "source": "https://github.com/symfony/console/tree/v5.1.8"
},
"funding": [
{
@@ -469,7 +197,7 @@
"type": "tidelift"
}
],
- "time": "2020-10-07T15:23:00+00:00"
+ "time": "2020-10-24T12:01:57+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -1038,16 +766,16 @@
},
{
"name": "symfony/string",
- "version": "v5.1.7",
+ "version": "v5.1.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "4a9afe9d07bac506f75bcee8ed3ce76da5a9343e"
+ "reference": "a97573e960303db71be0dd8fda9be3bca5e0feea"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/4a9afe9d07bac506f75bcee8ed3ce76da5a9343e",
- "reference": "4a9afe9d07bac506f75bcee8ed3ce76da5a9343e",
+ "url": "https://api.github.com/repos/symfony/string/zipball/a97573e960303db71be0dd8fda9be3bca5e0feea",
+ "reference": "a97573e960303db71be0dd8fda9be3bca5e0feea",
"shasum": ""
},
"require": {
@@ -1065,11 +793,6 @@
"symfony/var-exporter": "^4.4|^5.0"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.1-dev"
- }
- },
"autoload": {
"psr-4": {
"Symfony\\Component\\String\\": ""
@@ -1106,7 +829,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v5.1.7"
+ "source": "https://github.com/symfony/string/tree/v5.1.8"
},
"funding": [
{
@@ -1122,22 +845,22 @@
"type": "tidelift"
}
],
- "time": "2020-09-15T12:23:47+00:00"
+ "time": "2020-10-24T12:01:57+00:00"
}
],
"packages-dev": [
{
"name": "phpstan/phpstan",
- "version": "0.12.52",
+ "version": "0.12.53",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "e96dd5e7ae9aefed663bc7e285ad96792b67eadc"
+ "reference": "dbbdb0d7c2434ecd5289f6114d16473e694caa67"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e96dd5e7ae9aefed663bc7e285ad96792b67eadc",
- "reference": "e96dd5e7ae9aefed663bc7e285ad96792b67eadc",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dbbdb0d7c2434ecd5289f6114d16473e694caa67",
+ "reference": "dbbdb0d7c2434ecd5289f6114d16473e694caa67",
"shasum": ""
},
"require": {
@@ -1168,7 +891,7 @@
"description": "PHPStan - PHP Static Analysis Tool",
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
- "source": "https://github.com/phpstan/phpstan/tree/0.12.52"
+ "source": "https://github.com/phpstan/phpstan/tree/0.12.53"
},
"funding": [
{
@@ -1184,7 +907,115 @@
"type": "tidelift"
}
],
- "time": "2020-10-25T07:23:44+00:00"
+ "time": "2020-11-01T14:51:50+00:00"
+ },
+ {
+ "name": "psr/http-factory",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-factory.git",
+ "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+ "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0.0",
+ "psr/http-message": "^1.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interfaces for PSR-7 HTTP message factories",
+ "keywords": [
+ "factory",
+ "http",
+ "message",
+ "psr",
+ "psr-17",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-factory/tree/master"
+ },
+ "time": "2019-04-30T12:38:16+00:00"
+ },
+ {
+ "name": "psr/http-message",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-message.git",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP messages",
+ "homepage": "https://github.com/php-fig/http-message",
+ "keywords": [
+ "http",
+ "http-message",
+ "psr",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-message/tree/master"
+ },
+ "time": "2016-08-06T14:39:51+00:00"
}
],
"aliases": [],
diff --git a/errors/debug_cap.go b/errors/debug_cap.go
deleted file mode 100755
index 2c8a2f78..00000000
--- a/errors/debug_cap.go
+++ /dev/null
@@ -1,10 +0,0 @@
-// +build !debug
-
-package errors
-
-import "bytes"
-
-type stack struct{}
-
-func (e *Error) populateStack() {}
-func (e *Error) printStack(*bytes.Buffer) {}
diff --git a/errors/debug_stack.go b/errors/debug_stack.go
deleted file mode 100755
index fa77ddc8..00000000
--- a/errors/debug_stack.go
+++ /dev/null
@@ -1,116 +0,0 @@
-// +build debug
-
-package errors
-
-import (
- "bytes"
- "fmt"
- "runtime"
- "strings"
-)
-
-type stack struct {
- callers []uintptr
- // TODO(adg): add time of creation
-}
-
-func (e *Error) populateStack() {
- e.callers = callers()
-
- e2, ok := e.Err.(*Error)
- if !ok {
- return
- }
-
- i := 0
-
- ok = false
- for ; i < len(e.callers) && i < len(e2.callers); i++ {
- // check for similar
- if e.callers[len(e.callers)-1-i] != e2.callers[len(e2.callers)-1-i] {
- break
- }
- ok = true
- }
-
- if ok { //we have common PCs
- e2Head := e2.callers[:len(e2.callers)-i]
- eTail := e.callers
-
- e.callers = make([]uintptr, len(e2Head)+len(eTail))
-
- copy(e.callers, e2Head)
- copy(e.callers[len(e2Head):], eTail)
-
- e2.callers = nil
- }
-}
-
-// frame returns the nth frame, with the frame at top of stack being 0.
-func frame(callers []uintptr, n int) runtime.Frame {
- frames := runtime.CallersFrames(callers)
- var f runtime.Frame
- for i := len(callers) - 1; i >= n; i-- {
- var ok bool
- f, ok = frames.Next()
- if !ok {
- break
- }
- }
- return f
-}
-
-func (e *Error) printStack(b *bytes.Buffer) {
- c := callers()
-
- var prev string
- var diff bool
- for i := 0; i < len(e.callers); i++ {
- pc := e.callers[len(e.callers)-i-1] // get current PC
- fn := runtime.FuncForPC(pc) // get function by pc
- name := fn.Name()
-
- if !diff && i < len(c) {
- ppc := c[len(c)-i-1]
- pname := runtime.FuncForPC(ppc).Name()
- if name == pname {
- continue
- }
- diff = true
- }
-
- if name == prev {
- continue
- }
-
- trim := 0
- for {
- j := strings.IndexAny(name[trim:], "./")
- if j < 0 {
- break
- }
- if !strings.HasPrefix(prev, name[:j+trim]) {
- break
- }
- trim += j + 1 // skip over the separator
- }
-
- // Do the printing.
- appendStrToBuf(b, Separator)
- file, line := fn.FileLine(pc)
- fmt.Fprintf(b, "%v:%d: ", file, line)
- if trim > 0 {
- b.WriteString("...")
- }
- b.WriteString(name[trim:])
-
- prev = name
- }
-}
-
-func callers() []uintptr {
- var stk [64]uintptr
- const skip = 4
- n := runtime.Callers(skip, stk[:])
- return stk[:n]
-}
diff --git a/errors/debug_test.go b/errors/debug_test.go
deleted file mode 100755
index bc866bc8..00000000
--- a/errors/debug_test.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// +build debug
-
-package errors
-
-import (
- "fmt"
- "regexp"
- "strings"
- "testing"
-)
-
-var errorLines = strings.Split(strings.TrimSpace(`
- .*/errors/debug_test.go:\d+: github.com/ValeryPiashchynski/errors.func1:
- .*/errors/debug_test.go:\d+: ...T.func2:
- .*/errors/debug_test.go:\d+: ...func3:
- .*/errors/debug_test.go:\d+: ...func4: func2 invoke func3: Network error:
- func4 operation: error in action
-`), "\n")
-
-var errorLineREs = make([]*regexp.Regexp, len(errorLines))
-
-func init() {
- for i, s := range errorLines {
- errorLineREs[i] = regexp.MustCompile(fmt.Sprintf("^%s", s))
- }
-}
-
-func TestsDebug(t *testing.T) {
- got := printErr(t, func1())
- lines := strings.Split(got, "\n")
- for i, re := range errorLineREs {
- if i >= len(lines) {
- // Handled by line number check.
- break
- }
- if !re.MatchString(lines[i]) {
- t.Errorf("error does not match at line %v, got:\n\t%q\nwant:\n\t%q", i, lines[i], re)
- }
- }
- if got, want := len(lines), len(errorLines); got != want {
- t.Errorf("got %v lines of errors, want %v", got, want)
- }
-}
-
-type T struct{}
-
-func printErr(t *testing.T, err error) string {
- return err.Error()
-}
-
-func func1() error {
- var t T
- return t.func2()
-}
-
-func (T) func2() error {
- o := Op("func2 invoke func3")
- return E(o, func3())
-}
-
-func func3() error {
- return func4()
-}
-
-func func4() error {
- o := Op("func4 operation")
- return E(o, Network, Str("error in action"))
-}
-
-///Users/0xdev/Projects/repo/errors/debug_test.go:53: github.com/ValeryPiashchynski/errors.func1:
-///Users/0xdev/Projects/repo/errors/debug_test.go:58: ...T.func2:
-///Users/0xdev/Projects/repo/errors/debug_test.go:62: ...func3:
-///Users/0xdev/Projects/repo/errors/debug_test.go:67: ...func4: func2 invoke func3: Network error:
-//func4 operation: error in action
diff --git a/errors/errors.go b/errors/errors.go
deleted file mode 100755
index ec621b67..00000000
--- a/errors/errors.go
+++ /dev/null
@@ -1,215 +0,0 @@
-package errors
-
-import (
- "bytes"
- "encoding"
- "errors"
- "fmt"
- "log"
- "runtime"
-)
-
-type Error struct {
- Op Op
- Kind Kind
- Err error
-
- // Stack information
- stack
-}
-
-func (e *Error) isZero() bool {
- return e.Op == "" && e.Kind == 0 && e.Err == nil
-}
-
-var (
- _ error = (*Error)(nil)
- _ encoding.BinaryUnmarshaler = (*Error)(nil)
- _ encoding.BinaryMarshaler = (*Error)(nil)
-)
-
-// Op describes an operation
-type Op string
-
-// separator -> new line plus tabulator to intend error if previuos not nil
-var Separator = ":\n\t"
-
-type Kind uint8
-
-// Kinds of errors.
-const (
- Undefined Kind = iota // Undefined error.
- ErrWatcherStopped
- TimeOut
-)
-
-func (k Kind) String() string {
- switch k {
- case Undefined:
- return "UNDEF"
- case ErrWatcherStopped:
- return "Watcher stopped"
- case TimeOut:
- return "TimedOut"
- }
- return "unknown error kind"
-}
-
-// E builds an error value from its arguments.
-func E(args ...interface{}) error {
- e := &Error{}
- if len(args) == 0 {
- msg := "errors.E called with 0 args"
- _, file, line, ok := runtime.Caller(1)
- if ok {
- msg = fmt.Sprintf("%v - %v:%v", msg, file, line)
- }
- e.Err = errors.New(msg)
- }
-
- for _, arg := range args {
- switch arg := arg.(type) {
- case Op:
- e.Op = arg
- case string:
- e.Err = Str(arg)
- case Kind:
- e.Kind = arg
- case *Error:
- // Make a copy
- eCopy := *arg
- e.Err = &eCopy
- case error:
- e.Err = arg
- // add map map[string]string
- default:
- _, file, line, _ := runtime.Caller(1)
- log.Printf("errors.E: bad call from %s:%d: %v", file, line, args)
- return Errorf("unknown type %T, value %v in error call", arg, arg)
- }
- }
-
- // Populate stack information
- e.populateStack()
-
- prev, ok := e.Err.(*Error)
- if !ok {
- return e
- }
-
- if prev.Kind == e.Kind {
- prev.Kind = Undefined
- }
-
- if e.Kind == Undefined {
- e.Kind = prev.Kind
- prev.Kind = Undefined
- }
- return e
-}
-
-func (e *Error) Error() string {
- b := new(bytes.Buffer)
- e.printStack(b)
- if e.Op != "" {
- appendStrToBuf(b, ": ")
- b.WriteString(string(e.Op))
- }
-
- if e.Kind != 0 {
- appendStrToBuf(b, ": ")
- b.WriteString(e.Kind.String())
- }
- if e.Err != nil {
- if prevErr, ok := e.Err.(*Error); ok {
- if !prevErr.isZero() {
- // indent - separator
- appendStrToBuf(b, Separator)
- b.WriteString(e.Err.Error())
- }
- } else {
- appendStrToBuf(b, ": ")
- b.WriteString(e.Err.Error())
- }
- }
- if b.Len() == 0 {
- return "no error"
- }
- return b.String()
-}
-
-// errors.New
-func Str(text string) error {
- return &errorString{text}
-}
-
-type errorString struct {
- s string
-}
-
-func (e *errorString) Error() string {
- return e.s
-}
-
-func Errorf(format string, args ...interface{}) error {
- return &errorString{fmt.Sprintf(format, args...)}
-}
-
-func Match(err1, err2 error) bool {
- e1, ok := err1.(*Error)
- if !ok {
- return false
- }
- e2, ok := err2.(*Error)
- if !ok {
- return false
- }
- if e1.Op != "" && e2.Op != e1.Op {
- return false
- }
- if e1.Kind != Undefined && e2.Kind != e1.Kind {
- return false
- }
- if e1.Err != nil {
- if _, ok := e1.Err.(*Error); ok {
- return Match(e1.Err, e2.Err)
- }
- if e2.Err == nil || e2.Err.Error() != e1.Err.Error() {
- return false
- }
- }
- return true
-}
-
-// Is reports whether err is an *Error of the given Kind
-func Is(kind Kind, err error) bool {
- e, ok := err.(*Error)
- if !ok {
- return false
- }
- if e.Kind != Undefined {
- return e.Kind == kind
- }
- if e.Err != nil {
- return Is(kind, e.Err)
- }
- return false
-}
-
-// Do smt with no care about result (and panics)
-func SafelyDo(work func()) {
- defer func() {
- if err := recover(); err != nil {
- log.Printf("work failed: %s", err)
- }
- }()
-
- work()
-}
-
-func appendStrToBuf(b *bytes.Buffer, str string) {
- if b.Len() == 0 {
- return
- }
- b.WriteString(str)
-}
diff --git a/errors/marshal.go b/errors/marshal.go
deleted file mode 100755
index 7c8a63ef..00000000
--- a/errors/marshal.go
+++ /dev/null
@@ -1,102 +0,0 @@
-package errors
-
-import (
- "encoding/binary"
- "log"
-)
-
-func (e *Error) MarshalAppend(b []byte) []byte {
- if e == nil {
- return b
- }
-
- b = appendString(b, string(e.Op))
-
- var tmp [16]byte
- N := binary.PutVarint(tmp[:], int64(e.Kind))
- b = append(b, tmp[:N]...)
- b = MarshalErrorAppend(e.Err, b)
- return b
-}
-
-func (e *Error) MarshalBinary() ([]byte, error) {
- return e.MarshalAppend(nil), nil
-}
-
-func MarshalErrorAppend(err error, b []byte) []byte {
- if err == nil {
- return b
- }
- if e, ok := err.(*Error); ok {
- b = append(b, 'E')
- return e.MarshalAppend(b)
- }
- // Ordinary error.
- b = append(b, 'e')
- b = appendString(b, err.Error())
- return b
-}
-
-func MarshalError(err error) []byte {
- return MarshalErrorAppend(err, nil)
-}
-
-func (e *Error) UnmarshalBinary(b []byte) error {
- if len(b) == 0 {
- return nil
- }
- data, b := getBytes(b)
- if data != nil {
- e.Op = Op(data)
- }
- k, N := binary.Varint(b)
- e.Kind = Kind(k)
- b = b[N:]
- e.Err = UnmarshalError(b)
- return nil
-}
-
-func UnmarshalError(b []byte) error {
- if len(b) == 0 {
- return nil
- }
- code := b[0]
- b = b[1:]
- switch code {
- case 'e':
- var data []byte
- data, b = getBytes(b)
- if len(b) != 0 {
- log.Printf("Unmarshal error: trailing bytes")
- }
- return Str(string(data))
- case 'E':
- var err Error
- err.UnmarshalBinary(b)
- return &err
- default:
- log.Printf("Unmarshal error: corrupt data %q", b)
- return Str(string(b))
- }
-}
-
-func appendString(b []byte, str string) []byte {
- var tmp [16]byte
- N := binary.PutUvarint(tmp[:], uint64(len(str)))
- b = append(b, tmp[:N]...)
- b = append(b, str...)
- return b
-}
-
-func getBytes(b []byte) (data, remaining []byte) {
- u, N := binary.Uvarint(b)
- if len(b) < N+int(u) {
- log.Printf("Unmarshal error: bad encoding")
- return nil, nil
- }
- if N == 0 {
- log.Printf("Unmarshal error: bad encoding")
- return nil, b
- }
- return b[N : N+int(u)], b[N+int(u):]
-}
diff --git a/go.mod b/go.mod
index 3cd3e0ae..cb7a7a1f 100755
--- a/go.mod
+++ b/go.mod
@@ -4,21 +4,18 @@ go 1.15
require (
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
- github.com/fatih/color v1.7.0
+ github.com/fatih/color v1.10.0
github.com/go-ole/go-ole v1.2.4 // indirect
github.com/json-iterator/go v1.1.10
github.com/pkg/errors v0.9.1
- github.com/shirou/gopsutil v2.20.9+incompatible
+ github.com/shirou/gopsutil v3.20.10+incompatible
github.com/spf13/viper v1.7.1
- github.com/spiral/endure v1.0.0-beta10
- github.com/spiral/errors v1.0.0
- github.com/spiral/goridge/v2 v2.4.5
+ github.com/spiral/endure v1.0.0-beta15
+ github.com/spiral/errors v1.0.2
+ github.com/spiral/goridge/v2 v2.4.6
github.com/stretchr/testify v1.6.1
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a
go.uber.org/multierr v1.6.0
go.uber.org/zap v1.16.0
- golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
- golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 // indirect
- gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
- gopkg.in/yaml.v2 v2.2.5 // indirect
+ golang.org/x/sync v0.0.0-20190423024810-112230192c58
)
diff --git a/go.sum b/go.sum
index 9e37905e..8433a2c9 100755
--- a/go.sum
+++ b/go.sum
@@ -35,8 +35,6 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/corona10/goimagehash v1.0.2 h1:pUfB0LnsJASMPGEZLj7tGY251vF+qLGqOgEP4rUs6kA=
-github.com/corona10/goimagehash v1.0.2/go.mod h1:/l9umBhvcHQXVtQO1V6Gp1yD20STawkhRnnX0D1bvVI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -44,8 +42,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
-github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
+github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
+github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -56,12 +54,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/goccy/go-graphviz v0.0.8 h1:hYQikvj368s8+rmfzFOZeiCXvSocGH7rfAyLTOy/7AM=
-github.com/goccy/go-graphviz v0.0.8/go.mod h1:wXVsXxmyMQU6TN3zGRttjNn3h+iCAS7xQFC6TlNvLhk=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
-github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@@ -108,10 +102,8 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
@@ -131,8 +123,12 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@@ -150,8 +146,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY=
-github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
@@ -176,8 +170,8 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/shirou/gopsutil v2.20.9+incompatible h1:msXs2frUV+O/JLva9EDLpuJ84PrFsdCTCQex8PUdtkQ=
-github.com/shirou/gopsutil v2.20.9+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/gopsutil v3.20.10+incompatible h1:kQuRhh6h6y4luXvnmtu/lJEGtdJ3q8lbu9NQY99GP+o=
+github.com/shirou/gopsutil v3.20.10+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
@@ -195,12 +189,14 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
-github.com/spiral/endure v1.0.0-beta10 h1:eAFnJspvmMRDL3u7iwWK8eewogMhq4TTG3CjCBPnbeI=
-github.com/spiral/endure v1.0.0-beta10/go.mod h1:mXFf8zPqr1SJ1cG0Zf59f6X+MvJzrdIwVjzQpa107e0=
-github.com/spiral/errors v1.0.0 h1:wdmJqAFY2Uf8KFK6b8Wkh6vxX++2+GwJWAUplrNTLD0=
-github.com/spiral/errors v1.0.0/go.mod h1:SwMSZVdZkkJVgXNNafccqOaxWg0XPzVU/dEdUEInE0o=
-github.com/spiral/goridge/v2 v2.4.5 h1:rg4lLEJLrEh1Wj6G1qTsYVbYiQvig6mOR1F9GyDIGm8=
-github.com/spiral/goridge/v2 v2.4.5/go.mod h1:C/EZKFPON9lypi8QO7I5ObgVmrIzTmhZqFz/tmypcGc=
+github.com/spiral/endure v1.0.0-beta15 h1:pBFn9LKQLPSzrG7kGE30T0VEjp2A6yT6p2BRRUpN978=
+github.com/spiral/endure v1.0.0-beta15/go.mod h1:iGh1Zf1cckkJa5J9Obm8d/96kKYvlJBv/D0iHOuYWLQ=
+github.com/spiral/errors v1.0.1 h1:OyKLwQH+42hhaRYuXGzfPKCFOmawA/PYXTY9wsK99n4=
+github.com/spiral/errors v1.0.1/go.mod h1:SwMSZVdZkkJVgXNNafccqOaxWg0XPzVU/dEdUEInE0o=
+github.com/spiral/errors v1.0.2 h1:i/XMmA2VJt9sD64N4/zgQ9Y0cwlNQRLDaxOZPZV09D4=
+github.com/spiral/errors v1.0.2/go.mod h1:SwMSZVdZkkJVgXNNafccqOaxWg0XPzVU/dEdUEInE0o=
+github.com/spiral/goridge/v2 v2.4.6 h1:9u/mrxCtOSy0lnumrpPCSOlGBX/Vprid/hFsnzWrd6k=
+github.com/spiral/goridge/v2 v2.4.6/go.mod h1:mYjL+Ny7nVfLqjRwIYV2pUSQ61eazvVclHII6FfZfYc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -234,7 +230,6 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -242,9 +237,6 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
-golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -278,9 +270,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -293,9 +284,11 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
-golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
@@ -346,9 +339,8 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@@ -356,9 +348,8 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
-gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/log/interface.go b/log/interface.go
new file mode 100644
index 00000000..e2f2ce31
--- /dev/null
+++ b/log/interface.go
@@ -0,0 +1,16 @@
+package log
+
+type (
+ // Logger is an general RR log interface
+ Logger interface {
+ Debug(msg string, keyvals ...interface{})
+ Info(msg string, keyvals ...interface{})
+ Warn(msg string, keyvals ...interface{})
+ Error(msg string, keyvals ...interface{})
+ }
+)
+
+// With creates a child logger and adds structured context to it
+type WithLogger interface {
+ With(keyvals ...interface{}) Logger
+}
diff --git a/log/zap_adapter.go b/log/zap_adapter.go
new file mode 100644
index 00000000..65f8d04b
--- /dev/null
+++ b/log/zap_adapter.go
@@ -0,0 +1,56 @@
+package log
+
+import (
+ "fmt"
+
+ "go.uber.org/zap"
+)
+
+type ZapAdapter struct {
+ zl *zap.Logger
+}
+
+// Create NewZapAdapter which uses general log interface
+func NewZapAdapter(zapLogger *zap.Logger) *ZapAdapter {
+ return &ZapAdapter{
+ zl: zapLogger.WithOptions(zap.AddCallerSkip(1)),
+ }
+}
+
+func (log *ZapAdapter) fields(keyvals []interface{}) []zap.Field {
+ // we should have even number of keys and values
+ if len(keyvals)%2 != 0 {
+ return []zap.Field{zap.Error(fmt.Errorf("odd number of keyvals pairs: %v", keyvals))}
+ }
+
+ var fields []zap.Field
+ for i := 0; i < len(keyvals); i += 2 {
+ key, ok := keyvals[i].(string)
+ if !ok {
+ key = fmt.Sprintf("%v", keyvals[i])
+ }
+ fields = append(fields, zap.Any(key, keyvals[i+1]))
+ }
+
+ return fields
+}
+
+func (log *ZapAdapter) Debug(msg string, keyvals ...interface{}) {
+ log.zl.Debug(msg, log.fields(keyvals)...)
+}
+
+func (log *ZapAdapter) Info(msg string, keyvals ...interface{}) {
+ log.zl.Info(msg, log.fields(keyvals)...)
+}
+
+func (log *ZapAdapter) Warn(msg string, keyvals ...interface{}) {
+ log.zl.Warn(msg, log.fields(keyvals)...)
+}
+
+func (log *ZapAdapter) Error(msg string, keyvals ...interface{}) {
+ log.zl.Error(msg, log.fields(keyvals)...)
+}
+
+func (log *ZapAdapter) With(keyvals ...interface{}) Logger {
+ return NewZapAdapter(log.zl.With(log.fields(keyvals)...))
+}
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
new file mode 100644
index 00000000..50c2a587
--- /dev/null
+++ b/phpstan.neon.dist
@@ -0,0 +1,5 @@
+parameters:
+ level: 'max'
+ checkMissingIterableValueType: false
+ paths:
+ - src \ No newline at end of file
diff --git a/pipe_factory.go b/pipe_factory.go
index 807d7793..d6242775 100755
--- a/pipe_factory.go
+++ b/pipe_factory.go
@@ -6,8 +6,9 @@ import (
"os/exec"
"strings"
- "github.com/pkg/errors"
+ "github.com/spiral/errors"
"github.com/spiral/goridge/v2"
+ "go.uber.org/multierr"
)
// PipeFactory connects to stack using standard
@@ -71,40 +72,23 @@ func (f *PipeFactory) SpawnWorkerWithContext(ctx context.Context, cmd *exec.Cmd)
if err != nil {
c <- SpawnResult{
w: nil,
- err: errors.Wrap(err, "process error"),
+ err: errors.E(err, "process error"),
}
return
}
// errors bundle
- var errs []string
- if pid, errF := fetchPID(relay); pid != w.Pid() {
- if errF != nil {
- errs = append(errs, errF.Error())
- }
-
- // todo kill timeout
- errK := w.Kill()
- if errK != nil {
- errs = append(errs, fmt.Errorf("error killing the worker with PID number %d, Created: %s", w.Pid(), w.Created()).Error())
- }
-
- if wErr := w.Wait(ctx); wErr != nil {
- errs = append(errs, wErr.Error())
- }
-
- if len(errs) > 0 {
- c <- SpawnResult{
- w: nil,
- err: errors.New(strings.Join(errs, " : ")),
- }
- } else {
- c <- SpawnResult{
- w: nil,
- err: nil,
- }
+ pid, err := fetchPID(relay)
+ if pid != w.Pid() || err != nil {
+ err = multierr.Combine(
+ err,
+ w.Kill(),
+ w.Wait(context.Background()),
+ )
+ c <- SpawnResult{
+ w: nil,
+ err: err,
}
-
return
}
@@ -130,6 +114,7 @@ func (f *PipeFactory) SpawnWorkerWithContext(ctx context.Context, cmd *exec.Cmd)
}
func (f *PipeFactory) SpawnWorker(cmd *exec.Cmd) (WorkerBase, error) {
+ const op = errors.Op("spawn worker")
w, err := InitBaseWorker(cmd)
if err != nil {
return nil, err
@@ -154,7 +139,7 @@ func (f *PipeFactory) SpawnWorker(cmd *exec.Cmd) (WorkerBase, error) {
// Start the worker
err = w.Start()
if err != nil {
- return nil, errors.Wrap(err, "process error")
+ return nil, errors.E(op, err, "process error")
}
// errors bundle
@@ -174,7 +159,7 @@ func (f *PipeFactory) SpawnWorker(cmd *exec.Cmd) (WorkerBase, error) {
}
if len(errs) > 0 {
- return nil, errors.New(strings.Join(errs, "/"))
+ return nil, errors.E(op, strings.Join(errs, "/"))
}
}
diff --git a/plugins/app/app.go b/plugins/app/plugin.go
index 312e5bc6..839685bd 100644
--- a/plugins/app/app.go
+++ b/plugins/app/plugin.go
@@ -7,10 +7,9 @@ import (
"os/exec"
"strings"
- "go.uber.org/zap"
-
"github.com/spiral/errors"
"github.com/spiral/roadrunner/v2"
+ "github.com/spiral/roadrunner/v2/log"
"github.com/spiral/roadrunner/v2/plugins/config"
"github.com/spiral/roadrunner/v2/util"
)
@@ -26,15 +25,15 @@ type WorkerFactory interface {
NewWorkerPool(ctx context.Context, opt roadrunner.Config, env Env) (roadrunner.Pool, error)
}
-// App manages worker
-type App struct {
+// Plugin manages worker
+type Plugin struct {
cfg Config
- log *zap.Logger
+ log log.Logger
factory roadrunner.Factory
}
// Init application provider.
-func (app *App) Init(cfg config.Provider, log *zap.Logger) error {
+func (app *Plugin) Init(cfg config.Configurer, log log.Logger) error {
err := cfg.UnmarshalKey(ServiceName, &app.cfg)
if err != nil {
return err
@@ -46,11 +45,11 @@ func (app *App) Init(cfg config.Provider, log *zap.Logger) error {
}
// Name contains service name.
-func (app *App) Name() string {
+func (app *Plugin) Name() string {
return ServiceName
}
-func (app *App) Serve() chan error {
+func (app *Plugin) Serve() chan error {
errCh := make(chan error, 1)
var err error
@@ -62,7 +61,7 @@ func (app *App) Serve() chan error {
return errCh
}
-func (app *App) Stop() error {
+func (app *Plugin) Stop() error {
if app.factory == nil {
return nil
}
@@ -71,7 +70,7 @@ func (app *App) Stop() error {
}
// CmdFactory provides worker command factory assocated with given context.
-func (app *App) CmdFactory(env Env) (func() *exec.Cmd, error) {
+func (app *Plugin) CmdFactory(env Env) (func() *exec.Cmd, error) {
var cmdArgs []string
// create command according to the config
@@ -97,7 +96,7 @@ func (app *App) CmdFactory(env Env) (func() *exec.Cmd, error) {
}
// NewWorker issues new standalone worker.
-func (app *App) NewWorker(ctx context.Context, env Env) (roadrunner.WorkerBase, error) {
+func (app *Plugin) NewWorker(ctx context.Context, env Env) (roadrunner.WorkerBase, error) {
spawnCmd, err := app.CmdFactory(env)
if err != nil {
return nil, err
@@ -114,7 +113,7 @@ func (app *App) NewWorker(ctx context.Context, env Env) (roadrunner.WorkerBase,
}
// NewWorkerPool issues new worker pool.
-func (app *App) NewWorkerPool(ctx context.Context, opt roadrunner.Config, env Env) (roadrunner.Pool, error) {
+func (app *Plugin) NewWorkerPool(ctx context.Context, opt roadrunner.Config, env Env) (roadrunner.Pool, error) {
spawnCmd, err := app.CmdFactory(env)
if err != nil {
return nil, err
@@ -131,7 +130,7 @@ func (app *App) NewWorkerPool(ctx context.Context, opt roadrunner.Config, env En
}
// creates relay and worker factory.
-func (app *App) initFactory() (roadrunner.Factory, error) {
+func (app *Plugin) initFactory() (roadrunner.Factory, error) {
if app.cfg.Relay == "" || app.cfg.Relay == "pipes" {
return roadrunner.NewPipeFactory(), nil
}
@@ -157,7 +156,7 @@ func (app *App) initFactory() (roadrunner.Factory, error) {
}
}
-func (app *App) setEnv(e Env) []string {
+func (app *Plugin) setEnv(e Env) []string {
env := append(os.Environ(), fmt.Sprintf("RR_RELAY=%s", app.cfg.Relay))
for k, v := range e {
env = append(env, fmt.Sprintf("%s=%s", strings.ToUpper(k), v))
@@ -166,13 +165,13 @@ func (app *App) setEnv(e Env) []string {
return env
}
-func (app *App) collectLogs(event interface{}) {
+func (app *Plugin) collectLogs(event interface{}) {
if we, ok := event.(roadrunner.WorkerEvent); ok {
switch we.Event {
case roadrunner.EventWorkerError:
- app.log.Error(we.Payload.(error).Error(), zap.Int64("pid", we.Worker.Pid()))
+ app.log.Error(we.Payload.(error).Error(), "pid", we.Worker.Pid())
case roadrunner.EventWorkerLog:
- app.log.Debug(strings.TrimRight(string(we.Payload.([]byte)), " \n\t"), zap.Int64("pid", we.Worker.Pid()))
+ app.log.Debug(strings.TrimRight(string(we.Payload.([]byte)), " \n\t"), "pid", we.Worker.Pid())
}
}
}
diff --git a/plugins/app/tests/app_test.go b/plugins/app/tests/app_test.go
new file mode 100644
index 00000000..3c416b59
--- /dev/null
+++ b/plugins/app/tests/app_test.go
@@ -0,0 +1,358 @@
+package tests
+
+import (
+ "os"
+ "os/signal"
+ "testing"
+ "time"
+
+ "github.com/spiral/endure"
+ "github.com/spiral/roadrunner/v2/plugins/app"
+ "github.com/spiral/roadrunner/v2/plugins/config"
+ "github.com/spiral/roadrunner/v2/plugins/logger"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAppPipes(t *testing.T) {
+ container, err := endure.NewContainer(nil, endure.RetryOnFail(true), endure.SetLogLevel(endure.DebugLevel))
+ if err != nil {
+ t.Fatal(err)
+ }
+ // config plugin
+ vp := &config.Viper{}
+ vp.Path = "configs/.rr.yaml"
+ vp.Prefix = "rr"
+ err = container.Register(vp)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&app.Plugin{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&Foo{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&logger.ZapLogger{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Init()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ errCh, err := container.Serve()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // stop by CTRL+C
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, os.Interrupt)
+
+ // stop after 10 seconds
+ tt := time.NewTicker(time.Second * 10)
+
+ for {
+ select {
+ case e := <-errCh:
+ assert.NoError(t, e.Error)
+ assert.NoError(t, container.Stop())
+ return
+ case <-c:
+ er := container.Stop()
+ if er != nil {
+ panic(er)
+ }
+ return
+ case <-tt.C:
+ tt.Stop()
+ assert.NoError(t, container.Stop())
+ return
+ }
+ }
+}
+
+func TestAppSockets(t *testing.T) {
+ container, err := endure.NewContainer(nil, endure.RetryOnFail(true), endure.SetLogLevel(endure.DebugLevel))
+ if err != nil {
+ t.Fatal(err)
+ }
+ // config plugin
+ vp := &config.Viper{}
+ vp.Path = "configs/.rr-sockets.yaml"
+ vp.Prefix = "rr"
+ err = container.Register(vp)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&app.Plugin{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&Foo2{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&logger.ZapLogger{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Init()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ errCh, err := container.Serve()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // stop by CTRL+C
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, os.Interrupt)
+
+ // stop after 10 seconds
+ tt := time.NewTicker(time.Second * 10)
+
+ for {
+ select {
+ case e := <-errCh:
+ assert.NoError(t, e.Error)
+ assert.NoError(t, container.Stop())
+ return
+ case <-c:
+ er := container.Stop()
+ if er != nil {
+ panic(er)
+ }
+ return
+ case <-tt.C:
+ tt.Stop()
+ assert.NoError(t, container.Stop())
+ return
+ }
+ }
+}
+
+func TestAppTCP(t *testing.T) {
+ container, err := endure.NewContainer(nil, endure.RetryOnFail(true), endure.SetLogLevel(endure.DebugLevel))
+ if err != nil {
+ t.Fatal(err)
+ }
+ // config plugin
+ vp := &config.Viper{}
+ vp.Path = "configs/.rr-tcp.yaml"
+ vp.Prefix = "rr"
+ err = container.Register(vp)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&app.Plugin{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&Foo3{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&logger.ZapLogger{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Init()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ errCh, err := container.Serve()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // stop by CTRL+C
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, os.Interrupt)
+
+ // stop after 10 seconds
+ tt := time.NewTicker(time.Second * 10)
+
+ for {
+ select {
+ case e := <-errCh:
+ assert.NoError(t, e.Error)
+ assert.NoError(t, container.Stop())
+ return
+ case <-c:
+ er := container.Stop()
+ if er != nil {
+ panic(er)
+ }
+ return
+ case <-tt.C:
+ tt.Stop()
+ assert.NoError(t, container.Stop())
+ return
+ }
+ }
+}
+
+func TestAppWrongConfig(t *testing.T) {
+ container, err := endure.NewContainer(nil, endure.RetryOnFail(true), endure.SetLogLevel(endure.DebugLevel))
+ if err != nil {
+ t.Fatal(err)
+ }
+ // config plugin
+ vp := &config.Viper{}
+ vp.Path = "configs/.rrrrrrrrrr.yaml"
+ vp.Prefix = "rr"
+ err = container.Register(vp)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&app.Plugin{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&Foo3{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&logger.ZapLogger{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ assert.Error(t, container.Init())
+}
+
+func TestAppWrongRelay(t *testing.T) {
+ container, err := endure.NewContainer(nil, endure.RetryOnFail(true), endure.SetLogLevel(endure.DebugLevel))
+ if err != nil {
+ t.Fatal(err)
+ }
+ // config plugin
+ vp := &config.Viper{}
+ vp.Path = "configs/.rr-wrong-relay.yaml"
+ vp.Prefix = "rr"
+ err = container.Register(vp)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&app.Plugin{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&Foo3{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&logger.ZapLogger{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Init()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = container.Serve()
+ assert.Error(t, err)
+}
+
+func TestAppWrongCommand(t *testing.T) {
+ container, err := endure.NewContainer(nil, endure.RetryOnFail(true), endure.SetLogLevel(endure.DebugLevel))
+ if err != nil {
+ t.Fatal(err)
+ }
+ // config plugin
+ vp := &config.Viper{}
+ vp.Path = "configs/.rr-wrong-command.yaml"
+ vp.Prefix = "rr"
+ err = container.Register(vp)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&app.Plugin{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&Foo3{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&logger.ZapLogger{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Init()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = container.Serve()
+ assert.Error(t, err)
+}
+
+func TestAppNoAppSectionInConfig(t *testing.T) {
+ container, err := endure.NewContainer(nil, endure.RetryOnFail(true), endure.SetLogLevel(endure.DebugLevel))
+ if err != nil {
+ t.Fatal(err)
+ }
+ // config plugin
+ vp := &config.Viper{}
+ vp.Path = "configs/.rr-wrong-command.yaml"
+ vp.Prefix = "rr"
+ err = container.Register(vp)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&app.Plugin{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&Foo3{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Register(&logger.ZapLogger{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = container.Init()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = container.Serve()
+ assert.Error(t, err)
+}
diff --git a/plugins/app/tests/configs/.rr-no-app-section.yaml b/plugins/app/tests/configs/.rr-no-app-section.yaml
new file mode 100644
index 00000000..d129ae8a
--- /dev/null
+++ b/plugins/app/tests/configs/.rr-no-app-section.yaml
@@ -0,0 +1,9 @@
+upp:
+ command: "php ../../../tests/client.php echo pipes"
+ user: ""
+ group: ""
+ env:
+ "RR_CONFIG": "/some/place/on/the/C134"
+ "RR_CONFIG2": "C138"
+ relay: "pipes"
+ relayTimeout: "20s" \ No newline at end of file
diff --git a/plugins/app/tests/configs/.rr-sockets.yaml b/plugins/app/tests/configs/.rr-sockets.yaml
new file mode 100644
index 00000000..9bd62693
--- /dev/null
+++ b/plugins/app/tests/configs/.rr-sockets.yaml
@@ -0,0 +1,9 @@
+app:
+ command: "php socket.php"
+ user: ""
+ group: ""
+ env:
+ "RR_CONFIG": "/some/place/on/the/C134"
+ "RR_CONFIG2": "C138"
+ relay: "unix://unix.sock"
+ relayTimeout: "20s" \ No newline at end of file
diff --git a/plugins/app/tests/configs/.rr-tcp.yaml b/plugins/app/tests/configs/.rr-tcp.yaml
new file mode 100644
index 00000000..c5a26d37
--- /dev/null
+++ b/plugins/app/tests/configs/.rr-tcp.yaml
@@ -0,0 +1,9 @@
+app:
+ command: "php tcp.php"
+ user: ""
+ group: ""
+ env:
+ "RR_CONFIG": "/some/place/on/the/C134"
+ "RR_CONFIG2": "C138"
+ relay: "tcp://localhost:9999"
+ relayTimeout: "20s" \ No newline at end of file
diff --git a/plugins/app/tests/.rr.yaml b/plugins/app/tests/configs/.rr-wrong-command.yaml
index 171f51dc..4bd019d3 100644
--- a/plugins/app/tests/.rr.yaml
+++ b/plugins/app/tests/configs/.rr-wrong-command.yaml
@@ -1,9 +1,9 @@
app:
- command: "php hello.php"
+ command: "php some_absent_file.php"
user: ""
group: ""
env:
"RR_CONFIG": "/some/place/on/the/C134"
"RR_CONFIG2": "C138"
relay: "pipes"
- relayTimeout: "20s" \ No newline at end of file
+ relayTimeout: "20s"
diff --git a/plugins/app/tests/configs/.rr-wrong-relay.yaml b/plugins/app/tests/configs/.rr-wrong-relay.yaml
new file mode 100644
index 00000000..d8ffe8f8
--- /dev/null
+++ b/plugins/app/tests/configs/.rr-wrong-relay.yaml
@@ -0,0 +1,9 @@
+app:
+ command: "php ../../../tests/client.php echo pipes"
+ user: ""
+ group: ""
+ env:
+ "RR_CONFIG": "/some/place/on/the/C134"
+ "RR_CONFIG2": "C138"
+ relay: "pupes"
+ relayTimeout: "20s" \ No newline at end of file
diff --git a/plugins/app/tests/configs/.rr.yaml b/plugins/app/tests/configs/.rr.yaml
new file mode 100644
index 00000000..221aff92
--- /dev/null
+++ b/plugins/app/tests/configs/.rr.yaml
@@ -0,0 +1,9 @@
+app:
+ command: "php ../../../tests/client.php echo pipes"
+ user: ""
+ group: ""
+ env:
+ "RR_CONFIG": "/some/place/on/the/C134"
+ "RR_CONFIG2": "C138"
+ relay: "pipes"
+ relayTimeout: "20s" \ No newline at end of file
diff --git a/plugins/app/tests/hello.php b/plugins/app/tests/hello.php
deleted file mode 100644
index bf9e82cc..00000000
--- a/plugins/app/tests/hello.php
+++ /dev/null
@@ -1 +0,0 @@
-<?php echo "hello1 - " . time(); \ No newline at end of file
diff --git a/plugins/app/tests/plugin_1.go b/plugins/app/tests/plugin_1.go
deleted file mode 100644
index 7259ea9d..00000000
--- a/plugins/app/tests/plugin_1.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package tests
-
-import (
- "errors"
- "fmt"
-
- "github.com/spiral/roadrunner/v2/plugins/app"
- "github.com/spiral/roadrunner/v2/plugins/config"
-)
-
-type Foo struct {
- configProvider config.Provider
- spawner app.WorkerFactory
-}
-
-func (f *Foo) Init(p config.Provider, spw app.WorkerFactory) error {
- f.configProvider = p
- f.spawner = spw
- return nil
-}
-
-func (f *Foo) Serve() chan error {
- errCh := make(chan error, 1)
-
- r := &app.Config{}
- err := f.configProvider.UnmarshalKey("app", r)
- if err != nil {
- errCh <- err
- return errCh
- }
-
- cmd, err := f.spawner.CmdFactory(nil)
- if err != nil {
- errCh <- err
- return errCh
- }
- if cmd == nil {
- errCh <- errors.New("command is nil")
- return errCh
- }
- a := cmd()
- out, err := a.Output()
- if err != nil {
- errCh <- err
- return errCh
- }
-
- fmt.Println(string(out))
-
- return errCh
-}
-
-func (f *Foo) Stop() error {
- return nil
-}
diff --git a/plugins/app/tests/plugin_2.go b/plugins/app/tests/plugin_2.go
deleted file mode 100644
index fbb9ca11..00000000
--- a/plugins/app/tests/plugin_2.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package tests
-
-import (
- "context"
- "errors"
- "fmt"
- "time"
-
- "github.com/spiral/roadrunner/v2"
- "github.com/spiral/roadrunner/v2/plugins/app"
- "github.com/spiral/roadrunner/v2/plugins/config"
-)
-
-type Foo2 struct {
- configProvider config.Provider
- wf app.WorkerFactory
-}
-
-func (f *Foo2) Init(p config.Provider, workerFactory app.WorkerFactory) error {
- f.configProvider = p
- f.wf = workerFactory
- return nil
-}
-
-func (f *Foo2) Serve() chan error {
- errCh := make(chan error, 1)
-
- r := &app.Config{}
- err := f.configProvider.UnmarshalKey("app", r)
- if err != nil {
- errCh <- err
- return errCh
- }
-
- cmd, err := f.wf.CmdFactory(nil)
- if err != nil {
- errCh <- err
- return errCh
- }
- if cmd == nil {
- errCh <- errors.New("command is nil")
- return errCh
- }
- a := cmd()
- out, err := a.Output()
- if err != nil {
- errCh <- err
- return errCh
- }
-
- w, err := f.wf.NewWorker(context.Background(), nil)
- if err != nil {
- errCh <- err
- return errCh
- }
-
- _ = w
-
- poolConfig := roadrunner.Config{
- NumWorkers: 10,
- MaxJobs: 100,
- AllocateTimeout: time.Second * 10,
- DestroyTimeout: time.Second * 10,
- Supervisor: &roadrunner.SupervisorConfig{
- WatchTick: 60,
- TTL: 1000,
- IdleTTL: 10,
- ExecTTL: 10,
- MaxWorkerMemory: 1000,
- },
- }
-
- pool, err := f.wf.NewWorkerPool(context.Background(), poolConfig, nil)
- if err != nil {
- errCh <- err
- return errCh
- }
-
- _ = pool
-
- fmt.Println(string(out))
-
- return errCh
-}
-
-func (f *Foo2) Stop() error {
- return nil
-}
diff --git a/plugins/app/tests/plugin_pipes.go b/plugins/app/tests/plugin_pipes.go
new file mode 100644
index 00000000..fc999718
--- /dev/null
+++ b/plugins/app/tests/plugin_pipes.go
@@ -0,0 +1,130 @@
+package tests
+
+import (
+ "context"
+ "time"
+
+ "github.com/spiral/errors"
+ "github.com/spiral/roadrunner/v2"
+ "github.com/spiral/roadrunner/v2/plugins/app"
+ "github.com/spiral/roadrunner/v2/plugins/config"
+)
+
+const ConfigSection = "app"
+const Response = "test"
+
+var testPoolConfig = roadrunner.Config{
+ NumWorkers: 10,
+ MaxJobs: 100,
+ AllocateTimeout: time.Second * 10,
+ DestroyTimeout: time.Second * 10,
+ Supervisor: &roadrunner.SupervisorConfig{
+ WatchTick: 60,
+ TTL: 1000,
+ IdleTTL: 10,
+ ExecTTL: 10,
+ MaxWorkerMemory: 1000,
+ },
+}
+
+type Foo struct {
+ configProvider config.Configurer
+ wf app.WorkerFactory
+ pool roadrunner.Pool
+}
+
+func (f *Foo) Init(p config.Configurer, workerFactory app.WorkerFactory) error {
+ f.configProvider = p
+ f.wf = workerFactory
+ return nil
+}
+
+func (f *Foo) Serve() chan error {
+ const op = errors.Op("serve")
+
+ // test payload for echo
+ r := roadrunner.Payload{
+ Context: nil,
+ Body: []byte(Response),
+ }
+
+ errCh := make(chan error, 1)
+
+ conf := &app.Config{}
+ var err error
+ err = f.configProvider.UnmarshalKey(ConfigSection, conf)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // test CMDFactory
+ cmd, err := f.wf.CmdFactory(nil)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+ if cmd == nil {
+ errCh <- errors.E(op, "command is nil")
+ return errCh
+ }
+
+ // test worker creation
+ w, err := f.wf.NewWorker(context.Background(), nil)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // test that our worker is functional
+ sw, err := roadrunner.NewSyncWorker(w)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ rsp, err := sw.Exec(r)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ if string(rsp.Body) != Response {
+ errCh <- errors.E("response from worker is wrong", errors.Errorf("response: %s", rsp.Body))
+ return errCh
+ }
+
+ // should not be errors
+ err = sw.Stop(context.Background())
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // test pool
+ f.pool, err = f.wf.NewWorkerPool(context.Background(), testPoolConfig, nil)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // test pool execution
+ rsp, err = f.pool.Exec(r)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // echo of the "test" should be -> test
+ if string(rsp.Body) != Response {
+ errCh <- errors.E("response from worker is wrong", errors.Errorf("response: %s", rsp.Body))
+ return errCh
+ }
+
+ return errCh
+}
+
+func (f *Foo) Stop() error {
+ f.pool.Destroy(context.Background())
+ return nil
+}
diff --git a/plugins/app/tests/plugin_sockets.go b/plugins/app/tests/plugin_sockets.go
new file mode 100644
index 00000000..585264f6
--- /dev/null
+++ b/plugins/app/tests/plugin_sockets.go
@@ -0,0 +1,111 @@
+package tests
+
+import (
+ "context"
+
+ "github.com/spiral/errors"
+ "github.com/spiral/roadrunner/v2"
+ "github.com/spiral/roadrunner/v2/plugins/app"
+ "github.com/spiral/roadrunner/v2/plugins/config"
+)
+
+type Foo2 struct {
+ configProvider config.Configurer
+ wf app.WorkerFactory
+ pool roadrunner.Pool
+}
+
+func (f *Foo2) Init(p config.Configurer, workerFactory app.WorkerFactory) error {
+ f.configProvider = p
+ f.wf = workerFactory
+ return nil
+}
+
+func (f *Foo2) Serve() chan error {
+ const op = errors.Op("serve")
+ var err error
+ errCh := make(chan error, 1)
+ conf := &app.Config{}
+
+ // test payload for echo
+ r := roadrunner.Payload{
+ Context: nil,
+ Body: []byte(Response),
+ }
+
+ err = f.configProvider.UnmarshalKey(ConfigSection, conf)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // test CMDFactory
+ cmd, err := f.wf.CmdFactory(nil)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+ if cmd == nil {
+ errCh <- errors.E(op, "command is nil")
+ return errCh
+ }
+
+ // test worker creation
+ w, err := f.wf.NewWorker(context.Background(), nil)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // test that our worker is functional
+ sw, err := roadrunner.NewSyncWorker(w)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ rsp, err := sw.Exec(r)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ if string(rsp.Body) != Response {
+ errCh <- errors.E("response from worker is wrong", errors.Errorf("response: %s", rsp.Body))
+ return errCh
+ }
+
+ // should not be errors
+ err = sw.Stop(context.Background())
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // test pool
+ f.pool, err = f.wf.NewWorkerPool(context.Background(), testPoolConfig, nil)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // test pool execution
+ rsp, err = f.pool.Exec(r)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // echo of the "test" should be -> test
+ if string(rsp.Body) != Response {
+ errCh <- errors.E("response from worker is wrong", errors.Errorf("response: %s", rsp.Body))
+ return errCh
+ }
+
+ return errCh
+}
+
+func (f *Foo2) Stop() error {
+ f.pool.Destroy(context.Background())
+ return nil
+}
diff --git a/plugins/app/tests/plugin_tcp.go b/plugins/app/tests/plugin_tcp.go
new file mode 100644
index 00000000..6abc533d
--- /dev/null
+++ b/plugins/app/tests/plugin_tcp.go
@@ -0,0 +1,111 @@
+package tests
+
+import (
+ "context"
+
+ "github.com/spiral/errors"
+ "github.com/spiral/roadrunner/v2"
+ "github.com/spiral/roadrunner/v2/plugins/app"
+ "github.com/spiral/roadrunner/v2/plugins/config"
+)
+
+type Foo3 struct {
+ configProvider config.Configurer
+ wf app.WorkerFactory
+ pool roadrunner.Pool
+}
+
+func (f *Foo3) Init(p config.Configurer, workerFactory app.WorkerFactory) error {
+ f.configProvider = p
+ f.wf = workerFactory
+ return nil
+}
+
+func (f *Foo3) Serve() chan error {
+ const op = errors.Op("serve")
+ var err error
+ errCh := make(chan error, 1)
+ conf := &app.Config{}
+
+ // test payload for echo
+ r := roadrunner.Payload{
+ Context: nil,
+ Body: []byte(Response),
+ }
+
+ err = f.configProvider.UnmarshalKey(ConfigSection, conf)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // test CMDFactory
+ cmd, err := f.wf.CmdFactory(nil)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+ if cmd == nil {
+ errCh <- errors.E(op, "command is nil")
+ return errCh
+ }
+
+ // test worker creation
+ w, err := f.wf.NewWorker(context.Background(), nil)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // test that our worker is functional
+ sw, err := roadrunner.NewSyncWorker(w)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ rsp, err := sw.Exec(r)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ if string(rsp.Body) != Response {
+ errCh <- errors.E("response from worker is wrong", errors.Errorf("response: %s", rsp.Body))
+ return errCh
+ }
+
+ // should not be errors
+ err = sw.Stop(context.Background())
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // test pool
+ f.pool, err = f.wf.NewWorkerPool(context.Background(), testPoolConfig, nil)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // test pool execution
+ rsp, err = f.pool.Exec(r)
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ // echo of the "test" should be -> test
+ if string(rsp.Body) != Response {
+ errCh <- errors.E("response from worker is wrong", errors.Errorf("response: %s", rsp.Body))
+ return errCh
+ }
+
+ return errCh
+}
+
+func (f *Foo3) Stop() error {
+ f.pool.Destroy(context.Background())
+ return nil
+}
diff --git a/plugins/app/tests/socket.php b/plugins/app/tests/socket.php
new file mode 100644
index 00000000..143c3ce4
--- /dev/null
+++ b/plugins/app/tests/socket.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * @var Goridge\RelayInterface $relay
+ */
+
+use Spiral\Goridge;
+use Spiral\RoadRunner;
+
+require dirname(__DIR__) . "/../../vendor_php/autoload.php";
+
+$relay = new Goridge\SocketRelay(
+ "unix.sock",
+ null,
+ Goridge\SocketRelay::SOCK_UNIX
+ );
+
+$rr = new RoadRunner\Worker($relay);
+
+while ($in = $rr->receive($ctx)) {
+ try {
+ $rr->send((string)$in);
+ } catch (\Throwable $e) {
+ $rr->error((string)$e);
+ }
+}
diff --git a/plugins/app/tests/tcp.php b/plugins/app/tests/tcp.php
new file mode 100644
index 00000000..2d6fb00a
--- /dev/null
+++ b/plugins/app/tests/tcp.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * @var Goridge\RelayInterface $relay
+ */
+
+use Spiral\Goridge;
+use Spiral\RoadRunner;
+
+require dirname(__DIR__) . "/../../vendor_php/autoload.php";
+
+$relay = new Goridge\SocketRelay("localhost", 9999);
+$rr = new RoadRunner\Worker($relay);
+
+while ($in = $rr->receive($ctx)) {
+ try {
+ $rr->send((string)$in);
+ } catch (\Throwable $e) {
+ $rr->error((string)$e);
+ }
+} \ No newline at end of file
diff --git a/plugins/config/provider.go b/plugins/config/configurer.go
index ac33b3de..00010eae 100755
--- a/plugins/config/provider.go
+++ b/plugins/config/configurer.go
@@ -1,9 +1,9 @@
package config
-type Provider interface {
+type Configurer interface {
// UnmarshalKey reads configuration section into configuration object.
//
- // func (h *HttpService) Init(cp config.Provider) error {
+ // func (h *HttpService) Init(cp config.Configurer) error {
// h.config := &HttpConfig{}
// if err := configProvider.UnmarshalKey("http", h.config); err != nil {
// return err
diff --git a/plugins/config/viper.go b/plugins/config/plugin.go
index 4e85af6b..2555d28a 100755
--- a/plugins/config/viper.go
+++ b/plugins/config/plugin.go
@@ -8,14 +8,14 @@ import (
"github.com/spf13/viper"
)
-type ViperProvider struct {
+type Viper struct {
viper *viper.Viper
Path string
Prefix string
}
// Inits config provider.
-func (v *ViperProvider) Init() error {
+func (v *Viper) Init() error {
v.viper = viper.New()
// read in environment variables that match
@@ -36,7 +36,7 @@ func (v *ViperProvider) Init() error {
}
// Overwrite overwrites existing config with provided values
-func (v *ViperProvider) Overwrite(values map[string]string) error {
+func (v *Viper) Overwrite(values map[string]string) error {
if len(values) != 0 {
for _, flag := range values {
key, value, err := parseFlag(flag)
@@ -51,7 +51,7 @@ func (v *ViperProvider) Overwrite(values map[string]string) error {
}
// UnmarshalKey reads configuration section into configuration object.
-func (v *ViperProvider) UnmarshalKey(name string, out interface{}) error {
+func (v *Viper) UnmarshalKey(name string, out interface{}) error {
err := v.viper.UnmarshalKey(name, &out)
if err != nil {
return err
@@ -60,12 +60,12 @@ func (v *ViperProvider) UnmarshalKey(name string, out interface{}) error {
}
// Get raw config in a form of config section.
-func (v *ViperProvider) Get(name string) interface{} {
+func (v *Viper) Get(name string) interface{} {
return v.viper.Get(name)
}
// Has checks if config section exists.
-func (v *ViperProvider) Has(name string) bool {
+func (v *Viper) Has(name string) bool {
return v.viper.IsSet(name)
}
diff --git a/plugins/config/tests/.rr.yaml b/plugins/config/tests/.rr.yaml
index df9077d0..732a1366 100755
--- a/plugins/config/tests/.rr.yaml
+++ b/plugins/config/tests/.rr.yaml
@@ -1,21 +1,12 @@
reload:
- # enable or disable file watcher
enabled: true
- # sync interval
interval: 1s
- # global patterns to sync
patterns: [".php"]
- # list of included for sync services
services:
http:
- # recursive search for file patterns to add
recursive: true
- # ignored folders
ignore: ["vendor"]
- # service specific file pattens to sync
patterns: [".php", ".go",".md",]
- # directories to sync. If recursive is set to true,
- # recursive sync will be applied only to the directories in `dirs` section
dirs: ["."]
jobs:
recursive: false
@@ -24,5 +15,4 @@ reload:
rpc:
recursive: true
patterns: [".json"]
- # to include all project directories from workdir, leave `dirs` empty or add a dot "."
dirs: [""]
diff --git a/plugins/config/tests/config_test.go b/plugins/config/tests/config_test.go
index 14e60ac2..422e7eee 100755
--- a/plugins/config/tests/config_test.go
+++ b/plugins/config/tests/config_test.go
@@ -12,11 +12,11 @@ import (
)
func TestViperProvider_Init(t *testing.T) {
- container, err := endure.NewContainer(endure.DebugLevel, endure.RetryOnFail(true))
+ container, err := endure.NewContainer(nil, endure.RetryOnFail(true), endure.SetLogLevel(endure.DebugLevel))
if err != nil {
t.Fatal(err)
}
- vp := &config.ViperProvider{}
+ vp := &config.Viper{}
vp.Path = ".rr.yaml"
vp.Prefix = "rr"
err = container.Register(vp)
diff --git a/plugins/config/tests/plugin1.go b/plugins/config/tests/plugin1.go
index 7c5f2afd..a276c15f 100755
--- a/plugins/config/tests/plugin1.go
+++ b/plugins/config/tests/plugin1.go
@@ -23,11 +23,11 @@ type ServiceConfig struct {
}
type Foo struct {
- configProvider config.Provider
+ configProvider config.Configurer
}
// Depends on S2 and DB (S3 in the current case)
-func (f *Foo) Init(p config.Provider) error {
+func (f *Foo) Init(p config.Configurer) error {
f.configProvider = p
return nil
}
diff --git a/plugins/logger/encoder.go b/plugins/logger/encoder.go
index 66cd84f1..4ff583c4 100644
--- a/plugins/logger/encoder.go
+++ b/plugins/logger/encoder.go
@@ -61,6 +61,6 @@ func UTCTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
// returns string hash
func stringHash(name string, base int) int {
h := fnv.New32a()
- h.Write([]byte(name))
+ _, _ = h.Write([]byte(name))
return int(h.Sum32()) % base
}
diff --git a/plugins/logger/zap_logger.go b/plugins/logger/plugin.go
index 8c1739f2..f05d0ff0 100644
--- a/plugins/logger/zap_logger.go
+++ b/plugins/logger/plugin.go
@@ -2,6 +2,7 @@ package logger
import (
"github.com/spiral/endure"
+ "github.com/spiral/roadrunner/v2/log"
"github.com/spiral/roadrunner/v2/plugins/config"
"go.uber.org/zap"
)
@@ -9,14 +10,6 @@ import (
// ServiceName declares service name.
const ServiceName = "logs"
-type LogFactory interface {
- // GlobalLogger returns global log instance.
- GlobalLogger() *zap.Logger
-
- // NamedLogger returns logger dedicated to the specific channel. Similar to Named() but also reads the core params.
- NamedLogger(name string) *zap.Logger
-}
-
// ZapLogger manages zap logger.
type ZapLogger struct {
base *zap.Logger
@@ -25,8 +18,8 @@ type ZapLogger struct {
}
// Init logger service.
-func (z *ZapLogger) Init(cfg config.Provider) (err error) {
- err = cfg.UnmarshalKey(ServiceName, &z.cfg)
+func (z *ZapLogger) Init(cfg config.Configurer) error {
+ err := cfg.UnmarshalKey(ServiceName, &z.cfg)
if err != nil {
return err
}
@@ -41,28 +34,32 @@ func (z *ZapLogger) Init(cfg config.Provider) (err error) {
}
// DefaultLogger returns default logger.
-func (z *ZapLogger) DefaultLogger() (*zap.Logger, error) {
- return z.base, nil
+func (z *ZapLogger) DefaultLogger() (log.Logger, error) {
+ return log.NewZapAdapter(z.base), nil
}
// NamedLogger returns logger dedicated to the specific channel. Similar to Named() but also reads the core params.
-func (z *ZapLogger) NamedLogger(name string) (*zap.Logger, error) {
+func (z *ZapLogger) NamedLogger(name string) (log.Logger, error) {
if cfg, ok := z.channels.Channels[name]; ok {
- return cfg.BuildLogger()
+ l, err := cfg.BuildLogger()
+ if err != nil {
+ return nil, err
+ }
+ return log.NewZapAdapter(l), nil
}
- return z.base.Named(name), nil
+ return log.NewZapAdapter(z.base.Named(name)), nil
}
// NamedLogger returns logger dedicated to the specific channel. Similar to Named() but also reads the core params.
-func (z *ZapLogger) ServiceLogger(n endure.Named) (*zap.Logger, error) {
+func (z *ZapLogger) ServiceLogger(n endure.Named) (log.Logger, error) {
return z.NamedLogger(n.Name())
}
// Provides declares factory methods.
func (z *ZapLogger) Provides() []interface{} {
return []interface{}{
- z.DefaultLogger,
z.ServiceLogger,
+ z.DefaultLogger,
}
}
diff --git a/plugins/logger/tests/.rr.yaml b/plugins/logger/tests/.rr.yaml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/plugins/logger/tests/.rr.yaml
diff --git a/plugins/app/tests/factory_test.go b/plugins/logger/tests/logger_test.go
index 7c885797..1df74c47 100644
--- a/plugins/app/tests/factory_test.go
+++ b/plugins/logger/tests/logger_test.go
@@ -7,18 +7,18 @@ import (
"time"
"github.com/spiral/endure"
- "github.com/spiral/roadrunner/v2/plugins/app"
"github.com/spiral/roadrunner/v2/plugins/config"
+ "github.com/spiral/roadrunner/v2/plugins/logger"
"github.com/stretchr/testify/assert"
)
-func TestFactory(t *testing.T) {
- container, err := endure.NewContainer(endure.DebugLevel, endure.RetryOnFail(true))
+func TestLogger(t *testing.T) {
+ container, err := endure.NewContainer(nil, endure.RetryOnFail(true), endure.SetLogLevel(endure.DebugLevel))
if err != nil {
t.Fatal(err)
}
// config plugin
- vp := &config.ViperProvider{}
+ vp := &config.Viper{}
vp.Path = ".rr.yaml"
vp.Prefix = "rr"
err = container.Register(vp)
@@ -26,17 +26,12 @@ func TestFactory(t *testing.T) {
t.Fatal(err)
}
- err = container.Register(&app.App{})
+ err = container.Register(&Plugin{})
if err != nil {
t.Fatal(err)
}
- err = container.Register(&Foo{})
- if err != nil {
- t.Fatal(err)
- }
-
- err = container.Register(&Foo2{})
+ err = container.Register(&logger.ZapLogger{})
if err != nil {
t.Fatal(err)
}
@@ -55,7 +50,8 @@ func TestFactory(t *testing.T) {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
- tt := time.NewTicker(time.Second * 2)
+ // stop after 10 seconds
+ tt := time.NewTicker(time.Second * 10)
for {
select {
diff --git a/plugins/logger/tests/plugin.go b/plugins/logger/tests/plugin.go
new file mode 100644
index 00000000..75d2736d
--- /dev/null
+++ b/plugins/logger/tests/plugin.go
@@ -0,0 +1,40 @@
+package tests
+
+import (
+ "github.com/spiral/errors"
+ "github.com/spiral/roadrunner/v2/log"
+ "github.com/spiral/roadrunner/v2/plugins/config"
+)
+
+type Plugin struct {
+ config config.Configurer
+ log log.Logger
+}
+
+func (p1 *Plugin) Init(cfg config.Configurer, log log.Logger) error {
+ p1.config = cfg
+ p1.log = log
+ return nil
+}
+
+func (p1 *Plugin) Serve() chan error {
+ errCh := make(chan error, 1)
+ p1.log.Error("error", "test", errors.E(errors.Str("test")))
+ p1.log.Info("error", "test", errors.E(errors.Str("test")))
+ p1.log.Debug("error", "test", errors.E(errors.Str("test")))
+ p1.log.Warn("error", "test", errors.E(errors.Str("test")))
+
+ p1.log.Error("error", "test")
+ p1.log.Info("error", "test")
+ p1.log.Debug("error", "test")
+ p1.log.Warn("error", "test")
+ return errCh
+}
+
+func (p1 *Plugin) Stop() error {
+ return nil
+}
+
+func (p1 *Plugin) Name() string {
+ return "logger_plugin"
+}
diff --git a/plugins/rpc/rpc.go b/plugins/rpc/plugin.go
index f299bd55..6401c0e2 100755
--- a/plugins/rpc/rpc.go
+++ b/plugins/rpc/plugin.go
@@ -1,18 +1,19 @@
package rpc
import (
+ "net"
"net/rpc"
-
- "go.uber.org/zap"
+ "sync/atomic"
"github.com/spiral/endure"
"github.com/spiral/errors"
"github.com/spiral/goridge/v2"
+ "github.com/spiral/roadrunner/v2/log"
"github.com/spiral/roadrunner/v2/plugins/config"
)
-// RPCPluggable declares the ability to create set of public RPC methods.
-type RPCPluggable interface {
+// Pluggable declares the ability to create set of public RPC methods.
+type Pluggable interface {
endure.Named
// Provides RPC methods for the given service.
@@ -20,21 +21,23 @@ type RPCPluggable interface {
}
// ServiceName contains default service name.
-const ServiceName = "rpc"
+const ServiceName = "RPC"
-// Service is RPC service.
-type Service struct {
+// Plugin is RPC service.
+type Plugin struct {
cfg Config
- log *zap.Logger
+ log log.Logger
rpc *rpc.Server
- services []RPCPluggable
- close chan struct{}
+ services []Pluggable
+ listener net.Listener
+ closed *uint32
}
// Init rpc service. Must return true if service is enabled.
-func (s *Service) Init(cfg config.Provider, log *zap.Logger) error {
+func (s *Plugin) Init(cfg config.Configurer, log log.Logger) error {
+ const op = errors.Op("RPC Init")
if !cfg.Has(ServiceName) {
- return errors.E(errors.Disabled)
+ return errors.E(op, errors.Disabled)
}
err := cfg.UnmarshalKey(ServiceName, &s.cfg)
@@ -44,66 +47,68 @@ func (s *Service) Init(cfg config.Provider, log *zap.Logger) error {
s.cfg.InitDefaults()
if s.cfg.Disabled {
- return errors.E(errors.Disabled)
+ return errors.E(op, errors.Disabled)
}
s.log = log
+ state := uint32(0)
+ s.closed = &state
+ atomic.StoreUint32(s.closed, 0)
return s.cfg.Valid()
}
// Serve serves the service.
-func (s *Service) Serve() chan error {
+func (s *Plugin) Serve() chan error {
+ const op = errors.Op("register service")
errCh := make(chan error, 1)
- s.close = make(chan struct{}, 1)
s.rpc = rpc.NewServer()
- names := make([]string, 0, len(s.services))
+ services := make([]string, 0, len(s.services))
// Attach all services
for i := 0; i < len(s.services); i++ {
svc, err := s.services[i].RPCService()
if err != nil {
- errCh <- errors.E(errors.Op("register service"), err)
+ errCh <- errors.E(op, err)
return errCh
}
err = s.Register(s.services[i].Name(), svc)
if err != nil {
- errCh <- errors.E(errors.Op("register service"), err)
+ errCh <- errors.E(op, err)
return errCh
}
- names = append(names, s.services[i].Name())
+ services = append(services, s.services[i].Name())
}
- ln, err := s.cfg.Listener()
+ var err error
+ s.listener, err = s.cfg.Listener()
if err != nil {
errCh <- err
return errCh
}
- s.log.Debug("Started RPC service", zap.String("address", s.cfg.Listen), zap.Any("services", names))
+ s.log.Debug("Started RPC service", "address", s.cfg.Listen, "services", services)
go func() {
for {
- select {
- case <-s.close:
- // log error
- err := ln.Close()
- if err != nil {
- errCh <- errors.E(errors.Op("close RPC socket"), err)
- }
- return
- default:
- conn, err := ln.Accept()
- if err != nil {
- continue
+ conn, err := s.listener.Accept()
+ if err != nil {
+ if atomic.LoadUint32(s.closed) == 1 {
+ // just log and continue, this is not a critical issue, we just called Stop
+ s.log.Error("listener accept error, connection closed", "error", err)
+ return
}
- go s.rpc.ServeCodec(goridge.NewCodec(conn))
+ s.log.Error("listener accept error", "error", err)
+ errCh <- errors.E(errors.Op("listener accept"), errors.Serve, err)
+ return
}
+
+ go s.rpc.ServeCodec(goridge.NewCodec(conn))
}
}()
@@ -111,25 +116,30 @@ func (s *Service) Serve() chan error {
}
// Stop stops the service.
-func (s *Service) Stop() error {
- s.close <- struct{}{}
+func (s *Plugin) Stop() error {
+ // store closed state
+ atomic.StoreUint32(s.closed, 1)
+ err := s.listener.Close()
+ if err != nil {
+ return errors.E(errors.Op("stop RPC socket"), err)
+ }
return nil
}
// Name contains service name.
-func (s *Service) Name() string {
+func (s *Plugin) Name() string {
return ServiceName
}
// Depends declares services to collect for RPC.
-func (s *Service) Depends() []interface{} {
+func (s *Plugin) Collects() []interface{} {
return []interface{}{
s.RegisterPlugin,
}
}
// RegisterPlugin registers RPC service plugin.
-func (s *Service) RegisterPlugin(p RPCPluggable) error {
+func (s *Plugin) RegisterPlugin(p Pluggable) error {
s.services = append(s.services, p)
return nil
}
@@ -142,7 +152,7 @@ func (s *Service) RegisterPlugin(p RPCPluggable) error {
// - one return value, of type error
// It returns an error if the receiver is not an exported type or has
// no suitable methods. It also logs the error using package log.
-func (s *Service) Register(name string, svc interface{}) error {
+func (s *Plugin) Register(name string, svc interface{}) error {
if s.rpc == nil {
return errors.E("RPC service is not configured")
}
@@ -151,7 +161,7 @@ func (s *Service) Register(name string, svc interface{}) error {
}
// Client creates new RPC client.
-func (s *Service) Client() (*rpc.Client, error) {
+func (s *Plugin) Client() (*rpc.Client, error) {
conn, err := s.cfg.Dialer()
if err != nil {
return nil, err
diff --git a/plugins/rpc/tests/.rr-rpc-disabled.yaml b/plugins/rpc/tests/.rr-rpc-disabled.yaml
new file mode 100644
index 00000000..624fb3c5
--- /dev/null
+++ b/plugins/rpc/tests/.rr-rpc-disabled.yaml
@@ -0,0 +1,3 @@
+rpc:
+ listen: tcp://127.0.0.1:6001
+ disabled: true \ No newline at end of file
diff --git a/plugins/rpc/tests/.rr.yaml b/plugins/rpc/tests/.rr.yaml
new file mode 100644
index 00000000..76e8b440
--- /dev/null
+++ b/plugins/rpc/tests/.rr.yaml
@@ -0,0 +1,3 @@
+rpc:
+ listen: tcp://127.0.0.1:6001
+ disabled: false \ No newline at end of file
diff --git a/plugins/rpc/tests/plugin1.go b/plugins/rpc/tests/plugin1.go
new file mode 100644
index 00000000..788e6a2c
--- /dev/null
+++ b/plugins/rpc/tests/plugin1.go
@@ -0,0 +1,42 @@
+package tests
+
+import (
+ "fmt"
+
+ "github.com/spiral/roadrunner/v2/plugins/config"
+)
+
+type Plugin1 struct {
+ config config.Configurer
+}
+
+func (p1 *Plugin1) Init(cfg config.Configurer) error {
+ p1.config = cfg
+ return nil
+}
+
+func (p1 *Plugin1) Serve() chan error {
+ errCh := make(chan error, 1)
+ return errCh
+}
+
+func (p1 *Plugin1) Stop() error {
+ return nil
+}
+
+func (p1 *Plugin1) Name() string {
+ return "rpc_test.plugin1"
+}
+
+func (p1 *Plugin1) RPCService() (interface{}, error) {
+ return &PluginRpc{srv: p1}, nil
+}
+
+type PluginRpc struct {
+ srv *Plugin1
+}
+
+func (r *PluginRpc) Hello(in string, out *string) error {
+ *out = fmt.Sprintf("Hello, username: %s", in)
+ return nil
+}
diff --git a/plugins/rpc/tests/plugin2.go b/plugins/rpc/tests/plugin2.go
new file mode 100644
index 00000000..854bf097
--- /dev/null
+++ b/plugins/rpc/tests/plugin2.go
@@ -0,0 +1,54 @@
+package tests
+
+import (
+ "net"
+ "net/rpc"
+ "time"
+
+ "github.com/spiral/errors"
+ "github.com/spiral/goridge/v2"
+)
+
+// plugin2 makes a call to the plugin1 via RPC
+// this is just a simulation of external call FOR TEST
+// you don't need to do such things :)
+type Plugin2 struct {
+}
+
+func (p2 *Plugin2) Init() error {
+ return nil
+}
+
+func (p2 *Plugin2) Serve() chan error {
+ errCh := make(chan error, 1)
+
+ go func() {
+ time.Sleep(time.Second * 3)
+
+ conn, err := net.Dial("tcp", "127.0.0.1:6001")
+ if err != nil {
+ errCh <- errors.E(errors.Serve, err)
+ return
+ }
+ client := rpc.NewClientWithCodec(goridge.NewClientCodec(conn))
+ var ret string
+ err = client.Call("rpc_test.plugin1.Hello", "Valery", &ret)
+ if err != nil {
+ errCh <- err
+ return
+ }
+ if ret != "Hello, username: Valery" {
+ errCh <- errors.E("wrong response")
+ return
+ }
+ // to stop exec
+ errCh <- errors.E(errors.Disabled)
+ return
+ }()
+
+ return errCh
+}
+
+func (p2 *Plugin2) Stop() error {
+ return nil
+}
diff --git a/plugins/rpc/tests/rpc_test.go b/plugins/rpc/tests/rpc_test.go
new file mode 100644
index 00000000..88267dfb
--- /dev/null
+++ b/plugins/rpc/tests/rpc_test.go
@@ -0,0 +1,169 @@
+package tests
+
+import (
+ "os"
+ "os/signal"
+ "syscall"
+ "testing"
+ "time"
+
+ "github.com/spiral/endure"
+ "github.com/spiral/errors"
+ "github.com/spiral/roadrunner/v2/plugins/config"
+ "github.com/spiral/roadrunner/v2/plugins/logger"
+ "github.com/spiral/roadrunner/v2/plugins/rpc"
+ "github.com/stretchr/testify/assert"
+)
+
+// graph https://bit.ly/3ensdNb
+func TestRpcInit(t *testing.T) {
+ cont, err := endure.NewContainer(nil, endure.SetLogLevel(endure.DebugLevel))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = cont.Register(&Plugin1{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = cont.Register(&Plugin2{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ v := &config.Viper{}
+ v.Path = ".rr.yaml"
+ v.Prefix = "rr"
+ err = cont.Register(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = cont.Register(&rpc.Plugin{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = cont.Register(&logger.ZapLogger{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = cont.Init()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ch, err := cont.Serve()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ sig := make(chan os.Signal, 1)
+
+ signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
+ tt := time.NewTimer(time.Second * 10)
+
+ for {
+ select {
+ case e := <-ch:
+ // just stop, this is ok
+ if errors.Is(errors.Disabled, e.Error) {
+ return
+ }
+ assert.Fail(t, "error", e.Error.Error())
+ err = cont.Stop()
+ if err != nil {
+ assert.FailNow(t, "error", err.Error())
+ }
+ case <-sig:
+ err = cont.Stop()
+ if err != nil {
+ assert.FailNow(t, "error", err.Error())
+ }
+ return
+ case <-tt.C:
+ // timeout
+ err = cont.Stop()
+ if err != nil {
+ assert.FailNow(t, "error", err.Error())
+ }
+ assert.Fail(t, "timeout")
+ }
+ }
+}
+
+// graph https://bit.ly/3ensdNb
+func TestRpcDisabled(t *testing.T) {
+ cont, err := endure.NewContainer(nil, endure.SetLogLevel(endure.DebugLevel))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = cont.Register(&Plugin1{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = cont.Register(&Plugin2{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ v := &config.Viper{}
+ v.Path = ".rr-rpc-disabled.yaml"
+ v.Prefix = "rr"
+ err = cont.Register(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = cont.Register(&rpc.Plugin{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = cont.Register(&logger.ZapLogger{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = cont.Init()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ch, err := cont.Serve()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ sig := make(chan os.Signal, 1)
+
+ signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
+ tt := time.NewTimer(time.Second * 20)
+
+ for {
+ select {
+ case e := <-ch:
+ // RPC is turned off, should be and dial error
+ if errors.Is(errors.Disabled, e.Error) {
+ assert.FailNow(t, "should not be disabled error")
+ }
+ assert.Error(t, e.Error)
+ err = cont.Stop()
+ assert.Error(t, err)
+ return
+ case <-sig:
+ err = cont.Stop()
+ if err != nil {
+ assert.FailNow(t, "error", err.Error())
+ }
+ return
+ case <-tt.C:
+ // timeout
+ return
+ }
+ }
+}
diff --git a/static_pool.go b/static_pool.go
index be7ad6e3..66dac7c3 100755
--- a/static_pool.go
+++ b/static_pool.go
@@ -5,7 +5,7 @@ import (
"fmt"
"os/exec"
- "github.com/spiral/roadrunner/v2/errors"
+ "github.com/spiral/errors"
"github.com/spiral/roadrunner/v2/util"
)
diff --git a/supervisor_pool.go b/supervisor_pool.go
index 5dca3c22..92d03e77 100755
--- a/supervisor_pool.go
+++ b/supervisor_pool.go
@@ -5,7 +5,7 @@ import (
"sync"
"time"
- "github.com/spiral/roadrunner/v2/errors"
+ "github.com/spiral/errors"
"github.com/spiral/roadrunner/v2/util"
)
diff --git a/sync_worker.go b/sync_worker.go
index d933077b..282254e5 100755
--- a/sync_worker.go
+++ b/sync_worker.go
@@ -5,7 +5,7 @@ import (
"fmt"
"time"
- "github.com/spiral/roadrunner/v2/errors"
+ "github.com/spiral/errors"
"github.com/spiral/roadrunner/v2/util"
"go.uber.org/multierr"
diff --git a/worker_watcher.go b/worker_watcher.go
index d289750e..36b3e029 100755
--- a/worker_watcher.go
+++ b/worker_watcher.go
@@ -6,7 +6,7 @@ import (
"sync"
"time"
- "github.com/spiral/roadrunner/v2/errors"
+ "github.com/spiral/errors"
"github.com/spiral/roadrunner/v2/util"
)