diff --git a/cmd/tnf/claim/add/add.go b/cmd/tnf/claim/add/add.go index c0f6c0fdc..69ea0a3b1 100644 --- a/cmd/tnf/claim/add/add.go +++ b/cmd/tnf/claim/add/add.go @@ -9,8 +9,8 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/test-network-function/cnf-certification-test/pkg/claim" "github.com/test-network-function/cnf-certification-test/pkg/junit" - "github.com/test-network-function/test-network-function-claim/pkg/claim" ) var ( diff --git a/cmd/tnf/claim/add/add_test.go b/cmd/tnf/claim/add/add_test.go index 4ef364631..d7479bbdf 100644 --- a/cmd/tnf/claim/add/add_test.go +++ b/cmd/tnf/claim/add/add_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/test-network-function/test-network-function-claim/pkg/claim" + "github.com/test-network-function/cnf-certification-test/pkg/claim" ) func TestReadClaim(t *testing.T) { @@ -17,9 +17,8 @@ func TestReadClaim(t *testing.T) { expectedClaimRoot: &claim.Root{ Claim: &claim.Claim{ Versions: &claim.Versions{ - K8s: "1.23.1", - Tnf: "0.3.1", - ClaimFormat: "v0.0.1", + K8s: "1.23.1", + Tnf: "0.3.1", }, Metadata: &claim.Metadata{ EndTime: "1:33:00", diff --git a/cmd/tnf/claim/compare/versions/versions.go b/cmd/tnf/claim/compare/versions/versions.go index 14f945c9d..3b984cff5 100644 --- a/cmd/tnf/claim/compare/versions/versions.go +++ b/cmd/tnf/claim/compare/versions/versions.go @@ -5,7 +5,7 @@ import ( "log" "github.com/test-network-function/cnf-certification-test/cmd/tnf/claim/compare/diff" - officialClaimScheme "github.com/test-network-function/test-network-function-claim/pkg/claim" + officialClaimScheme "github.com/test-network-function/cnf-certification-test/pkg/claim" ) type DiffReport struct { diff --git a/cmd/tnf/claim/compare/versions/versions_test.go b/cmd/tnf/claim/compare/versions/versions_test.go index 2234cfb34..9038dff8c 100644 --- a/cmd/tnf/claim/compare/versions/versions_test.go +++ b/cmd/tnf/claim/compare/versions/versions_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/test-network-function/cnf-certification-test/cmd/tnf/claim/compare/diff" - officialClaimScheme "github.com/test-network-function/test-network-function-claim/pkg/claim" + officialClaimScheme "github.com/test-network-function/cnf-certification-test/pkg/claim" ) func TestCompare(t *testing.T) { @@ -30,7 +30,6 @@ func TestCompare(t *testing.T) { name: "matching versions", args: args{ claim1Versions: &officialClaimScheme.Versions{ - ClaimFormat: "1", K8s: "22", OcClient: "333", Ocp: "4444", @@ -38,7 +37,6 @@ func TestCompare(t *testing.T) { TnfGitCommit: "666666", }, claim2Versions: &officialClaimScheme.Versions{ - ClaimFormat: "1", K8s: "22", OcClient: "333", Ocp: "4444", @@ -52,7 +50,6 @@ func TestCompare(t *testing.T) { name: "non matching versions 1", args: args{ claim1Versions: &officialClaimScheme.Versions{ - ClaimFormat: "1", K8s: "22AAA", OcClient: "333", Ocp: "4444", @@ -60,7 +57,6 @@ func TestCompare(t *testing.T) { TnfGitCommit: "666666", }, claim2Versions: &officialClaimScheme.Versions{ - ClaimFormat: "1", K8s: "22", OcClient: "333", Ocp: "4444", @@ -83,7 +79,6 @@ func TestCompare(t *testing.T) { name: "non matching versions 2", args: args{ claim1Versions: &officialClaimScheme.Versions{ - ClaimFormat: "1", K8s: "22AAA", OcClient: "333", Ocp: "4444", @@ -91,7 +86,6 @@ func TestCompare(t *testing.T) { TnfGitCommit: "666666", }, claim2Versions: &officialClaimScheme.Versions{ - ClaimFormat: "1", K8s: "22", OcClient: "333", Ocp: "4444", diff --git a/cmd/tnf/claim/show/csv/csv.go b/cmd/tnf/claim/show/csv/csv.go index f1f10f5c5..02c0e70ba 100644 --- a/cmd/tnf/claim/show/csv/csv.go +++ b/cmd/tnf/claim/show/csv/csv.go @@ -11,7 +11,7 @@ import ( "github.com/spf13/cobra" "github.com/test-network-function/cnf-certification-test/cmd/tnf/pkg/claim" "github.com/test-network-function/cnf-certification-test/cnf-certification-test/identifiers" - claimschema "github.com/test-network-function/test-network-function-claim/pkg/claim" + claimschema "github.com/test-network-function/cnf-certification-test/pkg/claim" ) var ( @@ -92,12 +92,6 @@ func dumpCsv(_ *cobra.Command, _ []string) error { return fmt.Errorf("failed to parse claim file %s: %v", claimFilePathFlag, err) } - // Check claim format version - err = claim.CheckVersion(claimScheme.Claim.Versions.ClaimFormat) - if err != nil { - return err - } - // loads the mapping between CNF name and type CNFTypeMap, err := loadCNFTypeMap(CNFListFilePathFlag) if err != nil { diff --git a/cmd/tnf/claim/show/failures/failures.go b/cmd/tnf/claim/show/failures/failures.go index 7c1753006..cd9e4df60 100644 --- a/cmd/tnf/claim/show/failures/failures.go +++ b/cmd/tnf/claim/show/failures/failures.go @@ -290,12 +290,6 @@ func showFailures(_ *cobra.Command, _ []string) error { return fmt.Errorf("failed to parse claim file %s: %v", claimFilePathFlag, err) } - // Check claim format version - err = claim.CheckVersion(claimScheme.Claim.Versions.ClaimFormat) - if err != nil { - return err - } - // Order test case results by test suite, using a helper map. resultsByTestSuite := map[string][]*claim.TestCaseResult{} for id := range claimScheme.Claim.Results { diff --git a/cmd/tnf/generate/catalog/catalog.go b/cmd/tnf/generate/catalog/catalog.go index 7d51082c7..0bc513ec2 100644 --- a/cmd/tnf/generate/catalog/catalog.go +++ b/cmd/tnf/generate/catalog/catalog.go @@ -26,7 +26,7 @@ import ( "github.com/sirupsen/logrus" "github.com/test-network-function/cnf-certification-test/cnf-certification-test/identifiers" "github.com/test-network-function/cnf-certification-test/pkg/arrayhelper" - "github.com/test-network-function/test-network-function-claim/pkg/claim" + "github.com/test-network-function/cnf-certification-test/pkg/claim" "github.com/spf13/cobra" ) diff --git a/cmd/tnf/generate/catalog/catalog_test.go b/cmd/tnf/generate/catalog/catalog_test.go index 78a24e9ed..5cdf26029 100644 --- a/cmd/tnf/generate/catalog/catalog_test.go +++ b/cmd/tnf/generate/catalog/catalog_test.go @@ -24,7 +24,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/test-network-function/cnf-certification-test/pkg/arrayhelper" - "github.com/test-network-function/test-network-function-claim/pkg/claim" + "github.com/test-network-function/cnf-certification-test/pkg/claim" ) func TestNewCommand(t *testing.T) { diff --git a/cmd/tnf/generate/qe_coverage/qe_coverage.go b/cmd/tnf/generate/qe_coverage/qe_coverage.go index 9e4d2bc86..c02a8ed9d 100644 --- a/cmd/tnf/generate/qe_coverage/qe_coverage.go +++ b/cmd/tnf/generate/qe_coverage/qe_coverage.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cobra" "github.com/test-network-function/cnf-certification-test/cnf-certification-test/identifiers" - "github.com/test-network-function/test-network-function-claim/pkg/claim" + "github.com/test-network-function/cnf-certification-test/pkg/claim" ) type TestCoverageSummaryReport struct { diff --git a/cmd/tnf/generate/qe_coverage/qe_coverage_test.go b/cmd/tnf/generate/qe_coverage/qe_coverage_test.go index eb90c4407..cdcb2e15b 100644 --- a/cmd/tnf/generate/qe_coverage/qe_coverage_test.go +++ b/cmd/tnf/generate/qe_coverage/qe_coverage_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/test-network-function/test-network-function-claim/pkg/claim" + "github.com/test-network-function/cnf-certification-test/pkg/claim" ) type catalogEntry struct { diff --git a/cmd/tnf/pkg/claim/claim.go b/cmd/tnf/pkg/claim/claim.go index db9d92012..f948afc0d 100644 --- a/cmd/tnf/pkg/claim/claim.go +++ b/cmd/tnf/pkg/claim/claim.go @@ -6,7 +6,7 @@ import ( "os" "github.com/Masterminds/semver/v3" - officialClaimScheme "github.com/test-network-function/test-network-function-claim/pkg/claim" + officialClaimScheme "github.com/test-network-function/cnf-certification-test/pkg/claim" ) const ( diff --git a/cnf-certification-test/identifiers/identifiers.go b/cnf-certification-test/identifiers/identifiers.go index 29e166136..efe9bf0a1 100644 --- a/cnf-certification-test/identifiers/identifiers.go +++ b/cnf-certification-test/identifiers/identifiers.go @@ -20,7 +20,7 @@ import ( "strings" "github.com/test-network-function/cnf-certification-test/cnf-certification-test/common" - "github.com/test-network-function/test-network-function-claim/pkg/claim" + "github.com/test-network-function/cnf-certification-test/pkg/claim" ) // shared description text diff --git a/cnf-certification-test/identifiers/identifiers_test.go b/cnf-certification-test/identifiers/identifiers_test.go index b0d404d1f..df3bbf378 100644 --- a/cnf-certification-test/identifiers/identifiers_test.go +++ b/cnf-certification-test/identifiers/identifiers_test.go @@ -21,8 +21,8 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/test-network-function/cnf-certification-test/pkg/claim" "github.com/test-network-function/cnf-certification-test/pkg/stringhelper" - "github.com/test-network-function/test-network-function-claim/pkg/claim" ) func TestGetGinkgoTestIDAndLabels(t *testing.T) { diff --git a/cnf-certification-test/results/results.go b/cnf-certification-test/results/results.go index 5a1064241..d07a866b5 100644 --- a/cnf-certification-test/results/results.go +++ b/cnf-certification-test/results/results.go @@ -23,7 +23,7 @@ import ( "github.com/test-network-function/cnf-certification-test/cnf-certification-test/identifiers" "github.com/test-network-function/cnf-certification-test/pkg/testhelper" - "github.com/test-network-function/test-network-function-claim/pkg/claim" + "github.com/test-network-function/cnf-certification-test/pkg/claim" ) const ( diff --git a/cnf-certification-test/suite_test.go b/cnf-certification-test/suite_test.go index 60b2325c4..2946edeac 100644 --- a/cnf-certification-test/suite_test.go +++ b/cnf-certification-test/suite_test.go @@ -34,12 +34,12 @@ import ( "github.com/onsi/ginkgo/v2" log "github.com/sirupsen/logrus" "github.com/test-network-function/cnf-certification-test/cnf-certification-test/results" + "github.com/test-network-function/cnf-certification-test/pkg/claim" "github.com/test-network-function/cnf-certification-test/pkg/claimhelper" "github.com/test-network-function/cnf-certification-test/pkg/collector" "github.com/test-network-function/cnf-certification-test/pkg/loghelper" "github.com/test-network-function/cnf-certification-test/pkg/provider" "github.com/test-network-function/cnf-certification-test/pkg/testhelper" - "github.com/test-network-function/test-network-function-claim/pkg/claim" _ "github.com/test-network-function/cnf-certification-test/cnf-certification-test/accesscontrol" _ "github.com/test-network-function/cnf-certification-test/cnf-certification-test/certification" @@ -54,8 +54,8 @@ import ( _ "github.com/test-network-function/cnf-certification-test/cnf-certification-test/preflight" "github.com/test-network-function/cnf-certification-test/cnf-certification-test/webserver" "github.com/test-network-function/cnf-certification-test/internal/clientsholder" + "github.com/test-network-function/cnf-certification-test/internal/version" "github.com/test-network-function/cnf-certification-test/pkg/configuration" - "github.com/test-network-function/cnf-certification-test/pkg/diagnostics" ) const ( @@ -71,23 +71,9 @@ const ( ) var ( - claimPath *string - junitPath *string - // GitCommit is the latest commit in the current git branch - GitCommit string - // GitRelease is the list of tags (if any) applied to the latest commit - // in the current branch - GitRelease string - // GitPreviousRelease is the last release at the date of the latest commit - // in the current branch - GitPreviousRelease string - // gitDisplayRelease is a string used to hold the text to display - // the version on screen and in the claim file - gitDisplayRelease string - // ClaimFormat is the current version for the claim file format to be produced by the TNF test suite. - // A client decoding this claim file must support decoding its specific version. - ClaimFormatVersion string - serverMode *bool + claimPath *string + junitPath *string + serverMode *bool ) func init() { @@ -126,18 +112,6 @@ func getK8sClientsConfigFileNames() []string { return fileNames } -// getGitVersion returns the git display version: the latest previously released -// build in case this build is not released. Otherwise display the build version -func getGitVersion() string { - if GitRelease == "" { - gitDisplayRelease = "Unreleased build post " + GitPreviousRelease - } else { - gitDisplayRelease = GitRelease - } - - return gitDisplayRelease + " ( " + GitCommit + " )" -} - func PreRun(t *testing.T) (claimData *claim.Claim, claimRoot *claim.Root) { // When running unit tests, skip the suite if os.Getenv("UNIT_TEST") != "" { @@ -154,8 +128,7 @@ func PreRun(t *testing.T) (claimData *claim.Claim, claimRoot *claim.Root) { setLogLevel() ginkgoConfig, _ := ginkgo.GinkgoConfiguration() - log.Infof("TNF Version : %v", getGitVersion()) - log.Infof("Claim Format Version: %s", ClaimFormatVersion) + log.Infof("TNF Version : %v", version.GetGitVersion()) log.Infof("Ginkgo Version : %v", ginkgo.GINKGO_VERSION) log.Infof("Labels filter : %v", ginkgoConfig.LabelFilter) log.Infof("run test with webserver : %v", *serverMode) @@ -167,7 +140,7 @@ func PreRun(t *testing.T) (claimData *claim.Claim, claimRoot *claim.Root) { claimData = claimRoot.Claim claimData.Configurations = make(map[string]interface{}) claimData.Nodes = make(map[string]interface{}) - incorporateVersions(claimData) + claimhelper.IncorporateVersions(claimData) configurations, err := claimhelper.MarshalConfigurations() if err != nil { @@ -278,17 +251,6 @@ func ContinueRun(diagnosticMode bool, env *provider.TestEnvironment, claimData * } } -// incorporateTNFVersion adds the TNF version to the claim. -func incorporateVersions(claimData *claim.Claim) { - claimData.Versions = &claim.Versions{ - Tnf: gitDisplayRelease, - TnfGitCommit: GitCommit, - OcClient: diagnostics.GetVersionOcClient(), - Ocp: diagnostics.GetVersionOcp(), - K8s: diagnostics.GetVersionK8s(), - ClaimFormat: ClaimFormatVersion, - } -} func StartServer() { server := &http.Server{ Addr: ":8084", // Server address diff --git a/internal/version/version.go b/internal/version/version.go new file mode 100644 index 000000000..eda2a9103 --- /dev/null +++ b/internal/version/version.go @@ -0,0 +1,43 @@ +// Copyright (C) 2020-2023 Red Hat, Inc. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +package version + +var ( + // GitCommit is the latest commit in the current git branch + GitCommit string + // GitRelease is the list of tags (if any) applied to the latest commit + // in the current branch + GitRelease string + // GitPreviousRelease is the last release at the date of the latest commit + // in the current branch + GitPreviousRelease string +) + +// GetGitVersion returns the git display version: the latest previously released +// build in case this build is not released. Otherwise display the build version +func GetGitVersion() string { + // gitDisplayRelease is a string used to hold the text to display + // the version on screen and in the claim file + var gitDisplayRelease string + if GitRelease == "" { + gitDisplayRelease = "Unreleased build post " + GitPreviousRelease + } else { + gitDisplayRelease = GitRelease + } + + return gitDisplayRelease + " ( " + GitCommit + " )" +} diff --git a/pkg/claim/catalog.go b/pkg/claim/catalog.go new file mode 100644 index 000000000..0ab73d2d6 --- /dev/null +++ b/pkg/claim/catalog.go @@ -0,0 +1,73 @@ +// Copyright (C) 2023 Red Hat, Inc. +// +// This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later +// version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied +// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with this program; if not, write to the Free +// Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +package claim + +import ( + "strings" +) + +// TestCaseDescription describes a JUnit test case. +type TestCaseDescription struct { + // Identifier is the unique test identifier. + Identifier Identifier `json:"identifier" yaml:"identifier"` + + // Description is a helpful description of the purpose of the test case. + Description string `json:"description" yaml:"description"` + + // Remediation is an optional suggested remediation for passing the test. + Remediation string `json:"remediation,omitempty" yaml:"remediation,omitempty"` + + // BestPracticeReference is a helpful best practice references of the test case. + BestPracticeReference string `json:"BestPracticeReference" yaml:"BestPracticeReference"` + + // ExceptionProcess will show any possible exception processes documented for partners to follow. + ExceptionProcess string `json:"exceptionProcess,omitempty" yaml:"exceptionProcess,omitempty"` + + // Tags will show all of the ginkgo tags that the test case applies to + Tags string `json:"tags,omitempty" yaml:"tags,omitempty"` + + // Whether or not automated tests exist for the test case. Not to be rendered. + Qe bool `json:"qe" yaml:"qe"` + + // classification for each test case + CategoryClassification map[string]string `json:"categoryclassification" yaml:"categoryclassification"` + /* an example to how it CategoryClassification would be + { + "ForTelco": "Mandatory", + "FarEdge" : "Optional", + "ForNonTelco": "Optional", + "ForVZ": "Mandatory" + }*/ +} + +func formTestTags(tags ...string) string { + return strings.Join(tags, ",") +} + +func BuildTestCaseDescription(testID, suiteName, description, remediation, exception, reference string, qe bool, categoryclassification map[string]string, tags ...string) (TestCaseDescription, Identifier) { + aID := Identifier{ + Tags: formTestTags(tags...), + Id: suiteName + "-" + testID, + Suite: suiteName, + } + aTCDescription := TestCaseDescription{} + aTCDescription.Identifier = aID + aTCDescription.Description = description + aTCDescription.Remediation = remediation + aTCDescription.ExceptionProcess = exception + aTCDescription.BestPracticeReference = reference + aTCDescription.Tags = strings.Join(tags, ",") + aTCDescription.Qe = qe + aTCDescription.CategoryClassification = categoryclassification + return aTCDescription, aID +} diff --git a/pkg/claim/doc.go b/pkg/claim/doc.go new file mode 100644 index 000000000..fe257facd --- /dev/null +++ b/pkg/claim/doc.go @@ -0,0 +1,16 @@ +// Copyright (C) 2020 Red Hat, Inc. +// +// This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later +// version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied +// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with this program; if not, write to the Free +// Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +/* +Package claim provides a test-network-definition claim schema. +*/ +package claim diff --git a/pkg/claim/schema.go b/pkg/claim/schema.go new file mode 100644 index 000000000..588f72da8 --- /dev/null +++ b/pkg/claim/schema.go @@ -0,0 +1,1123 @@ +// Copyright (C) 2020 Red Hat, Inc. +// +// This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later +// version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied +// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with this program; if not, write to the Free +// Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +// +// Code generated by `test-network-function-claim/cmd/generate/generate.go` on: 2023-07-25 17:14:11.780893296 -0500 CDT m=+0.000814695 +// +// `https://github.com/a-h/generate` provides a generic set of interfaces to convert JSON schema into +// workable GoLang struct implementations. However, the code generator is limited and does not allow +// type remapping. By default, JSON Schema "object" types are remapped to custom struct definitions. +// This becomes a problem in our case, as we do not define certain facets such as "Hosts" or +// "LshwOutput". This CLI driven generator augments the stock generator to allow overrides to generic +// "map[string]interface{}", which is capable of representing arbitrary JSON data. +// +// Warning: Do not edit this file by hand. Instead, use Makefile targets. +// + +// Code generated by schema-generate. DO NOT EDIT. + +package claim + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" +) + +// CatalogInfo test specific information from the catalog +type CatalogInfo struct { + + // Link to the best practice document supporting this test case + BestPracticeReference string `json:"bestPracticeReference"` + + // The test description. + Description string `json:"description"` + + // Indicates the exception process if defined + ExceptionProcess string `json:"exceptionProcess"` + + // steps required to fix a failing test case + Remediation string `json:"remediation"` +} + +// CategoryClassification categoryClassification is the classification for a single test case. +type CategoryClassification struct { + + // indicates whether this test case is mandatory or optional in the Extended scenario + Extended string `json:"Extended,omitempty"` + + // indicates whether this test case is mandatory or optional in the FarEdge scenario + FarEdge string `json:"FarEdge,omitempty"` + + // indicates whether this test case is mandatory or optional in the NonTelco scenario + NonTelco string `json:"NonTelco,omitempty"` + + // indicates whether this test case is mandatory or optional in the Telco scenario + Telco string `json:"Telco,omitempty"` +} + +// Claim +type Claim struct { + + // Tests within test-network-function often require configuration. For example, the generic test suite requires listing all CNF containers. This information is used to derive per-container IP address information, which is then used as input to the connectivity test suite. Test suites within test-network-function may use multiple configurations, but each with a unique name. + Configurations map[string]interface{} `json:"configurations"` + Metadata *Metadata `json:"metadata"` + + // An OpenShift cluster is composed of an arbitrary number of Nodes used for platform and application services. Since a claim must be reproducible, a variety of per-Node information must be collected and stored in the claim. Node names are unique within a given OpenShift cluster. + Nodes map[string]interface{} `json:"nodes"` + + // The test-network-function test results. Results are a JSON representation of the JUnit output. + RawResults map[string]interface{} `json:"rawResults"` + + // The results for each unique test case. + Results map[string]interface{} `json:"results,omitempty"` + Versions *Versions `json:"versions"` +} + +// Identifier identifier is a per testcase unique identifier. +type Identifier struct { + + // id stores a unique id for the testcase. + Id string `json:"id"` + + // suite stores the test suite name for the testcase. + Suite string `json:"suite"` + + // tags stores the different tags applied to a test. + Tags string `json:"tags,omitempty"` +} + +// Metadata +type Metadata struct { + + // The UTC end time of a claim evaluation. This is recorded when the test-network-function test suite completes. + EndTime string `json:"endTime"` + + // The UTC start time of a claim evaluation. This is recorded when the test-network-function test suite is invoked. + StartTime string `json:"startTime"` +} + +// Result result is the result of running a testcase. +type Result struct { + + // Ginkgo writer output during the test run. + CapturedTestOutput string `json:"capturedTestOutput"` + + // Test detailed information from catalog + CatalogInfo *CatalogInfo `json:"catalogInfo"` + + // Category classification for the test + CategoryClassification *CategoryClassification `json:"categoryClassification"` + + // The duration of the test in nanoseconds. + Duration int `json:"duration"` + + // The end time of the test. + EndTime string `json:"endTime,omitempty"` + + // The content of the line where the failure happened + FailureLineContent string `json:"failureLineContent"` + + // The Filename and line number where the failure happened + FailureLocation string `json:"failureLocation"` + + // Describes the test failure in detail. + FailureReason string `json:"failureReason"` + + // The start time of the test. + StartTime string `json:"startTime"` + + // The test result state: INVALID SPEC STATE, pending,skipped,passed,failed,aborted,panicked,interrupted + State string `json:"state"` + + // The test identifier + TestID *Identifier `json:"testID"` +} + +// Root A test-network-function claim is an attestation of the tests performed, the results and the various configurations. Since a claim must be reproducible, it also includes an overview of the systems under test and their physical configurations. +type Root struct { + Claim *Claim `json:"claim"` +} + +// Versions +type Versions struct { + + // The Kubernetes release version. + K8s string `json:"k8s,omitempty"` + + // The oc client release version. + OcClient string `json:"ocClient,omitempty"` + + // OCP cluster release version. + Ocp string `json:"ocp,omitempty"` + + // The test-network-function (tnf) release version. + Tnf string `json:"tnf"` + + // The test-network-function (tnf) Git Commit. + TnfGitCommit string `json:"tnfGitCommit,omitempty"` +} + +func (strct *CatalogInfo) MarshalJSON() ([]byte, error) { + buf := bytes.NewBuffer(make([]byte, 0)) + buf.WriteString("{") + comma := false + // "BestPracticeReference" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "bestPracticeReference" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"bestPracticeReference\": ") + if tmp, err := json.Marshal(strct.BestPracticeReference); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "Description" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "description" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"description\": ") + if tmp, err := json.Marshal(strct.Description); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "ExceptionProcess" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "exceptionProcess" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"exceptionProcess\": ") + if tmp, err := json.Marshal(strct.ExceptionProcess); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "Remediation" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "remediation" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"remediation\": ") + if tmp, err := json.Marshal(strct.Remediation); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + + buf.WriteString("}") + rv := buf.Bytes() + return rv, nil +} + +func (strct *CatalogInfo) UnmarshalJSON(b []byte) error { + bestPracticeReferenceReceived := false + descriptionReceived := false + exceptionProcessReceived := false + remediationReceived := false + var jsonMap map[string]json.RawMessage + if err := json.Unmarshal(b, &jsonMap); err != nil { + return err + } + // parse all the defined properties + for k, v := range jsonMap { + switch k { + case "bestPracticeReference": + if err := json.Unmarshal([]byte(v), &strct.BestPracticeReference); err != nil { + return err + } + bestPracticeReferenceReceived = true + case "description": + if err := json.Unmarshal([]byte(v), &strct.Description); err != nil { + return err + } + descriptionReceived = true + case "exceptionProcess": + if err := json.Unmarshal([]byte(v), &strct.ExceptionProcess); err != nil { + return err + } + exceptionProcessReceived = true + case "remediation": + if err := json.Unmarshal([]byte(v), &strct.Remediation); err != nil { + return err + } + remediationReceived = true + default: + return fmt.Errorf("additional property not allowed: \"" + k + "\"") + } + } + // check if bestPracticeReference (a required property) was received + if !bestPracticeReferenceReceived { + return errors.New("\"bestPracticeReference\" is required but was not present") + } + // check if description (a required property) was received + if !descriptionReceived { + return errors.New("\"description\" is required but was not present") + } + // check if exceptionProcess (a required property) was received + if !exceptionProcessReceived { + return errors.New("\"exceptionProcess\" is required but was not present") + } + // check if remediation (a required property) was received + if !remediationReceived { + return errors.New("\"remediation\" is required but was not present") + } + return nil +} + +func (strct *CategoryClassification) MarshalJSON() ([]byte, error) { + buf := bytes.NewBuffer(make([]byte, 0)) + buf.WriteString("{") + comma := false + // Marshal the "Extended" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"Extended\": ") + if tmp, err := json.Marshal(strct.Extended); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // Marshal the "FarEdge" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"FarEdge\": ") + if tmp, err := json.Marshal(strct.FarEdge); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // Marshal the "NonTelco" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"NonTelco\": ") + if tmp, err := json.Marshal(strct.NonTelco); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // Marshal the "Telco" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"Telco\": ") + if tmp, err := json.Marshal(strct.Telco); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + + buf.WriteString("}") + rv := buf.Bytes() + return rv, nil +} + +func (strct *CategoryClassification) UnmarshalJSON(b []byte) error { + var jsonMap map[string]json.RawMessage + if err := json.Unmarshal(b, &jsonMap); err != nil { + return err + } + // parse all the defined properties + for k, v := range jsonMap { + switch k { + case "Extended": + if err := json.Unmarshal([]byte(v), &strct.Extended); err != nil { + return err + } + case "FarEdge": + if err := json.Unmarshal([]byte(v), &strct.FarEdge); err != nil { + return err + } + case "NonTelco": + if err := json.Unmarshal([]byte(v), &strct.NonTelco); err != nil { + return err + } + case "Telco": + if err := json.Unmarshal([]byte(v), &strct.Telco); err != nil { + return err + } + default: + return fmt.Errorf("additional property not allowed: \"" + k + "\"") + } + } + return nil +} + +func (strct *Claim) MarshalJSON() ([]byte, error) { + buf := bytes.NewBuffer(make([]byte, 0)) + buf.WriteString("{") + comma := false + // "Configurations" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "configurations" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"configurations\": ") + if tmp, err := json.Marshal(strct.Configurations); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "Metadata" field is required + if strct.Metadata == nil { + return nil, errors.New("metadata is a required field") + } + // Marshal the "metadata" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"metadata\": ") + if tmp, err := json.Marshal(strct.Metadata); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "Nodes" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "nodes" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"nodes\": ") + if tmp, err := json.Marshal(strct.Nodes); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "RawResults" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "rawResults" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"rawResults\": ") + if tmp, err := json.Marshal(strct.RawResults); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // Marshal the "results" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"results\": ") + if tmp, err := json.Marshal(strct.Results); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "Versions" field is required + if strct.Versions == nil { + return nil, errors.New("versions is a required field") + } + // Marshal the "versions" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"versions\": ") + if tmp, err := json.Marshal(strct.Versions); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + + buf.WriteString("}") + rv := buf.Bytes() + return rv, nil +} + +func (strct *Claim) UnmarshalJSON(b []byte) error { + configurationsReceived := false + metadataReceived := false + nodesReceived := false + rawResultsReceived := false + versionsReceived := false + var jsonMap map[string]json.RawMessage + if err := json.Unmarshal(b, &jsonMap); err != nil { + return err + } + // parse all the defined properties + for k, v := range jsonMap { + switch k { + case "configurations": + if err := json.Unmarshal([]byte(v), &strct.Configurations); err != nil { + return err + } + configurationsReceived = true + case "metadata": + if err := json.Unmarshal([]byte(v), &strct.Metadata); err != nil { + return err + } + metadataReceived = true + case "nodes": + if err := json.Unmarshal([]byte(v), &strct.Nodes); err != nil { + return err + } + nodesReceived = true + case "rawResults": + if err := json.Unmarshal([]byte(v), &strct.RawResults); err != nil { + return err + } + rawResultsReceived = true + case "results": + if err := json.Unmarshal([]byte(v), &strct.Results); err != nil { + return err + } + case "versions": + if err := json.Unmarshal([]byte(v), &strct.Versions); err != nil { + return err + } + versionsReceived = true + default: + return fmt.Errorf("additional property not allowed: \"" + k + "\"") + } + } + // check if configurations (a required property) was received + if !configurationsReceived { + return errors.New("\"configurations\" is required but was not present") + } + // check if metadata (a required property) was received + if !metadataReceived { + return errors.New("\"metadata\" is required but was not present") + } + // check if nodes (a required property) was received + if !nodesReceived { + return errors.New("\"nodes\" is required but was not present") + } + // check if rawResults (a required property) was received + if !rawResultsReceived { + return errors.New("\"rawResults\" is required but was not present") + } + // check if versions (a required property) was received + if !versionsReceived { + return errors.New("\"versions\" is required but was not present") + } + return nil +} + +func (strct *Identifier) MarshalJSON() ([]byte, error) { + buf := bytes.NewBuffer(make([]byte, 0)) + buf.WriteString("{") + comma := false + // "Id" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "id" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"id\": ") + if tmp, err := json.Marshal(strct.Id); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "Suite" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "suite" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"suite\": ") + if tmp, err := json.Marshal(strct.Suite); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // Marshal the "tags" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"tags\": ") + if tmp, err := json.Marshal(strct.Tags); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + + buf.WriteString("}") + rv := buf.Bytes() + return rv, nil +} + +func (strct *Identifier) UnmarshalJSON(b []byte) error { + idReceived := false + suiteReceived := false + var jsonMap map[string]json.RawMessage + if err := json.Unmarshal(b, &jsonMap); err != nil { + return err + } + // parse all the defined properties + for k, v := range jsonMap { + switch k { + case "id": + if err := json.Unmarshal([]byte(v), &strct.Id); err != nil { + return err + } + idReceived = true + case "suite": + if err := json.Unmarshal([]byte(v), &strct.Suite); err != nil { + return err + } + suiteReceived = true + case "tags": + if err := json.Unmarshal([]byte(v), &strct.Tags); err != nil { + return err + } + default: + return fmt.Errorf("additional property not allowed: \"" + k + "\"") + } + } + // check if id (a required property) was received + if !idReceived { + return errors.New("\"id\" is required but was not present") + } + // check if suite (a required property) was received + if !suiteReceived { + return errors.New("\"suite\" is required but was not present") + } + return nil +} + +func (strct *Metadata) MarshalJSON() ([]byte, error) { + buf := bytes.NewBuffer(make([]byte, 0)) + buf.WriteString("{") + comma := false + // "EndTime" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "endTime" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"endTime\": ") + if tmp, err := json.Marshal(strct.EndTime); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "StartTime" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "startTime" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"startTime\": ") + if tmp, err := json.Marshal(strct.StartTime); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + + buf.WriteString("}") + rv := buf.Bytes() + return rv, nil +} + +func (strct *Metadata) UnmarshalJSON(b []byte) error { + endTimeReceived := false + startTimeReceived := false + var jsonMap map[string]json.RawMessage + if err := json.Unmarshal(b, &jsonMap); err != nil { + return err + } + // parse all the defined properties + for k, v := range jsonMap { + switch k { + case "endTime": + if err := json.Unmarshal([]byte(v), &strct.EndTime); err != nil { + return err + } + endTimeReceived = true + case "startTime": + if err := json.Unmarshal([]byte(v), &strct.StartTime); err != nil { + return err + } + startTimeReceived = true + default: + return fmt.Errorf("additional property not allowed: \"" + k + "\"") + } + } + // check if endTime (a required property) was received + if !endTimeReceived { + return errors.New("\"endTime\" is required but was not present") + } + // check if startTime (a required property) was received + if !startTimeReceived { + return errors.New("\"startTime\" is required but was not present") + } + return nil +} + +func (strct *Result) MarshalJSON() ([]byte, error) { + buf := bytes.NewBuffer(make([]byte, 0)) + buf.WriteString("{") + comma := false + // "CapturedTestOutput" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "capturedTestOutput" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"capturedTestOutput\": ") + if tmp, err := json.Marshal(strct.CapturedTestOutput); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "CatalogInfo" field is required + if strct.CatalogInfo == nil { + return nil, errors.New("catalogInfo is a required field") + } + // Marshal the "catalogInfo" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"catalogInfo\": ") + if tmp, err := json.Marshal(strct.CatalogInfo); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "CategoryClassification" field is required + if strct.CategoryClassification == nil { + return nil, errors.New("categoryClassification is a required field") + } + // Marshal the "categoryClassification" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"categoryClassification\": ") + if tmp, err := json.Marshal(strct.CategoryClassification); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "Duration" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "duration" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"duration\": ") + if tmp, err := json.Marshal(strct.Duration); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // Marshal the "endTime" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"endTime\": ") + if tmp, err := json.Marshal(strct.EndTime); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "FailureLineContent" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "failureLineContent" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"failureLineContent\": ") + if tmp, err := json.Marshal(strct.FailureLineContent); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "FailureLocation" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "failureLocation" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"failureLocation\": ") + if tmp, err := json.Marshal(strct.FailureLocation); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "FailureReason" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "failureReason" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"failureReason\": ") + if tmp, err := json.Marshal(strct.FailureReason); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "StartTime" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "startTime" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"startTime\": ") + if tmp, err := json.Marshal(strct.StartTime); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "State" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "state" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"state\": ") + if tmp, err := json.Marshal(strct.State); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "TestID" field is required + if strct.TestID == nil { + return nil, errors.New("testID is a required field") + } + // Marshal the "testID" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"testID\": ") + if tmp, err := json.Marshal(strct.TestID); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + + buf.WriteString("}") + rv := buf.Bytes() + return rv, nil +} + +func (strct *Result) UnmarshalJSON(b []byte) error { + capturedTestOutputReceived := false + catalogInfoReceived := false + categoryClassificationReceived := false + durationReceived := false + failureLineContentReceived := false + failureLocationReceived := false + failureReasonReceived := false + startTimeReceived := false + stateReceived := false + testIDReceived := false + var jsonMap map[string]json.RawMessage + if err := json.Unmarshal(b, &jsonMap); err != nil { + return err + } + // parse all the defined properties + for k, v := range jsonMap { + switch k { + case "capturedTestOutput": + if err := json.Unmarshal([]byte(v), &strct.CapturedTestOutput); err != nil { + return err + } + capturedTestOutputReceived = true + case "catalogInfo": + if err := json.Unmarshal([]byte(v), &strct.CatalogInfo); err != nil { + return err + } + catalogInfoReceived = true + case "categoryClassification": + if err := json.Unmarshal([]byte(v), &strct.CategoryClassification); err != nil { + return err + } + categoryClassificationReceived = true + case "duration": + if err := json.Unmarshal([]byte(v), &strct.Duration); err != nil { + return err + } + durationReceived = true + case "endTime": + if err := json.Unmarshal([]byte(v), &strct.EndTime); err != nil { + return err + } + case "failureLineContent": + if err := json.Unmarshal([]byte(v), &strct.FailureLineContent); err != nil { + return err + } + failureLineContentReceived = true + case "failureLocation": + if err := json.Unmarshal([]byte(v), &strct.FailureLocation); err != nil { + return err + } + failureLocationReceived = true + case "failureReason": + if err := json.Unmarshal([]byte(v), &strct.FailureReason); err != nil { + return err + } + failureReasonReceived = true + case "startTime": + if err := json.Unmarshal([]byte(v), &strct.StartTime); err != nil { + return err + } + startTimeReceived = true + case "state": + if err := json.Unmarshal([]byte(v), &strct.State); err != nil { + return err + } + stateReceived = true + case "testID": + if err := json.Unmarshal([]byte(v), &strct.TestID); err != nil { + return err + } + testIDReceived = true + default: + return fmt.Errorf("additional property not allowed: \"" + k + "\"") + } + } + // check if capturedTestOutput (a required property) was received + if !capturedTestOutputReceived { + return errors.New("\"capturedTestOutput\" is required but was not present") + } + // check if catalogInfo (a required property) was received + if !catalogInfoReceived { + return errors.New("\"catalogInfo\" is required but was not present") + } + // check if categoryClassification (a required property) was received + if !categoryClassificationReceived { + return errors.New("\"categoryClassification\" is required but was not present") + } + // check if duration (a required property) was received + if !durationReceived { + return errors.New("\"duration\" is required but was not present") + } + // check if failureLineContent (a required property) was received + if !failureLineContentReceived { + return errors.New("\"failureLineContent\" is required but was not present") + } + // check if failureLocation (a required property) was received + if !failureLocationReceived { + return errors.New("\"failureLocation\" is required but was not present") + } + // check if failureReason (a required property) was received + if !failureReasonReceived { + return errors.New("\"failureReason\" is required but was not present") + } + // check if startTime (a required property) was received + if !startTimeReceived { + return errors.New("\"startTime\" is required but was not present") + } + // check if state (a required property) was received + if !stateReceived { + return errors.New("\"state\" is required but was not present") + } + // check if testID (a required property) was received + if !testIDReceived { + return errors.New("\"testID\" is required but was not present") + } + return nil +} + +func (strct *Root) MarshalJSON() ([]byte, error) { + buf := bytes.NewBuffer(make([]byte, 0)) + buf.WriteString("{") + comma := false + // "Claim" field is required + if strct.Claim == nil { + return nil, errors.New("claim is a required field") + } + // Marshal the "claim" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"claim\": ") + if tmp, err := json.Marshal(strct.Claim); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + + buf.WriteString("}") + rv := buf.Bytes() + return rv, nil +} + +func (strct *Root) UnmarshalJSON(b []byte) error { + claimReceived := false + var jsonMap map[string]json.RawMessage + if err := json.Unmarshal(b, &jsonMap); err != nil { + return err + } + // parse all the defined properties + for k, v := range jsonMap { + switch k { + case "claim": + if err := json.Unmarshal([]byte(v), &strct.Claim); err != nil { + return err + } + claimReceived = true + default: + return fmt.Errorf("additional property not allowed: \"" + k + "\"") + } + } + // check if claim (a required property) was received + if !claimReceived { + return errors.New("\"claim\" is required but was not present") + } + return nil +} + +func (strct *Versions) MarshalJSON() ([]byte, error) { + buf := bytes.NewBuffer(make([]byte, 0)) + buf.WriteString("{") + comma := false + // Marshal the "k8s" field + buf.WriteString("\"k8s\": ") + if tmp, err := json.Marshal(strct.K8s); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // Marshal the "ocClient" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"ocClient\": ") + if tmp, err := json.Marshal(strct.OcClient); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // Marshal the "ocp" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"ocp\": ") + if tmp, err := json.Marshal(strct.Ocp); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // "Tnf" field is required + // only required object types supported for marshal checking (for now) + // Marshal the "tnf" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"tnf\": ") + if tmp, err := json.Marshal(strct.Tnf); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + // Marshal the "tnfGitCommit" field + if comma { + buf.WriteString(",") + } + buf.WriteString("\"tnfGitCommit\": ") + if tmp, err := json.Marshal(strct.TnfGitCommit); err != nil { + return nil, err + } else { + buf.Write(tmp) + } + comma = true + + buf.WriteString("}") + rv := buf.Bytes() + return rv, nil +} + +func (strct *Versions) UnmarshalJSON(b []byte) error { + claimFormatReceived := false + tnfReceived := false + var jsonMap map[string]json.RawMessage + if err := json.Unmarshal(b, &jsonMap); err != nil { + return err + } + // parse all the defined properties + for k, v := range jsonMap { + switch k { + case "k8s": + if err := json.Unmarshal([]byte(v), &strct.K8s); err != nil { + return err + } + case "ocClient": + if err := json.Unmarshal([]byte(v), &strct.OcClient); err != nil { + return err + } + case "ocp": + if err := json.Unmarshal([]byte(v), &strct.Ocp); err != nil { + return err + } + case "tnf": + if err := json.Unmarshal([]byte(v), &strct.Tnf); err != nil { + return err + } + tnfReceived = true + case "tnfGitCommit": + if err := json.Unmarshal([]byte(v), &strct.TnfGitCommit); err != nil { + return err + } + default: + return fmt.Errorf("additional property not allowed: \"" + k + "\"") + } + } + // check if claimFormat (a required property) was received + if !claimFormatReceived { + return errors.New("\"claimFormat\" is required but was not present") + } + // check if tnf (a required property) was received + if !tnfReceived { + return errors.New("\"tnf\" is required but was not present") + } + return nil +} diff --git a/pkg/claim/schema_test.go b/pkg/claim/schema_test.go new file mode 100644 index 000000000..73575b54c --- /dev/null +++ b/pkg/claim/schema_test.go @@ -0,0 +1,254 @@ +// Copyright (C) 2020 Red Hat, Inc. +// +// This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later +// version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied +// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with this program; if not, write to the Free +// Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +package claim + +import ( + "encoding/json" + "fmt" + "os" + "path" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" +) + +type testCase struct { + expectedMarshallJSONError bool + expectedStartTime string + expectedEndTime string +} + +var testCases = map[string]*testCase{ + "claim-valid": { + expectedMarshallJSONError: false, + expectedStartTime: "1970-01-01T10:05:08+01:00", + expectedEndTime: "1970-01-01T10:05:08+01:00", + }, + "claim-invalid-junit-payload": { + expectedMarshallJSONError: true, + }, + "claim-invalid-additional-property": { + expectedMarshallJSONError: true, + }, + "claim-invalid-bool-results": { + expectedMarshallJSONError: true, + }, + // A little confusing; since we remap the "results" field, this interface{} value is not actually checked. + // This is a limitation of the JSON Schema go client generator, and is perfectly fine for this context. + "claim-invalid-non-result-result": { + expectedMarshallJSONError: false, + }, + "invalid-json": { + expectedMarshallJSONError: true, + }, + "missing-claim": { + expectedMarshallJSONError: true, + }, +} + +func getTestFile(testCaseName string) string { + return path.Join("testdata", testCaseName+".json") +} + +func getTestFileContents(testCaseName string) ([]byte, error) { + testFilePath := getTestFile(testCaseName) + return os.ReadFile(testFilePath) +} + +func TestRoot_MarshalJSON(t *testing.T) { + for testCaseName, testCaseDefinition := range testCases { + contents, err := getTestFileContents(testCaseName) + + // raw data read tests + assert.Nil(t, err) + assert.NotNil(t, contents) + + // try to UnmarshallJSON the input + root := &Root{} + err = json.Unmarshal(contents, root) + fmt.Println(testCaseName) + assert.Equal(t, testCaseDefinition.expectedMarshallJSONError, err != nil) + + if testCaseDefinition.expectedMarshallJSONError == false { + // start time assertion + assert.Equal(t, "1970-01-01T10:05:08+01:00", root.Claim.Metadata.StartTime) + assert.Equal(t, "1970-01-01T10:05:08+01:00", root.Claim.Metadata.EndTime) + + generatedContents, err := json.Marshal(root) + assert.Nil(t, err) + assert.NotNil(t, generatedContents) + } + } +} + +func TestResult_MarshalJSON(t *testing.T) { + type fields struct { + CapturedTestOutput string + CatalogInfo *CatalogInfo + CategoryClassification *CategoryClassification + Duration int + EndTime string + FailureLineContent string + FailureLocation string + FailureReason string + StartTime string + State string + TestID *Identifier + } + tests := []struct { + name string + fields fields + want []byte + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + strct := &Result{ + CapturedTestOutput: tt.fields.CapturedTestOutput, + CatalogInfo: tt.fields.CatalogInfo, + CategoryClassification: tt.fields.CategoryClassification, + Duration: tt.fields.Duration, + EndTime: tt.fields.EndTime, + FailureLineContent: tt.fields.FailureLineContent, + FailureLocation: tt.fields.FailureLocation, + FailureReason: tt.fields.FailureReason, + StartTime: tt.fields.StartTime, + State: tt.fields.State, + TestID: tt.fields.TestID, + } + got, err := strct.MarshalJSON() + if (err != nil) != tt.wantErr { + t.Errorf("Result.MarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Result.MarshalJSON() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestResult_UnmarshalJSON(t *testing.T) { + type args struct { + b []byte + } + tests := []struct { + name string + want *Result + args args + wantErr bool + }{ + { + name: "ok", + want: &Result{ + //nolint:lll + CapturedTestOutput: "{\"CompliantObjectsOut\":[{\"ObjectType\":\"Container\",\"ObjectFieldsKeys\":[\"Reason For Compliance\",\"Namespace\",\"Pod Name\",\"Container Name\"],\"ObjectFieldsValues\":[\"Container is not modified\",\"tnf\",\"test-0\",\"test\"]},{\"ObjectType\":\"Container\",\"ObjectFieldsKeys\":[\"Reason For Compliance\",\"Namespace\",\"Pod Name\",\"Container Name\"],\"ObjectFieldsValues\":[\"Container is not modified\",\"tnf\",\"test-1\",\"test\"]},{\"ObjectType\":\"Container\",\"ObjectFieldsKeys\":[\"Reason For Compliance\",\"Namespace\",\"Pod Name\",\"Container Name\"],\"ObjectFieldsValues\":[\"Container is not modified\",\"tnf\",\"test-d78fbf8d6-jxgl2\",\"test\"]},{\"ObjectType\":\"Container\",\"ObjectFieldsKeys\":[\"Reason For Compliance\",\"Namespace\",\"Pod Name\",\"Container Name\"],\"ObjectFieldsValues\":[\"Container is not modified\",\"tnf\",\"test-d78fbf8d6-n4jlv\",\"test\"]}],\"NonCompliantObjectsOut\":null}\n", + CatalogInfo: &CatalogInfo{ + BestPracticeReference: "https://test-network-function.github.io/cnf-best-practices/#cnf-best-practices-image-standards", + //nolint:lll + Description: "Ensures that the Container Base Image is not altered post-startup. This test is a heuristic, and ensures that there are no changes to the following directories: 1) /var/lib/rpm 2) /var/lib/dpkg 3) /bin 4) /sbin 5) /lib 6) /lib64 7) /usr/bin 8) /usr/sbin 9) /usr/lib 10) /usr/lib64", + ExceptionProcess: "No exceptions", + //nolint:lll + Remediation: "Ensure that Container applications do not modify the Container Base Image. In particular, ensure that the following directories are not modified: 1) /var/lib/rpm 2) /var/lib/dpkg 3) /bin 4) /sbin 5) /lib 6) /lib64 7) /usr/bin 8) /usr/sbin 9) /usr/lib 10) /usr/lib64 Ensure that all required binaries are built directly into the container image, and are not installed post startup.", + }, + CategoryClassification: &CategoryClassification{ + Extended: "Mandatory", + FarEdge: "Mandatory", + NonTelco: "Mandatory", + Telco: "Mandatory", + }, + Duration: 7745320473, + EndTime: "2023-07-25 09:10:25.557493221 -0500 CDT m=+51.038323513", + FailureLineContent: "", + FailureLocation: ":0", + FailureReason: "", + StartTime: "2023-07-25 09:10:17.812172748 -0500 CDT m=+43.293003040", + State: "passed", + TestID: &Identifier{ + Id: "platform-alteration-base-image", + Suite: "platform-alteration", + Tags: "common", + }, + }, + //nolint:lll + args: args{b: []byte(` + { + "capturedTestOutput": "{\"CompliantObjectsOut\":[{\"ObjectType\":\"Container\",\"ObjectFieldsKeys\":[\"Reason For Compliance\",\"Namespace\",\"Pod Name\",\"Container Name\"],\"ObjectFieldsValues\":[\"Container is not modified\",\"tnf\",\"test-0\",\"test\"]},{\"ObjectType\":\"Container\",\"ObjectFieldsKeys\":[\"Reason For Compliance\",\"Namespace\",\"Pod Name\",\"Container Name\"],\"ObjectFieldsValues\":[\"Container is not modified\",\"tnf\",\"test-1\",\"test\"]},{\"ObjectType\":\"Container\",\"ObjectFieldsKeys\":[\"Reason For Compliance\",\"Namespace\",\"Pod Name\",\"Container Name\"],\"ObjectFieldsValues\":[\"Container is not modified\",\"tnf\",\"test-d78fbf8d6-jxgl2\",\"test\"]},{\"ObjectType\":\"Container\",\"ObjectFieldsKeys\":[\"Reason For Compliance\",\"Namespace\",\"Pod Name\",\"Container Name\"],\"ObjectFieldsValues\":[\"Container is not modified\",\"tnf\",\"test-d78fbf8d6-n4jlv\",\"test\"]}],\"NonCompliantObjectsOut\":null}\n", + "catalogInfo": { + "bestPracticeReference": "https://test-network-function.github.io/cnf-best-practices/#cnf-best-practices-image-standards", + "description": "Ensures that the Container Base Image is not altered post-startup. This test is a heuristic, and ensures that there are no changes to the following directories: 1) /var/lib/rpm 2) /var/lib/dpkg 3) /bin 4) /sbin 5) /lib 6) /lib64 7) /usr/bin 8) /usr/sbin 9) /usr/lib 10) /usr/lib64", + "exceptionProcess": "No exceptions", + "remediation": "Ensure that Container applications do not modify the Container Base Image. In particular, ensure that the following directories are not modified: 1) /var/lib/rpm 2) /var/lib/dpkg 3) /bin 4) /sbin 5) /lib 6) /lib64 7) /usr/bin 8) /usr/sbin 9) /usr/lib 10) /usr/lib64 Ensure that all required binaries are built directly into the container image, and are not installed post startup." + }, + "categoryClassification": { + "Extended": "Mandatory", + "FarEdge": "Mandatory", + "NonTelco": "Mandatory", + "Telco": "Mandatory" + }, + "duration": 7745320473, + "endTime": "2023-07-25 09:10:25.557493221 -0500 CDT m=+51.038323513", + "failureLineContent": "", + "failureLocation": ":0", + "failureReason": "", + "startTime": "2023-07-25 09:10:17.812172748 -0500 CDT m=+43.293003040", + "state": "passed", + "testID": { + "id": "platform-alteration-base-image", + "suite": "platform-alteration", + "tags": "common" + } + } + `)}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := &Result{} + if err := got.UnmarshalJSON(tt.args.b); (err != nil) != tt.wantErr { + t.Errorf("Result.UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + } + deepEqual(got, tt.want) + }) + } +} + +func deepEqual(r1, r2 *Result) bool { + r1Nil, r2Nil := r1, r2 + r1Nil.TestID = nil + r1Nil.CategoryClassification = nil + r1Nil.CatalogInfo = nil + r2Nil.TestID = nil + r2Nil.CategoryClassification = nil + r2Nil.CatalogInfo = nil + + equal := reflect.DeepEqual(r1, r2) + if !equal { + return false + } + equal = reflect.DeepEqual(r1.CategoryClassification, r2.CategoryClassification) + if !equal { + return false + } + reflect.DeepEqual(r1.TestID, r2.TestID) + if !equal { + return false + } + reflect.DeepEqual(r1.CatalogInfo, r2.CatalogInfo) + + return equal +} diff --git a/pkg/claim/testdata/claim-invalid-additional-property.json b/pkg/claim/testdata/claim-invalid-additional-property.json new file mode 100644 index 000000000..0f52ee9c7 --- /dev/null +++ b/pkg/claim/testdata/claim-invalid-additional-property.json @@ -0,0 +1,468 @@ +{ + "anAdditionalPropertyInTheRootPayload": "shouldCauseAMarshalError", + "claim": { + "metadata": { + "startTime": "1970-01-01T10:05:08+01:00", + "endTime": "1970-01-01T10:05:08+01:00" + }, + "versions": { + "tnf": "v0.0.1", + "claimFormat":"v0.0.1" + }, + "configurations": {}, + "rawResults": { + "name": "CNF Certification Test Suite", + "tests": "7", + "failures": "1", + "errors": "0", + "time": "16.374", + "testcase": [ + { + "name": "cisco_kiknos when partner(partner) creates an IPSEC tunnel should report the tunnel was created through the CLI", + "classname": "CNF Certification Test Suite", + "time": "0", + "skipped": [] + }, + { + "name": "cisco_kiknos when partner(partner) creates an IPSEC tunnel should pass ICMP traffic", + "classname": "CNF Certification Test Suite", + "time": "0", + "skipped": [] + }, + { + "name": "cisco_kiknos when partner(partner) creates an IPSEC tunnel should pass UDP traffic", + "classname": "CNF Certification Test Suite", + "time": "0", + "skipped": [] + }, + { + "name": "generic Both Pods are on the Default network when a Ping is issued from ikester(ikester) to partner(partner) 172.17.0.6 partner(partner) should reply", + "classname": "CNF Certification Test Suite", + "time": "4.078620157" + }, + { + "name": "generic Both Pods are on the Default network when a Ping is issued from partner(partner) to ikester(ikester) 172.17.0.4 ikester(ikester) should reply", + "classname": "CNF Certification Test Suite", + "time": "4.095576392" + }, + { + "name": "generic Both Pods are on the Default network when a Ping is issued from test(test) to partner(partner) 172.17.0.6 partner(partner) should reply", + "classname": "CNF Certification Test Suite", + "time": "4.096696259" + }, + { + "name": "generic Both Pods are on the Default network when a Ping is issued from partner(partner) to test(test) 172.17.0.7 test(test) should reply", + "classname": "CNF Certification Test Suite", + "time": "4.096464621" + }, + { + "name": "generic when test(test) is checked for Red Hat version Should report a proper Red Hat version", + "classname": "CNF Certification Test Suite", + "time": "0.002463245" + }, + { + "name": "generic when ikester(ikester) is checked for Red Hat version Should report a proper Red Hat version", + "classname": "CNF Certification Test Suite", + "time": "0.001596069", + "failure": { + "type": "Failure", + "#text": "/Users/ryangoulding/workspace/test-network-function/test-network-function/generic/generic_cnf_tests.go:135\nExpected\n : 1\nto equal\n : 0\n/Users/ryangoulding/workspace/test-network-function/test-network-function/generic/generic_cnf_tests.go:140" + } + }, + { + "name": "generic when partner(partner) is checked for Red Hat version Should report a proper Red Hat version", + "classname": "CNF Certification Test Suite", + "time": "0.002391653" + }, + { + "name": "casa-cnf when Registrations are polled from the \"nfregistrations.mgmt.casa.io\" Custom Resource The appropriate registrations should be reported", + "classname": "CNF Certification Test Suite", + "time": "0", + "skipped": [] + }, + { + "name": "casa-cnf when nrf1(AMF) is checked for registration Should be registered", + "classname": "CNF Certification Test Suite", + "time": "0", + "skipped": [] + }, + { + "name": "casa-cnf when nrf1(SMF) is checked for registration Should be registered", + "classname": "CNF Certification Test Suite", + "time": "0", + "skipped": [] + } + ] + }, + "results": { + "{\"url\":\"https://test-network-function.com/tnf/test\",{\"version\":\"v1.0.0\"}": [ + { + "testText": "someText", + "isMeasurement": false, + "filename": "/dev/null", + "lineNumber": 4, + "passed": true, + "duration": 100 + } + ] + }, + "nodes": { + "host1": { + "lshwOutput": { + "id": "raspberrypi", + "class": "system", + "claimed": true, + "description": "ARMv7 Processor rev 4 (v7l)", + "product": "Raspberry Pi 3 Model B Plus Rev 1.3", + "serial": "000000006b968331", + "width": 32, + "capabilities": { + "smp": "Symmetric Multi-Processing" + }, + "children": [ + { + "id": "core", + "class": "bus", + "claimed": true, + "description": "Motherboard", + "physid": "0", + "children": [ + { + "id": "cpu:0", + "class": "processor", + "claimed": true, + "description": "CPU", + "product": "cpu", + "physid": "0", + "businfo": "cpu@0", + "units": "Hz", + "size": 1400000000, + "capacity": 1400000000, + "capabilities": { + "half": "Unknown", + "thumb": "Thumb instruction set", + "fastmult": "Fast Multiplication", + "vfp": "VFP (vector floating point instructions)", + "edsp": "DSP extensions", + "neon": "NEON aka MPE - Media Processing Engine", + "vfpv3": "VFP version 3", + "tls": "TLS register", + "vfpv4": "VFP version 4", + "idiva": "SDIV and UDIV hardware division in ARM mode", + "idivt": "SDIV and UDIV hardware division in Thumb mode", + "vfpd32": "Unknown", + "lpae": "Large Physical Address Extension architecture", + "evtstrm": "Unknown", + "crc32": true, + "cpufreq": "CPU Frequency scaling" + } + }, + { + "id": "cpu:1", + "class": "processor", + "claimed": true, + "description": "CPU", + "product": "cpu", + "physid": "1", + "businfo": "cpu@1", + "units": "Hz", + "size": 1400000000, + "capacity": 1400000000, + "capabilities": { + "half": "Unknown", + "thumb": "Thumb instruction set", + "fastmult": "Fast Multiplication", + "vfp": "VFP (vector floating point instructions)", + "edsp": "DSP extensions", + "neon": "NEON aka MPE - Media Processing Engine", + "vfpv3": "VFP version 3", + "tls": "TLS register", + "vfpv4": "VFP version 4", + "idiva": "SDIV and UDIV hardware division in ARM mode", + "idivt": "SDIV and UDIV hardware division in Thumb mode", + "vfpd32": "Unknown", + "lpae": "Large Physical Address Extension architecture", + "evtstrm": "Unknown", + "crc32": true, + "cpufreq": "CPU Frequency scaling" + } + }, + { + "id": "cpu:2", + "class": "processor", + "claimed": true, + "description": "CPU", + "product": "cpu", + "physid": "2", + "businfo": "cpu@2", + "units": "Hz", + "size": 1400000000, + "capacity": 1400000000, + "capabilities": { + "half": "Unknown", + "thumb": "Thumb instruction set", + "fastmult": "Fast Multiplication", + "vfp": "VFP (vector floating point instructions)", + "edsp": "DSP extensions", + "neon": "NEON aka MPE - Media Processing Engine", + "vfpv3": "VFP version 3", + "tls": "TLS register", + "vfpv4": "VFP version 4", + "idiva": "SDIV and UDIV hardware division in ARM mode", + "idivt": "SDIV and UDIV hardware division in Thumb mode", + "vfpd32": "Unknown", + "lpae": "Large Physical Address Extension architecture", + "evtstrm": "Unknown", + "crc32": true, + "cpufreq": "CPU Frequency scaling" + } + }, + { + "id": "cpu:3", + "class": "processor", + "claimed": true, + "description": "CPU", + "product": "cpu", + "physid": "3", + "businfo": "cpu@3", + "units": "Hz", + "size": 1400000000, + "capacity": 1400000000, + "capabilities": { + "half": "Unknown", + "thumb": "Thumb instruction set", + "fastmult": "Fast Multiplication", + "vfp": "VFP (vector floating point instructions)", + "edsp": "DSP extensions", + "neon": "NEON aka MPE - Media Processing Engine", + "vfpv3": "VFP version 3", + "tls": "TLS register", + "vfpv4": "VFP version 4", + "idiva": "SDIV and UDIV hardware division in ARM mode", + "idivt": "SDIV and UDIV hardware division in Thumb mode", + "vfpd32": "Unknown", + "lpae": "Large Physical Address Extension architecture", + "evtstrm": "Unknown", + "crc32": true, + "cpufreq": "CPU Frequency scaling" + } + }, + { + "id": "memory", + "class": "memory", + "claimed": true, + "description": "System memory", + "physid": "4", + "units": "bytes", + "size": 971063296 + } + ] + }, + { + "id": "usbhost", + "class": "bus", + "claimed": true, + "handle": "USB:1:1", + "product": "DWC OTG Controller", + "vendor": "Linux 4.19.66-v7+ dwc_otg_hcd", + "physid": "1", + "businfo": "usb@1", + "logicalname": "usb1", + "version": "4.19", + "configuration": { + "driver": "hub", + "slots": "1", + "speed": "480Mbit/s" + }, + "capabilities": { + "usb-2.00": "USB 2.0" + }, + "children": [ + { + "id": "usb", + "class": "bus", + "claimed": true, + "handle": "USB:1:2", + "description": "USB hub", + "product": "USB 2.0 Hub", + "vendor": "Standard Microsystems Corp.", + "physid": "1", + "businfo": "usb@1:1", + "version": "b.b3", + "configuration": { + "driver": "hub", + "maxpower": "2mA", + "slots": "4", + "speed": "480Mbit/s" + }, + "capabilities": { + "usb-2.00": "USB 2.0" + }, + "children": [ + { + "id": "usb:0", + "class": "bus", + "claimed": true, + "handle": "USB:1:3", + "description": "USB hub", + "product": "USB 2.0 Hub", + "vendor": "Standard Microsystems Corp.", + "physid": "1", + "businfo": "usb@1:1.1", + "version": "b.b3", + "configuration": { + "driver": "hub", + "maxpower": "2mA", + "slots": "3", + "speed": "480Mbit/s" + }, + "capabilities": { + "usb-2.00": "USB 2.0" + }, + "children": [ + { + "id": "usb", + "class": "generic", + "claimed": true, + "handle": "USB:1:5", + "description": "Generic USB device", + "vendor": "Standard Microsystems Corp.", + "physid": "1", + "businfo": "usb@1:1.1.1", + "version": "3.00", + "configuration": { + "driver": "lan78xx", + "maxpower": "2mA", + "speed": "480Mbit/s" + }, + "capabilities": { + "usb-2.10": true + } + } + ] + }, + { + "id": "usb:1", + "class": "printer", + "claimed": true, + "handle": "USB:1:4", + "description": "Printer", + "product": "MP490 series", + "vendor": "Canon", + "physid": "2", + "businfo": "usb@1:1.2", + "logicalname": "scsi0", + "version": "0.02", + "serial": "0217F4", + "configuration": { + "driver": "usb-storage", + "maxpower": "2mA", + "speed": "480Mbit/s" + }, + "capabilities": { + "usb-2.00": "USB 2.0", + "bidirectional": "Bidirectional", + "emulated": "Emulated device" + }, + "children": [ + { + "id": "disk", + "class": "disk", + "claimed": true, + "handle": "SCSI:00:00:00:00", + "description": "SCSI Disk", + "product": "MP490 series", + "vendor": "Canon", + "physid": "0.0.0", + "businfo": "scsi@0:0.0.0", + "logicalname": "/dev/sda", + "dev": "8:0", + "version": "0102", + "configuration": { + "ansiversion": "2", + "logicalsectorsize": "512", + "sectorsize": "512" + }, + "capabilities": { + "removable": "support is removable" + }, + "children": [ + { + "id": "medium", + "class": "disk", + "claimed": true, + "physid": "0", + "logicalname": "/dev/sda", + "dev": "8:0" + } + ] + } + ] + } + ] + } + ] + }, + { + "id": "network:0", + "class": "network", + "claimed": true, + "description": "Ethernet interface", + "physid": "2", + "logicalname": "eth0", + "serial": "b8:27:eb:96:83:31", + "units": "bit/s", + "size": 10000000, + "capacity": 1000000000, + "configuration": { + "autonegotiation": "on", + "broadcast": "yes", + "driver": "lan78xx", + "duplex": "half", + "link": "no", + "multicast": "yes", + "port": "MII", + "speed": "10Mbit/s" + }, + "capabilities": { + "ethernet": true, + "physical": "Physical interface", + "tp": "twisted pair", + "mii": "Media Independent Interface", + "10bt": "10Mbit/s", + "10bt-fd": "10Mbit/s (full duplex)", + "100bt": "100Mbit/s", + "100bt-fd": "100Mbit/s (full duplex)", + "1000bt-fd": "1Gbit/s (full duplex)", + "autonegotiation": "Auto-negotiation" + } + }, + { + "id": "network:1", + "class": "network", + "claimed": true, + "description": "Wireless interface", + "physid": "3", + "logicalname": "wlan0", + "serial": "b8:27:eb:c3:d6:64", + "configuration": { + "broadcast": "yes", + "driver": "brcmfmac", + "driverversion": "7.45.154", + "firmware": "01-4fbe0b04", + "ip": "192.168.1.5", + "multicast": "yes", + "wireless": "IEEE 802.11" + }, + "capabilities": { + "ethernet": true, + "physical": "Physical interface", + "wireless": "Wireless-LAN" + } + } + ] + } + } + } + } +} diff --git a/pkg/claim/testdata/claim-invalid-bool-results.json b/pkg/claim/testdata/claim-invalid-bool-results.json new file mode 100644 index 000000000..ac26f4d6a --- /dev/null +++ b/pkg/claim/testdata/claim-invalid-bool-results.json @@ -0,0 +1,220 @@ +{ + "claim": { + "configurations": { + "generic": { + "containersUnderTest": { + "{\"namespace\":\"default\",\"podName\":\"vendor-container1-649d949d4c-stxcc\",\"containerName\":\"vendor-container1\"}": { + "defaultNetworkDevice": "eth0", + "multusIpAddresses": [ + "192.168.1.3" + ] + }, + "{\"namespace\":\"default\",\"podName\":\"vendor-container2-98f77dfbc-6c6dc\",\"containerName\":\"vendor-container2\"}": { + "defaultNetworkDevice": "eth0", + "multusIpAddresses": [ + "192.168.1.3" + ] + } + }, + "partnerContainers": { + "{\"namespace\":\"default\",\"podName\":\"partner\",\"containerName\":\"partner\"}": { + "defaultNetworkDevice": "eth0", + "multusIpAddresses": [ + "192.168.1.1" + ] + } + }, + "testOrchestrator": "{\"namespace\":\"default\",\"podName\":\"partner\",\"containerName\":\"partner\"}" + } + }, + "metadata": { + "endTime": "1970-01-01T10:05:08+01:00", + "startTime": "1970-01-01T10:05:08+01:00" + }, + "nodes": { + "apiVersion": "v1", + "items": [ + { + "apiVersion": "v1", + "kind": "Node", + "metadata": { + "annotations": { + "machineconfiguration.openshift.io/currentConfig": "rendered-master-c780491175691e89d2b3b34c86baf1a6", + "machineconfiguration.openshift.io/desiredConfig": "rendered-master-c780491175691e89d2b3b34c86baf1a6", + "machineconfiguration.openshift.io/reason": "", + "machineconfiguration.openshift.io/state": "Done", + "volumes.kubernetes.io/controller-managed-attach-detach": "true" + }, + "creationTimestamp": "2020-11-13T16:42:44Z", + "labels": { + "beta.kubernetes.io/arch": "amd64", + "beta.kubernetes.io/os": "linux", + "kubernetes.io/arch": "amd64", + "kubernetes.io/hostname": "master-0", + "kubernetes.io/os": "linux", + "node-role.kubernetes.io/master": "", + "node.openshift.io/os_id": "rhcos" + }, + "name": "master-0", + "resourceVersion": "22191357", + "selfLink": "/api/v1/nodes/master-0", + "uid": "e0c8fac4-07dd-4dd3-a181-9415d30f4235" + }, + "spec": {}, + "status": { + "addresses": [ + { + "address": "192.168.1.110", + "type": "InternalIP" + }, + { + "address": "master-0", + "type": "Hostname" + } + ], + "allocatable": { + "cpu": "79500m", + "ephemeral-storage": "1078575967288", + "hugepages-1Gi": "0", + "hugepages-2Mi": "0", + "memory": "190981Mi", + "pods": "250" + }, + "capacity": { + "cpu": "80", + "ephemeral-storage": "1144038Mi", + "hugepages-1Gi": "0", + "hugepages-2Mi": "0", + "memory": "192105Mi", + "pods": "250" + }, + "conditions": [ + { + "lastHeartbeatTime": "2020-12-14T19:23:17Z", + "lastTransitionTime": "2020-11-19T21:02:44Z", + "message": "kubelet has sufficient memory available", + "reason": "KubeletHasSufficientMemory", + "status": "False", + "type": "MemoryPressure" + }, + { + "lastHeartbeatTime": "2020-12-14T19:23:17Z", + "lastTransitionTime": "2020-11-19T21:02:44Z", + "message": "kubelet has no disk pressure", + "reason": "KubeletHasNoDiskPressure", + "status": "False", + "type": "DiskPressure" + }, + { + "lastHeartbeatTime": "2020-12-14T19:23:17Z", + "lastTransitionTime": "2020-11-19T21:02:44Z", + "message": "kubelet has sufficient PID available", + "reason": "KubeletHasSufficientPID", + "status": "False", + "type": "PIDPressure" + }, + { + "lastHeartbeatTime": "2020-12-14T19:23:17Z", + "lastTransitionTime": "2020-11-19T21:02:44Z", + "message": "kubelet is posting ready status", + "reason": "KubeletReady", + "status": "True", + "type": "Ready" + } + ], + "daemonEndpoints": { + "kubeletEndpoint": { + "Port": 10250 + } + }, + "images": [ + { + "names": [ + "quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:8cea2679f40cd5e5bb95b7f511d444ea7ad74800bcc366d0129eb682459cdffd", + "quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:" + ], + "sizeBytes": 819896785 + } + ], + "nodeInfo": { + "architecture": "amd64", + "bootID": "f24d12e7-202b-4978-bf70-f96f1b5ea3bd", + "containerRuntimeVersion": "cri-o://1.17.4-8.dev.rhaos4.4.git5f5c5e4.el8", + "kernelVersion": "4.18.0-147.8.1.el8_1.x86_64", + "kubeProxyVersion": "v1.17.1", + "kubeletVersion": "v1.17.1", + "machineID": "89842748b08741f99dd5db5433ae16b6", + "operatingSystem": "linux", + "osImage": "Red Hat Enterprise Linux CoreOS 44.81.202004260825-0 (Ootpa)", + "systemUUID": "80ff6508-d095-e711-906e-0017a4403562" + } + } + } + ], + "kind": "List", + "metadata": { + "resourceVersion": "", + "selfLink": "" + } + }, + "results": { + "identifier": { + "url": "https://test-network-function.com/tnf/test", + "version": "v1.0.0" + }, + "results": [ + { + "testText": "someText", + "isMeasurement": false, + "filename": "/dev/null", + "lineNumber": 4, + "passed": true, + "duration": 100 + } + ] + }, + "rawResults": { + "cnf-certification-tests_junit": { + "testsuite": { + "-errors": "0", + "-failures": "0", + "-name": "CNF Certification Test Suite", + "-tests": "5", + "-time": "8.376", + "testcase": [ + { + "-classname": "CNF Certification Test Suite", + "-name": "generic Both Pods are on the Default network when a Ping is issued from test(test) to partner(partner) 10.130.4.64 partner(partner) should reply", + "-time": "4.132041197" + }, + { + "-classname": "CNF Certification Test Suite", + "-name": "generic Both Pods are on the Default network when a Ping is issued from partner(partner) to test(test) 10.128.8.3 test(test) should reply", + "-time": "4.102927471" + }, + { + "-classname": "CNF Certification Test Suite", + "-name": "generic when test(test) is checked for Red Hat version Should report a proper Red Hat version", + "-time": "0.002270972" + }, + { + "-classname": "CNF Certification Test Suite", + "-name": "generic when partner(partner) is checked for Red Hat version Should report a proper Red Hat version", + "-time": "0.002174817" + }, + { + "-classname": "CNF Certification Test Suite", + "-name": "diagnostic when a cluster is set up and installed with OpenShift should report all available nodeSummary", + "-time": "0.133763681" + } + ] + } + } + }, + "versions": { + "tnf": "v0.0.3", + "claimFormat":"v0.0.1" + }, + "results": false + } +} \ No newline at end of file diff --git a/pkg/claim/testdata/claim-invalid-junit-payload.json b/pkg/claim/testdata/claim-invalid-junit-payload.json new file mode 100644 index 000000000..60a201aa3 --- /dev/null +++ b/pkg/claim/testdata/claim-invalid-junit-payload.json @@ -0,0 +1,384 @@ +{ + "claim": { + "metadata": { + "startTime": "1970-01-01T10:05:08+01:00", + "endTime": "1970-01-01T10:05:08+01:00" + }, + "versions": { + "tnf": "v0.0.1", + "claimFormat":"v0.0.1" + }, + "configurations": {}, + "rawResults": false, + "results": { + "{\"url\":\"https://test-network-function.com/tnf/test\",{\"version\":\"v1.0.0\"}": [ + { + "testText": "someText", + "isMeasurement": false, + "filename": "/dev/null", + "lineNumber": 4, + "passed": true, + "duration": 100 + } + ] + }, + "nodes": { + "host1": { + "lshwOutput": { + "id": "raspberrypi", + "class": "system", + "claimed": true, + "description": "ARMv7 Processor rev 4 (v7l)", + "product": "Raspberry Pi 3 Model B Plus Rev 1.3", + "serial": "000000006b968331", + "width": 32, + "capabilities": { + "smp": "Symmetric Multi-Processing" + }, + "children": [ + { + "id": "core", + "class": "bus", + "claimed": true, + "description": "Motherboard", + "physid": "0", + "children": [ + { + "id": "cpu:0", + "class": "processor", + "claimed": true, + "description": "CPU", + "product": "cpu", + "physid": "0", + "businfo": "cpu@0", + "units": "Hz", + "size": 1400000000, + "capacity": 1400000000, + "capabilities": { + "half": "Unknown", + "thumb": "Thumb instruction set", + "fastmult": "Fast Multiplication", + "vfp": "VFP (vector floating point instructions)", + "edsp": "DSP extensions", + "neon": "NEON aka MPE - Media Processing Engine", + "vfpv3": "VFP version 3", + "tls": "TLS register", + "vfpv4": "VFP version 4", + "idiva": "SDIV and UDIV hardware division in ARM mode", + "idivt": "SDIV and UDIV hardware division in Thumb mode", + "vfpd32": "Unknown", + "lpae": "Large Physical Address Extension architecture", + "evtstrm": "Unknown", + "crc32": true, + "cpufreq": "CPU Frequency scaling" + } + }, + { + "id": "cpu:1", + "class": "processor", + "claimed": true, + "description": "CPU", + "product": "cpu", + "physid": "1", + "businfo": "cpu@1", + "units": "Hz", + "size": 1400000000, + "capacity": 1400000000, + "capabilities": { + "half": "Unknown", + "thumb": "Thumb instruction set", + "fastmult": "Fast Multiplication", + "vfp": "VFP (vector floating point instructions)", + "edsp": "DSP extensions", + "neon": "NEON aka MPE - Media Processing Engine", + "vfpv3": "VFP version 3", + "tls": "TLS register", + "vfpv4": "VFP version 4", + "idiva": "SDIV and UDIV hardware division in ARM mode", + "idivt": "SDIV and UDIV hardware division in Thumb mode", + "vfpd32": "Unknown", + "lpae": "Large Physical Address Extension architecture", + "evtstrm": "Unknown", + "crc32": true, + "cpufreq": "CPU Frequency scaling" + } + }, + { + "id": "cpu:2", + "class": "processor", + "claimed": true, + "description": "CPU", + "product": "cpu", + "physid": "2", + "businfo": "cpu@2", + "units": "Hz", + "size": 1400000000, + "capacity": 1400000000, + "capabilities": { + "half": "Unknown", + "thumb": "Thumb instruction set", + "fastmult": "Fast Multiplication", + "vfp": "VFP (vector floating point instructions)", + "edsp": "DSP extensions", + "neon": "NEON aka MPE - Media Processing Engine", + "vfpv3": "VFP version 3", + "tls": "TLS register", + "vfpv4": "VFP version 4", + "idiva": "SDIV and UDIV hardware division in ARM mode", + "idivt": "SDIV and UDIV hardware division in Thumb mode", + "vfpd32": "Unknown", + "lpae": "Large Physical Address Extension architecture", + "evtstrm": "Unknown", + "crc32": true, + "cpufreq": "CPU Frequency scaling" + } + }, + { + "id": "cpu:3", + "class": "processor", + "claimed": true, + "description": "CPU", + "product": "cpu", + "physid": "3", + "businfo": "cpu@3", + "units": "Hz", + "size": 1400000000, + "capacity": 1400000000, + "capabilities": { + "half": "Unknown", + "thumb": "Thumb instruction set", + "fastmult": "Fast Multiplication", + "vfp": "VFP (vector floating point instructions)", + "edsp": "DSP extensions", + "neon": "NEON aka MPE - Media Processing Engine", + "vfpv3": "VFP version 3", + "tls": "TLS register", + "vfpv4": "VFP version 4", + "idiva": "SDIV and UDIV hardware division in ARM mode", + "idivt": "SDIV and UDIV hardware division in Thumb mode", + "vfpd32": "Unknown", + "lpae": "Large Physical Address Extension architecture", + "evtstrm": "Unknown", + "crc32": true, + "cpufreq": "CPU Frequency scaling" + } + }, + { + "id": "memory", + "class": "memory", + "claimed": true, + "description": "System memory", + "physid": "4", + "units": "bytes", + "size": 971063296 + } + ] + }, + { + "id": "usbhost", + "class": "bus", + "claimed": true, + "handle": "USB:1:1", + "product": "DWC OTG Controller", + "vendor": "Linux 4.19.66-v7+ dwc_otg_hcd", + "physid": "1", + "businfo": "usb@1", + "logicalname": "usb1", + "version": "4.19", + "configuration": { + "driver": "hub", + "slots": "1", + "speed": "480Mbit/s" + }, + "capabilities": { + "usb-2.00": "USB 2.0" + }, + "children": [ + { + "id": "usb", + "class": "bus", + "claimed": true, + "handle": "USB:1:2", + "description": "USB hub", + "product": "USB 2.0 Hub", + "vendor": "Standard Microsystems Corp.", + "physid": "1", + "businfo": "usb@1:1", + "version": "b.b3", + "configuration": { + "driver": "hub", + "maxpower": "2mA", + "slots": "4", + "speed": "480Mbit/s" + }, + "capabilities": { + "usb-2.00": "USB 2.0" + }, + "children": [ + { + "id": "usb:0", + "class": "bus", + "claimed": true, + "handle": "USB:1:3", + "description": "USB hub", + "product": "USB 2.0 Hub", + "vendor": "Standard Microsystems Corp.", + "physid": "1", + "businfo": "usb@1:1.1", + "version": "b.b3", + "configuration": { + "driver": "hub", + "maxpower": "2mA", + "slots": "3", + "speed": "480Mbit/s" + }, + "capabilities": { + "usb-2.00": "USB 2.0" + }, + "children": [ + { + "id": "usb", + "class": "generic", + "claimed": true, + "handle": "USB:1:5", + "description": "Generic USB device", + "vendor": "Standard Microsystems Corp.", + "physid": "1", + "businfo": "usb@1:1.1.1", + "version": "3.00", + "configuration": { + "driver": "lan78xx", + "maxpower": "2mA", + "speed": "480Mbit/s" + }, + "capabilities": { + "usb-2.10": true + } + } + ] + }, + { + "id": "usb:1", + "class": "printer", + "claimed": true, + "handle": "USB:1:4", + "description": "Printer", + "product": "MP490 series", + "vendor": "Canon", + "physid": "2", + "businfo": "usb@1:1.2", + "logicalname": "scsi0", + "version": "0.02", + "serial": "0217F4", + "configuration": { + "driver": "usb-storage", + "maxpower": "2mA", + "speed": "480Mbit/s" + }, + "capabilities": { + "usb-2.00": "USB 2.0", + "bidirectional": "Bidirectional", + "emulated": "Emulated device" + }, + "children": [ + { + "id": "disk", + "class": "disk", + "claimed": true, + "handle": "SCSI:00:00:00:00", + "description": "SCSI Disk", + "product": "MP490 series", + "vendor": "Canon", + "physid": "0.0.0", + "businfo": "scsi@0:0.0.0", + "logicalname": "/dev/sda", + "dev": "8:0", + "version": "0102", + "configuration": { + "ansiversion": "2", + "logicalsectorsize": "512", + "sectorsize": "512" + }, + "capabilities": { + "removable": "support is removable" + }, + "children": [ + { + "id": "medium", + "class": "disk", + "claimed": true, + "physid": "0", + "logicalname": "/dev/sda", + "dev": "8:0" + } + ] + } + ] + } + ] + } + ] + }, + { + "id": "network:0", + "class": "network", + "claimed": true, + "description": "Ethernet interface", + "physid": "2", + "logicalname": "eth0", + "serial": "b8:27:eb:96:83:31", + "units": "bit/s", + "size": 10000000, + "capacity": 1000000000, + "configuration": { + "autonegotiation": "on", + "broadcast": "yes", + "driver": "lan78xx", + "duplex": "half", + "link": "no", + "multicast": "yes", + "port": "MII", + "speed": "10Mbit/s" + }, + "capabilities": { + "ethernet": true, + "physical": "Physical interface", + "tp": "twisted pair", + "mii": "Media Independent Interface", + "10bt": "10Mbit/s", + "10bt-fd": "10Mbit/s (full duplex)", + "100bt": "100Mbit/s", + "100bt-fd": "100Mbit/s (full duplex)", + "1000bt-fd": "1Gbit/s (full duplex)", + "autonegotiation": "Auto-negotiation" + } + }, + { + "id": "network:1", + "class": "network", + "claimed": true, + "description": "Wireless interface", + "physid": "3", + "logicalname": "wlan0", + "serial": "b8:27:eb:c3:d6:64", + "configuration": { + "broadcast": "yes", + "driver": "brcmfmac", + "driverversion": "7.45.154", + "firmware": "01-4fbe0b04", + "ip": "192.168.1.5", + "multicast": "yes", + "wireless": "IEEE 802.11" + }, + "capabilities": { + "ethernet": true, + "physical": "Physical interface", + "wireless": "Wireless-LAN" + } + } + ] + } + } + } + } +} diff --git a/pkg/claim/testdata/claim-invalid-non-result-result.json b/pkg/claim/testdata/claim-invalid-non-result-result.json new file mode 100644 index 000000000..6008bcf71 --- /dev/null +++ b/pkg/claim/testdata/claim-invalid-non-result-result.json @@ -0,0 +1,226 @@ +{ + "claim": { + "configurations": { + "generic": { + "containersUnderTest": { + "{\"namespace\":\"default\",\"podName\":\"vendor-container1-649d949d4c-stxcc\",\"containerName\":\"vendor-container1\"}": { + "defaultNetworkDevice": "eth0", + "multusIpAddresses": [ + "192.168.1.3" + ] + }, + "{\"namespace\":\"default\",\"podName\":\"vendor-container2-98f77dfbc-6c6dc\",\"containerName\":\"vendor-container2\"}": { + "defaultNetworkDevice": "eth0", + "multusIpAddresses": [ + "192.168.1.3" + ] + } + }, + "partnerContainers": { + "{\"namespace\":\"default\",\"podName\":\"partner\",\"containerName\":\"partner\"}": { + "defaultNetworkDevice": "eth0", + "multusIpAddresses": [ + "192.168.1.1" + ] + } + }, + "testOrchestrator": "{\"namespace\":\"default\",\"podName\":\"partner\",\"containerName\":\"partner\"}" + } + }, + "metadata": { + "endTime": "1970-01-01T10:05:08+01:00", + "startTime": "1970-01-01T10:05:08+01:00" + }, + "nodes": { + "apiVersion": "v1", + "items": [ + { + "apiVersion": "v1", + "kind": "Node", + "metadata": { + "annotations": { + "machineconfiguration.openshift.io/currentConfig": "rendered-master-c780491175691e89d2b3b34c86baf1a6", + "machineconfiguration.openshift.io/desiredConfig": "rendered-master-c780491175691e89d2b3b34c86baf1a6", + "machineconfiguration.openshift.io/reason": "", + "machineconfiguration.openshift.io/state": "Done", + "volumes.kubernetes.io/controller-managed-attach-detach": "true" + }, + "creationTimestamp": "2020-11-13T16:42:44Z", + "labels": { + "beta.kubernetes.io/arch": "amd64", + "beta.kubernetes.io/os": "linux", + "kubernetes.io/arch": "amd64", + "kubernetes.io/hostname": "master-0", + "kubernetes.io/os": "linux", + "node-role.kubernetes.io/master": "", + "node.openshift.io/os_id": "rhcos" + }, + "name": "master-0", + "resourceVersion": "22191357", + "selfLink": "/api/v1/nodes/master-0", + "uid": "e0c8fac4-07dd-4dd3-a181-9415d30f4235" + }, + "spec": {}, + "status": { + "addresses": [ + { + "address": "192.168.1.110", + "type": "InternalIP" + }, + { + "address": "master-0", + "type": "Hostname" + } + ], + "allocatable": { + "cpu": "79500m", + "ephemeral-storage": "1078575967288", + "hugepages-1Gi": "0", + "hugepages-2Mi": "0", + "memory": "190981Mi", + "pods": "250" + }, + "capacity": { + "cpu": "80", + "ephemeral-storage": "1144038Mi", + "hugepages-1Gi": "0", + "hugepages-2Mi": "0", + "memory": "192105Mi", + "pods": "250" + }, + "conditions": [ + { + "lastHeartbeatTime": "2020-12-14T19:23:17Z", + "lastTransitionTime": "2020-11-19T21:02:44Z", + "message": "kubelet has sufficient memory available", + "reason": "KubeletHasSufficientMemory", + "status": "False", + "type": "MemoryPressure" + }, + { + "lastHeartbeatTime": "2020-12-14T19:23:17Z", + "lastTransitionTime": "2020-11-19T21:02:44Z", + "message": "kubelet has no disk pressure", + "reason": "KubeletHasNoDiskPressure", + "status": "False", + "type": "DiskPressure" + }, + { + "lastHeartbeatTime": "2020-12-14T19:23:17Z", + "lastTransitionTime": "2020-11-19T21:02:44Z", + "message": "kubelet has sufficient PID available", + "reason": "KubeletHasSufficientPID", + "status": "False", + "type": "PIDPressure" + }, + { + "lastHeartbeatTime": "2020-12-14T19:23:17Z", + "lastTransitionTime": "2020-11-19T21:02:44Z", + "message": "kubelet is posting ready status", + "reason": "KubeletReady", + "status": "True", + "type": "Ready" + } + ], + "daemonEndpoints": { + "kubeletEndpoint": { + "Port": 10250 + } + }, + "images": [ + { + "names": [ + "quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:8cea2679f40cd5e5bb95b7f511d444ea7ad74800bcc366d0129eb682459cdffd", + "quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:" + ], + "sizeBytes": 819896785 + } + ], + "nodeInfo": { + "architecture": "amd64", + "bootID": "f24d12e7-202b-4978-bf70-f96f1b5ea3bd", + "containerRuntimeVersion": "cri-o://1.17.4-8.dev.rhaos4.4.git5f5c5e4.el8", + "kernelVersion": "4.18.0-147.8.1.el8_1.x86_64", + "kubeProxyVersion": "v1.17.1", + "kubeletVersion": "v1.17.1", + "machineID": "89842748b08741f99dd5db5433ae16b6", + "operatingSystem": "linux", + "osImage": "Red Hat Enterprise Linux CoreOS 44.81.202004260825-0 (Ootpa)", + "systemUUID": "80ff6508-d095-e711-906e-0017a4403562" + } + } + } + ], + "kind": "List", + "metadata": { + "resourceVersion": "", + "selfLink": "" + } + }, + "results": { + "identifier": { + "url": "https://test-network-function.com/tnf/test", + "version": "v1.0.0" + }, + "results": [ + { + "testText": "someText", + "isMeasurement": false, + "filename": "/dev/null", + "lineNumber": 4, + "passed": true, + "duration": 100 + } + ] + }, + "rawResults": { + "cnf-certification-tests_junit": { + "testsuite": { + "-errors": "0", + "-failures": "0", + "-name": "CNF Certification Test Suite", + "-tests": "5", + "-time": "8.376", + "testcase": [ + { + "-classname": "CNF Certification Test Suite", + "-name": "generic Both Pods are on the Default network when a Ping is issued from test(test) to partner(partner) 10.130.4.64 partner(partner) should reply", + "-time": "4.132041197" + }, + { + "-classname": "CNF Certification Test Suite", + "-name": "generic Both Pods are on the Default network when a Ping is issued from partner(partner) to test(test) 10.128.8.3 test(test) should reply", + "-time": "4.102927471" + }, + { + "-classname": "CNF Certification Test Suite", + "-name": "generic when test(test) is checked for Red Hat version Should report a proper Red Hat version", + "-time": "0.002270972" + }, + { + "-classname": "CNF Certification Test Suite", + "-name": "generic when partner(partner) is checked for Red Hat version Should report a proper Red Hat version", + "-time": "0.002174817" + }, + { + "-classname": "CNF Certification Test Suite", + "-name": "diagnostic when a cluster is set up and installed with OpenShift should report all available nodeSummary", + "-time": "0.133763681" + } + ] + } + } + }, + "versions": { + "tnf": "v0.0.3", + "claimFormat":"v0.0.1" + }, + "results": { + "{\"url\":\"https://test-network-function.com/tnf/test\",{\"version\":\"v1.0.0\"}": [ + { + "notaresult": "absolutelynot" + } + ] + } + } +} \ No newline at end of file diff --git a/pkg/claim/testdata/claim-valid.json b/pkg/claim/testdata/claim-valid.json new file mode 100644 index 000000000..c3144642c --- /dev/null +++ b/pkg/claim/testdata/claim-valid.json @@ -0,0 +1,231 @@ +{ + "claim": { + "configurations": { + "generic": { + "containersUnderTest": { + "{\"namespace\":\"default\",\"podName\":\"vendor-container1-649d949d4c-stxcc\",\"containerName\":\"vendor-container1\"}": { + "defaultNetworkDevice": "eth0", + "multusIpAddresses": [ + "192.168.1.3" + ] + }, + "{\"namespace\":\"default\",\"podName\":\"vendor-container2-98f77dfbc-6c6dc\",\"containerName\":\"vendor-container2\"}": { + "defaultNetworkDevice": "eth0", + "multusIpAddresses": [ + "192.168.1.3" + ] + } + }, + "partnerContainers": { + "{\"namespace\":\"default\",\"podName\":\"partner\",\"containerName\":\"partner\"}": { + "defaultNetworkDevice": "eth0", + "multusIpAddresses": [ + "192.168.1.1" + ] + } + }, + "testOrchestrator": "{\"namespace\":\"default\",\"podName\":\"partner\",\"containerName\":\"partner\"}" + } + }, + "metadata": { + "endTime": "1970-01-01T10:05:08+01:00", + "startTime": "1970-01-01T10:05:08+01:00" + }, + "nodes": { + "apiVersion": "v1", + "items": [ + { + "apiVersion": "v1", + "kind": "Node", + "metadata": { + "annotations": { + "machineconfiguration.openshift.io/currentConfig": "rendered-master-c780491175691e89d2b3b34c86baf1a6", + "machineconfiguration.openshift.io/desiredConfig": "rendered-master-c780491175691e89d2b3b34c86baf1a6", + "machineconfiguration.openshift.io/reason": "", + "machineconfiguration.openshift.io/state": "Done", + "volumes.kubernetes.io/controller-managed-attach-detach": "true" + }, + "creationTimestamp": "2020-11-13T16:42:44Z", + "labels": { + "beta.kubernetes.io/arch": "amd64", + "beta.kubernetes.io/os": "linux", + "kubernetes.io/arch": "amd64", + "kubernetes.io/hostname": "master-0", + "kubernetes.io/os": "linux", + "node-role.kubernetes.io/master": "", + "node.openshift.io/os_id": "rhcos" + }, + "name": "master-0", + "resourceVersion": "22191357", + "selfLink": "/api/v1/nodes/master-0", + "uid": "e0c8fac4-07dd-4dd3-a181-9415d30f4235" + }, + "spec": {}, + "status": { + "addresses": [ + { + "address": "192.168.1.110", + "type": "InternalIP" + }, + { + "address": "master-0", + "type": "Hostname" + } + ], + "allocatable": { + "cpu": "79500m", + "ephemeral-storage": "1078575967288", + "hugepages-1Gi": "0", + "hugepages-2Mi": "0", + "memory": "190981Mi", + "pods": "250" + }, + "capacity": { + "cpu": "80", + "ephemeral-storage": "1144038Mi", + "hugepages-1Gi": "0", + "hugepages-2Mi": "0", + "memory": "192105Mi", + "pods": "250" + }, + "conditions": [ + { + "lastHeartbeatTime": "2020-12-14T19:23:17Z", + "lastTransitionTime": "2020-11-19T21:02:44Z", + "message": "kubelet has sufficient memory available", + "reason": "KubeletHasSufficientMemory", + "status": "False", + "type": "MemoryPressure" + }, + { + "lastHeartbeatTime": "2020-12-14T19:23:17Z", + "lastTransitionTime": "2020-11-19T21:02:44Z", + "message": "kubelet has no disk pressure", + "reason": "KubeletHasNoDiskPressure", + "status": "False", + "type": "DiskPressure" + }, + { + "lastHeartbeatTime": "2020-12-14T19:23:17Z", + "lastTransitionTime": "2020-11-19T21:02:44Z", + "message": "kubelet has sufficient PID available", + "reason": "KubeletHasSufficientPID", + "status": "False", + "type": "PIDPressure" + }, + { + "lastHeartbeatTime": "2020-12-14T19:23:17Z", + "lastTransitionTime": "2020-11-19T21:02:44Z", + "message": "kubelet is posting ready status", + "reason": "KubeletReady", + "status": "True", + "type": "Ready" + } + ], + "daemonEndpoints": { + "kubeletEndpoint": { + "Port": 10250 + } + }, + "images": [ + { + "names": [ + "quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:8cea2679f40cd5e5bb95b7f511d444ea7ad74800bcc366d0129eb682459cdffd", + "quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:" + ], + "sizeBytes": 819896785 + } + ], + "nodeInfo": { + "architecture": "amd64", + "bootID": "f24d12e7-202b-4978-bf70-f96f1b5ea3bd", + "containerRuntimeVersion": "cri-o://1.17.4-8.dev.rhaos4.4.git5f5c5e4.el8", + "kernelVersion": "4.18.0-147.8.1.el8_1.x86_64", + "kubeProxyVersion": "v1.17.1", + "kubeletVersion": "v1.17.1", + "machineID": "89842748b08741f99dd5db5433ae16b6", + "operatingSystem": "linux", + "osImage": "Red Hat Enterprise Linux CoreOS 44.81.202004260825-0 (Ootpa)", + "systemUUID": "80ff6508-d095-e711-906e-0017a4403562" + } + } + } + ], + "kind": "List", + "metadata": { + "resourceVersion": "", + "selfLink": "" + } + }, + "results": { + "identifier": { + "url": "https://test-network-function.com/tnf/test", + "version": "v1.0.0" + }, + "results": [ + { + "testText": "someText", + "isMeasurement": false, + "filename": "/dev/null", + "lineNumber": 4, + "passed": true, + "duration": 100 + } + ] + }, + "rawResults": { + "cnf-certification-tests_junit": { + "testsuite": { + "-errors": "0", + "-failures": "0", + "-name": "CNF Certification Test Suite", + "-tests": "5", + "-time": "8.376", + "testcase": [ + { + "-classname": "CNF Certification Test Suite", + "-name": "generic Both Pods are on the Default network when a Ping is issued from test(test) to partner(partner) 10.130.4.64 partner(partner) should reply", + "-time": "4.132041197" + }, + { + "-classname": "CNF Certification Test Suite", + "-name": "generic Both Pods are on the Default network when a Ping is issued from partner(partner) to test(test) 10.128.8.3 test(test) should reply", + "-time": "4.102927471" + }, + { + "-classname": "CNF Certification Test Suite", + "-name": "generic when test(test) is checked for Red Hat version Should report a proper Red Hat version", + "-time": "0.002270972" + }, + { + "-classname": "CNF Certification Test Suite", + "-name": "generic when partner(partner) is checked for Red Hat version Should report a proper Red Hat version", + "-time": "0.002174817" + }, + { + "-classname": "CNF Certification Test Suite", + "-name": "diagnostic when a cluster is set up and installed with OpenShift should report all available nodeSummary", + "-time": "0.133763681" + } + ] + } + } + }, + "versions": { + "tnf": "v0.0.3", + "claimFormat":"v0.0.1" + }, + "results": { + "{\"url\":\"https://test-network-function.com/tnf/test\",{\"version\":\"v1.0.0\"}": [ + { + "testText": "someText", + "isMeasurement": false, + "filename": "/dev/null", + "lineNumber": 4, + "passed": true, + "duration": 100 + } + ] + } + } +} \ No newline at end of file diff --git a/pkg/claim/testdata/invalid-json.json b/pkg/claim/testdata/invalid-json.json new file mode 100644 index 000000000..7f8c66c66 --- /dev/null +++ b/pkg/claim/testdata/invalid-json.json @@ -0,0 +1 @@ +this is not JSON diff --git a/pkg/claim/testdata/missing-claim.json b/pkg/claim/testdata/missing-claim.json new file mode 100644 index 000000000..7a73a41bf --- /dev/null +++ b/pkg/claim/testdata/missing-claim.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/pkg/claimhelper/claimhelper.go b/pkg/claimhelper/claimhelper.go index 8312f1c8f..b103b207a 100644 --- a/pkg/claimhelper/claimhelper.go +++ b/pkg/claimhelper/claimhelper.go @@ -26,10 +26,11 @@ import ( log "github.com/sirupsen/logrus" + "github.com/test-network-function/cnf-certification-test/internal/version" + "github.com/test-network-function/cnf-certification-test/pkg/claim" "github.com/test-network-function/cnf-certification-test/pkg/diagnostics" "github.com/test-network-function/cnf-certification-test/pkg/junit" "github.com/test-network-function/cnf-certification-test/pkg/provider" - "github.com/test-network-function/test-network-function-claim/pkg/claim" ) const ( @@ -40,6 +41,17 @@ const ( DateTimeFormatDirective = "2006-01-02T15:04:05+00:00" ) +// IncorporateTNFVersion adds the TNF version to the claim. +func IncorporateVersions(claimData *claim.Claim) { + claimData.Versions = &claim.Versions{ + Tnf: version.GetGitVersion(), + TnfGitCommit: version.GitCommit, + OcClient: diagnostics.GetVersionOcClient(), + Ocp: diagnostics.GetVersionOcp(), + K8s: diagnostics.GetVersionK8s(), + } +} + // MarshalConfigurations creates a byte stream representation of the test configurations. In the event of an error, // this method fatally fails. func MarshalConfigurations() (configurations []byte, err error) { diff --git a/pkg/scheduling/scheduling.go b/pkg/scheduling/scheduling.go index ed022b089..b3e19e641 100644 --- a/pkg/scheduling/scheduling.go +++ b/pkg/scheduling/scheduling.go @@ -35,7 +35,7 @@ const ( newLineCharacter = "\n" SharedCPUScheduling = "SHARED_CPU_SCHEDULING" - ExclusiveCPUScheduling = "EXCLUSIVE_CPU_SCHEDULING" + ExclusiveCPUScheduling = "EXCLUSIVE_CPU_SCHEDULING" //nolint:gosec IsolatedCPUScheduling = "ISOLATED_CPU_SCHEDULING" SchedulingRoundRobin = "SCHED_RR"