Skip to content

Commit 0b318ae

Browse files
committed
refactoring and testing
1 parent 0b11841 commit 0b318ae

File tree

2 files changed

+134
-22
lines changed

2 files changed

+134
-22
lines changed

internal/update/arduino/arduino.go

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -122,26 +122,45 @@ func (a *ArduinoPlatformUpdater) ListUpgradablePackages(cfg config.Configuration
122122
if platformSummary == nil {
123123
return nil, nil // No platform found
124124
}
125+
releasesMap := platformSummary.GetReleases()
125126

126-
installedVersionString := platformSummary.GetInstalledVersion()
127+
releases := make([]string, 0, len(releasesMap))
127128

128-
installedV, err := semver.NewVersion(installedVersionString)
129-
if err != nil {
130-
slog.Warn("Failed to parse installed version", "version", installedVersionString, "error", err)
129+
for k := range releasesMap {
130+
releases = append(releases, k)
131+
}
132+
bestVersion, err := findBestCandidate(
133+
platformSummary.GetInstalledVersion(),
134+
releases,
135+
cfg.MaxAllowedMajorVersion,
136+
)
137+
138+
if bestVersion == "" || err != nil {
131139
return nil, nil
132140
}
141+
return []update.UpgradablePackage{{
142+
Type: update.Arduino,
143+
Name: "arduino:zephyr",
144+
FromVersion: platformSummary.GetInstalledVersion(),
145+
ToVersion: bestVersion,
146+
}}, nil
147+
}
148+
func findBestCandidate(installedStr string, availableVersions []string, maxMajorConfig int) (string, error) {
149+
installedV, err := semver.NewVersion(installedStr)
150+
if err != nil {
151+
return "", err
152+
}
133153

134-
var maxMajor uint64
135-
if cfg.MaxAllowedMajorVersion > 0 {
136-
maxMajor = uint64(cfg.MaxAllowedMajorVersion)
154+
maxMajor := uint64(maxMajorConfig)
155+
if maxMajorConfig <= 0 {
156+
maxMajor = installedV.Major()
137157
}
158+
138159
var bestUpdateV *semver.Version
139160

140-
allReleases := platformSummary.GetReleases()
141-
for versionString := range allReleases {
142-
candidateV, err := semver.NewVersion(versionString)
161+
for _, vStr := range availableVersions {
162+
candidateV, err := semver.NewVersion(vStr)
143163
if err != nil {
144-
slog.Debug("Skipping unparsable version", "version", versionString, "error", err)
145164
continue
146165
}
147166

@@ -152,23 +171,15 @@ func (a *ArduinoPlatformUpdater) ListUpgradablePackages(cfg config.Configuration
152171
if !candidateV.GreaterThan(installedV) {
153172
continue
154173
}
155-
156174
if bestUpdateV == nil || candidateV.GreaterThan(bestUpdateV) {
157175
bestUpdateV = candidateV
158176
}
159177
}
178+
160179
if bestUpdateV == nil {
161-
slog.Debug("No suitable updates found within major version constraint")
162-
return nil, nil
180+
return "", nil
163181
}
164-
slog.Debug(" bestUpdateV.Original()", bestUpdateV.Original(), "")
165-
slog.Debug(" bestUpdateV.String()", bestUpdateV.String(), "")
166-
return []update.UpgradablePackage{{
167-
Type: update.Arduino,
168-
Name: "arduino:zephyr",
169-
FromVersion: platformSummary.GetInstalledVersion(),
170-
ToVersion: bestUpdateV.Original(),
171-
}}, nil
182+
return bestUpdateV.Original(), nil
172183
}
173184

174185
// UpgradePackages implements ServiceUpdater.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package arduino
2+
3+
import "testing"
4+
5+
func TestFindBestCandidate(t *testing.T) {
6+
tests := []struct {
7+
name string
8+
installed string
9+
available []string
10+
maxMajorConfig int
11+
expectedVersion string
12+
expectError bool
13+
}{
14+
{
15+
name: "Standard update: minor upgrade available",
16+
installed: "1.0.0",
17+
available: []string{"1.0.1", "1.1.0"},
18+
maxMajorConfig: 0,
19+
expectedVersion: "1.1.0",
20+
expectError: false,
21+
},
22+
{
23+
name: "Major update blocked by default (Config=0)",
24+
installed: "1.9.9",
25+
available: []string{"2.0.0", "1.9.10"},
26+
maxMajorConfig: 0,
27+
expectedVersion: "1.9.10",
28+
expectError: false,
29+
},
30+
{
31+
name: "Major update allowed by explicit config",
32+
installed: "1.9.9",
33+
available: []string{"2.0.0", "3.0.0"},
34+
maxMajorConfig: 2,
35+
expectedVersion: "2.0.0",
36+
expectError: false,
37+
},
38+
{
39+
name: "CRITICAL: Regression test for 'Zero Value' bug (Version 2+)",
40+
installed: "2.1.0",
41+
available: []string{"2.2.0", "3.0.0"},
42+
maxMajorConfig: 0,
43+
expectedVersion: "2.2.0",
44+
expectError: false,
45+
},
46+
{
47+
name: "No updates available (all older or same)",
48+
installed: "1.5.0",
49+
available: []string{"1.0.0", "1.5.0"},
50+
maxMajorConfig: 0,
51+
expectedVersion: "",
52+
expectError: false,
53+
},
54+
{
55+
name: "Handle unsorted list and pick highest valid",
56+
installed: "1.0.0",
57+
available: []string{"1.1.0", "1.5.0", "1.2.0"},
58+
maxMajorConfig: 0,
59+
expectedVersion: "1.5.0",
60+
expectError: false,
61+
},
62+
{
63+
name: "Skip invalid candidate strings",
64+
installed: "1.0.0",
65+
available: []string{"invalid-ver", "1.1.0"},
66+
maxMajorConfig: 0,
67+
expectedVersion: "1.1.0",
68+
expectError: false,
69+
},
70+
{
71+
name: "Error on invalid installed version string",
72+
installed: "not-a-semver",
73+
available: []string{"1.0.0"},
74+
maxMajorConfig: 0,
75+
expectedVersion: "",
76+
expectError: true,
77+
},
78+
{
79+
name: "Prerelease handling (standard logic ignores prereleases unless specifically handled)",
80+
installed: "1.0.0",
81+
available: []string{"1.0.1-beta"},
82+
maxMajorConfig: 0,
83+
expectedVersion: "1.0.1-beta",
84+
expectError: false,
85+
},
86+
}
87+
88+
for _, tt := range tests {
89+
t.Run(tt.name, func(t *testing.T) {
90+
got, err := findBestCandidate(tt.installed, tt.available, tt.maxMajorConfig)
91+
92+
if (err != nil) != tt.expectError {
93+
t.Errorf("findBestCandidate() error = %v, expectError %v", err, tt.expectError)
94+
return
95+
}
96+
if got != tt.expectedVersion {
97+
t.Errorf("findBestCandidate() = %v, want %v", got, tt.expectedVersion)
98+
}
99+
})
100+
}
101+
}

0 commit comments

Comments
 (0)