Skip to content

Commit 5023256

Browse files
authored
🧪 QD-12546 Add more tests to improve coverage
* 🧪 Add more tests to improve coverage * 🧱 QD-12546 Add Qodana baseline
1 parent ee544ca commit 5023256

39 files changed

+36966
-20
lines changed

.github/qodana.sarif.json

Lines changed: 31822 additions & 0 deletions
Large diffs are not rendered by default.

.github/workflows/ci.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,13 @@ jobs:
119119
- name: Merge coverage reports
120120
run: |
121121
mkdir -p .qodana/code-coverage
122-
find coverage-reports -name "*.out" -exec cat {} \; > .qodana/code-coverage/coverage.out
122+
echo "mode: set" > .qodana/code-coverage/coverage.out
123+
find coverage-reports -name "*.out" -exec tail -n +2 {} \; >> .qodana/code-coverage/coverage.out
123124
- uses: JetBrains/qodana-action@main
124125
env:
125126
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
126127
with:
128+
args: --baseline,.github/qodana.sarif.json
127129
use-nightly: true
128130
pr-mode: false
129131
upload-result: true

.github/workflows/test.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ jobs:
6767
run: go test -v -json ./... -timeout 0 -coverpkg=./... -coverprofile=coverage-${{ inputs.os }}.out | tparse -all -follow
6868
env:
6969
QODANA_LICENSE_ONLY_TOKEN: ${{ secrets.QODANA_LICENSE_ONLY_TOKEN }}
70+
QODANA_TEST_CONTAINER: ${{ inputs.os == 'ubuntu-latest' && inputs.container-engine == 'docker@latest' && '1' || '' }}
7071

7172
- name: Upload coverage
7273
uses: actions/upload-artifact@v6

cdnet/scripts/process-cltzip.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//go:build ignore
2+
13
// Compute SHA-256 checksum for clt.zip artifact.
24
package main
35

internal/cloud/cloud_test.go

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,82 @@ func TestGetProjectByStaging(t *testing.T) {
6868
}
6969
}
7070

