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

mendersoftware / gui / 1350829378

27 Jun 2024 01:46PM UTC coverage: 83.494% (-16.5%) from 99.965%
1350829378

Pull #4465

gitlab-ci

mzedel
chore: test fixes

Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #4465: MEN-7169 - feat: added multi sorting capabilities to devices view

4506 of 6430 branches covered (70.08%)

81 of 100 new or added lines in 14 files covered. (81.0%)

1661 existing lines in 163 files now uncovered.

8574 of 10269 relevant lines covered (83.49%)

160.6 hits per line

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

28.92
/src/js/utils/sockethook.js
1
// Copyright 2022 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
import { useCallback, useEffect, useRef, useState } from 'react';
15

16
import msgpack5 from 'msgpack5';
17
import Cookies from 'universal-cookie';
18

19
import { apiUrl } from '../api/general-api';
20
import { TIMEOUTS } from '../constants/appConstants';
21
import { DEVICE_MESSAGE_PROTOCOLS as MessageProtocols, DEVICE_MESSAGE_TYPES as MessageTypes } from '../constants/deviceConstants';
22

23
const cookies = new Cookies();
15✔
24

25
const MessagePack = msgpack5();
15✔
26

27
export const byteArrayToString = body => String.fromCharCode(...body);
15✔
28

29
export const blobToString = blob =>
15✔
UNCOV
30
  new Promise(resolve => {
×
UNCOV
31
    let fr = new FileReader();
×
UNCOV
32
    fr.onload = () => {
×
UNCOV
33
      resolve(fr.result);
×
34
    };
UNCOV
35
    fr.readAsArrayBuffer(blob);
×
36
  });
37

