Skip to content

Commit 3746afb

Browse files
committed
Add E2E search test for Azure DevOps
Signed-off-by: Jamie Magee <[email protected]>
1 parent 346b57b commit 3746afb

File tree

5 files changed

+116
-13
lines changed

5 files changed

+116
-13
lines changed

Makefile

+8
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,14 @@ e2e-gitlab: ## Runs e2e tests for GitLab only. TOKEN_TYPE is not used (since the
356356
e2e-gitlab: build-scorecard | $(GINKGO)
357357
TEST_GITLAB_EXTERNAL=1 TOKEN_TYPE="PAT" $(GINKGO) --race -p -vv -coverprofile=e2e-coverage.out --keep-separate-coverprofiles --focus ".*GitLab" ./...
358358

359+
e2e-azure-devops-token: ## Runs e2e tests that require a AZURE_DEVOPS_AUTH_TOKEN
360+
e2e-azure-devops-token: build-scorecard check-env-gitlab | $(GINKGO)
361+
TEST_AZURE_DEVOPS_EXTERNAL=1 TOKEN_TYPE="GITLAB_PAT" $(GINKGO) --race -p -vv -coverprofile=e2e-coverage.out --keep-separate-coverprofiles --focus '.*Azure DevOps' ./...
362+
363+
e2e-azure-devops: ## Runs e2e tests for Azure DevOps only. TOKEN_TYPE is not used (since these are public APIs), but must be set to something
364+
e2e-azure-devops: build-scorecard | $(GINKGO)
365+
TEST_AZURE_DEVOPS_EXTERNAL=1 TOKEN_TYPE="PAT" $(GINKGO) --race -p -vv -coverprofile=e2e-coverage.out --keep-separate-coverprofiles --focus ".*Azure DevOps" ./...
366+
359367
e2e-attestor: ## Runs e2e tests for scorecard-attestor
360368
cd attestor/e2e; go test -covermode=atomic -coverprofile=e2e-coverage.out; cd ../..
361369

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2024 OpenSSF Scorecard Authors
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+
15+
package azuredevopsrepo
16+
17+
import (
18+
"os"
19+
"testing"
20+
21+
. "github.com/onsi/ginkgo/v2"
22+
. "github.com/onsi/gomega"
23+
)
24+
25+
func TestAzureDevOpsRepoE2E(t *testing.T) {
26+
if val, exists := os.LookupEnv("SKIP_GINKGO"); exists && val == "1" {
27+
t.Skip()
28+
}
29+
if val, exists := os.LookupEnv("TEST_AZURE_DEVOPS_EXTERNAL"); !exists || val != "1" {
30+
t.Skip()
31+
}
32+
t.Parallel()
33+
RegisterFailHandler(Fail)
34+
RunSpecs(t, "Azure DevOps Repo Suite")
35+
}

clients/azuredevopsrepo/search.go

+10-6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"context"
1919
"errors"
2020
"fmt"
21+
"strings"
2122
"sync"
2223

2324
"github.com/microsoft/azure-devops-go-api/azuredevops/v7/search"
@@ -47,7 +48,7 @@ type (
4748
)
4849