71+
func TestGetCloudTeamsPageUrl(t *testing.T) {
72+
endpoint := QdRootEndpoint{Url: "https://qodana.cloud"}
73+
result := endpoint.GetCloudTeamsPageUrl("github", "/path/to/myproject")
74+
expected := "https://qodana.cloud/?origin=github&name=myproject"
75+
if result != expected {
76+
t.Errorf("GetCloudTeamsPageUrl() = %q, want %q", result, expected)
77+
}
78+
}
79+
80+
func TestParseProjectName(t *testing.T) {
81+
tests := []struct {
82+
name string
83+
data string
84+
want string
85+
wantErr bool
86+
}{
87+
{"valid json", `{"name": "my-project"}`, "my-project", false},
88+
{"empty name", `{"name": ""}`, "", false},
89+
{"invalid json", `{invalid}`, "", true},
90+
}
91+
for _, tt := range tests {
92+
t.Run(tt.name, func(t *testing.T) {
93+
got, err := parseProjectName([]byte(tt.data))
94+
if (err != nil) != tt.wantErr {
95+
t.Errorf("parseProjectName() error = %v, wantErr %v", err, tt.wantErr)
96+
return
97+
}
98+
if got != tt.want {
99+
t.Errorf("parseProjectName() = %v, want %v", got, tt.want)
100+
}
101+
})
102+
}
103+
}
104+
105+
func TestApiVersionMismatchError(t *testing.T) {
106+
err := &ApiVersionMismatchError{
107+
ApiKind: "Cloud",
108+
SupportedVersions: []string{"1.0", "1.1"},
109+
}
110+
msg := err.Error()
111+
if msg == "" {
112+
t.Error("Expected non-empty error message")
113+
}
114+
if len(msg) < 10 {
115+
t.Errorf("Error message too short: %s", msg)
116+
}
117+
}
118+
119+
func TestToCloudVersion(t *testing.T) {
120+
tests := []struct {
121+
version string
122+
wantMajor int
123+
wantMinor int
124+
wantErr bool
125+
}{
126+
{"1.0", 1, 0, false},
127+
{"2.5", 2, 5, false},
128+
{"invalid", 0, 0, true},
129+
{"1.2.3", 0, 0, true},
130+
{"a.b", 0, 0, true},
131+
{"1.b", 0, 0, true},
132+
}
133+
for _, tt := range tests {
134+
t.Run(tt.version, func(t *testing.T) {
135+
got, err := ToCloudVersion(tt.version)
136+
if (err != nil) != tt.wantErr {
137+
t.Errorf("ToCloudVersion(%q) error = %v, wantErr %v", tt.version, err, tt.wantErr)
138+
return
139+
}
140+
if !tt.wantErr && (got.Major != tt.wantMajor || got.Minor != tt.wantMinor) {
141+
t.Errorf("ToCloudVersion(%q) = %v, want {%d, %d}", tt.version, got, tt.wantMajor, tt.wantMinor)
142+
}
143+
})
144+
}
145+
}
146+
71147
func TestGetReportUrl(t *testing.T) {
72148
for _, tc := range []struct {
73149
name string
@@ -103,3 +179,84 @@ func TestGetReportUrl(t *testing.T) {
103179
)
104180
}
105181
}
182+
183+
func TestGetEnvWithDefault(t *testing.T) {
184+
tests := []struct {
185+
name string
186+
env string
187+
value string
188+
setEnv bool
189+
defaultValue string
190+
expected string
191+
}{
192+
{"env set", "TEST_ENV_SET", "value", true, "default", "value"},
193+
{"env not set", "TEST_ENV_NOT_SET", "", false, "default", "default"},
194+
}
195+
196+
for _, tt := range tests {
197+
t.Run(tt.name, func(t *testing.T) {
198+
if tt.setEnv {
199+
_ = os.Setenv(tt.env, tt.value)
200+
defer func() {
201+
_ = os.Unsetenv(tt.env)
202+
}()
203+
}
204+
if got := GetEnvWithDefault(tt.env, tt.defaultValue); got != tt.expected {
205+
t.Errorf("GetEnvWithDefault() = %v, want %v", got, tt.expected)
206+
}
207+
})
208+
}
209+
}
210+
211+
func TestGetEnvWithDefaultInt(t *testing.T) {
212+
t.Run("env set", func(t *testing.T) {
213+
_ = os.Setenv("TEST_INT_ENV", "42")
214+
defer func() {
215+
_ = os.Unsetenv("TEST_INT_ENV")
216+
}()
217+
if got := GetEnvWithDefaultInt("TEST_INT_ENV", 10); got != 42 {
218+
t.Errorf("GetEnvWithDefaultInt() = %v, want 42", got)
219+
}
220+
})
221+
222+
t.Run("env not set", func(t *testing.T) {
223+
if got := GetEnvWithDefaultInt("TEST_INT_NOT_SET", 99); got != 99 {
224+
t.Errorf("GetEnvWithDefaultInt() = %v, want 99", got)
225+
}
226+
})
227+
}
228+
229+
func TestParseRawURL(t *testing.T) {
230+
tests := []struct {
231+
name string
232+
url string
233+
wantErr bool
234+
}{
235+
{"valid https", "https://example.com", false},
236+
{"valid http", "http://example.com", false},
237+
{"without scheme", "example.com", false},
238+
}
239+
240+
for _, tt := range tests {
241+
t.Run(tt.name, func(t *testing.T) {
242+
_, err := parseRawURL(tt.url)
243+
if (err != nil) != tt.wantErr {
244+
t.Errorf("parseRawURL() error = %v, wantErr %v", err, tt.wantErr)
245+
}
246+
})
247+
}
248+
}
249+
250+
func TestExtractVersions(t *testing.T) {
251+
descriptions := []ApiVersionDescription{
252+
{Version: "1.0", URL: "http://example.com/v1"},
253+
{Version: "2.0", URL: "http://example.com/v2"},
254+
}
255+
versions := extractVersions(descriptions)
256+
if len(versions) != 2 {
257+
t.Errorf("extractVersions() returned %d versions, want 2", len(versions))
258+
}
259+
if versions[0] != "1.0" || versions[1] != "2.0" {
260+
t.Errorf("extractVersions() returned incorrect versions: %v", versions)
261+
}
262+
}

internal/cloud/endpoints_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,64 @@ func TestWrongVersion(t *testing.T) {
288288
}
289289
}
290290