38
export const useSession = ({ onClose, onHealthCheckFailed, onMessageReceived, onNotify, onOpen, token }) => {
15✔
39
  const [sessionId, setSessionId] = useState();
6✔
40
  const healthcheckTimeout = useRef();
6✔
41
  const socketRef = useRef();
6✔
42
  const sendMessage = useCallback(({ typ, body, props }) => {
6✔
43
    if (!socketRef.current) {
4!
44
      return;
4✔
45
    }
UNCOV
46
    const proto_header = { proto: MessageProtocols.Shell, typ, sid: socketRef.current.sessionId, props };
×
UNCOV
47
    const encodedData = MessagePack.encode({ hdr: proto_header, body });
×
UNCOV
48
    socketRef.current.send(encodedData);
×
49
  }, []);
50

51
  const close = useCallback(() => {
6✔
52
    if (!socketRef.current || socketRef.current?.readyState !== WebSocket.OPEN) {
5!
53
      return;
5✔
54
    }
UNCOV
55
    sendMessage({ typ: MessageTypes.Stop, body: {}, props: {} });
×
UNCOV
56
    socketRef.current.close();
×
UNCOV
57
    setSessionId();
×
58
  }, [sendMessage]);
59

60
  const healthcheckFailed = useCallback(() => {
6✔
UNCOV
61
    onHealthCheckFailed();
×
UNCOV
62
    close();
×
63
  }, [close, onHealthCheckFailed]);
64

65
  const onSocketMessage = useCallback(
6✔
66
    event =>
UNCOV
67
      blobToString(event.data).then(data => {
×
68
        const {
69
          hdr: { props = {}, proto, sid, typ },
×
70
          body
UNCOV
71
        } = MessagePack.decode(data);
×
UNCOV
72
        if (proto !== MessageProtocols.Shell) {
×
UNCOV
73
          return;
×
74
        }
UNCOV
75
        switch (typ) {
×
76
          case MessageTypes.New: {
UNCOV
77
            if (props.status == WebSocket.CLOSING) {
×
UNCOV
78
              onNotify(`Error: ${byteArrayToString(body)}`);
×
UNCOV
79
              setSessionId();
×
UNCOV
80
              return close();
×
81
            } else {
UNCOV
82
              clearTimeout(healthcheckTimeout.current);
×
UNCOV
83
              healthcheckTimeout.current = setTimeout(healthcheckFailed, 65 * TIMEOUTS.oneSecond);
×
UNCOV
84
              socketRef.current.sessionId = sid;
×
UNCOV
85
              return setSessionId(sid);
×
86
            }
87
          }
88
          case MessageTypes.Shell:
UNCOV
89
            return onMessageReceived(body);
×
90
          case MessageTypes.Stop:
UNCOV
91
            return close();
×
92
          case MessageTypes.Ping: {
UNCOV
93
            if (healthcheckTimeout.current) {
×
UNCOV
94
              clearTimeout(healthcheckTimeout.current);
×
95
            }
UNCOV
96
            sendMessage({ typ: MessageTypes.Pong });
×
97
            //
UNCOV
98
            const timeout = parseInt(props.timeout);
×
UNCOV
99
            if (timeout > 0) {
×
UNCOV
100
              healthcheckTimeout.current = setTimeout(healthcheckFailed, timeout * TIMEOUTS.oneSecond);
×
101
            }
UNCOV
102
            return;
×
103
          }
104
          default:
UNCOV
105
            break;
×
106
        }
107
      }),
108
    [close, healthcheckFailed, onMessageReceived, onNotify, sendMessage]
109
  );
110

111
  const onSocketError = useCallback(
6✔
112
    error => {
UNCOV
113
      onNotify(`WebSocket error: ${error.message}`);
×
UNCOV
114
      close();
×
UNCOV
115
      clearTimeout(healthcheckTimeout.current);
×
116
    },
117
    [close, onNotify]
118
  );
119

120
  const onSocketOpen = useCallback(() => {
6✔
UNCOV
121
    sendMessage({ typ: MessageTypes.New, props: {} });
×
UNCOV
122
    onOpen(true);
×
123
  }, [onOpen, sendMessage]);
124

125
  const onSocketClose = useCallback(
6✔
126
    e => {
UNCOV
127
      console.log('closing');
×
UNCOV
128
      onClose(e);
×
UNCOV
129
      close();
×
130
    },
131
    [close, onClose]
132
  );
133

134
  const connect = useCallback(
6✔
135
    deviceId => {
UNCOV
136
      const uri = `wss://${window.location.host}${apiUrl.v1}/deviceconnect/devices/${deviceId}/connect`;
×
UNCOV
137
      setSessionId();
×
UNCOV
138
      cookies.set('JWT', token, { path: '/', secure: true, sameSite: 'strict', maxAge: 5 });
×
UNCOV
139
      try {
×
UNCOV
140
        socketRef.current = new WebSocket(uri);
×
141
      } catch (error) {
UNCOV
142
        console.log(error);
×
143
      }
144
    },
145
    [token]
146
  );
147

148
  useEffect(() => {
6✔
149
    if (!socketRef.current) {
4!
150
      return;
4✔
151
    }
152

UNCOV
153
    socketRef.current.addEventListener('close', onSocketClose);
×
UNCOV
154
    socketRef.current.addEventListener('error', onSocketError);
×
UNCOV
155
    socketRef.current.addEventListener('message', onSocketMessage);
×
UNCOV
156
    socketRef.current.addEventListener('open', onSocketOpen);
×
157

UNCOV
158
    return () => {
×
UNCOV
159
      socketRef.current.removeEventListener('close', onSocketClose);
×
UNCOV
160
      socketRef.current.removeEventListener('error', onSocketError);
×
UNCOV
161
      socketRef.current.removeEventListener('message', onSocketMessage);
×
UNCOV
162
      socketRef.current.removeEventListener('open', onSocketOpen);
×
163
    };
164
  }, [onSocketClose, onSocketError, onSocketMessage, onSocketOpen, socketRef.current?.readyState]);
165

166
  return [connect, sendMessage, close, socketRef.current?.readyState ?? WebSocket.CLOSED, sessionId];
6✔
167
};
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