Files
Lucas Bajolet 47a4ad201b packer_test: make packer test suite modular
Having only one test suite for the whole of Packer makes it harder to
segregate between test types, and makes for a longer runtime as no tests
run in parallel by default.

This commit splits the packer_test suite into several components in
order to make extension easier.

First we have `lib`: this package embeds the core for running Packer
test suites. This ships facilities to build your own test suite for
Packer core, and exposes convenience methods and structures for building
plugins, packer core, and use it to run a test suite in a temporary
directory.

Then we have two separate test suites: one for plugins, and one for core
itself, the latter of which does not depend on plugins being compiled at
all.

This sets the stage for more specialised test suites in the future, each
of which can run in parallel on different parts of the code.
2024-08-06 11:09:31 -04:00

93 lines
2.7 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
//go:generate packer-sdc mapstructure-to-hcl2 -type Config,NestedFirst,NestedSecond
package dynamic
import (
"context"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer-plugin-sdk/common"
"github.com/hashicorp/packer-plugin-sdk/multistep"
"github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps"
"github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/template/config"
)
const BuilderId = "dynamic.builder"
type NestedSecond struct {
Name string `mapstructure:"name" required:"true"`
}
type NestedFirst struct {
Name string `mapstructure:"name" required:"true"`
Nesteds []NestedSecond `mapstructure:"extra" required:"false"`
}
type Config struct {
common.PackerConfig `mapstructure:",squash"`
Nesteds []NestedFirst `mapstructure:"extra" required:"false"`
}
type Builder struct {
config Config
runner multistep.Runner
}
func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
func (b *Builder) Prepare(raws ...interface{}) (generatedVars []string, warnings []string, err error) {
err = config.Decode(&b.config, &config.DecodeOpts{
PluginType: "packer.builder.dynamic",
Interpolate: true,
}, raws...)
if err != nil {
return nil, nil, err
}
// Return the placeholder for the generated data that will become available to provisioners and post-processors.
// If the builder doesn't generate any data, just return an empty slice of string: []string{}
buildGeneratedData := []string{"GeneratedMockData"}
return buildGeneratedData, nil, nil
}
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
steps := []multistep.Step{}
steps = append(steps,
&StepSayConfig{
b.config,
},
new(commonsteps.StepProvision),
)
// Setup the state bag and initial state for the steps
state := new(multistep.BasicStateBag)
state.Put("hook", hook)
state.Put("ui", ui)
// Set the value of the generated data that will become available to provisioners.
// To share the data with post-processors, use the StateData in the artifact.
state.Put("generated_data", map[string]interface{}{
"GeneratedMockData": "mock-build-data",
})
// Run!
b.runner = commonsteps.NewRunner(steps, b.config.PackerConfig, ui)
b.runner.Run(ctx, state)
// If there was an error, return that
if err, ok := state.GetOk("error"); ok {
return nil, err.(error)
}
artifact := &Artifact{
// Add the builder generated data to the artifact StateData so that post-processors
// can access them.
StateData: map[string]interface{}{"generated_data": state.Get("generated_data")},
}
return artifact, nil
}