Skip to content

Commit

Permalink
[chore][cmd/builder] Test for unreleased versions (#10030)
Browse files Browse the repository at this point in the history
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue.
Ex. Adding a feature - Explain what this achieves.-->
#### Description

Add a test to help prevent our replace statements from going out of date
and causing situations like
#10014.
This is also probably just a decent test case to have since it's a
syntactically valid but nonexistent version.

---------

Co-authored-by: Evan Bradley <evan-bradley@users.noreply.github.com>
Co-authored-by: Juraci Paixão Kröhling <juraci.github@kroehling.de>
  • Loading branch information
3 people authored May 9, 2024
1 parent 4458b43 commit 8e26836
Showing 1 changed file with 162 additions and 46 deletions.
208 changes: 162 additions & 46 deletions cmd/builder/internal/builder/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"golang.org/x/mod/modfile"
)

var (
goModTestFile = []byte(`// Copyright The OpenTelemetry Authors
const (
goModTestFile = `// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
module go.opentelemetry.io/collector/cmd/builder/internal/tester
go 1.20
Expand All @@ -30,7 +33,53 @@ require (
go.opentelemetry.io/collector/processor v0.94.1
go.opentelemetry.io/collector/receiver v0.94.1
go.opentelemetry.io/collector v0.96.0
)`)
)`
modulePrefix = "go.opentelemetry.io/collector"
)

var (
replaceModules = []string{
"",
"/component",
"/config/configauth",
"/config/configcompression",
"/config/configgrpc",
"/config/confighttp",
"/config/confignet",
"/config/configopaque",
"/config/configretry",
"/config/configtelemetry",
"/config/configtls",
"/config/internal",
"/confmap",
"/confmap/converter/expandconverter",
"/confmap/provider/envprovider",
"/confmap/provider/fileprovider",
"/confmap/provider/httpprovider",
"/confmap/provider/httpsprovider",
"/confmap/provider/yamlprovider",
"/consumer",
"/connector",
"/exporter",
"/exporter/debugexporter",
"/exporter/nopexporter",
"/exporter/otlpexporter",
"/exporter/otlphttpexporter",
"/extension",
"/extension/auth",
"/extension/zpagesextension",
"/featuregate",
"/processor",
"/processor/batchprocessor",
"/processor/memorylimiterprocessor",
"/receiver",
"/receiver/nopreceiver",
"/receiver/otlpreceiver",
"/otelcol",
"/pdata",
"/semconv",
"/service",
}
)

func newTestConfig() Config {
Expand Down Expand Up @@ -96,7 +145,7 @@ func TestVersioning(t *testing.T) {
cfgBuilder: func() Config {
cfg := newTestConfig()
tempDir := t.TempDir()
err := makeModule(tempDir, goModTestFile)
err := makeModule(tempDir, []byte(goModTestFile))
require.NoError(t, err)
cfg.Distribution.OutputPath = tempDir
cfg.SkipGenerate = true
Expand Down Expand Up @@ -279,6 +328,108 @@ func TestGenerateAndCompile(t *testing.T) {
}
}

// Test that the go.mod files that other tests in this file
// may generate have all their modules covered by our
// "replace" statements created in `generateReplaces`.
//
// An incomplete set of replace statements in these tests
// may cause them to fail during the release process, when
// the local version of modules in the release branch is
// not yet available on the Go package repository.
// Unless the replace statements route all modules to the
// local copy, `go get` will try to fetch the unreleased
// version remotely and some tests will fail.
func TestReplaceStatementsAreComplete(t *testing.T) {
var err error
dir := t.TempDir()
cfg := NewDefaultConfig()
cfg.Distribution.Go = "go"
cfg.Distribution.OutputPath = dir
// Use a deliberately nonexistent version to simulate an unreleased
// version of the package. Not strictly necessary since this test
// will catch gaps in the replace statements before a release is in
// progress.
cfg.Distribution.OtelColVersion = "1.9999.9999"
cfg.Replaces = append(cfg.Replaces, generateReplaces()...)
// Configure all components that we want to use elsewhere in these tests.
// This ensures the resulting go.mod file has maximum coverage of modules
// that exist in the Core repository.
cfg.Exporters, err = parseModules([]Module{
{
GoMod: "go.opentelemetry.io/collector/exporter/debugexporter v1.9999.9999",
},
{
GoMod: "go.opentelemetry.io/collector/exporter/nopexporter v1.9999.9999",
},
{
GoMod: "go.opentelemetry.io/collector/exporter/otlpexporter v1.9999.9999",
},
{
GoMod: "go.opentelemetry.io/collector/exporter/otlphttpexporter v1.9999.9999",
},
})
require.NoError(t, err)
cfg.Receivers, err = parseModules([]Module{
{
GoMod: "go.opentelemetry.io/collector/receiver/nopreceiver v1.9999.9999",
},
{
GoMod: "go.opentelemetry.io/collector/receiver/otlpreceiver v1.9999.9999",
},
})
require.NoError(t, err)
cfg.Extensions, err = parseModules([]Module{
{
GoMod: "go.opentelemetry.io/collector/extension/zpagesextension v1.9999.9999",
},
})
require.NoError(t, err)
cfg.Processors, err = parseModules([]Module{
{
GoMod: "go.opentelemetry.io/collector/processor/batchprocessor v1.9999.9999",
},
{
GoMod: "go.opentelemetry.io/collector/processor/memorylimiterprocessor v1.9999.9999",
},
})
require.NoError(t, err)

require.NoError(t, cfg.SetBackwardsCompatibility())
require.NoError(t, cfg.Validate())
require.NoError(t, cfg.ParseModules())
err = GenerateAndCompile(cfg)
require.NoError(t, err)

gomodpath := path.Join(dir, "go.mod")
// #nosec G304 We control this path and generate the file inside, so we can assume it is safe.
gomod, err := os.ReadFile(gomodpath)
require.NoError(t, err)

mod, err := modfile.Parse(gomodpath, gomod, nil)
require.NoError(t, err)

replaceMods := map[string]bool{}

for _, suffix := range replaceModules {
replaceMods[modulePrefix+suffix] = false
}

for _, req := range mod.Require {
if !strings.HasPrefix(req.Mod.Path, modulePrefix) {
continue
}

_, ok := replaceMods[req.Mod.Path]
assert.Truef(t, ok, "Module missing from replace statements list: %s", req.Mod.Path)

replaceMods[req.Mod.Path] = true
}

for k, v := range replaceMods {
assert.Truef(t, v, "Module not used: %s", k)
}
}

func makeModule(dir string, fileContents []byte) error {
// if the file does not exist, try to create it
if _, err := os.Stat(dir); os.IsNotExist(err) {
Expand All @@ -301,47 +452,12 @@ func generateReplaces() []string {
// The goal is find the root of the repo so we can replace the root module.
_, thisFile, _, _ := runtime.Caller(0)
workspaceDir := filepath.Dir(filepath.Dir(filepath.Dir(filepath.Dir(filepath.Dir(thisFile)))))
return []string{fmt.Sprintf("go.opentelemetry.io/collector => %s", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/component => %s/component", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/config/configauth => %s/config/configauth", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/config/configcompression => %s/config/configcompression", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/config/configgrpc => %s/config/configgrpc", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/config/confignet => %s/config/confignet", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/config/configopaque => %s/config/configopaque", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/config/configretry => %s/config/configretry", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/config/configtelemetry => %s/config/configtelemetry", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/config/configtls => %s/config/configtls", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/config/internal => %s/config/internal", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/confmap => %s/confmap", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/confmap/converter/expandconverter => %s/confmap/converter/expandconverter", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/confmap/provider/envprovider => %s/confmap/provider/envprovider", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/confmap/provider/fileprovider => %s/confmap/provider/fileprovider", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/confmap/provider/httpprovider => %s/confmap/provider/httpprovider", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/confmap/provider/httpsprovider => %s/confmap/provider/httpsprovider", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/confmap/provider/yamlprovider => %s/confmap/provider/yamlprovider", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/consumer => %s/consumer", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/connector => %s/connector", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/exporter => %s/exporter", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/exporter/debugexporter => %s/exporter/debugexporter", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/exporter/loggingexporter => %s/exporter/loggingexporter", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/exporter/nopexporter => %s/exporter/nopexporter", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/exporter/otlpexporter => %s/exporter/otlpexporter", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/exporter/otlphttpexporter => %s/exporter/otlphttpexporter", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/extension => %s/extension", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/extension/auth => %s/extension/auth", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/extension/ballastextension => %s/extension/ballastextension", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/extension/zpagesextension => %s/extension/zpagesextension", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/featuregate => %s/featuregate", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/processor => %s/processor", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/processor/batchprocessor => %s/processor/batchprocessor", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/processor/memorylimiterprocessor => %s/processor/memorylimiterprocessor", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/receiver => %s/receiver", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/receiver/nopreceiver => %s/receiver/nopreceiver", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/receiver/otlpreceiver => %s/receiver/otlpreceiver", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/otelcol => %s/otelcol", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/pdata => %s/pdata", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/pdata/testdata => %s/pdata/testdata", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/semconv => %s/semconv", workspaceDir),
fmt.Sprintf("go.opentelemetry.io/collector/service => %s/service", workspaceDir),
modules := replaceModules
replaces := make([]string, len(modules))

for i, mod := range modules {
replaces[i] = fmt.Sprintf("%s%s => %s%s", modulePrefix, mod, workspaceDir, mod)
}

return replaces
}

0 comments on commit 8e26836

Please sign in to comment.