Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
yahavi committed Nov 9, 2023
2 parents dc27aae + 93c64fa commit 0abdd92
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 10 deletions.
1 change: 1 addition & 0 deletions artifactory/services/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ type AdditionalRepositoryBaseParams struct {
PropertySets []string `json:"propertySets,omitempty"`
DownloadRedirect *bool `json:"downloadRedirect,omitempty"`
PriorityResolution *bool `json:"priorityResolution,omitempty"`
CdnRedirect *bool `json:"cdnRedirect,omitempty"`
}

type CargoRepositoryParams struct {
Expand Down
56 changes: 55 additions & 1 deletion artifactory/services/utils/aqlquerybuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,30 @@ package utils

import (
"fmt"
"golang.org/x/exp/slices"
"strconv"
"strings"
"unicode"

"golang.org/x/exp/slices"

"github.com/jfrog/jfrog-client-go/utils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
)

const spaceEncoding = "%20"

var specialAqlCharacters = map[rune]string{
'/': "%2F",
'\\': "%5C",
'|': "%7C",
'*': "%2A",
'?': "%3F",
'\'': "%22",
':': "%3A",
';': "%3B",
'%': "%25",
}

// Returns an AQL body string to search file in Artifactory by pattern, according the specified arguments requirements.
func CreateAqlBodyForSpecWithPattern(params *CommonParams) (string, error) {
searchPattern := prepareSourceSearchPattern(params.Pattern, params.Target)
Expand Down Expand Up @@ -149,6 +165,44 @@ func CreateAqlQueryForPypi(repo, file string) string {
return fmt.Sprintf(itemsPart, repo, file, buildIncludeQueryPart([]string{"name", "repo", "path", "actual_md5", "actual_sha1", "sha256"}))
}

// noinspection GoUnusedExportedFunction
func CreateAqlQueryForBuildInfoJson(project, buildName, buildNumber, timestamp string) string {
if project == "" {
project = "artifactory"
} else {
project = encodeForBuildInfoRepository(project)
}
itemsPart :=
`items.find({
"repo": "%s",
"path": {
"$match": "%s"
},
"name": {
"$match": "%s-%s.json"
}
})%s`
return fmt.Sprintf(itemsPart, project+"-build-info", encodeForBuildInfoRepository(buildName), encodeForBuildInfoRepository(buildNumber), timestamp, buildIncludeQueryPart([]string{"name", "repo", "path", "actual_sha1", "actual_md5"}))
}

func encodeForBuildInfoRepository(value string) string {
results := ""
for _, char := range value {
if unicode.IsSpace(char) {
char = ' '
}
if encoding, exist := specialAqlCharacters[char]; exist {
results += encoding
} else {
results += string(char)
}
}
slashEncoding := specialAqlCharacters['/']
results = strings.ReplaceAll(results, slashEncoding+" ", slashEncoding+spaceEncoding)
results = strings.ReplaceAll(results, " "+slashEncoding, spaceEncoding+slashEncoding)
return results
}

func CreateAqlQueryForLatestCreated(repo, path string) string {
itemsPart :=
`items.find({` +
Expand Down
33 changes: 33 additions & 0 deletions artifactory/services/utils/aqlquerybuilder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,36 @@ func TestBuildKeyValQueryPart(t *testing.T) {
})
}
}

var encodeForBuildInfoRepositoryProvider = []struct {
value string
expectedEncoding string
}{
// Shouldn't encode
{"", ""},
{"a", "a"},
{"a b", "a b"},
{"a.b", "a.b"},
{"a&b", "a&b"},

// Should encode
{"a/b", "a%2Fb"},
{"a\\b", "a%5Cb"},
{"a:b", "a%3Ab"},
{"a|b", "a%7Cb"},
{"a*b", "a%2Ab"},
{"a?b", "a%3Fb"},
{"a / b", "a %20%2F%20 b"},

// Should convert whitespace to space
{"a\tb", "a b"},
{"a\nb", "a b"},
}

func TestEncodeForBuildInfoRepository(t *testing.T) {
for _, testCase := range encodeForBuildInfoRepositoryProvider {
t.Run(testCase.value, func(t *testing.T) {
assert.Equal(t, testCase.expectedEncoding, encodeForBuildInfoRepository(testCase.value))
})
}
}
45 changes: 45 additions & 0 deletions tests/artifactoryaql_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package tests

import (
"encoding/json"
"fmt"
"io"
"strings"
"testing"

"github.com/jfrog/jfrog-client-go/artifactory/services/utils"
"github.com/stretchr/testify/assert"
)

