osbuild2: refactor files inputs
osbuild stage inputs were originally implemented in composer as stage-specific inputs, while in reality, they are defined as individual inputs, usually accepted by multiple stages. Therefore a single stage input can be passed to any stage, as long as the stage accepts it. Files inputs type was previously defined, but not used by any stage. Creation of proper inputs type structures is currently handled in `internal/distro/rhel85/stage_inputs.go` instead. Refactor files inputs type to be usable directly as an input type structure for stages, which accept it. For now, implement only the `org.osbuild.pipeline` origin and related input reference. Add unit tests for the `FilesInputs`. Define input origin names as string constants, so that they can be used by inputs implementations, instead of using string literals. Signed-off-by: Tomas Hozza <thozza@redhat.com>
This commit is contained in:
parent
241c5cc9d6
commit
8271910051
3 changed files with 197 additions and 6 deletions
|
|
@ -1,18 +1,102 @@
|
|||
package osbuild2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Inputs for individual files
|
||||
|
||||
// Provides all the files, named via their content hash, specified
|
||||
// via `references` in a new directory.
|
||||
type FilesInputs struct {
|
||||
File *FilesInput `json:"file"`
|
||||
}
|
||||
|
||||
func (FilesInputs) isStageInputs() {}
|
||||
|
||||
func NewFilesInputs(references FilesInputReferences) *FilesInputs {
|
||||
return &FilesInputs{
|
||||
File: NewFilesInput(references),
|
||||
}
|
||||
}
|
||||
|
||||
// IMPLEMENTED INTERFACES OF STAGES ACCEPTING THIS INPUTS TYPE
|
||||
|
||||
// SPECIFIC INPUT STRUCTURE
|
||||
|
||||
type FilesInput struct {
|
||||
inputCommon
|
||||
References FilesInputReferences `json:"references"`
|
||||
}
|
||||
|
||||
func (FilesInput) isInput() {}
|
||||
const InputTypeFiles string = "org.osbuild.files"
|
||||
|
||||
func NewFilesInput() *FilesInput {
|
||||
func NewFilesInput(references FilesInputReferences) *FilesInput {
|
||||
input := new(FilesInput)
|
||||
input.Type = "org.osbuild.files"
|
||||
input.Origin = "org.osbuild.source"
|
||||
input.Type = InputTypeFiles
|
||||
|
||||
switch t := references.(type) {
|
||||
case *FilesInputReferencesPipeline:
|
||||
input.Origin = InputOriginPipeline
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown FilesInputReferences type: %v", t))
|
||||
}
|
||||
|
||||
input.References = references
|
||||
|
||||
return input
|
||||
}
|
||||
|
||||
type rawFilesInput struct {
|
||||
inputCommon
|
||||
References json.RawMessage `json:"references"`
|
||||
}
|
||||
|
||||
func (f *FilesInput) UnmarshalJSON(data []byte) error {
|
||||
var rawFilesInput rawFilesInput
|
||||
if err := json.Unmarshal(data, &rawFilesInput); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var ref FilesInputReferences
|
||||
switch rawFilesInput.Origin {
|
||||
case InputOriginPipeline:
|
||||
ref = &FilesInputReferencesPipeline{}
|
||||
default:
|
||||
return fmt.Errorf("FilesInput: unknown input origin: %s", rawFilesInput.Origin)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(rawFilesInput.References, ref); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.Type = rawFilesInput.Type
|
||||
f.Origin = rawFilesInput.Origin
|
||||
f.References = ref
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SUPPORTED FILE INPUT REFERENCES
|
||||
|
||||
type FilesInputReferences interface {
|
||||
isFilesInputReferences()
|
||||
}
|
||||
|
||||
// The expected JSON structure is:
|
||||
// `"name:<pipeline_name>": {"file": "<filename>"}`
|
||||
type FilesInputReferencesPipeline map[string]FileReference
|
||||
|
||||
func (*FilesInputReferencesPipeline) isFilesInputReferences() {}
|
||||
|
||||
type FileReference struct {
|
||||
File string `json:"file"`
|
||||
}
|
||||
|
||||
func NewFilesInputReferencesPipeline(pieline, filename string) FilesInputReferences {
|
||||
ref := &FilesInputReferencesPipeline{
|
||||
fmt.Sprintf("name:%s", pieline): {File: filename},
|
||||
}
|
||||
return ref
|
||||
}
|
||||
|
||||
// TODO: define FilesInputReferences for "sources"
|
||||
|
|
|
|||
101
internal/osbuild2/files_input_test.go
Normal file
101
internal/osbuild2/files_input_test.go
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
package osbuild2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewFilesInputs(t *testing.T) {
|
||||
inputFilename := "image.raw"
|
||||
pipeline := "os"
|
||||
|
||||
expectedInput := &FilesInputs{
|
||||
File: &FilesInput{
|
||||
inputCommon: inputCommon{
|
||||
Type: InputTypeFiles,
|
||||
Origin: InputOriginPipeline,
|
||||
},
|
||||
References: &FilesInputReferencesPipeline{
|
||||
fmt.Sprintf("name:%s", pipeline): FileReference{File: inputFilename},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
actualInput := NewFilesInputs(NewFilesInputReferencesPipeline(pipeline, inputFilename))
|
||||
assert.Equal(t, expectedInput, actualInput)
|
||||
}
|
||||
|
||||
func TestFilesInput_UnmarshalJSON(t *testing.T) {
|
||||
type fields struct {
|
||||
Type string
|
||||
Origin string
|
||||
References FilesInputReferences
|
||||
}
|
||||
|
||||
type args struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "pipeline-origin",
|
||||
fields: fields{
|
||||
Type: InputTypeFiles,
|
||||
Origin: InputOriginPipeline,
|
||||
References: NewFilesInputReferencesPipeline("os", "image.raw"),
|
||||
},
|
||||
args: args{
|
||||
data: []byte(`{"type":"org.osbuild.files","origin":"org.osbuild.pipeline","references":{"name:os":{"file":"image.raw"}}}`),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unknown-origin",
|
||||
fields: fields{
|
||||
Type: InputTypeFiles,
|
||||
Origin: InputOriginSource,
|
||||
References: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for idx, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
input := &FilesInput{
|
||||
inputCommon: inputCommon{
|
||||
Type: tt.fields.Type,
|
||||
Origin: tt.fields.Origin,
|
||||
},
|
||||
References: tt.fields.References,
|
||||
}
|
||||
var gotInput FilesInput
|
||||
if err := json.Unmarshal(tt.args.data, &gotInput); (err != nil) != tt.wantErr {
|
||||
println("data: ", string(tt.args.data))
|
||||
t.Errorf("FilesInput.UnmarshalJSON() error = %v, wantErr %v [idx: %d]", err, tt.wantErr, idx)
|
||||
}
|
||||
if tt.wantErr {
|
||||
return
|
||||
}
|
||||
gotBytes, err := json.Marshal(input)
|
||||
if err != nil {
|
||||
t.Errorf("Could not marshal FilesInput: %v", err)
|
||||
}
|
||||
if !bytes.Equal(gotBytes, tt.args.data) {
|
||||
t.Errorf("Expected `%v`, got `%v` [idx: %d]", string(tt.args.data), string(gotBytes), idx)
|
||||
}
|
||||
if !reflect.DeepEqual(&gotInput, input) {
|
||||
t.Errorf("got {%v, %v, %v}, expected {%v, %v, %v} [%d]", gotInput.Type, gotInput.Origin, gotInput.References, input.Type, input.Origin, input.References, idx)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,12 @@ type Input interface {
|
|||
isInput()
|
||||
}
|
||||
|
||||
// TODO: define these using type aliases
|
||||
const (
|
||||
InputOriginSource string = "org.osbuild.source"
|
||||
InputOriginPipeline string = "org.osbuild.pipeline"
|
||||
)
|
||||
|
||||
// Fields shared between all Input types (should be embedded in each instance)
|
||||
type inputCommon struct {
|
||||
Type string `json:"type"`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue