Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for ansible #9

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ require (
github.com/docker/docker v27.1.1+incompatible
github.com/onsi/ginkgo/v2 v2.19.0
github.com/onsi/gomega v1.33.1
github.com/pkg/errors v0.9.1
gopkg.in/yaml.v3 v3.0.1
sigs.k8s.io/controller-runtime v0.18.3
)

Expand All @@ -31,7 +33,6 @@ require (
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
go.opentelemetry.io/otel v1.28.0 // indirect
Expand All @@ -48,6 +49,5 @@ require (
google.golang.org/grpc v1.66.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.1 // indirect
)
108 changes: 108 additions & 0 deletions test/acceptance/ansible_images_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package acceptance

import (
"fmt"
"log"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/securesign/structural-tests/test/support"
)

var _ = Describe("Trusted Artifact Signer Ansible", Ordered, func() {

var (
snapshotImages support.SnapshotMap
repositories *support.RepositoryList
ansibleTasImages support.AnsibleMap
ansibleOtherImages support.AnsibleMap
)

It("get and parse snapshot file", func() {
var err error
snapshotImages, err = support.ParseSnapshotImages()
Expect(err).NotTo(HaveOccurred())
Expect(snapshotImages).NotTo(BeEmpty(), "No images were detected in snapshot file")

repositories, err = support.LoadRepositoryList()
Expect(err).NotTo(HaveOccurred())
Expect(repositories.Data).NotTo(BeEmpty(), "No images were detected in repositories file")
})

It("get and parse ansible image definition file", func() {
allAnsibleTasImages, err := support.ParseAnsibleImages()
Expect(err).NotTo(HaveOccurred())
Expect(allAnsibleTasImages).NotTo(BeEmpty())

ansibleTasImages, ansibleOtherImages = support.SplitMap(allAnsibleTasImages, support.AnsibleTasImageKeys())
Expect(ansibleTasImages).NotTo(BeEmpty())
Expect(ansibleOtherImages).NotTo(BeEmpty())
support.LogMap(fmt.Sprintf("Ansible TAS images (%d):", len(ansibleTasImages)), ansibleTasImages)
support.LogMap(fmt.Sprintf("Ansible other images (%d):", len(ansibleOtherImages)), ansibleOtherImages)
})

It("ansible TAS images are listed in registry.redhat.io", func() {
var errs []error
for _, ansibleImage := range ansibleTasImages {
if repositories.FindByImage(ansibleImage) == nil {
errs = append(errs, fmt.Errorf("%w: %s", ErrNotFoundInRegistry, ansibleImage))
}
}
Expect(errs).To(BeEmpty())
})

It("ansible TAS images are all valid", func() {
Expect(support.GetMapKeys(ansibleTasImages)).To(ContainElements(support.AnsibleTasImageKeys()))
Expect(len(ansibleTasImages)).To(BeNumerically("==", len(support.AnsibleTasImageKeys())))
Expect(ansibleTasImages).To(HaveEach(MatchRegexp(support.TasImageDefinitionRegexp)))
})

It("ansible other images are all valid", func() {
Expect(support.GetMapKeys(ansibleOtherImages)).To(ContainElements(support.AnsibleOtherImageKeys()))
Expect(len(ansibleOtherImages)).To(BeNumerically("==", len(support.AnsibleOtherImageKeys())))
Expect(ansibleOtherImages).To(HaveEach(MatchRegexp(support.OtherImageDefinitionRegexp)))
})

It("all ansible TAS image hashes are also defined in releases snapshot", func() {
mapped := make(map[string]string)
for _, imageKey := range support.AnsibleTasImageKeys() {

// skip, while ansible uses older tuf image
if imageKey == "tas_single_node_tuf_image" {
log.Printf("Ansible uses differet TUF image - skipping")
log.Printf(" Ansible: %s", ansibleTasImages[imageKey])
log.Printf(" Snapshot: %s", snapshotImages[support.ConvertAnsibleImageKey(imageKey)])
continue
}

aSha := support.ExtractHash(ansibleTasImages[imageKey])
if _, keyExist := snapshotImages[support.ConvertAnsibleImageKey(imageKey)]; !keyExist {
mapped[imageKey] = "MISSING"
continue
}
sSha := support.ExtractHash(snapshotImages[support.ConvertAnsibleImageKey(imageKey)])
if aSha == sSha {
mapped[imageKey] = "match"
} else {
mapped[imageKey] = "DIFFERENT HASHES"
}
}
Expect(mapped).To(HaveEach("match"), "Ansible images are missing or have different hashes in snapshot file")
})

It("image hashes are all unique", func() {
aImageHashes := support.ExtractHashes(support.GetMapValues(ansibleTasImages))
hashesCounts := make(map[string]int)
for _, hash := range aImageHashes {
_, exist := hashesCounts[hash]
if exist {
hashesCounts[hash]++
} else {
hashesCounts[hash] = 1
}
}
Expect(hashesCounts).To(HaveEach(1))
Expect(ansibleTasImages).To(HaveLen(len(hashesCounts)))
})

})
2 changes: 1 addition & 1 deletion test/acceptance/fbc_images_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ var _ = Describe("File-based catalog images", Ordered, func() {
})

It("verify channels", func() {
expectedChannels := []string{"stable", "candidate-v1.1.0", "stable-v1.0"}
expectedChannels := []string{"stable", "stable-v1.0", "stable-v1.1"}
Expect(channels).To(HaveLen(len(expectedChannels)))

for _, channel := range channels {
Expand Down
18 changes: 11 additions & 7 deletions test/acceptance/operator_images_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,20 @@ var _ = Describe("Trusted Artifact Signer Operator", Ordered, func() {
operator string
)

It("get and parse snapshot.json file", func() {
It("get and parse snapshot file", func() {
var err error
snapshotImages, err = support.ParseSnapshotImages()
Expect(err).NotTo(HaveOccurred())
Expect(snapshotImages).NotTo(BeEmpty())
Expect(snapshotImages).NotTo(BeEmpty(), "No images were detected in snapshot file")

repositories, err = support.LoadRepositoryList()
Expect(err).NotTo(HaveOccurred())
Expect(snapshotImages).NotTo(BeEmpty())
Expect(repositories.Data).NotTo(BeEmpty(), "No images were detected in repositories file")
})

It("get operator image", func() {
operator = snapshotImages[support.OperatorImageKey]
Expect(operator).NotTo(BeEmpty())
Expect(operator).NotTo(BeEmpty(), "Operator image not detected in snapshot file")
log.Printf("Using %s\n", operator)
})

Expand Down Expand Up @@ -64,27 +64,31 @@ var _ = Describe("Trusted Artifact Signer Operator", Ordered, func() {
It("operator TAS images are all valid", func() {
Expect(support.GetMapKeys(operatorTasImages)).To(ContainElements(support.MandatoryTasOperatorImageKeys()))
Expect(len(operatorTasImages)).To(BeNumerically("==", len(support.MandatoryTasOperatorImageKeys())))
Expect(operatorTasImages).To(HaveEach(MatchRegexp(support.OperatorTasImageDefinitionRegexp)))
Expect(operatorTasImages).To(HaveEach(MatchRegexp(support.TasImageDefinitionRegexp)))
})

It("operator other images are all valid", func() {
Expect(support.GetMapKeys(operatorOtherImages)).To(ContainElements(support.OtherOperatorImageKeys()))
Expect(len(operatorOtherImages)).To(BeNumerically("==", len(support.OtherOperatorImageKeys())))
Expect(operatorOtherImages).To(HaveEach(MatchRegexp(support.OtherOperatorImageDefinitionRegexp)))
Expect(operatorOtherImages).To(HaveEach(MatchRegexp(support.OtherImageDefinitionRegexp)))
})

It("all image hashes are also defined in releases snapshot", func() {
mapped := make(map[string]string)
for _, imageKey := range support.MandatoryTasOperatorImageKeys() {
oSha := support.ExtractHash(operatorTasImages[imageKey])
if _, keyExist := snapshotImages[imageKey]; !keyExist {
mapped[imageKey] = "MISSING"
continue
}
sSha := support.ExtractHash(snapshotImages[imageKey])
if oSha == sSha {
mapped[imageKey] = "match"
} else {
mapped[imageKey] = "DIFFERENT HASHES"
}
}
Expect(mapped).To(HaveEach("match"))
Expect(mapped).To(HaveEach("match"), "Operator images are missing or have different hashes in snapshot file")
})

It("image hashes are all unique", func() {
Expand Down
2 changes: 1 addition & 1 deletion test/acceptance/releases_images_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var _ = Describe("Trusted Artifact Signer Releases", Ordered, func() {
snapshotImages, err = support.ParseSnapshotImages()
Expect(err).NotTo(HaveOccurred())
support.LogMap(fmt.Sprintf("Snapshot images (%d):", len(snapshotImages)), snapshotImages)
Expect(snapshotImages).NotTo(BeEmpty())
Expect(snapshotImages).NotTo(BeEmpty(), "No images were detected in snapshot file")
})

It("snapshot.json file contains valid images", func() {
Expand Down
31 changes: 30 additions & 1 deletion test/support/acceptance.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import (
"fmt"
"regexp"
"slices"
"strings"

"github.com/pkg/errors"
"gopkg.in/yaml.v3"
)

type OperatorMap map[string]string

func ParseSnapshotImages() (SnapshotMap, error) {
snapshotFileName := GetEnv(EnvReleasesSnapshotFile)
if snapshotFileName == "" {
return nil, fmt.Errorf("snapshot file name must be set. Use %s env variable for that", EnvReleasesSnapshotFile)
return nil, errors.New(fmt.Sprintf("snapshot file name must be set. Use %s env variable for that", EnvReleasesSnapshotFile))
}
content, err := GetFileContent(snapshotFileName)
if err != nil {
Expand Down Expand Up @@ -46,6 +50,31 @@ func ParseOperatorImages(helpContent string) (OperatorMap, OperatorMap) {
return operatorTasImages, operatorOtherImages
}

func ParseAnsibleImages() (AnsibleMap, error) {
ansibleFileName := GetEnv(EnvAnsibleImagesFile)
if ansibleFileName == "" {
return nil, errors.New(fmt.Sprintf("ansible images file name must be set. Use %s env variable for that", EnvAnsibleImagesFile))
}
content, err := GetFileContent(ansibleFileName)
if err != nil {
return nil, err
}
var ansibleImages AnsibleMap
err = yaml.Unmarshal([]byte(content), &ansibleImages)
if err != nil {
return nil, fmt.Errorf("failed to parse ansible images file: %w", err)
}
return ansibleImages, nil
}

func ConvertAnsibleImageKey(ansibleImageKey string) string {
if !strings.HasPrefix(ansibleImageKey, "tas_single_node_") {
return ansibleImageKey
}
result := strings.ReplaceAll(strings.TrimPrefix(ansibleImageKey, "tas_single_node_"), "_", "-")
return result
}

func ExtractHashes(images []string) []string {
result := make([]string, len(images))
for i, image := range images {
Expand Down
29 changes: 29 additions & 0 deletions test/support/ansible_map_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package support

import (
"fmt"
"strings"

"gopkg.in/yaml.v3"
)

type AnsibleMap map[string]string

func (data *AnsibleMap) UnmarshalYAML(value *yaml.Node) error {
*data = make(map[string]string)

var rawMap map[string]interface{}
if err := value.Decode(&rawMap); err != nil {
return fmt.Errorf("error while parsing yaml file: %w", err)
}

for key, val := range rawMap {
if strings.HasSuffix(key, "image") {
if strVal, ok := val.(string); ok {
(*data)[key] = strVal
}
}
}

return nil
}
25 changes: 24 additions & 1 deletion test/support/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,29 @@ func GetMapValues(m map[string]string) []string {
return result
}

func SplitMap(original map[string]string, keysToKeep []string) (map[string]string, map[string]string) {
remaining := make(map[string]string)
moved := make(map[string]string)

for key, value := range original {
if contains(keysToKeep, key) {
remaining[key] = value
} else {
moved[key] = value
}
}
return remaining, moved
}

func contains(source []string, value string) bool {
for _, v := range source {
if v == value {
return true
}
}
return false
}

func LogArray(message string, data []string) {
result := message + "\n"
for _, value := range data {
Expand All @@ -53,7 +76,7 @@ func LogArray(message string, data []string) {
func LogMap(message string, data map[string]string) {
result := message + "\n"
for key, value := range data {
result += fmt.Sprintf(" [%-28s] %s\n", key, value)
result += fmt.Sprintf(" [%-41s] %s\n", key, value)
}
log.Print(result)
}
31 changes: 28 additions & 3 deletions test/support/test_constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package support

const (
EnvReleasesSnapshotFile = "SNAPSHOT"
EnvAnsibleImagesFile = "ANSIBLE"
EnvRepositoriesFile = "REPOSITORIES"
EnvTestGithubToken = "TEST_GITHUB_TOKEN" // #nosec G101

Expand All @@ -10,9 +11,9 @@ const (

OperatorBundleClusterServiceVersionFile = "manifests/rhtas-operator.clusterserviceversion.yaml"

OperatorTasImageDefinitionRegexp = `^registry.redhat.io/rhtas/[\w/-]+@sha256:\w{64}$`
OtherOperatorImageDefinitionRegexp = `^(registry.redhat.io|registry.access.redhat.com)`
SnapshotImageDefinitionRegexp = `^[\.\w/-]+@sha256:\w{64}$`
TasImageDefinitionRegexp = `^registry.redhat.io/rhtas/[\w/-]+@sha256:\w{64}$`
OtherImageDefinitionRegexp = `^(registry.redhat.io|registry.access.redhat.com)`
SnapshotImageDefinitionRegexp = `^[\.\w/-]+@sha256:\w{64}$`

DefaultRepositoriesFile = "testdata/repositories.json"
)
Expand Down Expand Up @@ -49,6 +50,30 @@ func OtherOperatorImageKeys() []string {
}
}

func AnsibleTasImageKeys() []string {
return []string{
"tas_single_node_fulcio_server_image",
"tas_single_node_trillian_log_server_image",
"tas_single_node_trillian_log_signer_image",
"tas_single_node_rekor_server_image",
"tas_single_node_ctlog_image",
"tas_single_node_rekor_redis_image",
"tas_single_node_trillian_db_image",
"tas_single_node_tuf_image",
"tas_single_node_timestamp_authority_image",
"tas_single_node_rekor_search_ui_image",
"tas_single_node_createtree_image",
"tas_single_node_client_server_image",
}
}

func AnsibleOtherImageKeys() []string {
return []string{
"tas_single_node_trillian_netcat_image",
"tas_single_node_nginx_image",
}
}

type OSArchMatrix map[string][]string

func GetOSArchMatrix() OSArchMatrix {
Expand Down
Loading