• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / iot-manager / 1284435895

09 May 2024 10:28AM UTC coverage: 87.639% (+0.09%) from 87.551%
1284435895

Pull #283

gitlab-ci

tranchitella
feat: asynchronous processing of webhook requests and timeout

Changelog: process webhook requests asynchronously, returing `202 Accepted` instead of `204 No Content` or `200 OK`
Changelog: add a timeout for webhook requests, defaults to 10 seconds; you can modify it using the `webhooks_timeout_seconds` configuration setting

Ticket: MEN-7227

Signed-off-by: Fabio Tranchitella <fabio.tranchitella@northern.tech>
Pull Request #283: feat: asynchronous processing of webhook requests and timeout

49 of 53 new or added lines in 6 files covered. (92.45%)

902 existing lines in 13 files now uncovered.

3226 of 3681 relevant lines covered (87.64%)

11.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.78
/api/http/management_state.go
1
// Copyright 2021 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
package http
16

17
import (
18
        "net/http"
19

20
        "github.com/gin-gonic/gin"
21
        "github.com/google/uuid"
22
        "github.com/pkg/errors"
23

24
        "github.com/mendersoftware/go-lib-micro/rest.utils"
25

26
        "github.com/mendersoftware/iot-manager/app"
27
        "github.com/mendersoftware/iot-manager/model"
28
)
29

30
const (
31
        paramDeviceID      = "id"
32
        paramIntegrationID = "integrationId"
33
)
34

35
var (
36
        ErrEmptyDeviceID        = errors.New("device ID is empty")
37
        ErrInvalidIntegrationID = errors.New("integration ID is not a valid UUID")
38
)
39

40
// GET /devices/:id/state
UNCOV
41
func (h *ManagementHandler) GetDeviceState(c *gin.Context) {
7✔
UNCOV
42
        ctx, _, err := getContextAndIdentity(c)
7✔
UNCOV
43
        if err != nil {
8✔
UNCOV
44
                return
1✔
UNCOV
45
        }
1✔
46

UNCOV
47
        deviceID := c.Param(paramDeviceID)
6✔
UNCOV
48
        if deviceID == "" {
7✔
UNCOV
49
                rest.RenderError(c, http.StatusBadRequest, ErrEmptyDeviceID)
1✔
UNCOV
50
                return
1✔
UNCOV
51
        }
1✔
52

UNCOV
53
        device, err := h.app.GetDevice(ctx, deviceID)
5✔
UNCOV
54
        if err == app.ErrDeviceNotFound {
6✔
UNCOV
55
                rest.RenderError(c, http.StatusNotFound, app.ErrDeviceNotFound)
1✔
UNCOV
56
                return
1✔
UNCOV
57
        } else if err != nil {
6✔
UNCOV
58
                rest.RenderError(c, http.StatusInternalServerError, err)
1✔
UNCOV
59
                return
1✔
UNCOV
60
        }
1✔
61

UNCOV
62
        states := make(model.DeviceStates)
3✔
UNCOV
63
        for _, integrationID := range device.IntegrationIDs {
6✔
UNCOV
64
                state, err := h.app.GetDeviceStateIntegration(ctx, deviceID, integrationID)
3✔
UNCOV
65
                if state == nil && (err == nil ||
3✔
UNCOV
66
                        err == app.ErrIntegrationNotFound ||
3✔
UNCOV
67
                        err == app.ErrUnknownIntegration) {
4✔
UNCOV
68
                        continue
1✔
UNCOV
69
                } else if err != nil {
3✔
UNCOV
70
                        rest.RenderError(c, http.StatusInternalServerError, err)
1✔
UNCOV
71
                        return
1✔
UNCOV
72
                }
1✔
UNCOV
73
                states[integrationID.String()] = *state
1✔
74
        }
75

UNCOV
76
        c.JSON(http.StatusOK, states)
2✔
77
}
78

