diff --git a/cmd/test-reporter/main.go b/cmd/test-reporter/main.go
index a61124df..acd55150 100644
--- a/cmd/test-reporter/main.go
+++ b/cmd/test-reporter/main.go
@@ -22,7 +22,7 @@ var usage = strings.ReplaceAll(`
CLI to submit test results to BuildPulse
USAGE
- $ %s submit TEST_RESULTS_DIR --account-id=ACCOUNT_ID --repository-id=REPOSITORY_ID
+ $ %s submit TEST_RESULTS_PATH --account-id=ACCOUNT_ID --repository-id=REPOSITORY_ID
FLAGS
--account-id (required) BuildPulse account ID for the account that owns the repository
@@ -38,7 +38,7 @@ ENVIRONMENT VARIABLES
BUILDPULSE_SECRET_ACCESS_KEY BuildPulse secret access key for the account that owns the repository
EXAMPLE
- $ %s submit test/reports --account-id 42 --repository-id 8675309
+ $ %s submit test/reports/*.xml --account-id 42 --repository-id 8675309
`, "\t", " ")
func main() {
diff --git a/cmd/test-reporter/main_test.go b/cmd/test-reporter/main_test.go
index 95564acb..94894fa6 100644
--- a/cmd/test-reporter/main_test.go
+++ b/cmd/test-reporter/main_test.go
@@ -74,9 +74,9 @@ func TestCLI(t *testing.T) {
},
{
name: "submit subcommand with invalid args",
- args: fmt.Sprintf("submit %s --account-id bogus --repository-id 8675309", dir),
+ args: "submit some-non-existent-path",
errMsg: "exit status 1",
- out: `invalid value "bogus" for flag -account-id`,
+ out: `no XML reports found at TEST_RESULTS_PATH`,
},
{
name: "unsupported subcommand",
diff --git a/internal/cmd/submit/submit.go b/internal/cmd/submit/submit.go
index ec99fc2c..8f8f22eb 100644
--- a/internal/cmd/submit/submit.go
+++ b/internal/cmd/submit/submit.go
@@ -68,7 +68,7 @@ type Submit struct {
version *metadata.Version
envs map[string]string
- path string
+ paths []string
bucket string
accountID uint64
repositoryID uint64
@@ -111,20 +111,30 @@ func (s *Submit) Init(args []string, envs map[string]string, commitResolverFacto
}
s.logger.Printf("Using working directory: %v", dir)
- s.path = args[0]
- isFlag, err := regexp.MatchString("^-", s.path)
+ pathArgs, flagArgs := pathsAndFlagsFromArgs(args)
+ if len(pathArgs) == 0 {
+ return fmt.Errorf("missing TEST_RESULTS_PATH")
+ }
+
+ s.paths, err = xmlPathsFromArgs(pathArgs)
if err != nil {
return err
}
- if isFlag {
- return fmt.Errorf("missing TEST_RESULTS_DIR")
- }
- info, err := os.Stat(s.path)
- if err != nil || !info.IsDir() {
- return fmt.Errorf("path is not a directory: %s", s.path)
+ if len(s.paths) == 0 {
+ // To maintain backwards compatibility with releases prior to v0.19.0, if
+ // exactly one path was given, and it's a directory, and it contains no XML
+ // reports, continue without erroring. The resulting upload will contain
+ // *zero* XML reports. In all other scenarios, treat this as an error.
+ //
+ // TODO: Treat this scenario as an error for the next major version release.
+ info, err := os.Stat(pathArgs[0])
+ isSingleDir := len(pathArgs) == 1 && err == nil && info.IsDir()
+ if !isSingleDir {
+ return fmt.Errorf("no XML reports found at TEST_RESULTS_PATH: %s", strings.Join(pathArgs, " "))
+ }
}
- if err := s.fs.Parse(args[1:]); err != nil {
+ if err := s.fs.Parse(flagArgs); err != nil {
return err
}
@@ -165,7 +175,7 @@ func (s *Submit) Init(args []string, envs map[string]string, commitResolverFacto
return fmt.Errorf("invalid value \"%s\" for flag -tree: should be a 40-character SHA-1 hash", s.tree)
}
- info, err = os.Stat(s.repositoryPath)
+ info, err := os.Stat(s.repositoryPath)
if err != nil || !info.IsDir() {
return fmt.Errorf("invalid value for flag -repository-dir: %s is not a directory", s.repositoryPath)
}
@@ -195,72 +205,58 @@ func (s *Submit) Init(args []string, envs map[string]string, commitResolverFacto
// Run packages up the test results and sends them to BuildPulse. It returns the
// key that uniquely identifies the uploaded object.
func (s *Submit) Run() (string, error) {
- meta, err := metadata.NewMetadata(s.version, s.envs, s.commitResolver, time.Now, s.logger)
+ tarpath, err := s.bundle()
if err != nil {
return "", err
}
- yamlpath := filepath.Join(s.path, "buildpulse.yml")
- s.logger.Printf("Writing metadata to %s", yamlpath)
- yaml, err := meta.MarshalYAML()
- if err != nil {
- return "", err
- }
- err = ioutil.WriteFile(yamlpath, yaml, 0644)
+ s.logger.Printf("Gzipping tarball (%s)", tarpath)
+ zippath, err := toGz(tarpath)
if err != nil {
return "", err
}
- logpath := filepath.Join(s.path, "buildpulse.log")
- s.logger.Printf("Flushing log to %s", logpath)
- err = ioutil.WriteFile(logpath, []byte(s.logger.Text()), 0644)
+ s.logger.Printf("Sending %s to BuildPulse", zippath)
+ key, err := s.upload(zippath)
if err != nil {
return "", err
}
+ s.logger.Printf("Delivered test results to BuildPulse (%s)", key)
- s.logger.Printf("Preparing gzipped archive of test results and metadata at %s", s.path)
- path, err := toTarGz(s.path)
+ return key, nil
+}
+
+// bundle gathers the artifacts expected by BuildPulse, creates a tarball
+// containing those artifacts, and returns the path of the resulting file.
+func (s *Submit) bundle() (string, error) {
+ // Prepare the metadata file
+ //////////////////////////////////////////////////////////////////////////////
+
+ s.logger.Printf("Gathering metadata to describe the build")
+ meta, err := metadata.NewMetadata(s.version, s.envs, s.commitResolver, time.Now, s.logger)
if err != nil {
return "", err
}
- s.logger.Printf("Gzipped archive written to %s", path)
-
- s.logger.Printf("Sending %s to BuildPulse", path)
- key, err := s.upload(path)
+ yaml, err := meta.MarshalYAML()
if err != nil {
return "", err
}
- s.logger.Printf("Delivered test results to BuildPulse (%s)", key)
- return key, nil
-}
-
-// upload transmits the file at the given path to S3
-func (s *Submit) upload(path string) (string, error) {
- key := fmt.Sprintf("%d/%d/buildpulse-%s.gz", s.accountID, s.repositoryID, s.idgen())
-
- err := putS3Object(s.client, s.credentials.AccessKeyID, s.credentials.SecretAccessKey, s.bucket, key, path)
+ yamlfile, err := ioutil.TempFile("", "buildpulse-*.yml")
if err != nil {
return "", err
}
+ defer yamlfile.Close()
- return key, nil
-}
-
-// toTarGz creates a gzipped tarball containing the contents of the named
-// directory (dir) and returns the path of the resulting file.
-func toTarGz(dir string) (dest string, err error) {
- tarPath, err := toTar(dir)
+ s.logger.Printf("Writing metadata to %s", yamlfile.Name())
+ _, err = yamlfile.Write(yaml)
if err != nil {
return "", err
}
- return toGz(tarPath)
-}
+ // Initialize the tarfile for writing
+ //////////////////////////////////////////////////////////////////////////////
-// toTar creates a tarball containing the submittable contents of the named
-// directory (dir) and returns the path of the resulting file.
-func toTar(dir string) (dest string, err error) {
f, err := ioutil.TempFile("", "buildpulse-*.tar")
if err != nil {
return "", err
@@ -270,42 +266,61 @@ func toTar(dir string) (dest string, err error) {
t := tar.Create(f)
defer t.Close()
- err = t.Write(filepath.Join(dir, "buildpulse.yml"), "buildpulse.yml")
+ // Write the XML reports to the tarfile
+ //////////////////////////////////////////////////////////////////////////////
+
+ s.logger.Printf("Preparing tarball of test results:")
+ for _, p := range s.paths {
+ s.logger.Printf("- %s", p)
+ err = t.Write(p, p)
+ if err != nil {
+ return "", err
+ }
+ }
+
+ // Write the metadata file to the tarfile
+ //////////////////////////////////////////////////////////////////////////////
+
+ s.logger.Printf("Adding buildpulse.yml to tarball")
+ err = t.Write(yamlfile.Name(), "buildpulse.yml")
if err != nil {
return "", err
}
- err = t.Write(filepath.Join(dir, "buildpulse.log"), "buildpulse.log")
+ // Write the log to the tarfile
+ //////////////////////////////////////////////////////////////////////////////
+
+ logfile, err := ioutil.TempFile("", "buildpulse-*.log")
if err != nil {
return "", err
}
+ defer logfile.Close()
- err = filepath.WalkDir(dir, func(srcpath string, _ os.DirEntry, err error) error {
- if err != nil {
- return err
- }
+ s.logger.Printf("Flushing log to %s", logfile.Name())
+ _, err = logfile.Write([]byte(s.logger.Text()))
+ if err != nil {
+ return "", err
+ }
- if !isXML(srcpath) {
- return nil
- }
+ s.logger.Printf("Adding buildpulse.log to tarball")
+ err = t.Write(logfile.Name(), "buildpulse.log")
+ if err != nil {
+ return "", err
+ }
- destpath, err := filepath.Rel(dir, srcpath)
- if err != nil {
- return err
- }
+ return f.Name(), nil
+}
- err = t.Write(srcpath, destpath)
- if err != nil {
- return err
- }
+// upload transmits the file at the given path to S3
+func (s *Submit) upload(path string) (string, error) {
+ key := fmt.Sprintf("%d/%d/buildpulse-%s.gz", s.accountID, s.repositoryID, s.idgen())
- return nil
- })
+ err := putS3Object(s.client, s.credentials.AccessKeyID, s.credentials.SecretAccessKey, s.bucket, key, path)
if err != nil {
return "", err
}
- return f.Name(), nil
+ return key, nil
}
// toGz gzips the named file (src) and returns the path of the resulting file.
@@ -315,7 +330,7 @@ func toGz(src string) (dest string, err error) {
return "", err
}
- zipfile, err := ioutil.TempFile("", "buildpulse-*.tar.gz")
+ zipfile, err := ioutil.TempFile("", "buildpulse-*.gz")
if err != nil {
return "", err
}
@@ -367,6 +382,92 @@ func putS3Object(client *http.Client, id string, secret string, bucket string, o
return nil
}
+// flagRegex matches args that are flags.
+var flagRegex = regexp.MustCompile("^-")
+
+// pathsAndFlagsFromArgs returns a slice containing the subset of args that
+// represent paths and a slice containing the subset of args that represent
+// flags.
+func pathsAndFlagsFromArgs(args []string) ([]string, []string) {
+ for i, v := range args {
+ isFlag := flagRegex.MatchString(v)
+
+ if isFlag {
+ paths := args[0:i]
+ flags := args[i:]
+ return paths, flags
+ }
+ }
+
+ return args, []string{}
+}
+
+// xmlPathsFromArgs translates each path in args into a list of XML files present
+// at that path. It returns the resulting list of XML file paths.
+func xmlPathsFromArgs(args []string) ([]string, error) {
+ var paths []string
+
+ for _, arg := range args {
+ info, err := os.Stat(arg)
+ if err == nil && info.IsDir() {
+ xmls, err := xmlPathsFromDir(arg)
+ if err != nil {
+ return nil, err
+ }
+ paths = append(paths, xmls...)
+ } else {
+ xmls, err := xmlPathsFromGlob(arg)
+ if err != nil {
+ return nil, fmt.Errorf("invalid value \"%s\" for path: %v", arg, err)
+ }
+ paths = append(paths, xmls...)
+ }
+ }
+
+ return paths, nil
+}
+
+// xmlPathsFromDir returns a list of all the XML files in the given directory
+// and its subdirectories.
+func xmlPathsFromDir(dir string) ([]string, error) {
+ var paths []string
+
+ err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+
+ if isXML(info.Name()) {
+ paths = append(paths, path)
+ }
+
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return paths, nil
+}
+
+// xmlPathsFromGlob returns a list of all the XML files that match the given
+// glob pattern.
+func xmlPathsFromGlob(pattern string) ([]string, error) {
+ candidates, err := filepath.Glob(pattern)
+ if err != nil {
+ return nil, err
+ }
+
+ var paths []string
+ for _, p := range candidates {
+ if isXML(p) {
+ paths = append(paths, p)
+ }
+ }
+
+ return paths, nil
+}
+
// isXML returns true if the given filename has an XML extension
// (case-insensitive); false, otherwise.
func isXML(filename string) bool {
diff --git a/internal/cmd/submit/submit_test.go b/internal/cmd/submit/submit_test.go
index c5c654c4..dfa504c9 100644
--- a/internal/cmd/submit/submit_test.go
+++ b/internal/cmd/submit/submit_test.go
@@ -31,14 +31,11 @@ const (
)
func TestSubmit_Init(t *testing.T) {
- resultsDir, err := os.Getwd()
- require.NoError(t, err)
-
t.Run("MinimumRequiredArgs", func(t *testing.T) {
s := NewSubmit(&metadata.Version{}, logger.New())
- err = s.Init([]string{resultsDir, "--account-id", "42", "--repository-id", "8675309"}, exampleEnv, new(stubCommitResolverFactory))
+ err := s.Init([]string{"testdata/example-reports-dir/example-*.xml", "--account-id", "42", "--repository-id", "8675309"}, exampleEnv, new(stubCommitResolverFactory))
require.NoError(t, err)
- assert.Equal(t, resultsDir, s.path)
+ assert.ElementsMatch(t, []string{"testdata/example-reports-dir/example-1.xml"}, s.paths)
assert.EqualValues(t, 42, s.accountID)
assert.EqualValues(t, 8675309, s.repositoryID)
assert.Equal(t, "buildpulse-uploads", s.bucket)
@@ -49,30 +46,79 @@ func TestSubmit_Init(t *testing.T) {
assert.Equal(t, "Repository", s.commitResolver.Source())
})
+ t.Run("WithMultiplePathArgs", func(t *testing.T) {
+ s := NewSubmit(&metadata.Version{}, logger.New())
+ err := s.Init(
+ []string{"testdata/example-reports-dir/example-1.xml", "testdata/example-reports-dir/example-2.XML", "--account-id", "42", "--repository-id", "8675309"},
+ exampleEnv,
+ new(stubCommitResolverFactory),
+ )
+ require.NoError(t, err)
+ assert.ElementsMatch(t, []string{"testdata/example-reports-dir/example-1.xml", "testdata/example-reports-dir/example-2.XML"}, s.paths)
+ assert.EqualValues(t, 42, s.accountID)
+ assert.EqualValues(t, 8675309, s.repositoryID)
+ })
+
+ t.Run("WithDirectoryWithReportsAsPathArg", func(t *testing.T) {
+ s := NewSubmit(&metadata.Version{}, logger.New())
+ err := s.Init(
+ []string{"testdata/example-reports-dir/dir-with-xml-files/browserstack", "--account-id", "42", "--repository-id", "8675309"},
+ exampleEnv,
+ new(stubCommitResolverFactory),
+ )
+ require.NoError(t, err)
+ assert.ElementsMatch(t,
+ []string{
+ "testdata/example-reports-dir/dir-with-xml-files/browserstack/example-1.xml",
+ "testdata/example-reports-dir/dir-with-xml-files/browserstack/example-2.xml",
+ },
+ s.paths,
+ )
+ assert.EqualValues(t, 42, s.accountID)
+ assert.EqualValues(t, 8675309, s.repositoryID)
+ })
+
+ // To maintain backwards compatibility with releases prior to v0.19.0, if
+ // exactly one path is given, and it's a directory, and it contains no XML
+ // reports, then continue without erroring. The resulting upload will contain
+ // *zero* XML reports.
+ //
+ // TODO: Treat this scenario as an error for the next major version release.
+ t.Run("WithDirectoryWithoutReportsAsPathArg", func(t *testing.T) {
+ s := NewSubmit(&metadata.Version{}, logger.New())
+ err := s.Init(
+ []string{"testdata/example-reports-dir/dir-without-xml-files", "--account-id", "42", "--repository-id", "8675309"},
+ exampleEnv,
+ new(stubCommitResolverFactory),
+ )
+ require.NoError(t, err)
+ assert.Empty(t, s.paths)
+ assert.EqualValues(t, 42, s.accountID)
+ assert.EqualValues(t, 8675309, s.repositoryID)
+ })
+
t.Run("WithRepositoryDirArg", func(t *testing.T) {
repoDir := t.TempDir()
s := NewSubmit(&metadata.Version{}, logger.New())
- err = s.Init(
- []string{resultsDir, "--account-id", "42", "--repository-id", "8675309", "--repository-dir", repoDir},
+ err := s.Init(
+ []string{"testdata/example-reports-dir/example-*.xml", "--account-id", "42", "--repository-id", "8675309", "--repository-dir", repoDir},
exampleEnv,
new(stubCommitResolverFactory),
)
require.NoError(t, err)
- assert.Equal(t, resultsDir, s.path)
assert.Equal(t, repoDir, s.repositoryPath)
assert.Equal(t, "Repository", s.commitResolver.Source())
})
t.Run("WithTreeArg", func(t *testing.T) {
s := NewSubmit(&metadata.Version{}, logger.New())
- err = s.Init(
- []string{resultsDir, "--account-id", "42", "--repository-id", "8675309", "--tree", "0000000000000000000000000000000000000000"},
+ err := s.Init(
+ []string{"testdata/example-reports-dir/example-*.xml", "--account-id", "42", "--repository-id", "8675309", "--tree", "0000000000000000000000000000000000000000"},
exampleEnv,
new(stubCommitResolverFactory),
)
require.NoError(t, err)
- assert.Equal(t, resultsDir, s.path)
assert.Equal(t, "Static", s.commitResolver.Source())
})
@@ -85,8 +131,8 @@ func TestSubmit_Init(t *testing.T) {
"BUILDPULSE_BUCKET": "buildpulse-uploads-test",
}
s := NewSubmit(&metadata.Version{}, logger.New())
- err = s.Init(
- []string{resultsDir, "--account-id", "42", "--repository-id", "8675309", "--repository-dir", repoDir},
+ err := s.Init(
+ []string{"testdata/example-reports-dir/example-*.xml", "--account-id", "42", "--repository-id", "8675309", "--repository-dir", repoDir},
envs,
new(stubCommitResolverFactory),
)
@@ -112,7 +158,7 @@ func TestSubmit_Init_invalidArgs(t *testing.T) {
{
name: "FlagsWithNoPath",
args: "--account-id 1 --repository-id 2",
- errMsg: "missing TEST_RESULTS_DIR",
+ errMsg: "missing TEST_RESULTS_PATH",
},
{
name: "MissingAccountID",
@@ -219,7 +265,7 @@ func TestSubmit_Init_invalidEnv(t *testing.T) {
}
}
-func TestSubmit_Init_invalidPath(t *testing.T) {
+func TestSubmit_Init_invalidPaths(t *testing.T) {
t.Run("NonexistentPath", func(t *testing.T) {
s := NewSubmit(&metadata.Version{}, logger.New())
err := s.Init([]string{
@@ -231,18 +277,38 @@ func TestSubmit_Init_invalidPath(t *testing.T) {
&stubCommitResolverFactory{},
)
if assert.Error(t, err) {
- assert.Equal(t, "path is not a directory: some-nonexistent-path", err.Error())
+ assert.Equal(t, "no XML reports found at TEST_RESULTS_PATH: some-nonexistent-path", err.Error())
}
})
- t.Run("NonDirectoryPath", func(t *testing.T) {
- tmpfile, err := ioutil.TempFile("", "buildpulse-cli-test-fixture")
- require.NoError(t, err)
- defer os.Remove(tmpfile.Name())
+ t.Run("MultiplePathsWithNoReportFiles", func(t *testing.T) {
+ s := NewSubmit(&metadata.Version{}, logger.New())
+ err := s.Init([]string{
+ "testdata/example-reports-dir/dir-without-xml-files",
+ "testdata/example-reports-dir/example.txt",
+ "--account-id", "42",
+ "--repository-id", "8675309",
+ },
+ exampleEnv,
+ &stubCommitResolverFactory{},
+ )
+ if assert.Error(t, err) {
+ assert.Equal(t, "no XML reports found at TEST_RESULTS_PATH: testdata/example-reports-dir/dir-without-xml-files testdata/example-reports-dir/example.txt", err.Error())
+ }
+ })
+ t.Run("GlobPathMatchingNoReportFiles", func(t *testing.T) {
s := NewSubmit(&metadata.Version{}, logger.New())
- err = s.Init([]string{
- tmpfile.Name(),
+ err := s.Init([]string{"testdata/example-reports-dir/bogus*", "--account-id", "42", "--repository-id", "8675309"}, exampleEnv, &stubCommitResolverFactory{})
+ if assert.Error(t, err) {
+ assert.Equal(t, "no XML reports found at TEST_RESULTS_PATH: testdata/example-reports-dir/bogus*", err.Error())
+ }
+ })
+
+ t.Run("BadGlobPattern", func(t *testing.T) {
+ s := NewSubmit(&metadata.Version{}, logger.New())
+ err := s.Init([]string{
+ "[",
"--account-id", "42",
"--repository-id", "8675309",
},
@@ -250,7 +316,7 @@ func TestSubmit_Init_invalidPath(t *testing.T) {
&stubCommitResolverFactory{},
)
if assert.Error(t, err) {
- assert.Regexp(t, "path is not a directory: ", err.Error())
+ assert.Equal(t, `invalid value "[" for path: syntax error in pattern`, err.Error())
}
})
}
@@ -311,8 +377,6 @@ func TestSubmit_Init_invalidRepoPath(t *testing.T) {
}
func TestSubmit_Run(t *testing.T) {
- dir := t.TempDir()
-
r, err := recorder.New("testdata/s3-success")
require.NoError(t, err)
defer func() {
@@ -332,7 +396,7 @@ func TestSubmit_Run(t *testing.T) {
version: &metadata.Version{Number: "v1.2.3"},
commitResolver: metadata.NewStaticCommitResolver(&metadata.Commit{TreeSHA: "ccccccccccccccccccccdddddddddddddddddddd"}, log),
envs: envs,
- path: dir,
+ paths: []string{"testdata/example-reports-dir/example-1.xml"},
bucket: "buildpulse-uploads",
accountID: 42,
repositoryID: 8675309,
@@ -344,15 +408,52 @@ func TestSubmit_Run(t *testing.T) {
key, err := s.Run()
require.NoError(t, err)
+ assert.Equal(t, "42/8675309/buildpulse-00000000-0000-0000-0000-000000000000.gz", key)
+}
+
+func Test_bundle(t *testing.T) {
+ envs := map[string]string{
+ "GITHUB_ACTIONS": "true",
+ "GITHUB_SHA": "aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb",
+ }
+
+ log := logger.New()
+ s := &Submit{
+ logger: log,
+ version: &metadata.Version{Number: "v1.2.3"},
+ commitResolver: metadata.NewStaticCommitResolver(&metadata.Commit{TreeSHA: "ccccccccccccccccccccdddddddddddddddddddd"}, log),
+ envs: envs,
+ paths: []string{"testdata/example-reports-dir/example-1.xml"},
+ bucket: "buildpulse-uploads",
+ accountID: 42,
+ repositoryID: 8675309,
+ }
+
+ path, err := s.bundle()
+ require.NoError(t, err)
- yaml, err := ioutil.ReadFile(filepath.Join(dir, "buildpulse.yml"))
+ unzipDir := t.TempDir()
+ err = archiver.Unarchive(path, unzipDir)
+ require.NoError(t, err)
+
+ // Verify buildpulse.yml is present and contains expected content
+ yaml, err := ioutil.ReadFile(filepath.Join(unzipDir, "buildpulse.yml"))
require.NoError(t, err)
assert.Contains(t, string(yaml), ":ci_provider: github-actions")
assert.Contains(t, string(yaml), ":commit: aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb")
assert.Contains(t, string(yaml), ":tree: ccccccccccccccccccccdddddddddddddddddddd")
assert.Contains(t, string(yaml), ":reporter_version: v1.2.3")
- assert.Equal(t, "42/8675309/buildpulse-00000000-0000-0000-0000-000000000000.gz", key)
+ // Verify test report XML file is present and contains expected content
+ assertEqualContent(t,
+ "testdata/example-reports-dir/example-1.xml",
+ filepath.Join(unzipDir, "testdata/example-reports-dir/example-1.xml"),
+ )
+
+ // Verify buildpulse.log is present and contains expected content
+ logdata, err := ioutil.ReadFile(filepath.Join(unzipDir, "buildpulse.log"))
+ require.NoError(t, err)
+ assert.Contains(t, string(logdata), "Gathering metadata to describe the build")
}
func Test_upload(t *testing.T) {
@@ -445,39 +546,92 @@ func Test_upload(t *testing.T) {
}
}
-func Test_toTarGz(t *testing.T) {
- path, err := toTarGz("./testdata/example-test-results")
+func Test_toGz(t *testing.T) {
+ path, err := toGz("testdata/example-reports-dir/example.txt")
require.NoError(t, err)
+ assert.Regexp(t, `\.gz$`, path)
dir := t.TempDir()
- err = archiver.Unarchive(path, dir)
+ unzippedPath := filepath.Join(dir, "example.txt")
+ err = archiver.DecompressFile(path, unzippedPath)
require.NoError(t, err)
- // === Verify original directory content matches resulting directory content
- assertEqualContent(t,
- "testdata/example-test-results/buildpulse.yml",
- filepath.Join(dir, "buildpulse.yml"),
- )
- assertEqualContent(t,
- "testdata/example-test-results/junit/browserstack/example-1.xml",
- filepath.Join(dir, "junit/browserstack/example-1.xml"),
- )
- assertEqualContent(t,
- "testdata/example-test-results/junit/browserstack/example-2.XML",
- filepath.Join(dir, "junit/browserstack/example-2.XML"),
- )
- assertEqualContent(t,
- "testdata/example-test-results/junit/browsertest/example-3.xml",
- filepath.Join(dir, "junit/browsertest/example-3.xml"),
- )
+ // === Verify original content matches resulting content
+ assertEqualContent(t, "testdata/example-reports-dir/example.txt", unzippedPath)
+}
- // === Verify tarball excludes irrelevant files
- assert.FileExists(t, "testdata/example-test-results/junit/browsertest/example-3.txt")
- assert.NoFileExists(t, filepath.Join(dir, "junit/browsertest/example-3.txt"))
+func Test_xmlPathsFromDir(t *testing.T) {
+ tests := []struct {
+ name string
+ path string
+ want []string
+ }{
+ {
+ name: "DirectoryWithFilesAtRootAndInSubDirectories",
+ path: "testdata/example-reports-dir",
+ want: []string{
+ "testdata/example-reports-dir/example-1.xml",
+ "testdata/example-reports-dir/example-2.XML",
+ "testdata/example-reports-dir/dir-with-xml-files/browserstack/example-1.xml",
+ "testdata/example-reports-dir/dir-with-xml-files/browserstack/example-2.xml",
+ "testdata/example-reports-dir/dir-with-xml-files/browsertest/example-3.xml",
+ },
+ },
+ {
+ name: "DirectoryWithoutXMLFiles",
+ path: "testdata/example-reports-dir/dir-without-xml-files",
+ want: []string{},
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ reportPaths, err := xmlPathsFromDir(tt.path)
+ require.NoError(t, err)
+ assert.ElementsMatch(t, tt.want, reportPaths)
+ })
+ }
+}
+
+func Test_xmlPathsFromGlob(t *testing.T) {
+ tests := []struct {
+ name string
+ path string
+ want []string
+ }{
+ {
+ name: "ExactPathToSingleFile",
+ path: "testdata/example-reports-dir/example-1.xml",
+ want: []string{
+ "testdata/example-reports-dir/example-1.xml",
+ },
+ },
+ {
+ name: "PathMatchingFilesByWildcard",
+ path: "testdata/example-reports-dir/example*",
+ want: []string{
+ "testdata/example-reports-dir/example-1.xml",
+ "testdata/example-reports-dir/example-2.XML",
+ },
+ },
+ {
+ name: "PathMatchingDirectoriesAndFilesByWildcard",
+ path: "testdata/example-reports-dir/dir-with-xml-files/*/*.xml",
+ want: []string{
+ "testdata/example-reports-dir/dir-with-xml-files/browserstack/example-1.xml",
+ "testdata/example-reports-dir/dir-with-xml-files/browserstack/example-2.xml",
+ "testdata/example-reports-dir/dir-with-xml-files/browsertest/example-3.xml",
+ },
+ },
+ }
- // === Verify tarball excludes irrelevant directories (i.e., directories that contain no relevant files)
- assert.DirExists(t, "testdata/example-test-results/dir-without-relevant-files")
- assert.NoDirExists(t, filepath.Join(dir, "dir-without-relevant-files"))
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ reportPaths, err := xmlPathsFromGlob(tt.path)
+ require.NoError(t, err)
+ assert.ElementsMatch(t, tt.want, reportPaths)
+ })
+ }
}
// assertEqualContent asserts that two files have the same content.
diff --git a/internal/cmd/submit/testdata/example-test-results/junit/browserstack/example-1.xml b/internal/cmd/submit/testdata/example-reports-dir/dir-with-xml-files/browserstack/example-1.xml
similarity index 100%
rename from internal/cmd/submit/testdata/example-test-results/junit/browserstack/example-1.xml
rename to internal/cmd/submit/testdata/example-reports-dir/dir-with-xml-files/browserstack/example-1.xml
diff --git a/internal/cmd/submit/testdata/example-test-results/junit/browserstack/example-2.XML b/internal/cmd/submit/testdata/example-reports-dir/dir-with-xml-files/browserstack/example-2.xml
similarity index 100%
rename from internal/cmd/submit/testdata/example-test-results/junit/browserstack/example-2.XML
rename to internal/cmd/submit/testdata/example-reports-dir/dir-with-xml-files/browserstack/example-2.xml
diff --git a/internal/cmd/submit/testdata/example-test-results/junit/browsertest/example-3.txt b/internal/cmd/submit/testdata/example-reports-dir/dir-with-xml-files/browsertest/example-3.txt
similarity index 100%
rename from internal/cmd/submit/testdata/example-test-results/junit/browsertest/example-3.txt
rename to internal/cmd/submit/testdata/example-reports-dir/dir-with-xml-files/browsertest/example-3.txt
diff --git a/internal/cmd/submit/testdata/example-test-results/junit/browsertest/example-3.xml b/internal/cmd/submit/testdata/example-reports-dir/dir-with-xml-files/browsertest/example-3.xml
similarity index 100%
rename from internal/cmd/submit/testdata/example-test-results/junit/browsertest/example-3.xml
rename to internal/cmd/submit/testdata/example-reports-dir/dir-with-xml-files/browsertest/example-3.xml
diff --git a/internal/cmd/submit/testdata/example-test-results/dir-without-relevant-files/example.go b/internal/cmd/submit/testdata/example-reports-dir/dir-without-xml-files/example.go
similarity index 100%
rename from internal/cmd/submit/testdata/example-test-results/dir-without-relevant-files/example.go
rename to internal/cmd/submit/testdata/example-reports-dir/dir-without-xml-files/example.go
diff --git a/internal/cmd/submit/testdata/example-reports-dir/example-1.xml b/internal/cmd/submit/testdata/example-reports-dir/example-1.xml
new file mode 100644
index 00000000..8bcb2a42
--- /dev/null
+++ b/internal/cmd/submit/testdata/example-reports-dir/example-1.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/internal/cmd/submit/testdata/example-reports-dir/example-2.XML b/internal/cmd/submit/testdata/example-reports-dir/example-2.XML
new file mode 100644
index 00000000..36546aa1
--- /dev/null
+++ b/internal/cmd/submit/testdata/example-reports-dir/example-2.XML
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/internal/cmd/submit/testdata/example-reports-dir/example.txt b/internal/cmd/submit/testdata/example-reports-dir/example.txt
new file mode 100644
index 00000000..bfb04df9
--- /dev/null
+++ b/internal/cmd/submit/testdata/example-reports-dir/example.txt
@@ -0,0 +1,7 @@
+Bacon ipsum dolor sit amet shoulder fatback venison, tongue spare ribs sausage
+cow swine bacon boudin tri-tip biltong bresaola shank. Sirloin chicken pork
+loin, spare ribs cow pancetta pastrami jowl beef beef ribs ball tip tongue pork
+belly turkey chuck. T-bone tenderloin beef, swine short ribs pork chop ribeye.
+Beef ribs salami pork belly, cow ground round flank venison ham sirloin jowl.
+Bacon shoulder short loin, chuck fatback corned beef pork belly pig. Ribeye
+swine strip steak jowl pork chop. Bacon tongue pork chop biltong.
diff --git a/internal/cmd/submit/testdata/example-test-results/buildpulse.log b/internal/cmd/submit/testdata/example-test-results/buildpulse.log
deleted file mode 100644
index 297df73c..00000000
--- a/internal/cmd/submit/testdata/example-test-results/buildpulse.log
+++ /dev/null
@@ -1,3 +0,0 @@
- Current version: BuildPulse Test Reporter 0.17.0 (linux 45a62ed go1.16.5)
- Initiating `submit`
- ...
diff --git a/internal/cmd/submit/testdata/example-test-results/buildpulse.yml b/internal/cmd/submit/testdata/example-test-results/buildpulse.yml
deleted file mode 100644
index 2f1dcdd6..00000000
--- a/internal/cmd/submit/testdata/example-test-results/buildpulse.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-:branch: origin/some-branch
-:build_url: https://example.com/job/some-project/8675309
-:check: some-check
-:ci_provider: some-provider
-:commit: 1f192ff735f887dd7a25229b2ece0422d17931f5
-:repo_name_with_owner: some-owner/some-repo
-:reporter_os: linux
-:reporter_version: v1.2.3
-:timestamp: 2020-07-11T01:02:03Z