4950
func (s *searchHandler) search(request clients.SearchRequest) (clients.SearchResponse, error) {
50-
filters, err := s.buildFilters(request)
51+
filters, query, err := s.buildFilters(request)
5152
if err != nil {
5253
return clients.SearchResponse{}, fmt.Errorf("handler.buildQuery: %w", err)
5354
}
@@ -56,7 +57,7 @@ func (s *searchHandler) search(request clients.SearchRequest) (clients.SearchRes
5657
args := search.FetchCodeSearchResultsArgs{
5758
Request: &search.CodeSearchRequest{
5859
Filters: &filters,
59-
SearchText: &request.Query,
60+
SearchText: &query,
6061
Top: &searchResultsPageSize,
6162
},
6263
}
@@ -68,11 +69,14 @@ func (s *searchHandler) search(request clients.SearchRequest) (clients.SearchRes
6869
return searchResponseFrom(searchResults), nil
6970
}
7071

71-
func (s *searchHandler) buildFilters(request clients.SearchRequest) (map[string][]string, error) {
72+
func (s *searchHandler) buildFilters(request clients.SearchRequest) (map[string][]string, string, error) {
7273
filters := make(map[string][]string)
74+
query := strings.Builder{}
7375
if request.Query == "" {
74-
return filters, fmt.Errorf("%w", errEmptyQuery)
76+
return filters, query.String(), fmt.Errorf("%w", errEmptyQuery)
7577
}
78+
query.WriteString(request.Query)
79+
query.WriteString(" ")
7680

7781
filters["Project"] = []string{s.repourl.project}
7882
filters["Repository"] = []string{s.repourl.name}
@@ -81,10 +85,10 @@ func (s *searchHandler) buildFilters(request clients.SearchRequest) (map[string]
8185
filters["Path"] = []string{request.Path}
8286
}
8387
if request.Filename != "" {
84-
filters["Filename"] = []string{request.Filename}
88+
query.WriteString(fmt.Sprintf("file:%s", request.Filename))
8589
}
8690

87-
return filters, nil
91+
return filters, query.String(), nil
8892
}
8993

9094
func searchResponseFrom(searchResults *search.CodeSearchResponse) clients.SearchResponse {
+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2024 OpenSSF Scorecard Authors
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+
15+
package azuredevopsrepo
16+
17+
import (
18+
"context"
19+
20+
"github.com/ossf/scorecard/v5/clients"
21+
22+
. "github.com/onsi/ginkgo/v2"
23+
. "github.com/onsi/gomega"
24+
)
25+
26+
var _ = Describe("E2E TEST: azuredevopsrepo.searchHandler", func() {
27+
Context("Search - Azure DevOps", func() {
28+
It("Should return search results", func() {
29+
Skip("We don't have a public Azure DevOps repo to test against")
30+
repo, err := MakeAzureDevOpsRepo("https://dev.azure.com/jamiemagee/jamiemagee/_git/scorecard")
31+
Expect(err).Should(BeNil())
32+
33+
repoClient, err := CreateAzureDevOpsClient(context.Background(), repo)
34+
Expect(err).Should(BeNil())
35+
36+
err = repoClient.InitRepo(repo, clients.HeadSHA, 0)
37+
Expect(err).Should(BeNil())
38+
39+
request := clients.SearchRequest{
40+
Query: "scorecard",
41+
Filename: "README.md",
42+
}
43+
results, err := repoClient.Search(request)
44+
Expect(err).Should(BeNil())
45+
Expect(results.Hits).Should(BeNumerically(">", 0))
46+
Expect(len(results.Results)).Should(BeNumerically(">", 0))
47+
})
48+
})
49+
})

clients/azuredevopsrepo/search_test.go

+14-7
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func Test_buildFilters(t *testing.T) {
3232
repourl *Repo
3333
request clients.SearchRequest
3434
expectedErr error
35+
expectedQuery string
3536
name string
3637
}{
3738
{
@@ -44,6 +45,7 @@ func Test_buildFilters(t *testing.T) {
4445
name: "repo",
4546
},
4647
expectedFilters: make(map[string][]string),
48+
expectedQuery: "",
4749
expectedErr: errEmptyQuery,
4850
},
4951
{
@@ -59,7 +61,8 @@ func Test_buildFilters(t *testing.T) {
5961
"Project": {"project"},
6062
"Repository": {"repo"},
6163
},
62-
expectedErr: nil,
64+
expectedQuery: "query ",
65+
expectedErr: nil,
6366
},
6467
{
6568
name: "query and path",
@@ -76,7 +79,8 @@ func Test_buildFilters(t *testing.T) {
7679
"Repository": {"repo"},
7780
"Path": {"path"},
7881
},
79-
expectedErr: nil,
82+
expectedQuery: "query ",
83+
expectedErr: nil,
8084
},
8185
{
8286
name: "query and filename",
@@ -91,9 +95,9 @@ func Test_buildFilters(t *testing.T) {
9195
expectedFilters: map[string][]string{
9296
"Project": {"project"},
9397
"Repository": {"repo"},
94-
"Filename": {"filename"},
9598
},
96-
expectedErr: nil,
99+
expectedQuery: "query file:filename",
100+
expectedErr: nil,
97101
},
98102
{
99103
name: "query, path, and filename",
@@ -110,9 +114,9 @@ func Test_buildFilters(t *testing.T) {
110114
"Project": {"project"},
111115
"Repository": {"repo"},
112116
"Path": {"path"},
113-
"Filename": {"filename"},
114117
},
115-
expectedErr: nil,
118+
expectedQuery: "query file:filename",
119+
expectedErr: nil,
116120
},
117121
}
118122

@@ -122,10 +126,13 @@ func Test_buildFilters(t *testing.T) {
122126
s := searchHandler{
123127
repourl: tt.repourl,
124128
}
125-
filters, err := s.buildFilters(tt.request)
129+
filters, query, err := s.buildFilters(tt.request)
126130
if tt.expectedErr != nil && !errors.Is(err, tt.expectedErr) {
127131
t.Fatalf("buildFilters() error = %v, ExpectedErr %v", err, tt.expectedErr)
128132
}
133+
if query != tt.expectedQuery {
134+
t.Errorf("buildFilters() query = %v, ExpectedQuery %v", query, tt.expectedQuery)
135+
}
129136
if diff := cmp.Diff(filters, tt.expectedFilters); diff != "" {
130137
t.Errorf("buildFilters() mismatch (-want +got):\n%s", diff)
131138
}

0 commit comments

Comments
 (0)