Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 56 additions & 38 deletions cmd/create_data_stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"slices"

"github.com/AlecAivazis/survey/v2"
"github.com/Masterminds/semver/v3"

"github.com/spf13/cobra"

Expand All @@ -19,6 +20,8 @@ import (
"github.com/elastic/elastic-package/internal/surveyext"
)

var semver3_2_0 = semver.MustParse("3.2.0")

const createDataStreamLongDescription = `Use this command to create a new data stream.

The command can extend the package with a new data stream using embedded data stream template and wizard.`
Expand Down Expand Up @@ -53,42 +56,13 @@ func createDataStreamCommandAction(cmd *cobra.Command, args []string) error {
return fmt.Errorf("data-streams are not supported in input packages")
}

validator := surveyext.Validator{Cwd: "."}
qs := []*survey.Question{
{
Name: "name",
Prompt: &survey.Input{
Message: "Data stream name:",
Default: "new_data_stream",
},
Validate: survey.ComposeValidators(survey.Required, validator.DataStreamDoesNotExist, validator.DataStreamName),
},
{
Name: "title",
Prompt: &survey.Input{
Message: "Data stream title:",
Default: "New Data Stream",
},
Validate: survey.Required,
},
{
Name: "type",
Prompt: &survey.Select{
Message: "Type:",
Options: []string{"logs", "metrics"},
Default: "logs",
},
Validate: survey.Required,
},
{
Name: "subobjects",
Prompt: &survey.Confirm{
Message: "Enable creation of subobjects for fields with dots in their names?",
Default: false,
},
Validate: survey.Required,
},
sv, err := semver.NewVersion(manifest.SpecVersion)
if err != nil {
return fmt.Errorf("failed to obtain spec version from package manifest in \"%s\": %w", packageRoot, err)
}

qs := getInitialSurveyQuestionsForVersion(sv)

var answers newDataStreamAnswers
err = survey.Ask(qs, &answers)
if err != nil {
Expand Down Expand Up @@ -173,7 +147,7 @@ func createDataStreamCommandAction(cmd *cobra.Command, args []string) error {
}
}

descriptor := createDataStreamDescriptorFromAnswers(answers, packageRoot)
descriptor := createDataStreamDescriptorFromAnswers(answers, packageRoot, sv)
err = archetype.CreateDataStream(descriptor)
if err != nil {
return fmt.Errorf("can't create new data stream: %w", err)
Expand All @@ -183,14 +157,14 @@ func createDataStreamCommandAction(cmd *cobra.Command, args []string) error {
return nil
}

func createDataStreamDescriptorFromAnswers(answers newDataStreamAnswers, packageRoot string) archetype.DataStreamDescriptor {
func createDataStreamDescriptorFromAnswers(answers newDataStreamAnswers, packageRoot string, specVersion *semver.Version) archetype.DataStreamDescriptor {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we could unit test this function, checking the manifest it generates for given answers.

Further testing could be added to internal/packages/archetype/data_stream_test.go, but we wouldn't be really testing if the behaviour changes for the format version used in the package.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added some unit testing as suggested, also for the survey questions i've encapsulated this logic to at least check that the question is added or not based on the version.

manifest := packages.DataStreamManifest{
Name: answers.Name,
Title: answers.Title,
Type: answers.Type,
}

if !answers.Subobjects {
if !specVersion.LessThan(semver3_2_0) && !answers.Subobjects {
manifest.Elasticsearch = &packages.Elasticsearch{
IndexTemplate: &packages.ManifestIndexTemplate{
Mappings: &packages.ManifestMappings{
Expand Down Expand Up @@ -231,3 +205,47 @@ func createDataStreamDescriptorFromAnswers(answers newDataStreamAnswers, package
PackageRoot: packageRoot,
}
}

func getInitialSurveyQuestionsForVersion(specVersion *semver.Version) []*survey.Question {
validator := surveyext.Validator{Cwd: "."}
qs := []*survey.Question{
{
Name: "name",
Prompt: &survey.Input{
Message: "Data stream name:",
Default: "new_data_stream",
},
Validate: survey.ComposeValidators(survey.Required, validator.DataStreamDoesNotExist, validator.DataStreamName),
},
{
Name: "title",
Prompt: &survey.Input{
Message: "Data stream title:",
Default: "New Data Stream",
},
Validate: survey.Required,
},
{
Name: "type",
Prompt: &survey.Select{
Message: "Type:",
Options: []string{"logs", "metrics"},
Default: "logs",
},
Validate: survey.Required,
},
}

if !specVersion.LessThan(semver3_2_0) {
qs = append(qs, &survey.Question{
Name: "subobjects",
Prompt: &survey.Confirm{
Message: "Enable creation of subobjects for fields with dots in their names?",
Default: false,
},
Validate: survey.Required,
})
}

return qs
}
94 changes: 94 additions & 0 deletions cmd/create_data_stream_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.

package cmd

import (
"testing"

"github.com/AlecAivazis/survey/v2"
"github.com/Masterminds/semver/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGetSurveyQuestionsForVersion_BelowSemver3_2_0(t *testing.T) {
version := semver.MustParse("3.1.9")
questions := getInitialSurveyQuestionsForVersion(version)

require.Len(t, questions, 3, "should return 3 questions for spec version < 3.2.0")

assert.Equal(t, "name", questions[0].Name)
assert.IsType(t, &survey.Input{}, questions[0].Prompt)
assert.Equal(t, "title", questions[1].Name)
assert.IsType(t, &survey.Input{}, questions[1].Prompt)
assert.Equal(t, "type", questions[2].Name)
assert.IsType(t, &survey.Select{}, questions[2].Prompt)
}

func TestGetSurveyQuestionsForVersion_EqualSemver3_2_0(t *testing.T) {
version := semver.MustParse("3.2.0")
questions := getInitialSurveyQuestionsForVersion(version)

require.Len(t, questions, 4, "should return 4 questions for spec version >= 3.2.0")

assert.Equal(t, "subobjects", questions[3].Name)
assert.IsType(t, &survey.Confirm{}, questions[3].Prompt)
}

func TestGetSurveyQuestionsForVersion_AboveSemver3_2_0(t *testing.T) {
version := semver.MustParse("3.3.0")
questions := getInitialSurveyQuestionsForVersion(version)

require.Len(t, questions, 4, "should return 4 questions for spec version > 3.2.0")

assert.Equal(t, "subobjects", questions[3].Name)
assert.IsType(t, &survey.Confirm{}, questions[3].Prompt)
}

func TestCreateDataStreamDescriptorFromAnswers_SubobjectsFalseForSpecVersionBelow3_2_0(t *testing.T) {
specVersion := semver.MustParse("3.1.0")
answers := newDataStreamAnswers{
Name: "test_stream",
Title: "Test Stream",
Type: "logs",
Subobjects: false,
}
descriptor := createDataStreamDescriptorFromAnswers(answers, "/tmp/package", specVersion)

assert.Equal(t, "test_stream", descriptor.Manifest.Name)
assert.Equal(t, "Test Stream", descriptor.Manifest.Title)
assert.Equal(t, "logs", descriptor.Manifest.Type)
assert.Equal(t, "/tmp/package", descriptor.PackageRoot)
assert.Nil(t, descriptor.Manifest.Elasticsearch)
}

func TestCreateDataStreamDescriptorFromAnswers_SubobjectsFalseForSpecVersionGTE3_2_0(t *testing.T) {
specVersion := semver.MustParse("3.2.0")
answers := newDataStreamAnswers{
Name: "test_stream",
Title: "Test Stream",
Type: "logs",
Subobjects: false,
}
descriptor := createDataStreamDescriptorFromAnswers(answers, "/tmp/package", specVersion)

require.NotNil(t, descriptor.Manifest.Elasticsearch)
require.NotNil(t, descriptor.Manifest.Elasticsearch.IndexTemplate)
require.NotNil(t, descriptor.Manifest.Elasticsearch.IndexTemplate.Mappings)
assert.False(t, descriptor.Manifest.Elasticsearch.IndexTemplate.Mappings.Subobjects)
}

func TestCreateDataStreamDescriptorFromAnswers_SubobjectsTrueForSpecVersionGTE3_2_0(t *testing.T) {
specVersion := semver.MustParse("3.2.0")
answers := newDataStreamAnswers{
Name: "test_stream",
Title: "Test Stream",
Type: "logs",
Subobjects: true,
}
descriptor := createDataStreamDescriptorFromAnswers(answers, "/tmp/package", specVersion)

require.Nil(t, descriptor.Manifest.Elasticsearch)
}