291+
func TestNewLintersApiClient(t *testing.T) {
292+
endpoints := &QdApiEndpoints{
293+
RootEndpoint: &QdRootEndpoint{Url: "https://qodana.cloud"},
294+
LintersApiUrl: "https://linters.api.url/v1",
295+
CloudApiUrl: "https://cloud.api.url/v1",
296+
}
297+
298+
t.Run("creates client with token", func(t *testing.T) {
299+
client := endpoints.NewLintersApiClient("test-token")
300+
assert.NotNil(t, client)
301+
assert.Equal(t, "https://linters.api.url/v1", client.apiUrl)
302+
assert.Equal(t, "test-token", client.token)
303+
assert.NotNil(t, client.httpClient)
304+
})
305+
306+
t.Run("creates client without token", func(t *testing.T) {
307+
client := endpoints.NewLintersApiClient("")
308+
assert.NotNil(t, client)
309+
assert.Equal(t, "", client.token)
310+
})
311+
}
312+
313+
func TestNewCloudApiClient(t *testing.T) {
314+
endpoints := &QdApiEndpoints{
315+
RootEndpoint: &QdRootEndpoint{Url: "https://qodana.cloud"},
316+
LintersApiUrl: "https://linters.api.url/v1",
317+
CloudApiUrl: "https://cloud.api.url/v1",
318+
}
319+
320+
t.Run("creates client with token", func(t *testing.T) {
321+
client := endpoints.NewCloudApiClient("test-token")
322+
assert.NotNil(t, client)
323+
assert.Equal(t, "https://cloud.api.url/v1", client.apiUrl)
324+
assert.Equal(t, "test-token", client.token)
325+
})
326+
}
327+
328+
func TestAPIError(t *testing.T) {
329+
err := &APIError{
330+
StatusCode: 404,
331+
Message: "Not found",
332+
}
333+
assert.Equal(t, "response code '404', message 'Not found'", err.Error())
334+
}
335+
336+
func TestNewCloudRequest(t *testing.T) {
337+
t.Cleanup(func() {
338+
_ = os.Unsetenv(qdenv.QodanaCloudRequestRetriesEnv)
339+
_ = os.Unsetenv(qdenv.QodanaCloudRequestCooldownEnv)
340+
})
341+
342+
request := NewCloudRequest("/test/path")
343+
assert.Equal(t, "/test/path", request.Path)
344+
assert.Equal(t, "GET", request.Method)
345+
assert.Contains(t, request.AcceptedStatuses, http.StatusUnauthorized)
346+
assert.Contains(t, request.AcceptedStatuses, http.StatusNotFound)
347+
}
348+
291349
func runRequest(
292350
t *testing.T,
293351
cooldown int,

internal/cloud/license_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,3 +278,56 @@ func TestExtractLicenseKey(t *testing.T) {
278278
)
279279
}
280280
}
281+
282+
func TestGetLicensePlan(t *testing.T) {
283+
expectedPlan := "ULTIMATE_PLUS"
284+
svr := httptest.NewServer(
285+
http.HandlerFunc(
286+
func(w http.ResponseWriter, r *http.Request) {
287+
if r.URL.Path != qodanaLicenseUri {
288+
t.Errorf("expected uri to be '%s' got '%s'", qodanaLicenseUri, r.URL.Path)
289+
}
290+
_, _ = fmt.Fprintf(w, `{"licenseId":"test","licenseKey":"key","licensePlan":"%s"}`, expectedPlan)
291+
},
292+
),
293+
)
294+
defer svr.Close()
295+
296+
apis := QdApiEndpoints{LintersApiUrl: svr.URL}
297+
plan := apis.GetLicensePlan("test-token")
298+
if plan != expectedPlan {
299+
t.Errorf("expected plan '%s' got '%s'", expectedPlan, plan)
300+
}
301+
}
302+
303+
func TestDeserializeLicenseDataFields(t *testing.T) {
304+
data := `{
305+
"licenseId": "ABC123",
306+
"licenseKey": "KEY456",
307+
"expirationDate": "2025-12-31",
308+
"projectIdHash": "proj_hash",
309+
"organizationIdHash": "org_hash",
310+
"licensePlan": "ULTIMATE"
311+
}`
312+
313+
result := DeserializeLicenseData([]byte(data))
314+
315+
if result.LicenseID != "ABC123" {
316+
t.Errorf("LicenseID: expected 'ABC123' got '%s'", result.LicenseID)
317+
}
318+
if result.LicenseKey != "KEY456" {
319+
t.Errorf("LicenseKey: expected 'KEY456' got '%s'", result.LicenseKey)
320+
}
321+
if result.ExpirationDate != "2025-12-31" {
322+
t.Errorf("ExpirationDate: expected '2025-12-31' got '%s'", result.ExpirationDate)
323+
}
324+
if result.ProjectIdHash != "proj_hash" {
325+
t.Errorf("ProjectIdHash: expected 'proj_hash' got '%s'", result.ProjectIdHash)
326+
}
327+
if result.OrganisationIdHash != "org_hash" {
328+
t.Errorf("OrganisationIdHash: expected 'org_hash' got '%s'", result.OrganisationIdHash)
329+
}
330+
if result.LicensePlan != "ULTIMATE" {
331+
t.Errorf("LicensePlan: expected 'ULTIMATE' got '%s'", result.LicensePlan)
332+
}
333+
}

0 commit comments

Comments
 (0)