Skip to content

Commit 20f2251

Browse files
author
Roberto Sora
committed
Add testing for telemetry deaemon and repertory
1 parent d9db68a commit 20f2251

File tree

6 files changed

+40
-260
lines changed

6 files changed

+40
-260
lines changed

cli/daemon/daemon.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package daemon
1717

1818
import (
1919
"fmt"
20+
"github.com/arduino/arduino-cli/telemetry"
2021
"github.com/segmentio/stats/v4"
2122
"io"
2223
"io/ioutil"
@@ -30,7 +31,6 @@ import (
3031
srv_commands "github.com/arduino/arduino-cli/rpc/commands"
3132
srv_monitor "github.com/arduino/arduino-cli/rpc/monitor"
3233
srv_settings "github.com/arduino/arduino-cli/rpc/settings"
33-
"github.com/arduino/arduino-cli/telemetry"
3434
"github.com/sirupsen/logrus"
3535
"github.com/spf13/cobra"
3636
"github.com/spf13/viper"
@@ -59,6 +59,7 @@ func runDaemonCommand(cmd *cobra.Command, args []string) {
5959

6060
if viper.GetBool("telemetry.enabled") {
6161
telemetry.Activate("daemon")
62+
stats.Incr("daemon", stats.T("success", "true"))
6263
defer stats.Flush()
6364
}
6465

configuration/defaults.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func setDefaults(dataDir, userDir string) {
3838

3939
//telemetry settings
4040
viper.SetDefault("telemetry.enabled", true)
41-
viper.SetDefault("telemetry.addr", ":2112")
41+
viper.SetDefault("telemetry.addr", ":9090")
4242
viper.SetDefault("telemetry.pattern", "/metrics")
4343

4444
}

test/requirements.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@ simplejson==3.17.0
33
semver==2.9.0
44
pyserial==3.4
55
pyyaml==5.3
6+
prometheus-client==0.7.1
7+
requests==2.22.0
68
# temporary, replaces invoke==1.3.0 in favour of https://github.com/pyinvoke/invoke/pull/661
79
git+https://github.com/flazzarini/invoke.git

test/requirements.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,24 @@
55
# pip-compile test/requirements.in
66
#
77
attrs==19.1.0 # via pytest
8+
certifi==2019.11.28 # via requests
9+
chardet==3.0.4 # via requests
10+
idna==2.8 # via requests
811
importlib-metadata==1.5.0 # via pluggy, pytest
912
git+https://github.com/flazzarini/invoke.git
1013
more-itertools==7.1.0 # via pytest
1114
packaging==19.0 # via pytest
1215
pluggy==0.13.1 # via pytest
16+
prometheus-client==0.7.1
1317
py==1.8.0 # via pytest
1418
pyparsing==2.4.0 # via packaging
1519
pyserial==3.4
1620
pytest==5.3.4
1721
pyyaml==5.3
22+
requests==2.22.0
1823
semver==2.9.0
1924
simplejson==3.17.0
2025
six==1.12.0 # via packaging
26+
urllib3==1.25.8 # via requests
2127
wcwidth==0.1.7 # via pytest
2228
zipp==2.1.0 # via importlib-metadata

test/test_daemon.py

Lines changed: 28 additions & 257 deletions
Original file line numberDiff line numberDiff line change
@@ -12,265 +12,36 @@
1212
# otherwise use the software for commercial activities involving the Arduino
1313
# software without disclosing the source code of your own applications. To purchase
1414
# a commercial license, send an email to license@arduino.cc.
15-
import json
16-
import os
17-
import platform
18-
19-
import pytest
20-
21-
from .common import running_on_ci
22-
23-
24-
def test_compile_without_fqbn(run_command):
25-
# Init the environment explicitly
26-
result = run_command("core update-index")
27-
assert result.ok
28-
29-
# Download latest AVR
30-
result = run_command("core install arduino:avr")
31-
assert result.ok
32-
33-
# Build sketch without FQBN
34-
result = run_command("compile")
35-
assert result.failed
36-
37-
38-
def test_compile_with_simple_sketch(run_command, data_dir, working_dir):
39-
# Init the environment explicitly
40-
result = run_command("core update-index")
41-
assert result.ok
42-
43-
# Download latest AVR
44-
result = run_command("core install arduino:avr")
45-
assert result.ok
46-
47-
sketch_name = "CompileIntegrationTest"
48-
sketch_path = os.path.join(data_dir, sketch_name)
49-
fqbn = "arduino:avr:uno"
50-
51-
# Create a test sketch
52-
result = run_command("sketch new {}".format(sketch_path))
53-
assert result.ok
54-
assert "Sketch created in: {}".format(sketch_path) in result.stdout
55-
56-
# Build sketch for arduino:avr:uno
57-
log_file_name = "compile.log"
58-
log_file_path = os.path.join(data_dir, log_file_name)
59-
result = run_command(
60-
"compile -b {fqbn} {sketch_path} --log-format json --log-file {log_file} --log-level trace".format(
61-
fqbn=fqbn, sketch_path=sketch_path, log_file=log_file_path
62-
)
63-
)
64-
assert result.ok
65-
66-
# let's test from the logs if the hex file produced by successful compile is moved to our sketch folder
67-
log_json = open(log_file_path, "r")
68-
json_log_lines = log_json.readlines()
69-
expected_trace_sequence = [
70-
"Compile {sketch} for {fqbn} started".format(sketch=sketch_path, fqbn=fqbn),
71-
"Compile {sketch} for {fqbn} successful".format(sketch=sketch_name, fqbn=fqbn),
72-
]
73-
assert is_message_sequence_in_json_log_traces(
74-
expected_trace_sequence, json_log_lines
75-
)
76-
77-
# Test the --output flag with absolute path
78-
target = os.path.join(data_dir, "test.hex")
79-
result = run_command(
80-
"compile -b {fqbn} {sketch_path} -o {target}".format(
81-
fqbn=fqbn, sketch_path=sketch_path, target=target
82-
)
83-
)
84-
assert result.ok
85-
assert os.path.exists(target)
86-
87-
88-
@pytest.mark.skipif(
89-
running_on_ci() and platform.system() == "Windows",
90-
reason="Test disabled on Github Actions Win VM until tmpdir inconsistent behavior bug is fixed",
91-
)
92-
def test_output_flag_default_path(run_command, data_dir, working_dir):
93-
# Init the environment explicitly
94-
result = run_command("core update-index")
95-
assert result.ok
96-
97-
# Download latest AVR
98-
result = run_command("core install arduino:avr")
99-
assert result.ok
100-
101-
# Create a test sketch
102-
sketch_path = os.path.join(data_dir, "test_output_flag_default_path")
103-
fqbn = "arduino:avr:uno"
104-
result = run_command("sketch new {}".format(sketch_path))
105-
assert result.ok
106-
107-
# Test the --output flag defaulting to current working dir
108-
result = run_command(
109-
"compile -b {fqbn} {sketch_path} -o test".format(
110-
fqbn=fqbn, sketch_path=sketch_path
111-
)
112-
)
113-
assert result.ok
114-
assert os.path.exists(os.path.join(working_dir, "test.hex"))
115-
116-
# Test extension won't be added if already present
117-
result = run_command(
118-
"compile -b {fqbn} {sketch_path} -o test2.hex".format(
119-
fqbn=fqbn, sketch_path=sketch_path
120-
)
121-
)
122-
assert result.ok
123-
assert os.path.exists(os.path.join(working_dir, "test2.hex"))
124-
125-
126-
def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir):
127-
# Init the environment explicitly
128-
result = run_command("core update-index")
129-
assert result.ok
130-
131-
# Download latest AVR
132-
result = run_command("core install arduino:avr")
133-
assert result.ok
134-
135-
sketch_name = "CompileIntegrationTestSymlinkSelfLoop"
136-
sketch_path = os.path.join(data_dir, sketch_name)
137-
fqbn = "arduino:avr:uno"
138-
139-
# Create a test sketch
140-
result = run_command("sketch new {}".format(sketch_path))
141-
assert result.ok
142-
assert "Sketch created in: {}".format(sketch_path) in result.stdout
143-
144-
# create a symlink that loops on himself
145-
loop_file_path = os.path.join(sketch_path, "loop")
146-
os.symlink(loop_file_path, loop_file_path)
147-
148-
# Build sketch for arduino:avr:uno
149-
result = run_command(
150-
"compile -b {fqbn} {sketch_path}".format(fqbn=fqbn, sketch_path=sketch_path)
151-
)
152-
# The assertion is a bit relaxed in this case because win behaves differently from macOs and linux
153-
# returning a different error detailed message
154-
assert "Error during sketch processing" in result.stderr
155-
assert not result.ok
156-
157-
sketch_name = "CompileIntegrationTestSymlinkDirLoop"
158-
sketch_path = os.path.join(data_dir, sketch_name)
159-
fqbn = "arduino:avr:uno"
160-
161-
# Create a test sketch
162-
result = run_command("sketch new {}".format(sketch_path))
163-
assert result.ok
164-
assert "Sketch created in: {}".format(sketch_path) in result.stdout
165-
166-
# create a symlink that loops on the upper level
167-
loop_dir_path = os.path.join(sketch_path, "loop_dir")
168-
os.mkdir(loop_dir_path)
169-
loop_dir_symlink_path = os.path.join(loop_dir_path, "loop_dir_symlink")
170-
os.symlink(loop_dir_path, loop_dir_symlink_path)
171-
172-
# Build sketch for arduino:avr:uno
173-
result = run_command(
174-
"compile -b {fqbn} {sketch_path}".format(fqbn=fqbn, sketch_path=sketch_path)
175-
)
176-
# The assertion is a bit relaxed also in this case because macOS behaves differently from win and linux:
177-
# the cli does not follow recursively the symlink til breaking
178-
assert "Error during sketch processing" in result.stderr
179-
assert not result.ok
180-
181-
182-
@pytest.mark.skipif(running_on_ci(), reason="VMs have no serial ports")
183-
def test_compile_and_compile_combo(run_command, data_dir, detected_boards):
184-
# Init the environment explicitly
185-
result = run_command("core update-index")
186-
assert result.ok
187-
188-
# Install required core(s)
189-
result = run_command("core install arduino:avr")
190-
result = run_command("core install arduino:samd")
191-
assert result.ok
192-
193-
# Create a test sketch
194-
sketch_name = "CompileAndUploadIntegrationTest"
195-
sketch_path = os.path.join(data_dir, sketch_name)
196-
result = run_command("sketch new {}".format(sketch_path))
197-
assert result.ok
198-
assert "Sketch created in: {}".format(sketch_path) in result.stdout
199-
200-
# Build sketch for each detected board
201-
for board in detected_boards:
202-
log_file_name = "{fqbn}-compile.log".format(fqbn=board.fqbn.replace(":", "-"))
203-
log_file_path = os.path.join(data_dir, log_file_name)
204-
command_log_flags = "--log-format json --log-file {} --log-level trace".format(
205-
log_file_path
206-
)
207-
result = run_command(
208-
"compile -b {fqbn} --upload -p {address} {sketch_path} {log_flags}".format(
209-
fqbn=board.fqbn,
210-
address=board.address,
211-
sketch_path=sketch_path,
212-
log_flags=command_log_flags,
213-
)
214-
)
215-
assert result.ok
216-
# check from the logs if the bin file were uploaded on the current board
217-
log_json = open(log_file_path, "r")
218-
json_log_lines = log_json.readlines()
219-
expected_trace_sequence = [
220-
"Compile {sketch} for {fqbn} started".format(
221-
sketch=sketch_path, fqbn=board.fqbn
222-
),
223-
"Compile {sketch} for {fqbn} successful".format(
224-
sketch=sketch_name, fqbn=board.fqbn
225-
),
226-
"Upload {sketch} on {fqbn} started".format(
227-
sketch=sketch_path, fqbn=board.fqbn
228-
),
229-
"Upload {sketch} on {fqbn} successful".format(
230-
sketch=sketch_name, fqbn=board.fqbn
231-
),
232-
]
233-
assert is_message_sequence_in_json_log_traces(
234-
expected_trace_sequence, json_log_lines
235-
)
23615

16+
import os
17+
import subprocess
18+
import time
23719

238-
def is_message_sequence_in_json_log_traces(message_sequence, log_json_lines):
239-
trace_entries = []
240-
for entry in log_json_lines:
241-
entry = json.loads(entry)
242-
if entry.get("level") == "trace":
243-
if entry.get("msg") in message_sequence:
244-
trace_entries.append(entry.get("msg"))
245-
return message_sequence == trace_entries
20+
import requests
21+
import yaml
22+
from prometheus_client.parser import text_string_to_metric_families
24623

24724

248-
def test_compile_blacklisted_sketchname(run_command, data_dir):
249-
"""
250-
Compile should ignore folders named `RCS`, `.git` and the likes, but
251-
it should be ok for a sketch to be named like RCS.ino
252-
"""
25+
def test_telemetry_prometheus_endpoint(pytestconfig, data_dir, downloads_dir):
25326
# Init the environment explicitly
254-
result = run_command("core update-index")
255-
assert result.ok
256-
257-
# Download latest AVR
258-
result = run_command("core install arduino:avr")
259-
assert result.ok
260-
261-
sketch_name = "RCS"
262-
sketch_path = os.path.join(data_dir, sketch_name)
263-
fqbn = "arduino:avr:uno"
264-
265-
# Create a test sketch
266-
result = run_command("sketch new {}".format(sketch_path))
267-
assert result.ok
268-
assert "Sketch created in: {}".format(sketch_path) in result.stdout
269-
270-
# Build sketch for arduino:avr:uno
271-
log_file_name = "compile.log"
272-
log_file_path = os.path.join(data_dir, log_file_name)
273-
result = run_command(
274-
"compile -b {fqbn} {sketch_path}".format(fqbn=fqbn, sketch_path=sketch_path)
275-
)
276-
assert result.ok
27+
cli_path = os.path.join(str(pytestconfig.rootdir), "..", "arduino-cli")
28+
env = os.environ.copy()
29+
env["ARDUINO_DATA_DIR"] = data_dir
30+
env["ARDUINO_DOWNLOADS_DIR"] = downloads_dir
31+
env["ARDUINO_SKETCHBOOK_DIR"] = data_dir
32+
33+
subprocess.Popen([cli_path, "daemon"], env=env)
34+
35+
time.sleep(5)
36+
37+
# parse repertory file
38+
repertory_file = os.path.join(data_dir, "repertory.yaml")
39+
with open(repertory_file, 'r') as stream:
40+
repertory = yaml.safe_load(stream)
41+
42+
# Check if :9090/metrics endpoint is alive,
43+
# telemetry is enabled by default in daemon mode
44+
metrics = requests.get("http://localhost:9090/metrics").text
45+
family = next(text_string_to_metric_families(metrics))
46+
sample = family.samples[0]
47+
assert repertory["installation"]["id"] == sample.labels["installationID"]

test/test_main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def test_repertory_creation(run_command, data_dir):
8484
out_lines = run_command("version").stdout.strip().split("\n")
8585
assert len(out_lines) == 1
8686

87-
# json on file
87+
# parse repertory file
8888
repertory_file = os.path.join(data_dir, "repertory.yaml")
8989
with open(repertory_file, 'r') as stream:
9090
repertory = yaml.safe_load(stream)

0 commit comments

Comments
 (0)