79
// GET /devices/:id/state/:integrationId
UNCOV
80
func (h *ManagementHandler) GetDeviceStateIntegration(c *gin.Context) {
7✔
UNCOV
81
        ctx, _, err := getContextAndIdentity(c)
7✔
UNCOV
82
        if err != nil {
8✔
UNCOV
83
                return
1✔
UNCOV
84
        }
1✔
85

UNCOV
86
        deviceID := c.Param(paramDeviceID)
6✔
UNCOV
87
        if deviceID == "" {
7✔
UNCOV
88
                rest.RenderError(c, http.StatusBadRequest, ErrEmptyDeviceID)
1✔
UNCOV
89
                return
1✔
UNCOV
90
        }
1✔
UNCOV
91
        integrationID, err := uuid.Parse(c.Param(paramIntegrationID))
5✔
UNCOV
92
        if err != nil {
6✔
UNCOV
93
                rest.RenderError(c, http.StatusBadRequest, ErrInvalidIntegrationID)
1✔
UNCOV
94
                return
1✔
UNCOV
95
        }
1✔
96

UNCOV
97
        state, err := h.app.GetDeviceStateIntegration(ctx, deviceID, integrationID)
4✔
UNCOV
98
        if err == app.ErrIntegrationNotFound || err == app.ErrUnknownIntegration {
6✔
UNCOV
99
                rest.RenderError(c, http.StatusNotFound, err)
2✔
UNCOV
100
                return
2✔
UNCOV
101
        } else if err != nil {
5✔
UNCOV
102
                rest.RenderError(c, http.StatusInternalServerError, err)
1✔
UNCOV
103
                return
1✔
UNCOV
104
        }
1✔
105

UNCOV
106
        c.JSON(http.StatusOK, state)
1✔
107
}
108

109
// PUT /devices/:id/state/:integrationId
UNCOV
110
func (h *ManagementHandler) SetDeviceStateIntegration(c *gin.Context) {
7✔
UNCOV
111
        ctx, _, err := getContextAndIdentity(c)
7✔
UNCOV
112
        if err != nil {
8✔
UNCOV
113
                return
1✔
UNCOV
114
        }
1✔
115

UNCOV
116
        deviceID := c.Param(paramDeviceID)
6✔
UNCOV
117
        if deviceID == "" {
7✔
UNCOV
118
                rest.RenderError(c, http.StatusBadRequest, ErrEmptyDeviceID)
1✔
UNCOV
119
                return
1✔
UNCOV
120
        }
1✔
UNCOV
121
        integrationID, err := uuid.Parse(c.Param(paramIntegrationID))
5✔
UNCOV
122
        if err != nil {
6✔
UNCOV
123
                rest.RenderError(c, http.StatusBadRequest, ErrInvalidIntegrationID)
1✔
UNCOV
124
                return
1✔
UNCOV
125
        }
1✔
126

UNCOV
127
        state := &model.DeviceState{}
4✔
UNCOV
128
        if err := c.ShouldBindJSON(state); err != nil {
5✔
UNCOV
129
                rest.RenderError(c,
1✔
UNCOV
130
                        http.StatusBadRequest,
1✔
UNCOV
131
                        errors.Wrap(err, "malformed request body"),
1✔
UNCOV
132
                )
1✔
UNCOV
133
                return
1✔
UNCOV
134
        }
1✔
135

UNCOV
136
        state, err = h.app.SetDeviceStateIntegration(ctx, deviceID, integrationID, state)
3✔
UNCOV
137
        if err == app.ErrIntegrationNotFound || err == app.ErrUnknownIntegration {
3✔
138
                rest.RenderError(c, http.StatusNotFound, err)
×
139
                return
×
UNCOV
140
        } else if err == app.ErrDeviceStateConflict {
4✔
UNCOV
141
                rest.RenderError(c, http.StatusConflict, err)
1✔
UNCOV
142
                return
1✔
UNCOV
143
        } else if err != nil {
4✔
UNCOV
144
                rest.RenderError(c, http.StatusInternalServerError, err)
1✔
UNCOV
145
                return
1✔
UNCOV
146
        }
1✔
147

UNCOV
148
        c.JSON(http.StatusOK, state)
1✔
149
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc