Skip to content

Commit c1d9d4f

Browse files
rverdilejlsherrill
andcommitted
update config.yaml.example
fix query add limit add close method add new test cases add mock Co-authored-by: Justin Sherrill <[email protected]>
1 parent 71b39a5 commit c1d9d4f

File tree

10 files changed

+215
-30
lines changed

10 files changed

+215
-30
lines changed

README.md

+7-3
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ t, err := tangy.New(dbConfig, tangy.Logger{Enabled: false})
2424
if err != nil {
2525
return err
2626
}
27+
defer t.Close()
2728

28-
// Use Tangy to search for RPMs, by name, that are associated to a specific repository version
29+
// Use Tangy to search for RPMs, by name, that are associated to a specific repository version, returning up to the first 100 results
2930
versionHref := "/pulp/e1c6bee3/api/v3/repositories/rpm/rpm/018c1c95-4281-76eb-b277-842cbad524f4/versions/1/"
30-
rows, err := t.RpmRepositoryVersionPackageSearch(context.Background(), []string{versionHref}, "ninja")
31+
rows, err := t.RpmRepositoryVersionPackageSearch(context.Background(), []string{versionHref}, "ninja", 100)
3132
if err != nil {
3233
return err
3334
}
@@ -56,4 +57,7 @@ The default values provided in config.yaml.example will work with this server.
5657
`make compose-down`
5758

5859
#### Clean container volumes
59-
`make compose-clean`
60+
`make compose-clean`
61+
62+
### Mocking
63+
Tangy also exports a mock interface you can regenerate using the [mockery](https://github.com/vektra/mockery) tool.

configs/config.yaml.example

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ database:
99
# Configuration options for the pulp server
1010
server:
1111
url: "http://localhost:8087"
12-
username: "pulp"
12+
username: "admin"
1313
password: "password"
1414
storage_type: "local"
1515
download_policy: "on_demand"

example.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ func main() {
2727
fmt.Println(err)
2828
return
2929
}
30+
defer t.Close()
3031

3132
// Call helper function that creates and syncs a repository
3233
versionHref, err := CreateRepositoryVersion()
@@ -35,8 +36,8 @@ func main() {
3536
return
3637
}
3738

38-
// Use Tangy to search for RPMs, by name, that are associated to a specific repository version
39-
rows, err := t.RpmRepositoryVersionPackageSearch(context.Background(), []string{versionHref}, "ninja")
39+
// Use Tangy to search for RPMs, by name, that are associated to a specific repository version, returning up to the first 100 results
40+
rows, err := t.RpmRepositoryVersionPackageSearch(context.Background(), []string{versionHref}, "ninja", 100)
4041
if err != nil {
4142
fmt.Println(err)
4243
return
@@ -58,7 +59,7 @@ func CreateRepositoryVersion() (versionHref string, err error) {
5859
DownloadPolicy: "on_demand",
5960
})
6061

61-
domainName := "example_domain"
62+
domainName := "example-domain"
6263

6364
// Create domain and repository, then sync repository, to create a new repository version with rpm packages
6465
_, err = rpmZest.LookupOrCreateDomain(domainName)

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.20
44

55
require (
66
github.com/content-services/zest/release/v2023 v2023.11.1701177874
7+
github.com/google/uuid v1.4.0
78
github.com/jackc/pgx-zerolog v0.0.0-20230315001418-f978528409eb
89
github.com/jackc/pgx/v5 v5.5.1
910
github.com/rs/zerolog v1.31.0
@@ -32,6 +33,7 @@ require (
3233
github.com/spf13/afero v1.11.0 // indirect
3334
github.com/spf13/cast v1.6.0 // indirect
3435
github.com/spf13/pflag v1.0.5 // indirect
36+
github.com/stretchr/objx v0.5.0 // indirect
3537
github.com/subosito/gotenv v1.6.0 // indirect
3638
go.uber.org/atomic v1.9.0 // indirect
3739
go.uber.org/multierr v1.9.0 // indirect

go.sum

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
1010
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
1111
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
1212
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
13+
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
14+
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
1315
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
1416
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
1517
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
@@ -61,6 +63,7 @@ github.com/spf13/viper v1.18.1 h1:rmuU42rScKWlhhJDyXZRKJQHXFX02chSVW1IvkPGiVM=
6163
github.com/spf13/viper v1.18.1/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
6264
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
6365
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
66+
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
6467
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
6568
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
6669
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=

internal/test/integration/rpm_test.go

+62-6
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ type RpmSuite struct {
1818
client *zestwrapper.RpmZest
1919
tangy tangy.Tangy
2020
domainName string
21+
remoteHref string
22+
repoHref string
2123
}
2224

2325
const testRepoName = "rpm modular"
24-
const testRepoURL = "https://fixtures.pulpproject.org/rpm-modular/"
26+
const testRepoURL = "https://jlsherrill.fedorapeople.org/fake-repos/revision/one/"
27+
const testRepoURLTwo = "https://jlsherrill.fedorapeople.org/fake-repos/revision/two/"
2528

2629
func (r *RpmSuite) CreateTestRepository(t *testing.T) {
2730
domainName := RandStringBytes(10)
@@ -33,13 +36,27 @@ func (r *RpmSuite) CreateTestRepository(t *testing.T) {
3336
repoHref, remoteHref, err := r.client.CreateRepository(domainName, testRepoName, testRepoURL)
3437
require.NoError(t, err)
3538

39+
r.repoHref = repoHref
40+
r.remoteHref = remoteHref
41+
3642
syncTask, err := r.client.SyncRpmRepository(repoHref, remoteHref)
3743
require.NoError(t, err)
3844

3945
_, err = r.client.PollTask(syncTask)
4046
require.NoError(t, err)
4147
}
4248

49+
func (r *RpmSuite) UpdateTestRepository(t *testing.T, url string) {
50+
err := r.client.UpdateRemote(r.remoteHref, url)
51+
require.NoError(t, err)
52+
53+
syncTask, err := r.client.SyncRpmRepository(r.repoHref, r.remoteHref)
54+
require.NoError(t, err)
55+
56+
_, err = r.client.PollTask(syncTask)
57+
require.NoError(t, err)
58+
}
59+
4360
func TestRpmSuite(t *testing.T) {
4461
s := config.Get().Server
4562
rpmZest := zestwrapper.NewRpmZest(context.Background(), s)
@@ -51,7 +68,7 @@ func TestRpmSuite(t *testing.T) {
5168
Port: dbConfig.Port,
5269
User: dbConfig.User,
5370
Password: dbConfig.Password,
54-
}, tangy.Logger{Enabled: false})
71+
}, tangy.Logger{})
5572
require.NoError(t, err)
5673

5774
r := RpmSuite{}
@@ -64,12 +81,51 @@ func TestRpmSuite(t *testing.T) {
6481
func (r *RpmSuite) TestRpmRepositoryVersionPackageSearch() {
6582
resp, err := r.client.GetRpmRepositoryByName(r.domainName, testRepoName)
6683
require.NoError(r.T(), err)
67-
versionHref := resp.LatestVersionHref
68-
require.NotNil(r.T(), versionHref)
84+
firstVersionHref := resp.LatestVersionHref
85+
require.NotNil(r.T(), firstVersionHref)
86+
87+
// Search first repository version
88+
search, err := r.tangy.RpmRepositoryVersionPackageSearch(context.Background(), []string{*firstVersionHref}, "bea", 100)
89+
assert.NoError(r.T(), err)
90+
assert.Equal(r.T(), search[0].Name, "bear")
91+
search, err = r.tangy.RpmRepositoryVersionPackageSearch(context.Background(), []string{*firstVersionHref}, "cam", 100)
92+
assert.NoError(r.T(), err)
93+
assert.Empty(r.T(), search)
94+
95+
// Create second repository version
96+
r.UpdateTestRepository(r.T(), testRepoURLTwo)
97+
resp, err = r.client.GetRpmRepositoryByName(r.domainName, testRepoName)
98+
require.NoError(r.T(), err)
99+
secondVersionHref := resp.LatestVersionHref
100+
require.NotNil(r.T(), secondVersionHref)
101+
102+
// Search second repository version, should have new package
103+
search, err = r.tangy.RpmRepositoryVersionPackageSearch(context.Background(), []string{*secondVersionHref}, "bea", 100)
104+
assert.NoError(r.T(), err)
105+
assert.Equal(r.T(), search[0].Name, "bear")
106+
search, err = r.tangy.RpmRepositoryVersionPackageSearch(context.Background(), []string{*secondVersionHref}, "cam", 100)
107+
assert.NoError(r.T(), err)
108+
assert.Equal(r.T(), search[0].Name, "camel")
109+
110+
// Re-search the first version, should be the same
111+
search, err = r.tangy.RpmRepositoryVersionPackageSearch(context.Background(), []string{*firstVersionHref}, "bea", 100)
112+
assert.NoError(r.T(), err)
113+
assert.Equal(r.T(), search[0].Name, "bear")
114+
search, err = r.tangy.RpmRepositoryVersionPackageSearch(context.Background(), []string{*firstVersionHref}, "cam", 100)
115+
assert.NoError(r.T(), err)
116+
assert.Empty(r.T(), search)
117+
118+
// Search both versions
119+
search, err = r.tangy.RpmRepositoryVersionPackageSearch(context.Background(), []string{*firstVersionHref, *secondVersionHref}, "a", 100)
120+
assert.NoError(r.T(), err)
121+
assert.Len(r.T(), search, 2)
122+
assert.Equal(r.T(), search[0].Name, "bear")
123+
assert.Equal(r.T(), search[1].Name, "camel")
69124

70-
search, err := r.tangy.RpmRepositoryVersionPackageSearch(context.Background(), []string{*versionHref}, "ninja")
125+
// Test search limit
126+
search, err = r.tangy.RpmRepositoryVersionPackageSearch(context.Background(), []string{*secondVersionHref}, "a", 1)
71127
assert.NoError(r.T(), err)
72-
assert.Equal(r.T(), search[0].Name, "ninja-build")
128+
assert.Len(r.T(), search, 1)
73129
}
74130

75131
func RandStringBytes(n int) string {

internal/zestwrapper/rpm.go

+11
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,17 @@ func (r *RpmZest) CreateRepository(domain, name, url string) (repoHref string, r
116116
return *resp.PulpHref, *remoteResponse.PulpHref, nil
117117
}
118118

119+
func (r *RpmZest) UpdateRemote(remoteHref string, url string) error {
120+
_, httpResp, err := r.client.RemotesRpmAPI.RemotesRpmRpmPartialUpdate(r.ctx, remoteHref).PatchedrpmRpmRemote(zest.PatchedrpmRpmRemote{Url: &url}).Execute()
121+
if httpResp != nil {
122+
defer httpResp.Body.Close()
123+
}
124+
if err != nil {
125+
return err
126+
}
127+
return nil
128+
}
129+
119130
func (r *RpmZest) SyncRpmRepository(rpmRpmRepositoryHref string, remoteHref string) (string, error) {
120131
rpmRepositoryHref := *zest.NewRpmRepositorySyncURL()
121132
rpmRepositoryHref.SetRemote(remoteHref)

pkg/tangy/interface.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ type tangyImpl struct {
5050
logger Logger
5151
}
5252

53+
//go:generate mockery --name Tangy --filename tangy_mock.go --inpackage
5354
type Tangy interface {
54-
RpmRepositoryVersionPackageSearch(ctx context.Context, hrefs []string, search string) ([]RpmPackageSearch, error)
55+
RpmRepositoryVersionPackageSearch(ctx context.Context, hrefs []string, search string, limit int) ([]RpmPackageSearch, error)
56+
Close()
57+
}
58+
59+
// Close closes the DB connection pool
60+
func (t *tangyImpl) Close() {
61+
t.pool.Close()
5562
}

pkg/tangy/rpm.go

+58-16
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,64 @@ package tangy
22

33
import (
44
"context"
5+
"fmt"
6+
"strconv"
57
"strings"
68

9+
"github.com/google/uuid"
710
"github.com/jackc/pgx/v5"
811
)
912

13+
const DefaultLimit = 500
14+
1015
type RpmPackageSearch struct {
1116
Name string
1217
Summary string
1318
}
1419

15-
func (t *tangyImpl) RpmRepositoryVersionPackageSearch(ctx context.Context, hrefs []string, search string) ([]RpmPackageSearch, error) {
20+
// RpmRepositoryVersionPackageSearch search for RPMs, by name, associated to repository hrefs, returning an amount up to limit
21+
func (t *tangyImpl) RpmRepositoryVersionPackageSearch(ctx context.Context, hrefs []string, search string, limit int) ([]RpmPackageSearch, error) {
1622
conn, err := t.pool.Acquire(ctx)
1723
if err != nil {
1824
return nil, err
1925
}
2026
defer conn.Release()
2127

22-
query := `
23-
SELECT DISTINCT ON (rp.name) rp.name, rp.summary
24-
FROM core_repositoryversion crv
25-
INNER JOIN core_repository cr on crv.repository_id = cr.pulp_id
26-
INNER JOIN core_repositorycontent crc on cr.pulp_id = crc.repository_id
27-
INNER JOIN core_content cc on crc.content_id = cc.pulp_id
28-
INNER JOIN rpm_package rp on cc.pulp_id = rp.content_ptr_id
29-
WHERE CONCAT(crv.repository_id, '/', crv.number) = ANY ($1)
30-
AND rp.name ILIKE CONCAT( '%', $2::text, '%')
31-
ORDER BY rp.name ASC
32-
`
33-
concatenatedIdAndVersion := parseRepositoryVersionHrefs(hrefs)
34-
rows, err := conn.Query(context.Background(), query, concatenatedIdAndVersion, search)
28+
if limit == 0 {
29+
limit = DefaultLimit
30+
}
31+
32+
repositoryIDs, versions, err := parseRepositoryVersionHrefs(hrefs)
33+
if err != nil {
34+
return nil, fmt.Errorf("error parsing repository version hrefs: %w", err)
35+
}
36+
37+
var query string
38+
for i := 0; i < len(repositoryIDs); i++ {
39+
id := repositoryIDs[i]
40+
ver := versions[i]
41+
42+
query += fmt.Sprintf(`
43+
SELECT DISTINCT ON (rp.name) rp.name, rp.summary
44+
FROM rpm_package rp
45+
WHERE rp.content_ptr_id IN (
46+
SELECT crc.content_id
47+
FROM core_repositorycontent crc
48+
INNER JOIN core_repositoryversion crv ON (crc.version_added_id = crv.pulp_id)
49+
LEFT OUTER JOIN core_repositoryversion crv2 ON (crc.version_removed_id = crv2.pulp_id)
50+
WHERE crv.repository_id = '%v' AND crv.number <= %v AND NOT (crv2.number <= %v AND crv2.number IS NOT NULL)
51+
AND rp.name ILIKE CONCAT( '%%', '%v'::text, '%%') ORDER BY rp.name ASC LIMIT %v
52+
)
53+
`, id, ver, ver, search, limit)
54+
55+
if i == len(repositoryIDs)-1 {
56+
query += ";"
57+
break
58+
}
59+
60+
query += "UNION"
61+
}
62+
rows, err := conn.Query(context.Background(), query)
3563
if err != nil {
3664
return nil, err
3765
}
@@ -42,11 +70,25 @@ func (t *tangyImpl) RpmRepositoryVersionPackageSearch(ctx context.Context, hrefs
4270
return rpms, nil
4371
}
4472

45-
func parseRepositoryVersionHrefs(hrefs []string) (concatenatedIdAndVersion []string) {
73+
func parseRepositoryVersionHrefs(hrefs []string) (repositoryIDs []string, versions []int, err error) {
4674
// /pulp/e1c6bee3/api/v3/repositories/rpm/rpm/018c1c95-4281-76eb-b277-842cbad524f4/versions/1/
4775
for _, href := range hrefs {
4876
splitHref := strings.Split(href, "/")
49-
concatenatedIdAndVersion = append(concatenatedIdAndVersion, splitHref[8]+"/"+splitHref[10])
77+
id := splitHref[8]
78+
num := splitHref[10]
79+
80+
_, err = uuid.Parse(id)
81+
if err != nil {
82+
return nil, nil, fmt.Errorf("%v is not a valid uuid", id)
83+
}
84+
85+
ver, err := strconv.Atoi(num)
86+
if err != nil {
87+
return nil, nil, fmt.Errorf("%v is not a valid integer", num)
88+
}
89+
90+
repositoryIDs = append(repositoryIDs, id)
91+
versions = append(versions, ver)
5092
}
5193
return
5294
}

0 commit comments

Comments
 (0)