func TestCreateAqlQueryForBuildInfoJson(t *testing.T) {
initArtifactoryTest(t)

// Create a build
buildName := fmt.Sprintf("%s-%s", "a / \\ | \t * ? : ; \\ / %b", getRunId())
err := createDummyBuild(buildName)
assert.NoError(t, err)

// Run AQL to get the build from Artifactory
aqlQuery := utils.CreateAqlQueryForBuildInfoJson("", buildName, buildNumber, buildTimestamp)
stream, err := testsAqlService.ExecAql(aqlQuery)
assert.NoError(t, err)
defer func() {
assert.NoError(t, stream.Close())
}()

// Parse AQL results
aqlResults, err := io.ReadAll(stream)
assert.NoError(t, err)
parsedResult := new(utils.AqlSearchResult)
err = json.Unmarshal(aqlResults, parsedResult)
assert.NoError(t, err)
assert.Len(t, parsedResult.Results, 1)

// Verify build checksum exist
assert.NotEmpty(t, parsedResult.Results[0].Actual_Sha1)
assert.NotEmpty(t, parsedResult.Results[0].Actual_Md5)

// Delete build
encodedBuildName := strings.TrimSuffix(parsedResult.Results[0].Path, "-"+buildTimestamp+".json")
assert.NoError(t, deleteBuild(encodedBuildName))
}
1 change: 1 addition & 0 deletions tests/jfrogclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func setupIntegrationTests() {
createArtifactoryFederationManager()
createArtifactorySystemManager()
createArtifactoryStorageManager()
createArtifactoryAqlManager()
}

if *TestDistribution {
Expand Down
23 changes: 15 additions & 8 deletions tests/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"flag"
"fmt"
"net/http"
"net/url"
"os"
"path/filepath"
"runtime"
Expand Down Expand Up @@ -95,6 +96,7 @@ var (
testsFederationService *services.FederationService
testsSystemService *services.SystemService
testsStorageService *services.StorageService
testsAqlService *services.AqlService

// Distribution services
testsBundleSetSigningKeyService *distributionServices.SetSigningKeyService
Expand Down Expand Up @@ -133,6 +135,8 @@ var (

const (
HttpClientCreationFailureMessage = "Failed while attempting to create HttpClient: %s"
buildNumber = "1.0.0"
buildTimestamp = "1412067619893"
)

func init() {
Expand Down Expand Up @@ -413,6 +417,13 @@ func createArtifactoryStorageManager() {
testsStorageService = services.NewStorageService(artDetails, client)
}

func createArtifactoryAqlManager() {
artDetails := GetRtDetails()
client, err := createJfrogHttpClient(&artDetails)
failOnHttpClientCreation(err)
testsAqlService = services.NewAqlService(artDetails, client)
}

func createJfrogHttpClient(artDetailsPtr *auth.ServiceDetails) (*jfroghttpclient.JfrogHttpClient, error) {
artDetails := *artDetailsPtr
return jfroghttpclient.JfrogClientBuilder().
Expand Down Expand Up @@ -938,7 +949,7 @@ func isRepoExists(t *testing.T, repoKey string) bool {
func createDummyBuild(buildName string) error {
dataArtifactoryBuild := &buildinfo.BuildInfo{
Name: buildName,
Number: "1.0.0",
Number: buildNumber,
Started: "2014-09-30T12:00:19.893+0300",
Modules: []buildinfo.Module{{
Id: "example-module",
Expand All @@ -959,24 +970,20 @@ func createDummyBuild(buildName string) error {
}

func deleteBuild(buildName string) error {
err := deleteBuildIndex(buildName)
if err != nil {
return err
}

artDetails := GetRtDetails()
artHTTPDetails := artDetails.CreateHttpClientDetails()
client, err := httpclient.ClientBuilder().Build()
if err != nil {
return err
}

resp, _, err := client.SendDelete(artDetails.GetUrl()+"api/build/"+buildName+"?deleteAll=1", nil, artHTTPDetails, "")
buildName = url.PathEscape(buildName)
resp, _, err := client.SendDelete(artDetails.GetUrl()+"artifactory-build-info/"+buildName, nil, artHTTPDetails, "")

if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
if resp.StatusCode != http.StatusNoContent {
return errors.New("failed to delete build " + resp.Status)
}

Expand Down
1 change: 1 addition & 0 deletions tests/xraybinmgr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func TestXrayBinMgr(t *testing.T) {
func addBuildsToIndexing(t *testing.T) {
buildName := fmt.Sprintf("%s-%s", "build1", getRunId())
defer func() {
assert.NoError(t, deleteBuildIndex(buildName))
assert.NoError(t, deleteBuild(buildName))
}()
// Create a build
Expand Down
2 changes: 2 additions & 0 deletions tests/xraywatch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,14 @@ func testXrayWatchSelectedRepos(t *testing.T) {
err = createAndIndexBuild(t, build1Name)
assert.NoError(t, err)
defer func() {
assert.NoError(t, deleteBuildIndex(build1Name))
assert.NoError(t, deleteBuild(build1Name))
}()
build2Name := fmt.Sprintf("%s-%s", "build2", getRunId())
err = createAndIndexBuild(t, build2Name)
assert.NoError(t, err)
defer func() {
assert.NoError(t, deleteBuildIndex(build2Name))
assert.NoError(t, deleteBuild(build2Name))
}()
paramsSelectedRepos := utils.NewWatchParams()
Expand Down
2 changes: 1 addition & 1 deletion utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
const (
Development = "development"
Agent = "jfrog-client-go"
Version = "1.34.4"
Version = "1.34.5"
)

type MinVersionProduct string
Expand Down

0 comments on commit 0abdd92

Please sign in to comment.