Skip to content

Commit 24a2abe

Browse files
committed
refactoring and testing
1 parent 25d8cfc commit 24a2abe

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
@@ -113,26 +113,45 @@ func (a *ArduinoPlatformUpdater) ListUpgradablePackages(cfg config.Configuration
113113
if platformSummary == nil {
114114
return nil, nil // No platform found
115115
}
116+
releasesMap := platformSummary.GetReleases()
116117

117-
installedVersionString := platformSummary.GetInstalledVersion()
118+
releases := make([]string, 0, len(releasesMap))
118119

119-
installedV, err := semver.NewVersion(installedVersionString)
120-
if err != nil {
121-
slog.Warn("Failed to parse installed version", "version", installedVersionString, "error", err)
120+
for k := range releasesMap {
121+
releases = append(releases, k)
122+
}
123+
bestVersion, err := findBestCandidate(
124+
platformSummary.GetInstalledVersion(),
125+
releases,
126+
cfg.MaxAllowedMajorVersion,
127+
)
128+
129+
if bestVersion == "" || err != nil {
122130
return nil, nil
123131
}
132+
return []update.UpgradablePackage{{
133+
Type: update.Arduino,
134+
Name: "arduino:zephyr",
135+
FromVersion: platformSummary.GetInstalledVersion(),
136+
ToVersion: bestVersion,
137+
}}, nil
138+
}
139+
func findBestCandidate(installedStr string, availableVersions []string, maxMajorConfig int) (string, error) {
140+
installedV, err := semver.NewVersion(installedStr)
141+
if err != nil {
142+
return "", err
143+
}
124144

125-
var maxMajor uint64
126-
if cfg.MaxAllowedMajorVersion > 0 {
127-
maxMajor = uint64(cfg.MaxAllowedMajorVersion)
145+
maxMajor := uint64(maxMajorConfig)
146+
if maxMajorConfig <= 0 {
147+
maxMajor = installedV.Major()
128148
}
149+
129150
var bestUpdateV *semver.Version
130151

131-
allReleases := platformSummary.GetReleases()
132-
for versionString := range allReleases {
133-
candidateV, err := semver.NewVersion(versionString)
152+
for _, vStr := range availableVersions {
153+
candidateV, err := semver.NewVersion(vStr)
134154
if err != nil {
135-
slog.Debug("Skipping unparsable version", "version", versionString, "error", err)
136155
continue
137156
}
138157

@@ -143,23 +162,15 @@ func (a *ArduinoPlatformUpdater) ListUpgradablePackages(cfg config.Configuration
143162
if !candidateV.GreaterThan(installedV) {
144163
continue
145164
}
146-
147165
if bestUpdateV == nil || candidateV.GreaterThan(bestUpdateV) {
148166
bestUpdateV = candidateV
149167
}
150168
}
169+
151170
if bestUpdateV == nil {
152-
slog.Debug("No suitable updates found within major version constraint")
153-
return nil, nil
171+
return "", nil
154172
}
155-
slog.Debug(" bestUpdateV.Original()", bestUpdateV.Original(), "")
156-
slog.Debug(" bestUpdateV.String()", bestUpdateV.String(), "")
157-
return []update.UpgradablePackage{{
158-
Type: update.Arduino,
159-
Name: "arduino:zephyr",
160-
FromVersion: platformSummary.GetInstalledVersion(),
161-
ToVersion: bestUpdateV.Original(),
162-
}}, nil
173+
return bestUpdateV.Original(), nil
163174
}
164175

165176
// 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)