mirror of
https://github.com/absmach/magistrala.git
synced 2026-08-07 15:25:48 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2dc7f3eea1 | |||
| 62297fedec | |||
| f449f8b9c8 | |||
| 544ba57850 |
@@ -0,0 +1,23 @@
|
||||
## Test scenarios
|
||||
|
||||
Testing environment to be determined.
|
||||
|
||||
### Message publishing
|
||||
|
||||
In this scenario, large number of requests are sent to HTTP adapter service
|
||||
every second. This test checks how much time HTTP adapter took to response to
|
||||
each request.
|
||||
|
||||
#### Results
|
||||
|
||||
TBD
|
||||
|
||||
### Create and get client
|
||||
|
||||
In this scenario, large number of requests are sent to manager service to create
|
||||
client, and than to retrieve its data. This test checks how much time manager
|
||||
service took to response to each request.
|
||||
|
||||
#### Results
|
||||
|
||||
TBD
|
||||
@@ -1,3 +1,5 @@
|
||||
// +build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// +build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
target/
|
||||
.classpath
|
||||
.cache-tests
|
||||
.cache-main
|
||||
.settings/
|
||||
.project
|
||||
*.class
|
||||
bin/
|
||||
@@ -0,0 +1,49 @@
|
||||
# Load Test
|
||||
|
||||
This SBT project contains load tests written for mainflux platform.
|
||||
|
||||
## Setup
|
||||
|
||||
In order to run load tests you must have [openjdk8](http://openjdk.java.net/install/) and [sbt](https://www.scala-sbt.org/1.0/docs/Setup.html) installed on your machine.
|
||||
|
||||
## Configuration
|
||||
|
||||
Tests are configured to use variables from `JAVA_OPTS` presented in the
|
||||
following table. Note that any unset variables will be replaced with their
|
||||
default values.
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|------------------------------------------|-----------------------|
|
||||
| manager | Manager service URL | http://localhost:8180 |
|
||||
| http | HTTP adapter service URL | http://localhost:8182 |
|
||||
| requests | Number of requests to be sent per second | 100 |
|
||||
|
||||
## Usage
|
||||
|
||||
This project contains two simulations:
|
||||
|
||||
- `PublishSimulation`
|
||||
- `CreateAndRetrieveClientSimulation`
|
||||
|
||||
To run all tests you will have to run following commands:
|
||||
|
||||
```bash
|
||||
cd <path_to_mainflux_project>/load-test
|
||||
sbt gatling:test
|
||||
```
|
||||
|
||||
### Publish Simulation
|
||||
|
||||
`PublishSimulation` contains load tests for publishing messages. To run this test use following command:
|
||||
|
||||
```bash
|
||||
sbt "gatling:testOnly com.mainflux.loadtest.simulations.PublishSimulation"
|
||||
```
|
||||
|
||||
### Create And Retrieve Client Simulation
|
||||
|
||||
`CreateAndRetrieveClientSimulation` contains load tests for creating and retrieving clients. To run this test use following command:
|
||||
|
||||
```bash
|
||||
sbt "gatling:testOnly com.mainflux.loadtest.simulations.CreateAndRetrieveClientSimulation"
|
||||
```
|
||||
@@ -0,0 +1,18 @@
|
||||
enablePlugins(GatlingPlugin)
|
||||
|
||||
name := "load-test"
|
||||
version := "0.2.2"
|
||||
|
||||
scalaVersion := "2.12.4"
|
||||
|
||||
val gatlingVersion = "2.3.1"
|
||||
val circeVersion = "0.9.3"
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"io.gatling.highcharts" % "gatling-charts-highcharts" % gatlingVersion,
|
||||
"io.gatling" % "gatling-test-framework" % gatlingVersion,
|
||||
"org.scalaj" %% "scalaj-http" % "2.3.0",
|
||||
"io.circe" %% "circe-core" % circeVersion,
|
||||
"io.circe" %% "circe-generic" % circeVersion,
|
||||
"io.circe" %% "circe-parser" % circeVersion
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
sbt.version=1.1.2
|
||||
@@ -0,0 +1 @@
|
||||
addSbtPlugin("io.gatling" % "gatling-sbt" % "2.2.2")
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx</pattern>
|
||||
</encoder>
|
||||
<immediateFlush>false</immediateFlush>
|
||||
</appender>
|
||||
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
</appender>
|
||||
<root level="WARN">
|
||||
<appender-ref ref="ASYNC" />
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.mainflux.loadtest.simulations
|
||||
|
||||
object Constants {
|
||||
val ManagerUrl = System.getProperty("manager", "http://localhost:8180")
|
||||
val HttpAdapterUrl = System.getProperty("http", "http://localhost:8182")
|
||||
val RequestsPerSecond = Integer.getInteger("requests", 100)
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package com.mainflux.loadtest.simulations
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import scalaj.http.Http
|
||||
import io.gatling.core.Predef._
|
||||
import io.gatling.http.Predef._
|
||||
import io.gatling.jdbc.Predef._
|
||||
import io.circe._
|
||||
import io.circe.generic.auto._
|
||||
import io.circe.parser._
|
||||
import io.circe.syntax._
|
||||
import CreateAndRetrieveClientSimulation._
|
||||
import io.gatling.http.protocol.HttpProtocolBuilder.toHttpProtocol
|
||||
import io.gatling.http.request.builder.HttpRequestBuilder.toActionBuilder
|
||||
import com.mainflux.loadtest.simulations.Constants._
|
||||
|
||||
class CreateAndRetrieveClientSimulation extends Simulation {
|
||||
|
||||
// Register user
|
||||
Http(s"${ManagerUrl}/users")
|
||||
.postData(User)
|
||||
.header(HttpHeaderNames.ContentType, ContentType)
|
||||
.asString
|
||||
|
||||
// Login user
|
||||
val tokenRes = Http(s"${ManagerUrl}/tokens")
|
||||
.postData(User)
|
||||
.header(HttpHeaderNames.ContentType, ContentType)
|
||||
.asString
|
||||
.body
|
||||
|
||||
val tokenCursor = parse(tokenRes).getOrElse(Json.Null).hcursor
|
||||
val token = tokenCursor.downField("token").as[String].getOrElse("")
|
||||
|
||||
// Prepare testing scenario
|
||||
val httpProtocol = http
|
||||
.baseURL(ManagerUrl)
|
||||
.inferHtmlResources()
|
||||
.acceptHeader("*/*")
|
||||
.contentTypeHeader(ContentType)
|
||||
.userAgentHeader("curl/7.54.0")
|
||||
|
||||
val scn = scenario("CreateAndGetClient")
|
||||
.exec(http("CreateClientRequest")
|
||||
.post("/clients")
|
||||
.header(HttpHeaderNames.ContentType, ContentType)
|
||||
.header(HttpHeaderNames.Authorization, token)
|
||||
.body(StringBody(Client))
|
||||
.check(status.is(201))
|
||||
.check(headerRegex(HttpHeaderNames.Location, "(.*)").saveAs("location")))
|
||||
.exec(http("GetClientRequest")
|
||||
.get("${location}")
|
||||
.header(HttpHeaderNames.Authorization, token)
|
||||
.check(status.is(200)))
|
||||
|
||||
setUp(
|
||||
scn.inject(
|
||||
constantUsersPerSec(RequestsPerSecond.toDouble) during (15 second))).protocols(httpProtocol)
|
||||
}
|
||||
|
||||
object CreateAndRetrieveClientSimulation {
|
||||
val ContentType = "application/json; charset=utf-8"
|
||||
val User = """{"email":"john.doe@email.com", "password":"123"}"""
|
||||
val Client = """{"type":"device", "name":"weio"}"""
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.mainflux.loadtest.simulations
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import scalaj.http.Http
|
||||
import io.gatling.core.Predef._
|
||||
import io.gatling.http.Predef._
|
||||
import io.gatling.jdbc.Predef._
|
||||
import io.circe._
|
||||
import io.circe.generic.auto._
|
||||
import io.circe.parser._
|
||||
import io.circe.syntax._
|
||||
import PublishSimulation._
|
||||
import io.gatling.http.protocol.HttpProtocolBuilder.toHttpProtocol
|
||||
import io.gatling.http.request.builder.HttpRequestBuilder.toActionBuilder
|
||||
import com.mainflux.loadtest.simulations.Constants._
|
||||
|
||||
class PublishSimulation extends Simulation {
|
||||
|
||||
// Register user
|
||||
Http(s"${ManagerUrl}/users")
|
||||
.postData(User)
|
||||
.header(HttpHeaderNames.ContentType, ContentType)
|
||||
.asString
|
||||
|
||||
// Login user
|
||||
val tokenRes = Http(s"${ManagerUrl}/tokens")
|
||||
.postData(User)
|
||||
.header(HttpHeaderNames.ContentType, ContentType)
|
||||
.asString
|
||||
.body
|
||||
|
||||
val tokenCursor = parse(tokenRes).getOrElse(Json.Null).hcursor
|
||||
val token = tokenCursor.downField("token").as[String].getOrElse("")
|
||||
|
||||
// Register client
|
||||
val clientLocation = Http(s"${ManagerUrl}/clients")
|
||||
.postData(Client)
|
||||
.header(HttpHeaderNames.Authorization, token)
|
||||
.header(HttpHeaderNames.ContentType, ContentType)
|
||||
.asString
|
||||
.headers.get("Location").get(0)
|
||||
|
||||
val clientId = clientLocation.split("/")(2)
|
||||
|
||||
// Get client key
|
||||
val clientRes = Http(s"${ManagerUrl}/clients/${clientId}")
|
||||
.header(HttpHeaderNames.Authorization, token)
|
||||
.header(HttpHeaderNames.ContentType, ContentType)
|
||||
.asString
|
||||
.body
|
||||
|
||||
val clientCursor = parse(clientRes).getOrElse(Json.Null).hcursor
|
||||
val clientKey = clientCursor.downField("key").as[String].getOrElse("")
|
||||
|
||||
// Register channel
|
||||
val chanLocation = Http(s"${ManagerUrl}/channels")
|
||||
.postData(Channel)
|
||||
.header(HttpHeaderNames.Authorization, token)
|
||||
.header(HttpHeaderNames.ContentType, ContentType)
|
||||
.asString
|
||||
.headers.get("Location").get(0)
|
||||
|
||||
val chanId = chanLocation.split("/")(2)
|
||||
|
||||
// Connect client to channel
|
||||
Http(s"${ManagerUrl}/channels/${chanId}/clients/${clientId}")
|
||||
.method("PUT")
|
||||
.header(HttpHeaderNames.Authorization, token)
|
||||
.asString
|
||||
|
||||
// Prepare testing scenario
|
||||
val httpProtocol = http
|
||||
.baseURL(HttpAdapterUrl)
|
||||
.inferHtmlResources()
|
||||
.acceptHeader("*/*")
|
||||
.contentTypeHeader("application/json; charset=utf-8")
|
||||
.userAgentHeader("curl/7.54.0")
|
||||
|
||||
val scn = scenario("PublishMessage")
|
||||
.exec(http("PublishMessageRequest")
|
||||
.post(s"/channels/${chanId}/messages")
|
||||
.header(HttpHeaderNames.ContentType, "application/senml+json")
|
||||
.header(HttpHeaderNames.Authorization, clientKey)
|
||||
.body(StringBody(Message))
|
||||
.check(status.is(202)))
|
||||
|
||||
setUp(
|
||||
scn.inject(
|
||||
constantUsersPerSec(RequestsPerSecond.toDouble) during (15 second))).protocols(httpProtocol)
|
||||
}
|
||||
|
||||
object PublishSimulation {
|
||||
val ContentType = "application/json; charset=utf-8"
|
||||
val User = """{"email":"john.doe@email.com", "password":"123"}"""
|
||||
val Client = """{"type":"device", "name":"weio"}"""
|
||||
val Channel = """{"name":"mychan"}"""
|
||||
val Message = """[{"bn":"some-base-name:","bt":1.276020076001e+09, "bu":"A","bver":5, "n":"voltage","u":"V","v":120.1}, {"n":"current","t":-5,"v":1.2}, {"n":"current","t":-4,"v":1.3}]"""
|
||||
}
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
contentType = "application/json; charset=utf-8"
|
||||
contentType = "application/json"
|
||||
invalidEmail = "userexample.com"
|
||||
wrongID = "123e4567-e89b-12d3-a456-000000000042"
|
||||
id = "123e4567-e89b-12d3-a456-000000000001"
|
||||
@@ -316,28 +316,35 @@ func TestListClients(t *testing.T) {
|
||||
client.Key = id
|
||||
clients = append(clients, client)
|
||||
}
|
||||
|
||||
clientURL := fmt.Sprintf("%s/clients", ts.URL)
|
||||
cases := []struct {
|
||||
desc string
|
||||
auth string
|
||||
status int
|
||||
offset int
|
||||
limit int
|
||||
url string
|
||||
res []manager.Client
|
||||
}{
|
||||
{"get a list of clients", user.Email, http.StatusOK, 1, 5, clients[1:6]},
|
||||
{"get a list of clients with invalid token", invalidEmail, http.StatusForbidden, 0, 1, nil},
|
||||
{"get a list of clients with invalid offset", user.Email, http.StatusBadRequest, -1, 5, nil},
|
||||
{"get a list of clients with invalid limit", user.Email, http.StatusBadRequest, 1, -5, nil},
|
||||
{"get a list of clients with zero limit", user.Email, http.StatusBadRequest, 1, 0, nil},
|
||||
{"get a list of clients with limit greater than max", user.Email, http.StatusBadRequest, 0, 110, nil},
|
||||
{"get a list of clients", user.Email, http.StatusOK, fmt.Sprintf("%s?offset=%d&limit=%d", clientURL, 0, 5), clients[0:5]},
|
||||
{"get a list of clients with invalid token", invalidEmail, http.StatusForbidden, fmt.Sprintf("%s?offset=%d&limit=%d", clientURL, 0, 1), nil},
|
||||
{"get a list of clients with invalid offset", user.Email, http.StatusBadRequest, fmt.Sprintf("%s?offset=%d&limit=%d", clientURL, -1, 5), nil},
|
||||
{"get a list of clients with invalid limit", user.Email, http.StatusBadRequest, fmt.Sprintf("%s?offset=%d&limit=%d", clientURL, 1, -5), nil},
|
||||
{"get a list of clients with zero limit", user.Email, http.StatusBadRequest, fmt.Sprintf("%s?offset=%d&limit=%d", clientURL, 1, 0), nil},
|
||||
{"get a list of clients with no offset provided", user.Email, http.StatusOK, fmt.Sprintf("%s?limit=%d", clientURL, 5), clients[0:5]},
|
||||
{"get a list of clients with no limit provided", user.Email, http.StatusOK, fmt.Sprintf("%s?offset=%d", clientURL, 1), clients[1:11]},
|
||||
{"get a list of clients with redundant query params", user.Email, http.StatusOK, fmt.Sprintf("%s?offset=%d&limit=%d&value=something", clientURL, 0, 5), clients[0:5]},
|
||||
{"get a list of clients with limit greater than max", user.Email, http.StatusBadRequest, fmt.Sprintf("%s?offset=%d&limit=%d", clientURL, 0, 110), nil},
|
||||
{"get a list of clients with default URL", user.Email, http.StatusOK, fmt.Sprintf("%s%s", clientURL, ""), clients[0:10]},
|
||||
{"get a list of clients with invalid URL", user.Email, http.StatusBadRequest, fmt.Sprintf("%s%s", clientURL, "?%%"), nil},
|
||||
{"get a list of clients with invalid number of params", user.Email, http.StatusBadRequest, fmt.Sprintf("%s%s", clientURL, "?offset=4&limit=4&limit=5&offset=5"), nil},
|
||||
{"get a list of clients with invalid offset", user.Email, http.StatusBadRequest, fmt.Sprintf("%s%s", clientURL, "?offset=e&limit=5"), nil},
|
||||
{"get a list of clients with invalid limit", user.Email, http.StatusBadRequest, fmt.Sprintf("%s%s", clientURL, "?offset=5&limit=e"), nil},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
req := testRequest{
|
||||
client: cli,
|
||||
method: http.MethodGet,
|
||||
url: fmt.Sprintf("%s/clients?offset=%d&limit=%d", ts.URL, tc.offset, tc.limit),
|
||||
url: tc.url,
|
||||
token: tc.auth,
|
||||
}
|
||||
res, err := req.make()
|
||||
@@ -347,19 +354,6 @@ func TestListClients(t *testing.T) {
|
||||
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
|
||||
assert.ElementsMatch(t, tc.res, data["clients"], fmt.Sprintf("%s: expected body %s got %s", tc.desc, tc.res, data["clients"]))
|
||||
}
|
||||
req := testRequest{
|
||||
client: cli,
|
||||
method: http.MethodGet,
|
||||
url: fmt.Sprintf("%s/clients", ts.URL),
|
||||
token: user.Email,
|
||||
}
|
||||
defaults := "get a list of clients with no limit and offset params"
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", defaults, err))
|
||||
var data map[string][]manager.Client
|
||||
json.NewDecoder(res.Body).Decode(&data)
|
||||
assert.Equal(t, http.StatusOK, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", defaults, http.StatusOK, res.StatusCode))
|
||||
assert.ElementsMatch(t, clients[0:10], data["clients"], fmt.Sprintf("%s: expected body %s got %s", defaults, clients[0:10], data["clients"]))
|
||||
}
|
||||
|
||||
func TestRemoveClient(t *testing.T) {
|
||||
@@ -538,28 +532,36 @@ func TestListChannels(t *testing.T) {
|
||||
channel.ID = id
|
||||
channels = append(channels, channel)
|
||||
}
|
||||
channelURL := fmt.Sprintf("%s/channels", ts.URL)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
auth string
|
||||
status int
|
||||
offset int
|
||||
limit int
|
||||
url string
|
||||
res []manager.Channel
|
||||
}{
|
||||
{"get a list of channels", user.Email, http.StatusOK, 1, 5, channels[1:6]},
|
||||
{"get a list of channels with invalid token", invalidEmail, http.StatusForbidden, 0, 1, nil},
|
||||
{"get a list of channels with invalid offset", user.Email, http.StatusBadRequest, -1, 5, nil},
|
||||
{"get a list of channels with invalid limit", user.Email, http.StatusBadRequest, 1, -5, nil},
|
||||
{"get a list of channels with zero limit", user.Email, http.StatusBadRequest, 1, 0, nil},
|
||||
{"get a list of channels with limit greater than max", user.Email, http.StatusBadRequest, 0, 110, nil},
|
||||
{"get a list of channels", user.Email, http.StatusOK, fmt.Sprintf("%s?offset=%d&limit=%d", channelURL, 0, 6), channels[0:6]},
|
||||
{"get a list of channels with invalid token", invalidEmail, http.StatusForbidden, fmt.Sprintf("%s?offset=%d&limit=%d", channelURL, 0, 1), nil},
|
||||
{"get a list of channels with invalid offset", user.Email, http.StatusBadRequest, fmt.Sprintf("%s?offset=%d&limit=%d", channelURL, -1, 5), nil},
|
||||
{"get a list of channels with invalid limit", user.Email, http.StatusBadRequest, fmt.Sprintf("%s?offset=%d&limit=%d", channelURL, -1, 5), nil},
|
||||
{"get a list of channels with zero limit", user.Email, http.StatusBadRequest, fmt.Sprintf("%s?offset=%d&limit=%d", channelURL, 1, 0), nil},
|
||||
{"get a list of channels with no offset provided", user.Email, http.StatusOK, fmt.Sprintf("%s?limit=%d", channelURL, 5), channels[0:5]},
|
||||
{"get a list of channels with no limit provided", user.Email, http.StatusOK, fmt.Sprintf("%s?offset=%d", channelURL, 1), channels[1:11]},
|
||||
{"get a list of channels with redundant query params", user.Email, http.StatusOK, fmt.Sprintf("%s?offset=%d&limit=%d&value=something", channelURL, 0, 5), channels[0:5]},
|
||||
{"get a list of channels with limit greater than max", user.Email, http.StatusBadRequest, fmt.Sprintf("%s?offset=%d&limit=%d", channelURL, 0, 110), nil},
|
||||
{"get a list of channels with default URL", user.Email, http.StatusOK, fmt.Sprintf("%s%s", channelURL, ""), channels[0:10]},
|
||||
{"get a list of channels with invalid URL", user.Email, http.StatusBadRequest, fmt.Sprintf("%s%s", channelURL, "?%%"), nil},
|
||||
{"get a list of channels with invalid number of params", user.Email, http.StatusBadRequest, fmt.Sprintf("%s%s", channelURL, "?offset=4&limit=4&limit=5&offset=5"), nil},
|
||||
{"get a list of channels with invalid offset", user.Email, http.StatusBadRequest, fmt.Sprintf("%s%s", channelURL, "?offset=e&limit=5"), nil},
|
||||
{"get a list of channels with invalid limit", user.Email, http.StatusBadRequest, fmt.Sprintf("%s%s", channelURL, "?offset=5&limit=e"), nil},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
req := testRequest{
|
||||
client: client,
|
||||
method: http.MethodGet,
|
||||
url: fmt.Sprintf("%s/channels?offset=%d&limit=%d", ts.URL, tc.offset, tc.limit),
|
||||
url: tc.url,
|
||||
token: tc.auth,
|
||||
}
|
||||
res, err := req.make()
|
||||
@@ -569,19 +571,6 @@ func TestListChannels(t *testing.T) {
|
||||
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
|
||||
assert.ElementsMatch(t, tc.res, body["channels"], fmt.Sprintf("%s: expected body %s got %s", tc.desc, tc.res, body["channels"]))
|
||||
}
|
||||
req := testRequest{
|
||||
client: client,
|
||||
method: http.MethodGet,
|
||||
url: fmt.Sprintf("%s/channels", ts.URL),
|
||||
token: user.Email,
|
||||
}
|
||||
defaults := "get a list of channels with no limit and offset params"
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", defaults, err))
|
||||
var data map[string][]manager.Channel
|
||||
json.NewDecoder(res.Body).Decode(&data)
|
||||
assert.Equal(t, http.StatusOK, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", defaults, http.StatusOK, res.StatusCode))
|
||||
assert.ElementsMatch(t, channels[0:10], data["channels"], fmt.Sprintf("%s: expected body %s got %s", defaults, channels[0:10], data["channels"]))
|
||||
}
|
||||
|
||||
func TestRemoveChannel(t *testing.T) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// +build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// +build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
||||
@@ -7,8 +7,6 @@ import (
|
||||
"github.com/mainflux/mainflux/manager"
|
||||
)
|
||||
|
||||
const contentType = "application/json; charset=utf-8"
|
||||
|
||||
type apiRes interface {
|
||||
code() int
|
||||
headers() map[string]string
|
||||
|
||||
+11
-20
@@ -16,8 +16,12 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
var errUnsupportedContentType = errors.New("unsupported content type")
|
||||
var errInvalidQueryParams = errors.New("invalid query params")
|
||||
const contentType = "application/json"
|
||||
|
||||
var (
|
||||
errUnsupportedContentType = errors.New("unsupported content type")
|
||||
errInvalidQueryParams = errors.New("invalid query params")
|
||||
)
|
||||
|
||||
// MakeHandler returns a HTTP handler for API endpoints.
|
||||
func MakeHandler(svc manager.Service) http.Handler {
|
||||
@@ -250,28 +254,13 @@ func decodeView(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
}
|
||||
|
||||
func decodeList(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
|
||||
q, err := url.ParseQuery(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errInvalidQueryParams
|
||||
}
|
||||
offset := 0
|
||||
limit := 10
|
||||
|
||||
n := len(q)
|
||||
if n == 0 {
|
||||
req := listResourcesReq{
|
||||
key: r.Header.Get("Authorization"),
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
if n > 2 {
|
||||
return nil, errInvalidQueryParams
|
||||
}
|
||||
|
||||
off, lmt := q["offset"], q["limit"]
|
||||
|
||||
if len(off) > 1 || len(lmt) > 1 {
|
||||
@@ -281,14 +270,14 @@ func decodeList(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if len(off) == 1 {
|
||||
offset, err = strconv.Atoi(off[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errInvalidQueryParams
|
||||
}
|
||||
}
|
||||
|
||||
if len(lmt) == 1 {
|
||||
limit, err = strconv.Atoi(lmt[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errInvalidQueryParams
|
||||
}
|
||||
}
|
||||
req := listResourcesReq{
|
||||
@@ -342,6 +331,8 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
w.WriteHeader(http.StatusConflict)
|
||||
case errUnsupportedContentType:
|
||||
w.WriteHeader(http.StatusUnsupportedMediaType)
|
||||
case errInvalidQueryParams:
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
case io.ErrUnexpectedEOF:
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
case io.EOF:
|
||||
|
||||
@@ -71,11 +71,12 @@ func (crm *channelRepositoryMock) All(owner string, offset, limit int) []manager
|
||||
return channels
|
||||
}
|
||||
|
||||
first := fmt.Sprintf("%s%012d", chanId, offset)
|
||||
last := fmt.Sprintf("%s%012d", chanId, offset+limit)
|
||||
// Since IDs starts from 1, shift everything by one.
|
||||
first := fmt.Sprintf("%s%012d", chanId, offset+1)
|
||||
last := fmt.Sprintf("%s%012d", chanId, offset+limit+1)
|
||||
|
||||
for k, v := range crm.channels {
|
||||
if strings.HasPrefix(k, prefix) && v.ID > first && v.ID <= last {
|
||||
if strings.HasPrefix(k, prefix) && v.ID >= first && v.ID < last {
|
||||
channels = append(channels, v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,11 +75,12 @@ func (crm *clientRepositoryMock) All(owner string, offset, limit int) []manager.
|
||||
return clients
|
||||
}
|
||||
|
||||
first := fmt.Sprintf("%s%012d", cliId, offset)
|
||||
last := fmt.Sprintf("%s%012d", cliId, offset+limit)
|
||||
// Since IDs start from 1, shift everything by one.
|
||||
first := fmt.Sprintf("%s%012d", cliId, offset+1)
|
||||
last := fmt.Sprintf("%s%012d", cliId, offset+limit+1)
|
||||
|
||||
for k, v := range crm.clients {
|
||||
if strings.HasPrefix(k, prefix) && v.ID > first && v.ID <= last {
|
||||
if strings.HasPrefix(k, prefix) && v.ID >= first && v.ID < last {
|
||||
clients = append(clients, v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,3 +41,4 @@ pages:
|
||||
- License: LICENSE.txt
|
||||
- Architecture: architecture.md
|
||||
- Getting started: getting-started.md
|
||||
- Load test: load-test.md
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const version string = "0.2.0"
|
||||
const version string = "0.2.2"
|
||||
|
||||
type response struct {
|
||||
Version string
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// +build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// +build !test
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
||||
Reference in New Issue
Block a user