diff --git a/README-CN.md b/README-CN.md index 93e9ac6452..0a2142bf8e 100644 --- a/README-CN.md +++ b/README-CN.md @@ -7,6 +7,9 @@ [![Slack Invite]()](https://slack-invite.emqx.io) [![Twitter](https://img.shields.io/badge/Twiiter-EMQ%20X-1DA1F2?logo=twitter)](https://twitter.com/emqtt) + +[![We are hiring](https://www.emqx.io/static/img/github_readme_cn_bg.png)](https://emqx.io/cn/about/jobs) + [English](./README.md) | 简体中文 *EMQ X* 是一款完全开源,高度可伸缩,高可用的分布式 MQTT 消息服务器,适用于 IoT、M2M 和移动应用程序,可处理千万级别的并发客户端。 @@ -20,7 +23,13 @@ *EMQ X* 是跨平台的,支持 Linux、Unix、Mac OS 以及 Windows。这意味着 *EMQ X* 可以部署在 x86_64 架构的服务器上,也可以部署在 Raspberry Pi 这样的 ARM 设备上。 -获取适合你的二进制软件包,[点此下载](https://emqx.io/downloads)。 +**使用 EMQ X Docker 镜像安装** + +``` +docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8883:8883 -p 8084:8084 -p 18083:18083 emqx/emqx +``` + +**或者 [点此下载](https://emqx.io/downloads) 适合你的二进制软件包** - [单节点安装](https://docs.emqx.io/broker/v3/cn/install.html) - [集群安装](https://docs.emqx.io/broker/v3/cn/cluster.html) @@ -68,6 +77,7 @@ cd _rel/emqx && ./bin/emqx console - [Twitter](https://twitter.com/emqtt) - [Forum](https://groups.google.com/d/forum/emqtt) - [Blog](https://medium.com/@emqtt) +- [Reddit](https://www.reddit.com/r/emqx/) 欢迎你将任何 bug、问题和功能请求提交到 [emqx/emqx](https://github.com/emqx/emqx/issues)。 diff --git a/README.md b/README.md index 968697b071..c5e7221cc1 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,9 @@ [![Slack Invite]()](https://slack-invite.emqx.io) [![Twitter](https://img.shields.io/badge/Twiiter-EMQ%20X-1DA1F2?logo=twitter)](https://twitter.com/emqtt) + +[![We are hiring](https://www.emqx.io/static/img/github_readme_en_bg.png)](https://emqx.io/about/jobs) + English | [简体中文](./README-CN.md) *EMQ X* broker is a fully open source, highly scalable, highly available distributed MQTT messaging broker for IoT, M2M and Mobile applications that can handle tens of millions of concurrent clients. @@ -20,7 +23,13 @@ Starting from 3.0 release, *EMQ X* broker fully supports MQTT V5.0 protocol spec The *EMQ X* broker is cross-platform, which supports Linux, Unix, Mac OS and Windows. It means *EMQ X* can be deployed on x86_64 architecture servers and ARM devices like Raspberry Pi. -Download the binary package for your platform from [here](https://emqx.io/downloads). +**Installing via EMQ X Docker Image** + +``` +docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8883:8883 -p 8084:8084 -p 18083:18083 emqx/emqx +``` + +**Or download the binary package for your platform from [here](https://emqx.io/downloads).** - [Single Node Install](https://docs.emqx.io/broker/v3/en/install.html) - [Multi Node Install](https://docs.emqx.io/broker/v3/en/cluster.html) @@ -69,6 +78,7 @@ You can reach the EMQ community and developers via the following channels: - [Twitter](https://twitter.com/emqtt) - [Forum](https://groups.google.com/d/forum/emqtt) - [Blog](https://medium.com/@emqtt) +- [Reddit](https://www.reddit.com/r/emqx/) Please submit any bugs, issues, and feature requests to [emqx/emqx](https://github.com/emqx/emqx/issues). diff --git a/etc/certs/cacert.pem b/etc/certs/cacert.pem index 595baf450a..c6b117181f 100644 --- a/etc/certs/cacert.pem +++ b/etc/certs/cacert.pem @@ -1,17 +1,18 @@ -----BEGIN CERTIFICATE----- -MIICxjCCAa6gAwIBAgIJAJk1DbZBu8FDMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV -BAMMCE15VGVzdENBMB4XDTE3MTEwMjEzNDI0N1oXDTE5MTEwMjEzNDI0N1owEzER -MA8GA1UEAwwITXlUZXN0Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQDshDho6ef1JClDJ24peSsXdFnFO3xIB7+BSp1YPcOvmRECKUG0mLORw3hNm15m -8eGOn1iLGE/xKlaZ74/xjyq8f7qIGZCmvZj59m+eiJCAmy8SiUJZtSVoOlOzepJd -PoDgcBvDKA4ogZ3iJHMUNI3EdlD6nrKEJF2qe2JUrL0gv65uo2/N7XVNvE87Dk3J -83KyCAmeu+x+moS1ILnjs2DuPEGSxZqzf7IQMbXuNWJYAOZg9t4Fg0YjTiAaWw3G -JKAoMY4tI3JCqlvwGR4lH7kfk3WsD4ofGlFhxU4nEG0xgnJl8BcoJWD1A2RjGe1f -qCijqPSe93l2wt8OpbyHzwc7AgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0P -BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQAi+t5jBrMxFzoF76kyRd3riNDlWp0w -NCewkohBkwBHsQfHzSnc6c504jdyzkEiD42UcI8asPsJcsYrQ+Uo6OBn049u49Wn -zcSERVSVec1/TAPS/egFTU9QMWtPSAm8AEaQ6YYAuiwOLCcC+Cm/a3e3dWSRWt8o -LqKX6CWTlmKWe182MhFPpZYxZQLGapti4R4mb5QusUbc6tXbkcX82GjDPTOuAw7b -mWpzVd5xnlp7Vz+50u+YaAYUmCobg0hR/AuTrA4GDMlgzTnuZQhF6o8iVkypXOtS -Ufz6X3tVVErVVc7UUfzSnupHj1M2h4rzlQ3oqHoAEnXcJmV4f/Pf/6FW +MIIC0TCCAbmgAwIBAgIUDQN8HojZmyEV9+AzEz6j6juwThswDQYJKoZIhvcNAQEL +BQAwEzERMA8GA1UEAwwITXlUZXN0Q0EwHhcNMTkxMTE1MDcyNjU4WhcNMjkxMTEy +MDcyNjU4WjATMREwDwYDVQQDDAhNeVRlc3RDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALce8QYBpl7fxEhwW0wtBQygXisMcPTKzckz3RhU21TeqK1Z +6Fm03QyYvB239oYJLodVwzv5SNI75hZ43Vyp+SHt3M3DjcsU/8PflxFK4QR7TdhI +ddn6R59Gqt0MhAZ/df2dYt7cMaQV8/5plzxLvrv9X2fwo8BYAGp6g6wGAL8SJDT9 +jd9TGzBG/o3dLu3keEwcl0CMq3qUwxatBHMe2s7COKBrngD/CvRAL8tG3VTj7ep9 +n29SSS8qMzHhJdBahTDrYS+SeW61iFK1yLXSxCWNoMB0/g7/AktWuAXHdHRX9xaf +WNJ4RdoPxhqkVJ8SrC4JtC8ah6DchVysWnz2KwMCAwEAAaMdMBswDAYDVR0TBAUw +AwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAEgnPnHLdivykReJ +I8xf5DeWsgBUdVvhxz2E9Ole/u6ThulNLziwHernkTprskiKFJaF67ZzS7YddTdf +WsS0H5LhYaft5NnBcn9UHCKEycyr3AJZ6joB3Dd9CfMQEscnZHNmIXwPGxw4bYP6 +AElF0Iy7LY/Z8po/UACTBzCCSf5UkZ9Jy/rzxuvn/cfPcLNhDWk8b8MbmOfuyNPV +SfPGn7wXIt9iyyA4qyzEVMaXl8d94E48dV5Fc1sQEEo6gk16dQ9p64ePMvUih6an +kSz9X/n1+9sHq54pJmLZ2gfRvGPIPVIipSjAj4sjHvKzuC3CQTTXs9HzmN2nT0zx +gLxgEkY= -----END CERTIFICATE----- diff --git a/etc/certs/cert.pem b/etc/certs/cert.pem index fb76ecde6d..f6187c3f61 100644 --- a/etc/certs/cert.pem +++ b/etc/certs/cert.pem @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIC6jCCAdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhNeVRl -c3RDQTAeFw0xNzExMDIxMzQyNDhaFw0xOTExMDIxMzQyNDhaMC0xGjAYBgNVBAMT -EU1hY0Jvb2stQWlyLmxvY2FsMQ8wDQYDVQQKEwZzZXJ2ZXIwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQDUO/kL3ar3WsopPF12qAf+cwDHklGJIxJsjdoZ -XgI1lPEe1W1QXwb/G/tyf6Fj2J8CD5bfsRjDxAemFIBVrFwlunCk+Gs6xR7vzz4O -Fonoj4pmleruLQrNY/bHa2WN97OdISyXzhOgDwSaqobnF0n/f0Mx+9sdHO3p8LNB -3JXUyBpwDNr/TTfAb4pbQEu3LF4p7uyd1eLhKzUxSiWzKtjB1EYObA87fZu0tBJZ -iGujuFiI7tf4qWKeuAoRa/cXkgVZhk0utYauDoa7qBZ5O6ZdEko9ov0+i5+1JGU/ -w5wrSPNAnM2lYVUn0kJmcV2gwa4RZFjdqp+/Fx+HnKbnhZEnAgMBAAGjLzAtMAkG -A1UdEwQCMAAwCwYDVR0PBAQDAgUgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqG -SIb3DQEBCwUAA4IBAQByWhNxX/L5QYBiMY4JM1RRciV4uI3F2vsc0yMFDSrZza+5 -tNJQS86hjQsCRZh9VshezvT7k1yVsAC4pnu2pzob8H3KG4vYBafMdl2Ghgv3RMix -J3NrBhcoYYhXEoZHost+htxEi7P3QBo/qDkk48/d30+aDPbms6kQd8Fj8+C5tD3b -aznO5Qlni72uTaM7fNA8exoc/YZc83lsqv7v+UzNQR595jnYSIAZcgil1qqygOan -Zx/RsMGUz6EYI9lPpoyyVtw13SoQshfgwvUlvBMiekSuI/pp6N7QPK6C8DLO0tVv -gXJjDgioqHc3hcgG4cskLbfVnohiwdhQTFayrLEk +MIIC5zCCAc+gAwIBAgIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhNeVRl +c3RDQTAeFw0xOTExMTUwNzI2NThaFw0yMTExMTQwNzI2NThaMCoxFzAVBgNVBAMM +DjAwMDQubm92YWxvY2FsMQ8wDQYDVQQKDAZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDC5JE48PJ/BFTLEseEbrGIdYB6w29hme4KFKmAqlLQ +kpwwZJAsm/9iuXy6svJf7Tzzc173Jkgzw7DzhzSf1VgRDrOCQS+IU6s8UXfUMJt/ +AmP1SkU2mUJ/+pnEGRKtVkF9LCScinI95Iwt3xngdjMYXwk+S9Le3/8782ClBwZG +vffXQ7hd5HnShgyqFVePgrKmr879NTylfvAWPwux2kdXNnbOHIrhcZm0NeMNf7hs +UNURFlqo4rA0FV9dIHMryPkM7ygoaMog2XmcCnq/jf/MfPTQPYjQ9iLPOGrYi0pY +X12uFb55duRGsvs7MIkNc8fn2VERoC69QX+GK+zAUGZ/AgMBAAGjLzAtMAkGA1Ud +EwQCMAAwCwYDVR0PBAQDAgUgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3 +DQEBCwUAA4IBAQBpW7Ge5duo6/u3xIl0XhG/2dlSwlUUpO3Ecc13gmh44nJR66VH +BEiimsol6gIgcSTk4pVY1DLb/09Nwv0TILl3Dc4QtXhM4gIlNRR79mLVsnPTef5e +xkmesQaLihSCroHq8bONnO/Xgj5hCg8uI4j3vHtOikjABxQPOrCfc2uSrenU7aol +1HBijCY6R+pg6WxBOZ2Teiaoxjn78IxSKLXW0pLRJIPpet1hefR0sKkmPfVGyg8H +g7hqo+Houw8PQf2HLZnU656vyTlgIh6ES1x7Plb0cIw/LGr4rMkXs+DFg9SLbetT +ncT4plfucsek7ImN9Dw2w2hM2FZwB8ycZfmu -----END CERTIFICATE----- diff --git a/etc/certs/client-cert.pem b/etc/certs/client-cert.pem index 1c44b37167..50d5148f81 100644 --- a/etc/certs/client-cert.pem +++ b/etc/certs/client-cert.pem @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIC6jCCAdKgAwIBAgIBAjANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhNeVRl -c3RDQTAeFw0xNzExMDIxMzQyNDhaFw0xOTExMDIxMzQyNDhaMC0xGjAYBgNVBAMT -EU1hY0Jvb2stQWlyLmxvY2FsMQ8wDQYDVQQKEwZjbGllbnQwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQC8GptpL25hv1Qa3jCn4VLvDRH/SrHg9wXvqRkz -HuiKMxYT30m4+kcaXv350CJrkV+8lR24wdN7DBVewpCUnyUBbzkLccy1LUzunZ3z -nm37j6cautD3rlC9gsC9d0uJ745FLx5t/6f1jMk9rWxn+4iSGAnkWC3mVaQxP1zQ -q8GI97uob9HNb0OH6ygHJAcKOWB+85a29LIMa1uo/lT3hMr8sBg2vX+1F/gTusmW -xVoQc9XJxBCs995qsH0UkZIuOY0XZp9/qFfcZv2QmslG8DojIIHKcujzu8bItE2M -OyL5NlWLvN6qg59hHzF4+D+T+8GkhhKWSC+xdY14eQ5fB4S5AgMBAAGjLzAtMAkG -A1UdEwQCMAAwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqG -SIb3DQEBCwUAA4IBAQBLV4ZfhiKiFVnL/xO0MRGSKr3xd0LK64SW8Iw5DYkc0jNX -sDrRbj2I/KJ/Rc4AeKT751L+C+KBzYpFgiLrxDmt/5pmgiFH51hPQtL7kRC0z2NY -EY/P+u4IFVSo+b1hHYU7y+OMj6/Vvd4x0ETS4rHWI4mPDfGfvClEVLOktgRKrMU5 -9aTltF4U0FBUlYZTQBNBUFwBzj1+0lxK4EdhRmmWJ+uW9rgkQxpnUdbCPGvUKFRp -3AbdHBAU9H2zVd2VZoJu6r7LMp6agxu0rYLgmamRAt+8rnDXvy7H1ZNdjT6fTbUO -omVBMyJAc1+10gjpHw/EUD58t5/I5tZrnrANPgIs +MIIC5zCCAc+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhNeVRl +c3RDQTAeFw0xOTExMTUwNzI2NThaFw0yMTExMTQwNzI2NThaMCoxFzAVBgNVBAMM +DjAwMDQubm92YWxvY2FsMQ8wDQYDVQQKDAZjbGllbnQwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDcwo5SaoRpzkqy+Y9OADOL7U84h1VFfjb5Uu5raenO +elmHSaCZpVP2EsDUaWavtabHd9fa5Oq6lOyZPDZM6xttfi78EV4RRfEJ4XdvE54W +MZSDAGz4RwxfGOQWBSFyp1NrzT32eqeDSyBrE3jhWx9UUUMwthg5YYjCdBwK+Dwf +hsfS1YeAfXPNO/BGSTe0dPhjLztXe1BkFO5VAwkSXaPs2lBJddOgpTTLXQ3+hIPL +ozkiaTOMOvIMXsCspdhJbSc+jAAGZT5X9Tx7htYbPXIwyDJgeYGmLtr9XxPJ8XGR +rpxkB3zASRcwQzsxTcwkG4E32T53tKsljTkNt15rIoo3AgMBAAGjLzAtMAkGA1Ud +EwQCMAAwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3 +DQEBCwUAA4IBAQBRtQMvUmiB84RmrGwHCP8hcGUWTz03mtTjGrykNA7YQkA09cRl +RwiqYMWh6zHjdX1Ri3m9eIi/QSK/JX3S9zjZU9dSTtsdnMhkRL08kcxauv9gVXCG +G1Vf+lUVJxTqwuAmcLiDNg9/89sSlxQXFS7Jn9TwTvNiRoFoN5IiJ4LsXyr4uS9Y +S4Ul1aqetwpTV8bjpIbRJbOR8qBFshIZOPdgAT3RqbD/vpGzOvvV0c9g3VFLYoK3 +nQ63w1zhwYxC4MQD9rN7JRAKCDQBLNzf8PW0RSG9pVsf1IjaLxtsmQMgrAati/Ux +AG76LAn9sodtb4GtV8E9ITG0pMNlJyUovstS -----END CERTIFICATE----- diff --git a/etc/certs/client-key.pem b/etc/certs/client-key.pem index 008f78481a..ea17598bab 100644 --- a/etc/certs/client-key.pem +++ b/etc/certs/client-key.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/etc/certs/key.pem b/etc/certs/key.pem index 739f39880c..4c80ac6c6d 100644 --- a/etc/certs/key.pem +++ b/etc/certs/key.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/etc/emqx.conf b/etc/emqx.conf index 6f28bf59d6..14414b220d 100644 --- a/etc/emqx.conf +++ b/etc/emqx.conf @@ -417,7 +417,7 @@ log.file = emqx.log ## ## Value: Number ## Default: 10M -## Supported Unit: KB | MB | G +## Supported Unit: KB | MB | GB log.rotation.size = 10MB ## Maximum rotation count of log files. diff --git a/include/emqx.hrl b/include/emqx.hrl index 0a9bd646e2..b68c54b724 100644 --- a/include/emqx.hrl +++ b/include/emqx.hrl @@ -154,15 +154,13 @@ %% Banned %%-------------------------------------------------------------------- --type(banned_who() :: {clientid, binary()} - | {username, binary()} - | {ip_address, inet:ip_address()}). - -record(banned, { - who :: banned_who(), - reason :: binary(), + who :: {clientid, binary()} + | {username, binary()} + | {ip_address, inet:ip_address()}, by :: binary(), - desc :: binary(), + reason :: binary(), + at :: integer(), until :: integer() }). diff --git a/rebar.config b/rebar.config index 85811854a0..46574a1558 100644 --- a/rebar.config +++ b/rebar.config @@ -1,9 +1,11 @@ +{minimum_otp_vsn, "21.0"}. + {deps, - [{jsx, "2.9.0"}, % hex - {cowboy, "2.6.1"}, % hex - {gproc, "0.8.0"}, % hex - {esockd, {git, "https://github.com/emqx/esockd", {tag, "v5.5.2"}}}, - {ekka, {git, "https://github.com/emqx/ekka", {tag, "v0.6.2"}}}, + [{jsx, "2.10.0"}, + {cowboy, "2.7.0"}, + {gproc, "0.8.0"}, + {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.6.0"}}}, + {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.7.1"}}}, {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.4.1"}}}, {cuttlefish, {git, "https://github.com/emqx/cuttlefish", {tag, "v3.0.0"}}} ]}. diff --git a/src/emqx_banned.erl b/src/emqx_banned.erl index e9044c8c1d..6f2a317662 100644 --- a/src/emqx_banned.erl +++ b/src/emqx_banned.erl @@ -33,7 +33,7 @@ -export([start_link/0, stop/0]). -export([ check/1 - , add/1 + , create/1 , delete/1 , info/1 ]). @@ -74,21 +74,39 @@ start_link() -> stop() -> gen_server:stop(?MODULE). -spec(check(emqx_types:clientinfo()) -> boolean()). -check(#{clientid := ClientId, - username := Username, - peerhost := IPAddr}) -> - ets:member(?BANNED_TAB, {clientid, ClientId}) - orelse ets:member(?BANNED_TAB, {username, Username}) - orelse ets:member(?BANNED_TAB, {ipaddr, IPAddr}). - --spec(add(emqx_types:banned()) -> ok). -add(Banned) when is_record(Banned, banned) -> +check(ClientInfo) -> + do_check({clientid, maps:get(clientid, ClientInfo, undefined)}) + orelse do_check({username, maps:get(username, ClientInfo, undefined)}) + orelse do_check({peerhost, maps:get(peerhost, ClientInfo, undefined)}). + +do_check({_, undefined}) -> + false; +do_check(Who) when is_tuple(Who) -> + case mnesia:dirty_read(?BANNED_TAB, Who) of + [] -> false; + [#banned{until = Until}] -> + Until > erlang:system_time(millisecond) + end. + +-spec(create(emqx_types:banned()) -> ok). +create(#{who := Who, + by := By, + reason := Reason, + at := At, + until := Until}) -> + mnesia:dirty_write(?BANNED_TAB, #banned{who = Who, + by = By, + reason = Reason, + at = At, + until = Until}); +create(Banned) when is_record(Banned, banned) -> mnesia:dirty_write(?BANNED_TAB, Banned). -spec(delete({clientid, emqx_types:clientid()} | {username, emqx_types:username()} | {peerhost, emqx_types:peerhost()}) -> ok). -delete(Key) -> mnesia:dirty_delete(?BANNED_TAB, Key). +delete(Who) -> + mnesia:dirty_delete(?BANNED_TAB, Who). info(InfoKey) -> mnesia:table_info(?BANNED_TAB, InfoKey). diff --git a/src/emqx_channel.erl b/src/emqx_channel.erl index d3c15d8dfa..435cba730d 100644 --- a/src/emqx_channel.erl +++ b/src/emqx_channel.erl @@ -219,7 +219,6 @@ handle_in(?CONNECT_PACKET(ConnPkt), Channel) -> fun enrich_client/2, fun set_logger_meta/2, fun check_banned/2, - fun check_flapping/2, fun auth_connect/2], ConnPkt, Channel) of {ok, NConnPkt, NChannel} -> process_connect(NConnPkt, NChannel); @@ -942,7 +941,7 @@ set_logger_meta(_ConnPkt, #channel{clientinfo = #{clientid := ClientId}}) -> emqx_logger:set_metadata_clientid(ClientId). %%-------------------------------------------------------------------- -%% Check banned/flapping +%% Check banned %%-------------------------------------------------------------------- check_banned(_ConnPkt, #channel{clientinfo = ClientInfo = #{zone := Zone}}) -> @@ -951,13 +950,6 @@ check_banned(_ConnPkt, #channel{clientinfo = ClientInfo = #{zone := Zone}}) -> false -> ok end. -check_flapping(_ConnPkt, #channel{clientinfo = ClientInfo = #{zone := Zone}}) -> - case emqx_zone:enable_flapping_detect(Zone) - andalso emqx_flapping:check(ClientInfo) of - true -> {error, ?RC_CONNECTION_RATE_EXCEEDED}; - false -> ok - end. - %%-------------------------------------------------------------------- %% Auth Connect %%-------------------------------------------------------------------- diff --git a/src/emqx_connection.erl b/src/emqx_connection.erl index f8d984e4b0..081adb099a 100644 --- a/src/emqx_connection.erl +++ b/src/emqx_connection.erl @@ -101,7 +101,8 @@ -spec(start_link(esockd:transport(), esockd:socket(), proplists:proplist()) -> {ok, pid()}). start_link(Transport, Socket, Options) -> - CPid = proc_lib:spawn_link(?MODULE, init, [self(), Transport, Socket, Options]), + Args = [self(), Transport, Socket, Options], + CPid = proc_lib:spawn_link(?MODULE, init, Args), {ok, CPid}. %%-------------------------------------------------------------------- @@ -196,7 +197,7 @@ do_init(Parent, Transport, Socket, Options) -> IdleTimeout = emqx_zone:idle_timeout(Zone), IdleTimer = start_timer(IdleTimeout, idle_timeout), emqx_misc:tune_heap_size(emqx_zone:oom_policy(Zone)), - emqx_logger:set_metadata_peername(esockd_net:format(Peername)), + emqx_logger:set_metadata_peername(esockd:format(Peername)), State = #state{transport = Transport, socket = Socket, peername = Peername, @@ -601,7 +602,7 @@ handle_info(Info, State = #state{channel = Channel}) -> %% Ensure rate limit ensure_rate_limit(Stats, State = #state{limiter = Limiter}) -> - case ?ENABLED(limiter) andalso emqx_limiter:check(Stats, Limiter) of + case ?ENABLED(Limiter) andalso emqx_limiter:check(Stats, Limiter) of false -> State; {ok, Limiter1} -> State#state{limiter = Limiter1}; diff --git a/src/emqx_flapping.erl b/src/emqx_flapping.erl index ef1e0e3e93..3d6aabfe91 100644 --- a/src/emqx_flapping.erl +++ b/src/emqx_flapping.erl @@ -27,7 +27,7 @@ -export([start_link/0, stop/0]). %% API --export([check/1, detect/1]). +-export([detect/1]). %% gen_server callbacks -export([ init/1 @@ -54,8 +54,7 @@ clientid :: emqx_types:clientid(), peerhost :: emqx_types:peerhost(), started_at :: pos_integer(), - detect_cnt :: pos_integer(), - banned_at :: pos_integer() + detect_cnt :: pos_integer() }). -opaque(flapping() :: #flapping{}). @@ -68,27 +67,14 @@ start_link() -> stop() -> gen_server:stop(?MODULE). -%% @doc Check flapping when a MQTT client connected. --spec(check(emqx_types:clientinfo()) -> boolean()). -check(#{clientid := ClientId}) -> - check(ClientId, get_policy()). - -check(ClientId, #{banned_interval := Interval}) -> - case ets:lookup(?FLAPPING_TAB, {banned, ClientId}) of - [] -> false; - [#flapping{banned_at = BannedAt}] -> - now_diff(BannedAt) < Interval - end. - %% @doc Detect flapping when a MQTT client disconnected. -spec(detect(emqx_types:clientinfo()) -> boolean()). detect(Client) -> detect(Client, get_policy()). -detect(#{clientid := ClientId, peerhost := PeerHost}, - Policy = #{threshold := Threshold}) -> +detect(#{clientid := ClientId, peerhost := PeerHost}, Policy = #{threshold := Threshold}) -> try ets:update_counter(?FLAPPING_TAB, ClientId, {#flapping.detect_cnt, 1}) of Cnt when Cnt < Threshold -> false; - _Cnt -> case ets:lookup(?FLAPPING_TAB, ClientId) of + _Cnt -> case ets:take(?FLAPPING_TAB, ClientId) of [Flapping] -> ok = gen_server:cast(?MODULE, {detected, Flapping, Policy}), true; @@ -118,52 +104,44 @@ now_diff(TS) -> erlang:system_time(millisecond) - TS. %%-------------------------------------------------------------------- init([]) -> - #{duration := Duration, banned_interval := Interval} = get_policy(), ok = emqx_tables:new(?FLAPPING_TAB, [public, set, {keypos, 2}, {read_concurrency, true}, {write_concurrency, true} ]), - State = #{time => max(Duration, Interval) + 1, tref => undefined}, - {ok, ensure_timer(State), hibernate}. + {ok, #{}, hibernate}. handle_call(Req, _From, State) -> ?LOG(error, "Unexpected call: ~p", [Req]), {reply, ignored, State}. -handle_cast({detected, Flapping = #flapping{clientid = ClientId, - peerhost = PeerHost, - started_at = StartedAt, - detect_cnt = DetectCnt}, - #{duration := Duration}}, State) -> - case (Interval = now_diff(StartedAt)) < Duration of +handle_cast({detected, #flapping{clientid = ClientId, + peerhost = PeerHost, + started_at = StartedAt, + detect_cnt = DetectCnt}, + #{duration := Duration, banned_interval := Interval}}, State) -> + case now_diff(StartedAt) < Duration of true -> %% Flapping happened:( - %% Log first ?LOG(error, "Flapping detected: ~s(~s) disconnected ~w times in ~wms", - [ClientId, esockd_net:ntoa(PeerHost), DetectCnt, Duration]), - %% Banned. - BannedFlapping = Flapping#flapping{clientid = {banned, ClientId}, - banned_at = erlang:system_time(millisecond) - }, - alarm_handler:set_alarm({{flapping_detected, ClientId}, BannedFlapping}), - ets:insert(?FLAPPING_TAB, BannedFlapping); + [ClientId, inet:ntoa(PeerHost), DetectCnt, Duration]), + Now = erlang:system_time(millisecond), + Banned = #banned{who = {clientid, ClientId}, + by = <<"flapping detector">>, + reason = <<"flapping is detected">>, + at = Now, + until = Now + Interval}, + alarm_handler:set_alarm({{flapping_detected, ClientId}, Banned}), + emqx_banned:create(Banned); false -> ?LOG(warning, "~s(~s) disconnected ~w times in ~wms", - [ClientId, esockd_net:ntoa(PeerHost), DetectCnt, Interval]) + [ClientId, inet:ntoa(PeerHost), DetectCnt, Interval]) end, - ets:delete_object(?FLAPPING_TAB, Flapping), {noreply, State}; handle_cast(Msg, State) -> ?LOG(error, "Unexpected cast: ~p", [Msg]), {noreply, State}. -handle_info({timeout, TRef, expire_flapping}, State = #{tref := TRef}) -> - with_flapping_tab(fun expire_flapping/2, - [erlang:system_time(millisecond), - get_policy()]), - {noreply, ensure_timer(State#{tref => undefined}), hibernate}; - handle_info(Info, State) -> ?LOG(error, "Unexpected info: ~p", [Info]), {noreply, State}. @@ -173,34 +151,3 @@ terminate(_Reason, _State) -> code_change(_OldVsn, State, _Extra) -> {ok, State}. - -%%-------------------------------------------------------------------- -%% Internal functions -%%-------------------------------------------------------------------- - -ensure_timer(State = #{time := Time, tref := undefined}) -> - State#{tref => emqx_misc:start_timer(Time, expire_flapping)}; -ensure_timer(State) -> State. - -with_flapping_tab(Fun, Args) -> - case ets:info(?FLAPPING_TAB, size) of - undefined -> ok; - 0 -> ok; - _Size -> erlang:apply(Fun, Args) - end. - -expire_flapping(NowTime, #{duration := Duration, banned_interval := Interval}) -> - case ets:select(?FLAPPING_TAB, - [{#flapping{started_at = '$1', banned_at = undefined, _ = '_'}, - [{'<', '$1', NowTime-Duration}], ['$_']}, - {#flapping{clientid = {banned, '_'}, banned_at = '$1', _ = '_'}, - [{'<', '$1', NowTime-Interval}], ['$_']}]) of - [] -> ok; - Flappings -> - lists:foreach(fun(Flapping = #flapping{clientid = {banned, ClientId}}) -> - ets:delete_object(?FLAPPING_TAB, Flapping), - alarm_handler:clear_alarm({flapping_detected, ClientId}); - (_) -> ok - end, Flappings) - end. - diff --git a/src/emqx_frame.erl b/src/emqx_frame.erl index b402ad9899..91788227b6 100644 --- a/src/emqx_frame.erl +++ b/src/emqx_frame.erl @@ -89,12 +89,12 @@ parse(<<>>, {none, Options}) -> parse(<>, {none, Options = #{strict_mode := StrictMode}}) -> %% Validate header if strict mode. + StrictMode andalso validate_header(Type, Dup, QoS, Retain), Header = #mqtt_packet_header{type = Type, dup = bool(Dup), qos = QoS, retain = bool(Retain) }, - StrictMode andalso validate_header(Type, Dup, QoS, Retain), Header1 = case fixqos(Type, QoS) of QoS -> Header; FixedQoS -> Header#mqtt_packet_header{qos = FixedQoS} @@ -164,7 +164,8 @@ packet(Header, Variable, Payload) -> parse_packet(#mqtt_packet_header{type = ?CONNECT}, FrameBin, _Options) -> {ProtoName, Rest} = parse_utf8_string(FrameBin), <> = Rest, - % Note: Crash when reserved flag doesn't equal to 0, there is no strict compliance with the MQTT5.0. + % Note: Crash when reserved flag doesn't equal to 0, there is no strict + % compliance with the MQTT5.0. < +parse_packet(#mqtt_packet_header{type = ?PUBLISH, qos = QoS}, Bin, + #{strict_mode := StrictMode, version := Ver}) -> {TopicName, Rest} = parse_utf8_string(Bin), {PacketId, Rest1} = case QoS of ?QOS_0 -> {undefined, Rest}; _ -> parse_packet_id(Rest) end, - (PacketId =/= undefined) andalso validate_packet_id(PacketId), + (PacketId =/= undefined) andalso + StrictMode andalso validate_packet_id(PacketId), {Properties, Payload} = parse_properties(Rest1, Ver), Publish = #mqtt_packet_publish{topic_name = TopicName, packet_id = PacketId, @@ -215,15 +218,15 @@ parse_packet(#mqtt_packet_header{type = ?PUBLISH, qos = QoS}, Bin, #{version := }, {Publish, Payload}; -parse_packet(#mqtt_packet_header{type = PubAck}, <>, _Options) - when ?PUBACK =< PubAck, PubAck =< ?PUBCOMP -> - ok = validate_packet_id(PacketId), +parse_packet(#mqtt_packet_header{type = PubAck}, <>, #{strict_mode := StrictMode}) + when ?PUBACK =< PubAck, PubAck =< ?PUBCOMP -> + StrictMode andalso validate_packet_id(PacketId), #mqtt_packet_puback{packet_id = PacketId, reason_code = 0}; parse_packet(#mqtt_packet_header{type = PubAck}, <>, - #{version := Ver = ?MQTT_PROTO_V5}) - when ?PUBACK =< PubAck, PubAck =< ?PUBCOMP -> - ok = validate_packet_id(PacketId), + #{strict_mode := StrictMode, version := Ver = ?MQTT_PROTO_V5}) + when ?PUBACK =< PubAck, PubAck =< ?PUBCOMP -> + StrictMode andalso validate_packet_id(PacketId), {Properties, <<>>} = parse_properties(Rest, Ver), #mqtt_packet_puback{packet_id = PacketId, reason_code = ReasonCode, @@ -231,8 +234,8 @@ parse_packet(#mqtt_packet_header{type = PubAck}, <>, - #{version := Ver}) -> - ok = validate_packet_id(PacketId), + #{strict_mode := StrictMode, version := Ver}) -> + StrictMode andalso validate_packet_id(PacketId), {Properties, Rest1} = parse_properties(Rest, Ver), TopicFilters = parse_topic_filters(subscribe, Rest1), ok = validate_subqos([QoS || {_, #{qos := QoS}} <- TopicFilters]), @@ -242,8 +245,8 @@ parse_packet(#mqtt_packet_header{type = ?SUBSCRIBE}, <>, - #{version := Ver}) -> - ok = validate_packet_id(PacketId), + #{strict_mode := StrictMode, version := Ver}) -> + StrictMode andalso validate_packet_id(PacketId), {Properties, Rest1} = parse_properties(Rest, Ver), ReasonCodes = parse_reason_codes(Rest1), #mqtt_packet_suback{packet_id = PacketId, @@ -252,8 +255,8 @@ parse_packet(#mqtt_packet_header{type = ?SUBACK}, <>, - #{version := Ver}) -> - ok = validate_packet_id(PacketId), + #{strict_mode := StrictMode, version := Ver}) -> + StrictMode andalso validate_packet_id(PacketId), {Properties, Rest1} = parse_properties(Rest, Ver), TopicFilters = parse_topic_filters(unsubscribe, Rest1), #mqtt_packet_unsubscribe{packet_id = PacketId, @@ -261,13 +264,14 @@ parse_packet(#mqtt_packet_header{type = ?UNSUBSCRIBE}, <>, _Options) -> - ok = validate_packet_id(PacketId), +parse_packet(#mqtt_packet_header{type = ?UNSUBACK}, <>, + #{strict_mode := StrictMode}) -> + StrictMode andalso validate_packet_id(PacketId), #mqtt_packet_unsuback{packet_id = PacketId}; parse_packet(#mqtt_packet_header{type = ?UNSUBACK}, <>, - #{version := Ver}) -> - ok = validate_packet_id(PacketId), + #{strict_mode := StrictMode, version := Ver}) -> + StrictMode andalso validate_packet_id(PacketId), {Properties, Rest1} = parse_properties(Rest, Ver), ReasonCodes = parse_reason_codes(Rest1), #mqtt_packet_unsuback{packet_id = PacketId, @@ -296,8 +300,7 @@ parse_will_message(Packet = #mqtt_packet_connect{will_flag = true, will_topic = Topic, will_payload = Payload }, Rest2}; -parse_will_message(Packet, Bin) -> - {Packet, Bin}. +parse_will_message(Packet, Bin) -> {Packet, Bin}. -compile({inline, [parse_packet_id/1]}). parse_packet_id(<>) -> @@ -720,6 +723,7 @@ validate_header(?DISCONNECT, 0, 0, 0) -> ok; validate_header(?AUTH, 0, 0, 0) -> ok; validate_header(_Type, _Dup, _QoS, _Rt) -> error(bad_frame_header). +-compile({inline, [validate_packet_id/1]}). validate_packet_id(0) -> error(bad_packet_id); validate_packet_id(_) -> ok. diff --git a/src/emqx_listeners.erl b/src/emqx_listeners.erl index 036b60e106..afec377d74 100644 --- a/src/emqx_listeners.erl +++ b/src/emqx_listeners.erl @@ -176,5 +176,5 @@ format(Port) when is_integer(Port) -> format({Addr, Port}) when is_list(Addr) -> io_lib:format("~s:~w", [Addr, Port]); format({Addr, Port}) when is_tuple(Addr) -> - io_lib:format("~s:~w", [esockd_net:ntoab(Addr), Port]). + io_lib:format("~s:~w", [inet:ntoa(Addr), Port]). diff --git a/src/emqx_mod_presence.erl b/src/emqx_mod_presence.erl index b1e3ff8b0e..1d63970756 100644 --- a/src/emqx_mod_presence.erl +++ b/src/emqx_mod_presence.erl @@ -112,5 +112,5 @@ reason({Error, _}) when is_atom(Error) -> Error; reason(_) -> internal_error. -compile({inline, [ntoa/1]}). -ntoa(IpAddr) -> iolist_to_binary(esockd_net:ntoa(IpAddr)). +ntoa(IpAddr) -> iolist_to_binary(inet:ntoa(IpAddr)). diff --git a/src/emqx_plugins.erl b/src/emqx_plugins.erl index 4a597fda6c..d170538942 100644 --- a/src/emqx_plugins.erl +++ b/src/emqx_plugins.erl @@ -32,6 +32,10 @@ , load_expand_plugin/1 ]). +-ifdef(TEST). +-compile(export_all). +-compile(nowarn_export_all). +-endif. %%-------------------------------------------------------------------- %% APIs %%-------------------------------------------------------------------- @@ -82,7 +86,7 @@ load_expand_plugin(PluginDir) -> init_expand_plugin_config(PluginDir), Ebin = filename:join([PluginDir, "ebin"]), code:add_patha(Ebin), - Modules = filelib:wildcard(filename:join([Ebin ++ "*.beam"])), + Modules = filelib:wildcard(filename:join([Ebin, "*.beam"])), lists:foreach(fun(Mod) -> Module = list_to_atom(filename:basename(Mod, ".beam")), code:load_file(Module) diff --git a/src/emqx_session.erl b/src/emqx_session.erl index 6879dcc06f..653efc627d 100644 --- a/src/emqx_session.erl +++ b/src/emqx_session.erl @@ -157,7 +157,7 @@ -define(STATS_KEYS, [subscriptions_cnt, subscriptions_max, - inflight, + inflight_cnt, inflight_max, mqueue_len, mqueue_max, diff --git a/src/emqx_sup.erl b/src/emqx_sup.erl index f95e79b6df..915eff9382 100644 --- a/src/emqx_sup.erl +++ b/src/emqx_sup.erl @@ -43,7 +43,7 @@ start_link() -> supervisor:start_link({local, ?SUP}, ?MODULE, []). -spec(start_child(supervisor:child_spec()) -> startchild_ret()). -start_child(ChildSpec) when is_tuple(ChildSpec) -> +start_child(ChildSpec) when is_map(ChildSpec) -> supervisor:start_child(?SUP, ChildSpec). -spec(start_child(module(), worker | supervisor) -> startchild_ret()). diff --git a/src/emqx_sys.erl b/src/emqx_sys.erl index 66c3d2dc10..23a18896bd 100644 --- a/src/emqx_sys.erl +++ b/src/emqx_sys.erl @@ -45,6 +45,11 @@ , terminate/2 ]). +-ifdef(TEST). +-compile(export_all). +-compile(nowarn_export_all). +-endif. + -import(emqx_topic, [systop/1]). -import(emqx_misc, [start_timer/2]). @@ -192,7 +197,7 @@ uptime(hours, H) when H < 24 -> uptime(hours, H) -> [uptime(days, H div 24), integer_to_list(H rem 24), " hours, "]; uptime(days, D) -> - [integer_to_list(D), " days,"]. + [integer_to_list(D), " days, "]. publish(uptime, Uptime) -> safe_publish(systop(uptime), Uptime); diff --git a/src/emqx_sys_mon.erl b/src/emqx_sys_mon.erl index 7d6e5dd6c9..845372ec82 100644 --- a/src/emqx_sys_mon.erl +++ b/src/emqx_sys_mon.erl @@ -177,7 +177,7 @@ suppress(Key, SuccFun, State = #{events := Events}) -> end. procinfo(Pid) -> - case {emqx_vm:get_process_info(Pid), emqx_vm:get_process_gc(Pid)} of + case {emqx_vm:get_process_info(Pid), emqx_vm:get_process_gc_info(Pid)} of {undefined, _} -> undefined; {_, undefined} -> undefined; {Info, GcInfo} -> Info ++ GcInfo diff --git a/src/emqx_vm.erl b/src/emqx_vm.erl index 2fee256332..b59f57b7a6 100644 --- a/src/emqx_vm.erl +++ b/src/emqx_vm.erl @@ -19,6 +19,7 @@ -export([ schedulers/0 , scheduler_usage/1 , microsecs/0 + , system_info_keys/0 , get_system_info/0 , get_system_info/1 , get_memory/0 @@ -26,11 +27,12 @@ , loads/0 ]). --export([ get_process_list/0 +-export([ process_info_keys/0 , get_process_info/0 , get_process_info/1 - , get_process_gc/0 - , get_process_gc/1 + , process_gc_info_keys/0 + , get_process_gc_info/0 + , get_process_gc_info/1 , get_process_group_leader_info/1 , get_process_limit/0 ]). @@ -62,86 +64,83 @@ sl_alloc, ll_alloc, fix_alloc, - std_alloc]). - --define(PROCESS_LIST, [initial_call, - reductions, - memory, - message_queue_len, - current_function]). - --define(PROCESS_INFO, [initial_call, - current_function, - registered_name, - status, - message_queue_len, - group_leader, - priority, - trap_exit, - reductions, - %%binary, - last_calls, - catchlevel, - trace, - suspending, - sequential_trace_token, - error_handler]). - --define(PROCESS_GC, [memory, - total_heap_size, - heap_size, - stack_size, - min_heap_size]). - %fullsweep_after]). - --define(SYSTEM_INFO, [allocated_areas, - allocator, - alloc_util_allocators, - build_type, - check_io, - compat_rel, - creation, - debug_compiled, - dist, - dist_ctrl, - driver_version, - elib_malloc, - dist_buf_busy_limit, - %fullsweep_after, % included in garbage_collection - garbage_collection, - %global_heaps_size, % deprecated - heap_sizes, - heap_type, - info, - kernel_poll, - loaded, - logical_processors, - logical_processors_available, - logical_processors_online, - machine, - %min_heap_size, % included in garbage_collection - %min_bin_vheap_size, % included in garbage_collection - modified_timing_level, - multi_scheduling, - multi_scheduling_blockers, - otp_release, - port_count, - process_count, - process_limit, - scheduler_bind_type, - scheduler_bindings, - scheduler_id, - schedulers, - schedulers_online, - smp_support, - system_version, - system_architecture, - threads, - thread_pool_size, - trace_control_word, - update_cpu_info, - version, - wordsize]). + std_alloc + ]). + +-define(PROCESS_INFO_KEYS, [initial_call, + current_function, + registered_name, + status, + message_queue_len, + group_leader, + priority, + trap_exit, + reductions, + %%binary, + last_calls, + catchlevel, + trace, + suspending, + sequential_trace_token, + error_handler + ]). + +-define(PROCESS_GC_KEYS, [memory, + total_heap_size, + heap_size, + stack_size, + min_heap_size + ]). + +-define(SYSTEM_INFO_KEYS, [allocated_areas, + allocator, + alloc_util_allocators, + build_type, + check_io, + compat_rel, + creation, + debug_compiled, + dist, + dist_ctrl, + driver_version, + elib_malloc, + dist_buf_busy_limit, + %fullsweep_after, % included in garbage_collection + garbage_collection, + %global_heaps_size, % deprecated + heap_sizes, + heap_type, + info, + kernel_poll, + loaded, + logical_processors, + logical_processors_available, + logical_processors_online, + machine, + %min_heap_size, % included in garbage_collection + %min_bin_vheap_size, % included in garbage_collection + modified_timing_level, + multi_scheduling, + multi_scheduling_blockers, + otp_release, + port_count, + process_count, + process_limit, + scheduler_bind_type, + scheduler_bindings, + scheduler_id, + schedulers, + schedulers_online, + smp_support, + system_version, + system_architecture, + threads, + thread_pool_size, + trace_control_word, + update_cpu_info, + version, + wordsize + ]). -define(SOCKET_OPTS, [active, broadcast, @@ -166,7 +165,8 @@ send_timeout, send_timeout_close, sndbuf, - tos]). + tos + ]). schedulers() -> erlang:system_info(schedulers). @@ -178,16 +178,16 @@ microsecs() -> loads() -> [{load1, ftos(avg1()/256)}, {load5, ftos(avg5()/256)}, - {load15, ftos(avg15()/256)}]. + {load15, ftos(avg15()/256)} + ]. + +system_info_keys() -> ?SYSTEM_INFO_KEYS. get_system_info() -> - [{Key, format_system_info(Key, get_system_info(Key))} || Key <- ?SYSTEM_INFO]. + [{Key, format_system_info(Key, get_system_info(Key))} || Key <- ?SYSTEM_INFO_KEYS]. get_system_info(Key) -> - try erlang:system_info(Key) catch - error:badarg->undefined - end. -%% conversion functions for erlang:system_info(Key) + try erlang:system_info(Key) catch error:badarg-> undefined end. format_system_info(allocated_areas, List) -> [convert_allocated_areas(Value) || Value <- List]; @@ -221,8 +221,9 @@ convert_allocated_areas({Key, Value}) -> mem_info() -> Dataset = memsup:get_system_memory_data(), - [{total_memory, proplists:get_value(total_memory, Dataset)}, - {used_memory, proplists:get_value(total_memory, Dataset) - proplists:get_value(free_memory, Dataset)}]. + Total = proplists:get_value(total_memory, Dataset), + Free = proplists:get_value(free_memory, Dataset), + [{total_memory, Total}, {used_memory, Total - Free}]. ftos(F) -> S = io_lib:format("~.2f", [F]), S. @@ -300,24 +301,24 @@ container_value(Props, Pos, Type, Container) -> TypeProps = proplists:get_value(Type, Props), element(Pos, lists:keyfind(Container, 1, TypeProps)). -get_process_list()-> - [get_process_list(Pid) || Pid <- processes()]. - -get_process_list(Pid) when is_pid(Pid) -> - [{pid, Pid} | [process_info(Pid, Key) || Key <- ?PROCESS_LIST]]. +process_info_keys() -> + ?PROCESS_INFO_KEYS. get_process_info() -> - [get_process_info(Pid) || Pid <- processes()]. + get_process_info(self()). get_process_info(Pid) when is_pid(Pid) -> - process_info(Pid, ?PROCESS_INFO). + process_info(Pid, ?PROCESS_INFO_KEYS). + +process_gc_info_keys() -> + ?PROCESS_GC_KEYS. -get_process_gc() -> - [get_process_gc(Pid) || Pid <- processes()]. -get_process_gc(Pid) when is_pid(Pid) -> - process_info(Pid, ?PROCESS_GC). +get_process_gc_info() -> + get_process_gc_info(self()). +get_process_gc_info(Pid) when is_pid(Pid) -> + process_info(Pid, ?PROCESS_GC_KEYS). get_process_group_leader_info(LeaderPid) when is_pid(LeaderPid) -> - [{Key, Value}|| {Key, Value} <- process_info(LeaderPid), lists:member(Key, ?PROCESS_INFO)]. + [{Key, Value}|| {Key, Value} <- process_info(LeaderPid), lists:member(Key, ?PROCESS_INFO_KEYS)]. get_process_limit() -> erlang:system_info(process_limit). @@ -446,8 +447,7 @@ ports_type_count(Types) -> mapping(Entries) -> mapping(Entries, []). -mapping([], Acc) -> - Acc; +mapping([], Acc) -> Acc; mapping([{owner, V}|Entries], Acc) when is_pid(V) -> OwnerInfo = process_info(V), Owner = proplists:get_value(registered_name, OwnerInfo, undefined), @@ -470,10 +470,10 @@ cpu_util() -> compat_windows(Fun) -> case os:type() of {win32, nt} -> 0; - _Other -> handle_error(Fun()) + _Type -> + case catch Fun() of + Val when is_number(Val) -> Val; + _Error -> 0 + end end. -handle_error(Value) when is_number(Value) -> - Value; -handle_error({error, _Reason}) -> - 0. diff --git a/src/emqx_ws_connection.erl b/src/emqx_ws_connection.erl index c700cad194..4e27bd7808 100644 --- a/src/emqx_ws_connection.erl +++ b/src/emqx_ws_connection.erl @@ -218,7 +218,7 @@ websocket_init([Req, Opts]) -> IdleTimeout = emqx_zone:idle_timeout(Zone), IdleTimer = start_timer(IdleTimeout, idle_timeout), emqx_misc:tune_heap_size(emqx_zone:oom_policy(Zone)), - emqx_logger:set_metadata_peername(esockd_net:format(Peername)), + emqx_logger:set_metadata_peername(esockd:format(Peername)), {ok, #state{peername = Peername, sockname = Sockname, sockstate = running, diff --git a/test/emqx_SUITE.erl b/test/emqx_SUITE.erl index b612b100b7..be6ee88330 100644 --- a/test/emqx_SUITE.erl +++ b/test/emqx_SUITE.erl @@ -32,6 +32,13 @@ init_per_suite(Config) -> end_per_suite(_Config) -> emqx_ct_helpers:stop_apps([]). +t_restart(_) -> + ConfFile = "test.config", + Data = "[{emqx_statsd,[{interval,15000},{push_gateway,\"http://127.0.0.1:9091\"}]}].", + file:write_file(ConfFile, list_to_binary(Data)), + emqx:restart(ConfFile), + file:delete(ConfFile). + t_stop_start(_) -> emqx:stop(), false = emqx:is_running(node()), diff --git a/test/emqx_access_control_SUITE.erl b/test/emqx_access_control_SUITE.erl index 53bdba35df..8629c6e28d 100644 --- a/test/emqx_access_control_SUITE.erl +++ b/test/emqx_access_control_SUITE.erl @@ -19,22 +19,52 @@ -compile(export_all). -compile(nowarn_export_all). +-include("emqx_mqtt.hrl"). -include_lib("eunit/include/eunit.hrl"). all() -> emqx_ct:all(?MODULE). -init_per_testcase(_TestCase, Config) -> +init_per_suite(Config) -> + emqx_ct_helpers:boot_modules([router, broker]), + emqx_ct_helpers:start_apps([]), Config. -end_per_testcase(_TestCase, Config) -> - Config. +end_per_suite(_Config) -> + emqx_ct_helpers:stop_apps([]). + +t_authenticate(_) -> + emqx_zone:set_env(zone, allow_anonymous, false), + ?assertMatch({error, _}, emqx_access_control:authenticate(clientinfo())), + emqx_zone:set_env(zone, allow_anonymous, true), + ?assertMatch({ok, _}, emqx_access_control:authenticate(clientinfo())). + +t_check_acl(_) -> + emqx_zone:set_env(zone, acl_nomatch, deny), + application:set_env(emqx, enable_acl_cache, false), + Publish = ?PUBLISH_PACKET(?QOS_0, <<"t">>, 1, <<"payload">>), + ?assertEqual(deny, emqx_access_control:check_acl(clientinfo(), Publish, <<"t">>)), -% t_authenticate(_) -> -% error('TODO'). + emqx_zone:set_env(zone, acl_nomatch, allow), + application:set_env(emqx, enable_acl_cache, true), + Publish = ?PUBLISH_PACKET(?QOS_0, <<"t">>, 1, <<"payload">>), + ?assertEqual(allow, emqx_access_control:check_acl(clientinfo(), Publish, <<"t">>)). -% t_check_acl(_) -> -% error('TODO'). +t_reload_acl(_) -> + ?assertEqual(ok, emqx_access_control:reload_acl()). -% t_reload_acl(_) -> -% error('TODO'). +%%-------------------------------------------------------------------- +%% Helper functions +%%-------------------------------------------------------------------- +clientinfo() -> clientinfo(#{}). +clientinfo(InitProps) -> + maps:merge(#{zone => zone, + protocol => mqtt, + peerhost => {127,0,0,1}, + clientid => <<"clientid">>, + username => <<"username">>, + password => <<"passwd">>, + is_superuser => false, + peercert => undefined, + mountpoint => undefined + }, InitProps). diff --git a/test/emqx_access_rule_SUITE.erl b/test/emqx_access_rule_SUITE.erl index 667df5bc22..ce1b0b8129 100644 --- a/test/emqx_access_rule_SUITE.erl +++ b/test/emqx_access_rule_SUITE.erl @@ -23,15 +23,75 @@ all() -> emqx_ct:all(?MODULE). -init_per_testcase(_TestCase, Config) -> +init_per_suite(Config) -> + emqx_ct_helpers:boot_modules([router, broker]), + emqx_ct_helpers:start_apps([]), Config. -end_per_testcase(_TestCase, Config) -> - Config. +end_per_suite(_Config) -> + emqx_ct_helpers:stop_apps([]). + +t_compile(_) -> + Rule1 = {allow, all, pubsub, <<"%u">>}, + Compile1 = {allow, all, pubsub, [{pattern,[<<"%u">>]}]}, + + Rule2 = {allow, {ipaddr, "127.0.0.1"}, pubsub, <<"%c">>}, + Compile2 = {allow, {ipaddr, {{127,0,0,1}, {127,0,0,1}, 32}}, pubsub, [{pattern,[<<"%c">>]}]}, + + Rule3 = {allow, {'and', [{client, <<"testClient">>}, {user, <<"testUser">>}]}, pubsub, [<<"testTopics1">>, <<"testTopics2">>]}, + Compile3 = {allow, {'and', [{client, <<"testClient">>}, {user, <<"testUser">>}]}, pubsub, [[<<"testTopics1">>], [<<"testTopics2">>]]}, -% t_compile(_) -> -% error('TODO'). + Rule4 = {allow, {'or', [{client, all}, {user, all}]}, pubsub, [ <<"testTopics1">>, <<"testTopics2">>]}, + Compile4 = {allow, {'or', [{client, all}, {user, all}]}, pubsub, [[<<"testTopics1">>], [<<"testTopics2">>]]}, -% t_match(_) -> -% error('TODO'). + ?assertEqual(Compile1, emqx_access_rule:compile(Rule1)), + ?assertEqual(Compile2, emqx_access_rule:compile(Rule2)), + ?assertEqual(Compile3, emqx_access_rule:compile(Rule3)), + ?assertEqual(Compile4, emqx_access_rule:compile(Rule4)). +t_match(_) -> + ClientInfo1 = #{zone => external, + clientid => <<"testClient">>, + username => <<"TestUser">>, + peerhost => {127,0,0,1} + }, + ClientInfo2 = #{zone => external, + clientid => <<"testClient">>, + username => <<"TestUser">>, + peerhost => {192,168,0,10} + }, + ClientInfo3 = #{zone => external, + clientid => <<"testClient">>, + username => <<"TestUser">>, + peerhost => undefined + }, + ?assertEqual({matched, deny}, emqx_access_rule:match([], [], {deny, all})), + ?assertEqual({matched, allow}, emqx_access_rule:match([], [], {allow, all})), + ?assertEqual(nomatch, emqx_access_rule:match(ClientInfo1, <<"Test/Topic">>, + emqx_access_rule:compile({allow, {user, all}, pubsub, []}))), + ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"Test/Topic">>, + emqx_access_rule:compile({allow, {client, all}, pubsub, ["$SYS/#", "#"]}))), + ?assertEqual(nomatch, emqx_access_rule:match(ClientInfo3, <<"Test/Topic">>, + emqx_access_rule:compile({allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}))), + ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"Test/Topic">>, + emqx_access_rule:compile({allow, {ipaddr, "127.0.0.1"}, subscribe, ["$SYS/#", "#"]}))), + ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo2, <<"Test/Topic">>, + emqx_access_rule:compile({allow, {ipaddr, "192.168.0.1/24"}, subscribe, ["$SYS/#", "#"]}))), + ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"d/e/f/x">>, + emqx_access_rule:compile({allow, {user, "TestUser"}, subscribe, ["a/b/c", "d/e/f/#"]}))), + ?assertEqual(nomatch, emqx_access_rule:match(ClientInfo1, <<"d/e/f/x">>, + emqx_access_rule:compile({allow, {user, "admin"}, pubsub, ["d/e/f/#"]}))), + ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"testTopics/testClient">>, + emqx_access_rule:compile({allow, {client, "testClient"}, publish, ["testTopics/testClient"]}))), + ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"clients/testClient">>, + emqx_access_rule:compile({allow, all, pubsub, ["clients/%c"]}))), + ?assertEqual({matched, allow}, emqx_access_rule:match(#{username => <<"user2">>}, <<"users/user2/abc/def">>, + emqx_access_rule:compile({allow, all, subscribe, ["users/%u/#"]}))), + ?assertEqual({matched, deny}, emqx_access_rule:match(ClientInfo1, <<"d/e/f">>, + emqx_access_rule:compile({deny, all, subscribe, ["$SYS/#", "#"]}))), + ?assertEqual(nomatch, emqx_access_rule:match(ClientInfo1, <<"Topic">>, + emqx_access_rule:compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, <<"Topic">>}))), + ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"Topic">>, + emqx_access_rule:compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"TestUser">>}]}, publish, <<"Topic">>}))), + ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"Topic">>, + emqx_access_rule:compile({allow, {'or', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, ["Topic"]}))). diff --git a/test/emqx_banned_SUITE.erl b/test/emqx_banned_SUITE.erl index 7801aea9a1..849bcef90b 100644 --- a/test/emqx_banned_SUITE.erl +++ b/test/emqx_banned_SUITE.erl @@ -38,20 +38,20 @@ end_per_suite(_Config) -> t_add_delete(_) -> Banned = #banned{who = {clientid, <<"TestClient">>}, - reason = <<"test">>, by = <<"banned suite">>, - desc = <<"test">>, + reason = <<"test">>, + at = erlang:system_time(second), until = erlang:system_time(second) + 1000 }, - ok = emqx_banned:add(Banned), + ok = emqx_banned:create(Banned), ?assertEqual(1, emqx_banned:info(size)), ok = emqx_banned:delete({clientid, <<"TestClient">>}), ?assertEqual(0, emqx_banned:info(size)). t_check(_) -> - ok = emqx_banned:add(#banned{who = {clientid, <<"BannedClient">>}}), - ok = emqx_banned:add(#banned{who = {username, <<"BannedUser">>}}), - ok = emqx_banned:add(#banned{who = {ipaddr, {192,168,0,1}}}), + ok = emqx_banned:create(#banned{who = {clientid, <<"BannedClient">>}}), + ok = emqx_banned:create(#banned{who = {username, <<"BannedUser">>}}), + ok = emqx_banned:create(#banned{who = {peerhost, {192,168,0,1}}}), ?assertEqual(3, emqx_banned:info(size)), ClientInfo1 = #{clientid => <<"BannedClient">>, username => <<"user">>, @@ -75,7 +75,7 @@ t_check(_) -> ?assertNot(emqx_banned:check(ClientInfo4)), ok = emqx_banned:delete({clientid, <<"BannedClient">>}), ok = emqx_banned:delete({username, <<"BannedUser">>}), - ok = emqx_banned:delete({ipaddr, {192,168,0,1}}), + ok = emqx_banned:delete({peerhost, {192,168,0,1}}), ?assertNot(emqx_banned:check(ClientInfo1)), ?assertNot(emqx_banned:check(ClientInfo2)), ?assertNot(emqx_banned:check(ClientInfo3)), @@ -84,9 +84,8 @@ t_check(_) -> t_unused(_) -> {ok, Banned} = emqx_banned:start_link(), - ok = emqx_banned:add(#banned{who = {clientid, <<"BannedClient">>}, - until = erlang:system_time(second) - }), + ok = emqx_banned:create(#banned{who = {clientid, <<"BannedClient">>}, + until = erlang:system_time(second)}), ?assertEqual(ignored, gen_server:call(Banned, unexpected_req)), ?assertEqual(ok, gen_server:cast(Banned, unexpected_msg)), ?assertEqual(ok, Banned ! ok), diff --git a/test/emqx_channel_SUITE.erl b/test/emqx_channel_SUITE.erl index 7887eeca37..2c8bece494 100644 --- a/test/emqx_channel_SUITE.erl +++ b/test/emqx_channel_SUITE.erl @@ -495,9 +495,6 @@ t_enrich_client(_) -> t_check_banned(_) -> ok = emqx_channel:check_banned(connpkt(), channel()). -t_check_flapping(_) -> - ok = emqx_channel:check_flapping(connpkt(), channel()). - t_auth_connect(_) -> {ok, _Chan} = emqx_channel:auth_connect(connpkt(), channel()). diff --git a/test/emqx_cm_locker_SUITE.erl b/test/emqx_cm_locker_SUITE.erl index f476c99ac5..47b197a2a0 100644 --- a/test/emqx_cm_locker_SUITE.erl +++ b/test/emqx_cm_locker_SUITE.erl @@ -23,21 +23,23 @@ all() -> emqx_ct:all(?MODULE). -init_per_testcase(_TestCase, Config) -> +init_per_suite(Config) -> + emqx_ct_helpers:boot_modules(all), + emqx_ct_helpers:start_apps([]), Config. -end_per_testcase(_TestCase, Config) -> - Config. - -% t_start_link(_) -> -% error('TODO'). - -% t_trans(_) -> -% error('TODO'). +end_per_suite(_Config) -> + emqx_ct_helpers:stop_apps([]). -% t_lock(_) -> -% error('TODO'). +t_start_link(_) -> + emqx_cm_locker:start_link(). -% t_unlock(_) -> -% error('TODO'). +t_trans(_) -> + ok = emqx_cm_locker:trans(undefined, fun(_) -> ok end, []), + ok = emqx_cm_locker:trans(<<"clientid">>, fun(_) -> ok end). +t_lock_unlocak(_) -> + {true, _Nodes} = emqx_cm_locker:lock(<<"clientid">>), + {true, _Nodes} = emqx_cm_locker:lock(<<"clientid">>), + {true, _Nodes} = emqx_cm_locker:unlock(<<"clientid">>), + {true, _Nodes} = emqx_cm_locker:unlock(<<"clientid">>). diff --git a/test/emqx_flapping_SUITE.erl b/test/emqx_flapping_SUITE.erl index a9234c5419..e860d57038 100644 --- a/test/emqx_flapping_SUITE.erl +++ b/test/emqx_flapping_SUITE.erl @@ -45,13 +45,13 @@ t_detect_check(_) -> peerhost => {127,0,0,1} }, false = emqx_flapping:detect(ClientInfo), - false = emqx_flapping:check(ClientInfo), + false = emqx_banned:check(ClientInfo), false = emqx_flapping:detect(ClientInfo), - false = emqx_flapping:check(ClientInfo), + false = emqx_banned:check(ClientInfo), true = emqx_flapping:detect(ClientInfo), timer:sleep(100), - true = emqx_flapping:check(ClientInfo), - timer:sleep(300), - false = emqx_flapping:check(ClientInfo), + true = emqx_banned:check(ClientInfo), + timer:sleep(200), + false = emqx_banned:check(ClientInfo), ok = emqx_flapping:stop(). diff --git a/test/emqx_frame_SUITE.erl b/test/emqx_frame_SUITE.erl index f70a815fe3..35e8d1975a 100644 --- a/test/emqx_frame_SUITE.erl +++ b/test/emqx_frame_SUITE.erl @@ -40,7 +40,8 @@ all() -> {group, unsuback}, {group, ping}, {group, disconnect}, - {group, auth}]. + {group, auth} + ]. groups() -> [{parse, [parallel], @@ -333,7 +334,10 @@ t_serialize_parse_qos1_publish(_) -> payload = <<"haha">>}, ?assertEqual(Bin, serialize_to_binary(Packet)), ?assertMatch(Packet, parse_to_packet(Bin, #{strict_mode => true})), - ?catch_error(bad_packet_id, parse_serialize(?PUBLISH_PACKET(?QOS_1, <<"Topic">>, 0, <<>>))). + %% strict_mode = true + ?catch_error(bad_packet_id, parse_serialize(?PUBLISH_PACKET(?QOS_1, <<"Topic">>, 0, <<>>))), + %% strict_mode = false + _ = parse_serialize(?PUBLISH_PACKET(?QOS_1, <<"Topic">>, 0, <<>>), #{strict_mode => false}). t_serialize_parse_qos2_publish(_) -> Packet = ?PUBLISH_PACKET(?QOS_2, <<"Topic">>, 1, <<>>), @@ -341,7 +345,10 @@ t_serialize_parse_qos2_publish(_) -> ?assertEqual(Packet, parse_serialize(Packet)), ?assertEqual(Bin, serialize_to_binary(Packet)), ?assertMatch(Packet, parse_to_packet(Bin, #{strict_mode => true})), - ?catch_error(bad_packet_id, parse_serialize(?PUBLISH_PACKET(?QOS_2, <<"Topic">>, 0, <<>>))). + %% strict_mode = true + ?catch_error(bad_packet_id, parse_serialize(?PUBLISH_PACKET(?QOS_2, <<"Topic">>, 0, <<>>))), + %% strict_mode = false + _ = parse_serialize(?PUBLISH_PACKET(?QOS_2, <<"Topic">>, 0, <<>>), #{strict_mode => false}). t_serialize_parse_publish_v5(_) -> Props = #{'Payload-Format-Indicator' => 1, @@ -358,7 +365,10 @@ t_serialize_parse_puback(_) -> Packet = ?PUBACK_PACKET(1), ?assertEqual(<<64,2,0,1>>, serialize_to_binary(Packet)), ?assertEqual(Packet, parse_serialize(Packet)), - ?catch_error(bad_packet_id, parse_serialize(?PUBACK_PACKET(0))). + %% strict_mode = true + ?catch_error(bad_packet_id, parse_serialize(?PUBACK_PACKET(0))), + %% strict_mode = false + ?PUBACK_PACKET(0) = parse_serialize(?PUBACK_PACKET(0), #{strict_mode => false}). t_serialize_parse_puback_v3_4(_) -> Bin = <<64,2,0,1>>, @@ -376,7 +386,10 @@ t_serialize_parse_pubrec(_) -> Packet = ?PUBREC_PACKET(1), ?assertEqual(<<5:4,0:4,2,0,1>>, serialize_to_binary(Packet)), ?assertEqual(Packet, parse_serialize(Packet)), - ?catch_error(bad_packet_id, parse_serialize(?PUBREC_PACKET(0))). + %% strict_mode = true + ?catch_error(bad_packet_id, parse_serialize(?PUBREC_PACKET(0))), + %% strict_mode = false + ?PUBREC_PACKET(0) = parse_serialize(?PUBREC_PACKET(0), #{strict_mode => false}). t_serialize_parse_pubrec_v5(_) -> Packet = ?PUBREC_PACKET(16, ?RC_SUCCESS, #{'Reason-String' => <<"success">>}), @@ -391,6 +404,9 @@ t_serialize_parse_pubrel(_) -> Bin0 = <<6:4,0:4,2,0,1>>, ?assertMatch(Packet, parse_to_packet(Bin0, #{strict_mode => false})), ?catch_error(bad_frame_header, parse_to_packet(Bin0, #{strict_mode => true})), + %% strict_mode = false + ?PUBREL_PACKET(0) = parse_serialize(?PUBREL_PACKET(0), #{strict_mode => false}), + %% strict_mode = true ?catch_error(bad_packet_id, parse_serialize(?PUBREL_PACKET(0))). t_serialize_parse_pubrel_v5(_) -> @@ -402,6 +418,9 @@ t_serialize_parse_pubcomp(_) -> Bin = serialize_to_binary(Packet), ?assertEqual(<<7:4,0:4,2,0,1>>, Bin), ?assertEqual(Packet, parse_serialize(Packet)), + %% strict_mode = false + ?PUBCOMP_PACKET(0) = parse_serialize(?PUBCOMP_PACKET(0), #{strict_mode => false}), + %% strict_mode = true ?catch_error(bad_packet_id, parse_serialize(?PUBCOMP_PACKET(0))). t_serialize_parse_pubcomp_v5(_) -> @@ -419,7 +438,12 @@ t_serialize_parse_subscribe(_) -> %% SUBSCRIBE with bad qos 0 Bin0 = <>, ?assertMatch(Packet, parse_to_packet(Bin0, #{strict_mode => false})), + %% strict_mode = false + _ = parse_to_packet(Bin0, #{strict_mode => false}), ?catch_error(bad_frame_header, parse_to_packet(Bin0, #{strict_mode => true})), + %% strict_mode = false + _ = parse_serialize(?SUBSCRIBE_PACKET(0, TopicFilters), #{strict_mode => false}), + %% strict_mode = true ?catch_error(bad_packet_id, parse_serialize(?SUBSCRIBE_PACKET(0, TopicFilters))), ?catch_error(bad_subqos, parse_serialize(?SUBSCRIBE_PACKET(1, [{<<"t">>, #{qos => 3}}]))). @@ -432,6 +456,9 @@ t_serialize_parse_subscribe_v5(_) -> t_serialize_parse_suback(_) -> Packet = ?SUBACK_PACKET(10, [?QOS_0, ?QOS_1, 128]), ?assertEqual(Packet, parse_serialize(Packet)), + %% strict_mode = false + _ = parse_serialize(?SUBACK_PACKET(0, [?QOS_0]), #{strict_mode => false}), + %% strict_mode = true ?catch_error(bad_packet_id, parse_serialize(?SUBACK_PACKET(0, [?QOS_0]))). t_serialize_parse_suback_v5(_) -> @@ -451,6 +478,9 @@ t_serialize_parse_unsubscribe(_) -> Bin0 = <>, ?assertMatch(Packet, parse_to_packet(Bin0, #{strict_mode => false})), ?catch_error(bad_frame_header, parse_to_packet(Bin0, #{strict_mode => true})), + %% strict_mode = false + _ = parse_serialize(?UNSUBSCRIBE_PACKET(0, [<<"TopicA">>]), #{strict_mode => false}), + %% strict_mode = true ?catch_error(bad_packet_id, parse_serialize(?UNSUBSCRIBE_PACKET(0, [<<"TopicA">>]))). t_serialize_parse_unsubscribe_v5(_) -> diff --git a/test/emqx_misc_SUITE.erl b/test/emqx_misc_SUITE.erl index cb7661a3e1..f8462a7c12 100644 --- a/test/emqx_misc_SUITE.erl +++ b/test/emqx_misc_SUITE.erl @@ -138,3 +138,12 @@ drain(Acc) -> lists:reverse(Acc) end. +t_rand_seed(_) -> + ?assert(is_tuple(emqx_misc:rand_seed())). + +t_now_to_secs(_) -> + ?assert(is_integer(emqx_misc:now_to_secs(os:timestamp()))). + +t_now_to_ms(_) -> + ?assert(is_integer(emqx_misc:now_to_ms(os:timestamp()))). + diff --git a/test/emqx_mod_acl_internal_SUITE.erl b/test/emqx_mod_acl_internal_SUITE.erl index 05b406f7a8..e854fb8313 100644 --- a/test/emqx_mod_acl_internal_SUITE.erl +++ b/test/emqx_mod_acl_internal_SUITE.erl @@ -19,28 +19,53 @@ -compile(export_all). -compile(nowarn_export_all). +-include("emqx_mqtt.hrl"). -include_lib("eunit/include/eunit.hrl"). all() -> emqx_ct:all(?MODULE). -init_per_testcase(_TestCase, Config) -> +init_per_suite(Config) -> + emqx_ct_helpers:boot_modules(all), + emqx_ct_helpers:start_apps([emqx]), Config. -end_per_testcase(_TestCase, Config) -> - Config. +end_per_suite(_Config) -> + emqx_ct_helpers:stop_apps([emqx]). + +t_load_unload(_) -> + ?assertEqual({error,already_exists}, emqx_mod_acl_internal:load([])), + ?assertEqual(ok, emqx_mod_acl_internal:unload([])), + ?assertEqual(ok, emqx_mod_acl_internal:load([])). -% t_load(_) -> -% error('TODO'). +t_all_rules(_) -> + application:set_env(emqx, acl_file, ""), + ?assertMatch(#{}, emqx_mod_acl_internal:all_rules()), -% t_unload(_) -> -% error('TODO'). + application:set_env(emqx, acl_file, emqx_ct_helpers:deps_path(emqx, "etc/acl.conf")), + ?assertMatch(#{publish := _, subscribe := _}, emqx_mod_acl_internal:all_rules()). -% t_all_rules(_) -> -% error('TODO'). +t_check_acl(_) -> + Rules=#{publish => [{allow,all}], subscribe => [{deny, all}]}, + ?assertEqual({ok, allow}, emqx_mod_acl_internal:check_acl(clientinfo(), publish, <<"t">>, [], Rules)), + ?assertEqual({ok, deny}, emqx_mod_acl_internal:check_acl(clientinfo(), subscribe, <<"t">>, [], Rules)), + ?assertEqual(ok, emqx_mod_acl_internal:check_acl(clientinfo(), connect, <<"t">>, [], Rules)). -% t_check_acl(_) -> -% error('TODO'). +t_reload_acl(_) -> + ?assertEqual(ok, emqx_mod_acl_internal:reload_acl()). -% t_reload_acl(_) -> -% error('TODO'). +%%-------------------------------------------------------------------- +%% Helper functions +%%-------------------------------------------------------------------- +clientinfo() -> clientinfo(#{}). +clientinfo(InitProps) -> + maps:merge(#{zone => zone, + protocol => mqtt, + peerhost => {127,0,0,1}, + clientid => <<"clientid">>, + username => <<"username">>, + password => <<"passwd">>, + is_superuser => false, + peercert => undefined, + mountpoint => undefined + }, InitProps). diff --git a/test/emqx_mod_subscription_SUITE.erl b/test/emqx_mod_subscription_SUITE.erl index ed5acc3d60..644e303dd7 100644 --- a/test/emqx_mod_subscription_SUITE.erl +++ b/test/emqx_mod_subscription_SUITE.erl @@ -19,22 +19,44 @@ -compile(export_all). -compile(nowarn_export_all). +-include("emqx_mqtt.hrl"). -include_lib("eunit/include/eunit.hrl"). all() -> emqx_ct:all(?MODULE). -init_per_testcase(_TestCase, Config) -> +init_per_suite(Config) -> + emqx_ct_helpers:boot_modules(all), + emqx_ct_helpers:start_apps([emqx]), Config. -end_per_testcase(_TestCase, Config) -> - Config. +end_per_suite(_Config) -> + emqx_ct_helpers:stop_apps([emqx]). + +t_load(_) -> + ?assertEqual(ok, emqx_mod_subscription:load([{<<"connected/%c/%u">>, ?QOS_0}])). + +t_on_client_connected(_) -> + {ok, C} = emqtt:start_link([{host, "localhost"}, + {clientid, "myclient"}, + {username, "admin"}]), + {ok, _} = emqtt:connect(C), + emqtt:publish(C, <<"connected/myclient/admin">>, <<"Hello world">>, ?QOS_0), + {ok, #{topic := Topic, payload := Payload}} = receive_publish(100), + ?assertEqual(<<"connected/myclient/admin">>, Topic), + ?assertEqual(<<"Hello world">>, Payload), + ok = emqtt:disconnect(C). -% t_load(_) -> -% error('TODO'). +t_unload(_) -> + ?assertEqual(ok, emqx_mod_subscription:unload([{<<"connected/%c/%u">>, ?QOS_0}])). -% t_on_client_connected(_) -> -% error('TODO'). +%%-------------------------------------------------------------------- +%% Internal functions +%%-------------------------------------------------------------------- -% t_unload(_) -> -% error('TODO'). +receive_publish(Timeout) -> + receive + {publish, Publish} -> {ok, Publish} + after + Timeout -> {error, timeout} + end. diff --git a/test/emqx_plugins_SUITE.erl b/test/emqx_plugins_SUITE.erl index 402a0887ae..29d3d5964b 100644 --- a/test/emqx_plugins_SUITE.erl +++ b/test/emqx_plugins_SUITE.erl @@ -19,6 +19,7 @@ -compile(export_all). -compile(nowarn_export_all). +-include("emqx.hrl"). -include_lib("eunit/include/eunit.hrl"). all() -> emqx_ct:all(?MODULE). @@ -30,7 +31,7 @@ init_per_suite(Config) -> DataPath = proplists:get_value(data_dir, Config), AppPath = filename:join([DataPath, "emqx_mini_plugin"]), - Cmd = lists:flatten(io_lib:format("cd ~s && make", [AppPath])), + Cmd = lists:flatten(io_lib:format("cd ~s && make && cp -r etc _build/default/lib/emqx_mini_plugin/", [AppPath])), ct:pal("Executing ~s~n", [Cmd]), ct:pal("~n ~s~n", [os:cmd(Cmd)]), @@ -43,21 +44,6 @@ init_per_suite(Config) -> Config. -% t_load_expand_plugin(_) -> -% error('TODO'). - -% t_list(_) -> -% error('TODO'). - -% t_find_plugin(_) -> -% error('TODO'). - -% t_unload(_) -> -% error('TODO'). - -% t_init(_) -> -% error('TODO'). - set_sepecial_cfg(_) -> ExpandPath = filename:dirname(code:lib_dir(emqx_mini_plugin)), @@ -69,8 +55,92 @@ end_per_suite(_Config) -> emqx_ct_helpers:stop_apps([]). t_load(_) -> - {error, load_app_fail} = emqx_plugins:load_expand_plugin("./not_existed_path/"), + ?assertEqual([], emqx_plugins:load()), + ?assertEqual([], emqx_plugins:unload()), + + ?assertEqual({error, not_found}, emqx_plugins:load(not_existed_plugin)), + ?assertMatch({ok, _}, emqx_plugins:load(emqx_mini_plugin)), + ?assertEqual({error, already_started}, emqx_plugins:load(emqx_mini_plugin)), + ?assertEqual(ok, emqx_plugins:unload(emqx_mini_plugin)), + ?assertEqual({error, not_started}, emqx_plugins:unload(emqx_mini_plugin)), + + application:set_env(emqx, expand_plugins_dir, undefined), + application:set_env(emqx, plugins_loaded_file, undefined), + ?assertEqual(ignore, emqx_plugins:load()), + ?assertEqual(ignore, emqx_plugins:unload()). + + +t_init_config(_) -> + ConfFile = "emqx_mini_plugin.config", + Data = "[{emqx_mini_plugin,[{mininame ,test}]}].", + file:write_file(ConfFile, list_to_binary(Data)), + ?assertEqual(ok, emqx_plugins:init_config(ConfFile)), + file:delete(ConfFile), + ?assertEqual({ok,test}, application:get_env(emqx_mini_plugin, mininame)). + +t_load_expand_plugin(_) -> + ?assertEqual({error, load_app_fail}, emqx_plugins:load_expand_plugin("./not_existed_path/")). + +t_list(_) -> + ?assertMatch([{plugin, _, _, _, _, _, _, _, _} | _ ], emqx_plugins:list()). + +t_find_plugin(_) -> + ?assertMatch({plugin, emqx_mini_plugin, _, _, _, _, _, _, _}, emqx_plugins:find_plugin(emqx_mini_plugin)). + +t_plugin_type(_) -> + ?assertEqual(auth, emqx_plugins:plugin_type(auth)), + ?assertEqual(protocol, emqx_plugins:plugin_type(protocol)), + ?assertEqual(backend, emqx_plugins:plugin_type(backend)), + ?assertEqual(bridge, emqx_plugins:plugin_type(bridge)), + ?assertEqual(feature, emqx_plugins:plugin_type(undefined)). + +t_with_loaded_file(_) -> + ?assertMatch({error, _}, emqx_plugins:with_loaded_file("./not_existed_path/", fun(_) -> ok end)). + +t_plugin_loaded(_) -> + ?assertEqual(ok, emqx_plugins:plugin_loaded(emqx_mini_plugin, false)), + ?assertEqual(ok, emqx_plugins:plugin_loaded(emqx_mini_plugin, true)). + +t_plugin_unloaded(_) -> + ?assertEqual(ok, emqx_plugins:plugin_unloaded(emqx_mini_plugin, false)), + ?assertEqual(ok, emqx_plugins:plugin_unloaded(emqx_mini_plugin, true)). + +t_plugin(_) -> + try + emqx_plugins:plugin(not_existed_plugin, undefined) + catch + _Error:Reason:_Stacktrace -> + ?assertEqual({plugin_not_found,not_existed_plugin}, Reason) + end, + ?assertMatch({plugin, emqx_mini_plugin, _, _, _, _, _, _, _}, emqx_plugins:plugin(emqx_mini_plugin, undefined)). + +t_filter_plugins(_) -> + ?assertEqual([name1, name2], emqx_plugins:filter_plugins([name1, {name2,true}, {name3, false}])). + +t_load_plugin(_) -> + ok = meck:new(application, [unstick, non_strict, passthrough, no_history]), + ok = meck:expect(application, load, fun(already_loaded_app) -> {error, {already_loaded, already_loaded_app}}; + (error_app) -> {error, error}; + (_) -> ok end), + ok = meck:expect(application, ensure_all_started, fun(already_loaded_app) -> {error, {already_loaded_app, already_loaded}}; + (error_app) -> {error, error}; + (App) -> {ok, App} end), + + ?assertMatch({error, _}, emqx_plugins:load_plugin(#plugin{name = already_loaded_app}, true)), + ?assertMatch({ok, _}, emqx_plugins:load_plugin(#plugin{name = normal}, true)), + ?assertMatch({error,_}, emqx_plugins:load_plugin(#plugin{name = error_app}, true)), + + ok = meck:unload(application). + +t_unload_plugin(_) -> + ok = meck:new(application, [unstick, non_strict, passthrough, no_history]), + ok = meck:expect(application, stop, fun(not_started_app) -> {error, {not_started, not_started_app}}; + (error_app) -> {error, error}; + (_) -> ok end), + + ?assertEqual(ok, emqx_plugins:unload_plugin(not_started_app, true)), + ?assertEqual(ok, emqx_plugins:unload_plugin(normal, true)), + ?assertEqual({error,error}, emqx_plugins:unload_plugin(error_app, true)), + + ok = meck:unload(application). - {error, not_started} = emqx_plugins:unload(emqx_mini_plugin), - {ok, _} = emqx_plugins:load(emqx_mini_plugin), - ok = emqx_plugins:unload(emqx_mini_plugin). diff --git a/test/emqx_shared_sub_SUITE.erl b/test/emqx_shared_sub_SUITE.erl index 23b2828320..dcaa8b32cf 100644 --- a/test/emqx_shared_sub_SUITE.erl +++ b/test/emqx_shared_sub_SUITE.erl @@ -29,6 +29,9 @@ emqx_ct_helpers:wait_for( ?FUNCTION_NAME, ?LINE, fun() -> For end, Timeout)). +-define(ack, shared_sub_ack). +-define(no_ack, no_ack). + all() -> emqx_ct:all(?SUITE). init_per_suite(Config) -> @@ -39,17 +42,22 @@ init_per_suite(Config) -> end_per_suite(_Config) -> emqx_ct_helpers:stop_apps([]). -% t_is_ack_required(_) -> -% error('TODO'). +t_is_ack_required(_) -> + ?assertEqual(false, emqx_shared_sub:is_ack_required(#message{headers = #{}})). -% t_maybe_nack_dropped(_) -> -% error('TODO'). +t_maybe_nack_dropped(_) -> + ?assertEqual(ok, emqx_shared_sub:maybe_nack_dropped(#message{headers = #{}})), + ?assertEqual(ok, emqx_shared_sub:maybe_nack_dropped(#message{headers = #{shared_dispatch_ack => {self(), for_test}}})), + ?assertEqual(ok,receive {for_test, {shared_sub_nack, dropped}} -> ok after 100 -> timeout end). -% t_nack_no_connection(_) -> -% error('TODO'). +t_nack_no_connection(_) -> + ?assertEqual(ok, emqx_shared_sub:nack_no_connection(#message{headers = #{shared_dispatch_ack => {self(), for_test}}})), + ?assertEqual(ok,receive {for_test, {shared_sub_nack, no_connection}} -> ok after 100 -> timeout end). -% t_maybe_ack(_) -> -% error('TODO'). +t_maybe_ack(_) -> + ?assertEqual(#message{headers = #{}}, emqx_shared_sub:maybe_ack(#message{headers = #{}})), + ?assertEqual(#message{headers = #{shared_dispatch_ack => ?no_ack}}, emqx_shared_sub:maybe_ack(#message{headers = #{shared_dispatch_ack => {self(), for_test}}})), + ?assertEqual(ok,receive {for_test, ?ack} -> ok after 100 -> timeout end). % t_subscribers(_) -> % error('TODO'). @@ -239,14 +247,23 @@ last_message(ExpectedPayload, Pids) -> <<"not yet?">> end. -% t_dispatch(_) -> -% error('TODO'). +t_dispatch(_) -> + ok = ensure_config(random), + Topic = <<"foo">>, + ?assertEqual({error, no_subscribers}, emqx_shared_sub:dispatch(<<"group1">>, Topic, #delivery{message = #message{}})), + emqx:subscribe(Topic, #{qos => 2, share => <<"group1">>}), + ?assertEqual(ok, emqx_shared_sub:dispatch(<<"group1">>, Topic, #delivery{message = #message{}})). % t_unsubscribe(_) -> % error('TODO'). % t_subscribe(_) -> % error('TODO'). +t_uncovered_func(_) -> + ignored = gen_server:call(emqx_shared_sub, ignored), + ok = gen_server:cast(emqx_shared_sub, ignored), + ignored = emqx_shared_sub ! ignored, + {mnesia_table_event, []} = emqx_shared_sub ! {mnesia_table_event, []}. %%-------------------------------------------------------------------- %% help functions diff --git a/test/emqx_sup_SUITE.erl b/test/emqx_sup_SUITE.erl new file mode 100644 index 0000000000..4d2386bde2 --- /dev/null +++ b/test/emqx_sup_SUITE.erl @@ -0,0 +1,39 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2019 EMQ Technologies Co., Ltd. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +-module(emqx_sup_SUITE). + +-compile(export_all). +-compile(nowarn_export_all). + +-include_lib("eunit/include/eunit.hrl"). + +all() -> emqx_ct:all(?MODULE). + +init_per_suite(Config) -> + emqx_ct_helpers:boot_modules(all), + emqx_ct_helpers:start_apps([]), + Config. + +end_per_suite(_Config) -> + emqx_ct_helpers:stop_apps([]). + +t_child(_) -> + ?assertMatch({error, _}, emqx_sup:start_child(undef, worker)), + ?assertMatch({error, not_found}, emqx_sup:stop_child(undef)), + ?assertMatch({error, _}, emqx_sup:start_child(emqx_broker_sup, supervisor)), + ?assertEqual(ok, emqx_sup:stop_child(emqx_broker_sup)), + ?assertMatch({ok, _}, emqx_sup:start_child(emqx_broker_sup, supervisor)). \ No newline at end of file diff --git a/test/emqx_sys_SUITE.erl b/test/emqx_sys_SUITE.erl index ff86459369..dc8c1e865c 100644 --- a/test/emqx_sys_SUITE.erl +++ b/test/emqx_sys_SUITE.erl @@ -49,8 +49,11 @@ end_per_suite(_Config) -> % t_sysdescr(_) -> % error('TODO'). -% t_uptime(_) -> -% error('TODO'). +t_uptime(_) -> + ?assertEqual(<<"1 seconds">>, iolist_to_binary(emqx_sys:uptime(seconds, 1))), + ?assertEqual(<<"1 minutes, 0 seconds">>, iolist_to_binary(emqx_sys:uptime(seconds, 60))), + ?assertEqual(<<"1 hours, 0 minutes, 0 seconds">>, iolist_to_binary(emqx_sys:uptime(seconds, 3600))), + ?assertEqual(<<"1 days, 0 hours, 0 minutes, 0 seconds">>, iolist_to_binary(emqx_sys:uptime(seconds, 86400))). % t_datetime(_) -> % error('TODO'). diff --git a/test/emqx_sys_mon_SUITE.erl b/test/emqx_sys_mon_SUITE.erl index 99b63ae7fc..55644ecfef 100644 --- a/test/emqx_sys_mon_SUITE.erl +++ b/test/emqx_sys_mon_SUITE.erl @@ -69,11 +69,25 @@ init_per_testcase(t_sys_mon2, Config) -> ok; (_) -> ok end), + Config; +init_per_testcase(_, Config) -> + emqx_ct_helpers:boot_modules(all), + emqx_ct_helpers:start_apps([]), Config. end_per_testcase(_, _Config) -> emqx_ct_helpers:stop_apps([]). +t_procinfo(_) -> + ok = meck:new(emqx_vm, [passthrough, no_history]), + ok = meck:expect(emqx_vm, get_process_info, fun(_) -> [] end), + ok = meck:expect(emqx_vm, get_process_gc_info, fun(_) -> [] end), + ?assertEqual([], emqx_sys_mon:procinfo([])), + ok = meck:expect(emqx_vm, get_process_info, fun(_) -> ok end), + ok = meck:expect(emqx_vm, get_process_gc_info, fun(_) -> undefined end), + ?assertEqual(undefined, emqx_sys_mon:procinfo([])), + ok = meck:unload(emqx_vm). + t_sys_mon(_Config) -> lists:foreach( fun({PidOrPort, SysMonName,ValidateInfo, InfoOrPort}) -> diff --git a/test/emqx_vm_SUITE.erl b/test/emqx_vm_SUITE.erl index 1fa1cacbff..6ed6e65225 100644 --- a/test/emqx_vm_SUITE.erl +++ b/test/emqx_vm_SUITE.erl @@ -21,115 +21,29 @@ -include_lib("eunit/include/eunit.hrl"). --define(SYSTEM_INFO, [allocated_areas, - allocator, - alloc_util_allocators, - build_type, - check_io, - compat_rel, - creation, - debug_compiled, - dist, - dist_ctrl, - driver_version, - elib_malloc, - dist_buf_busy_limit, - %fullsweep_after, % included in garbage_collection - garbage_collection, - %global_heaps_size, % deprecated - heap_sizes, - heap_type, - info, - kernel_poll, - loaded, - logical_processors, - logical_processors_available, - logical_processors_online, - machine, - %min_heap_size, % included in garbage_collection - %min_bin_vheap_size, % included in garbage_collection - modified_timing_level, - multi_scheduling, - multi_scheduling_blockers, - otp_release, - port_count, - process_count, - process_limit, - scheduler_bind_type, - scheduler_bindings, - scheduler_id, - schedulers, - schedulers_online, - smp_support, - system_version, - system_architecture, - threads, - thread_pool_size, - trace_control_word, - update_cpu_info, - version, - wordsize]). - --define(PROCESS_INFO, [initial_call, - current_function, - registered_name, - status, - message_queue_len, - group_leader, - priority, - trap_exit, - reductions, - %%binary, - last_calls, - catchlevel, - trace, - suspending, - sequential_trace_token, - error_handler]). - --define(PROCESS_GC, [memory, - total_heap_size, - heap_size, - stack_size, - min_heap_size]). - %fullsweep_after]). - all() -> emqx_ct:all(?MODULE). t_load(_Config) -> - ?assertMatch([{load1, _}, - {load5, _}, - {load15, _} - ], emqx_vm:loads()). + ?assertMatch([{load1, _}, {load5, _}, {load15, _}], emqx_vm:loads()). t_systeminfo(_Config) -> - Keys = [Key || {Key, _} <- emqx_vm:get_system_info()], - ?SYSTEM_INFO = Keys, - ?assertEqual(undefined, emqx_vm:get_system_info(undefined)). + ?assertEqual(emqx_vm:system_info_keys(), + [Key || {Key, _} <- emqx_vm:get_system_info()]), + ?assertEqual(undefined, emqx_vm:get_system_info(undefined)). t_mem_info(_Config) -> application:ensure_all_started(os_mon), MemInfo = emqx_vm:mem_info(), - [{total_memory, _}, - {used_memory, _}]= MemInfo, + [{total_memory, _}, {used_memory, _}]= MemInfo, application:stop(os_mon). -t_process_list(_Config) -> - Pid = self(), - ProcessInfo = emqx_vm:get_process_list(), - true = lists:member({pid, Pid}, lists:concat(ProcessInfo)). - t_process_info(_Config) -> - ProcessInfos = emqx_vm:get_process_info(), - ProcessInfo = lists:last(ProcessInfos), - Keys = [K || {K, _V}<- ProcessInfo], - ?PROCESS_INFO = Keys. + ProcessInfo = emqx_vm:get_process_info(), + ?assertEqual(emqx_vm:process_info_keys(), [K || {K, _V}<- ProcessInfo]). t_process_gc(_Config) -> - ProcessGcs = emqx_vm:get_process_gc(), - ProcessGc = lists:last(ProcessGcs), - Keys = [K || {K, _V}<- ProcessGc], - ?PROCESS_GC = Keys. + GcInfo = emqx_vm:get_process_gc_info(), + ?assertEqual(emqx_vm:process_gc_info_keys(), [K || {K, _V}<- GcInfo]). t_get_ets_list(_Config) -> ets:new(test, [named_table]),