diff --git a/go.mod b/go.mod index 9051993537..ab843b0082 100644 --- a/go.mod +++ b/go.mod @@ -16,13 +16,12 @@ require ( github.com/fatih/color v1.13.0 github.com/go-git/go-billy/v5 v5.3.1 github.com/go-git/go-git/v5 v5.4.2 - github.com/google/go-cmp v0.5.7 github.com/google/go-github/v32 v32.1.0 github.com/google/go-querystring v1.1.0 github.com/jedib0t/go-pretty v4.3.0+incompatible - github.com/kylelemons/godebug v1.1.0 github.com/magefile/mage v1.13.0 github.com/mholt/archiver/v3 v3.5.1 + github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 github.com/olekukonko/tablewriter v0.0.5 github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.4.0 @@ -75,6 +74,7 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.3 // indirect github.com/google/btree v1.0.1 // indirect + github.com/google/go-cmp v0.5.7 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.2.0 // indirect diff --git a/go.sum b/go.sum index 84fb449302..6aedb554e6 100644 --- a/go.sum +++ b/go.sum @@ -783,8 +783,6 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -902,6 +900,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE= +github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8= github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ= github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= diff --git a/internal/testrunner/runners/pipeline/runner_test.go b/internal/testrunner/runners/pipeline/runner_test.go index 37954c9b24..d8c04ddbb0 100644 --- a/internal/testrunner/runners/pipeline/runner_test.go +++ b/internal/testrunner/runners/pipeline/runner_test.go @@ -10,7 +10,6 @@ import ( "strings" "testing" - "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" ) @@ -44,283 +43,6 @@ func TestStripEmptyTestResults(t *testing.T) { require.Equal(t, actual.events[3], json.RawMessage(thirdTestResult)) } -var diffUliteTests = []struct { - name string - a, b string - u int - want string -}{ - { - name: "no diff", - u: 3, - a: `a -b -c -d -`, - b: `a -b -c -d -`, - want: "", - }, - { - name: "first line", - u: 3, - a: `a change -b -c -d -e -`, - b: `a -b -c -d -e -`, - want: `--- want -+++ got -@@ -1 +1 @@ -- a change -+ a - b - c - d`, - }, - { - name: "last line", - u: 3, - a: `a -b -c -d -e change -`, - b: `a -b -c -d -e -`, - want: `--- want -+++ got -@@ -2 +2 @@ - b - c - d -- e change -+ e - `, - }, - { - name: "middle", - u: 3, - a: `a -b -c -d change -e -f -g -h -`, - b: `a -b -c -d -e -f -g -h -`, - want: `--- want -+++ got -@@ -1 +1 @@ - a - b - c -- d change -+ d - e - f - g`, - }, - { - name: "close pair", - u: 3, - a: `a -b -c -d change -e -f -g -h -i -j -k -l -m -`, - b: `a -b -c -d -e -f -g -h -i change -j -k -l -m -`, - want: `--- want -+++ got -@@ -1 +1 @@ - a - b - c -- d change -+ d - e - f - g - h -- i -+ i change - j - k - l`, - }, - { - name: "far pair", - u: 3, - a: `a -b -c change -d -e -f -g -h -i -j -k -l -m -`, - b: `a -b -c -d -e -f -g -h -i -j -k -l change -m -`, - want: `--- want -+++ got -@@ -1 +1 @@ - a - b -- c change -+ c - d - e - f -@@ -9 +9 @@ - i - j - k -- l -+ l change - m - `, - }, - { - name: "far pair addition", - u: 3, - a: `a -b -c change -d -e -f -g -a -b -c -d -e -f -g -h -i -j -k -l -m -`, - b: `a -b -c -d -e -f -g -h -i -j -k -l change -m -`, - want: `--- want -+++ got -@@ -1 +1 @@ - a - b -- c change -- d -- e -- f -- g -- a -- b - c - d - e -@@ -16 +9 @@ - i - j - k -- l -+ l change - m - `, - }, -} - -func TestDiffUlite(t *testing.T) { - for _, test := range diffUliteTests { - t.Run(test.name, func(t *testing.T) { - got := diffUlite(test.a, test.b, test.u) - if got != test.want { - t.Errorf("unexpected result\n%s", cmp.Diff(got, test.want)) - } - }) - } -} - var jsonUnmarshalUsingNumberTests = []struct { name string msg string diff --git a/internal/testrunner/runners/pipeline/test_result.go b/internal/testrunner/runners/pipeline/test_result.go index e6d082626b..0782b8b1f7 100644 --- a/internal/testrunner/runners/pipeline/test_result.go +++ b/internal/testrunner/runners/pipeline/test_result.go @@ -11,9 +11,8 @@ import ( "io" "os" "path/filepath" - "strings" - "github.com/kylelemons/godebug/diff" + "github.com/nsf/jsondiff" "github.com/pkg/errors" "github.com/elastic/elastic-package/internal/common" @@ -22,10 +21,6 @@ import ( const expectedTestResultSuffix = "-expected.json" -// diffContext is the number of context lines to show for diffs in test case -// mismatches. It is the equivalent of -U in a unified diff. -const diffContext = 3 - type testResult struct { events []json.RawMessage } @@ -70,87 +65,62 @@ func compareResults(testCasePath string, config *testConfig, result *testResult) return errors.Wrap(err, "marshalling expected test results failed") } - report := diffUlite(string(expected), string(actual), diffContext) + report, err := diffJson(expected, actual) + if err != nil { + return errors.Wrap(err, "comparing expected test result") + } if report != "" { return testrunner.ErrTestCaseFailed{ Reason: "Expected results are different from actual ones", Details: report, } } + return nil } -// diffUlite implements a unified diff-like rendering with u lines of context. -// It differs from a complete unified diff in that it does not provide the length -// of the chunk, so it cannot be used to generate patches, but can be used for -// human inspection. -func diffUlite(a, b string, u int) string { - chunks := diff.DiffChunks(strings.Split(a, "\n"), strings.Split(b, "\n")) - if len(chunks) == 0 { - return "" +func compareJsonNumbers(a, b json.Number) bool { + if a == b { + // Equal literals, so they are the same. + return true } - - buf := new(bytes.Buffer) - fmt.Fprintf(buf, "--- want\n+++ got\n") - gotLine := 1 - wantLine := 1 - - for i, c := range chunks { - if i == 0 && (len(c.Added) != 0 || len(c.Deleted) != 0) { - fmt.Fprintf(buf, "@@ -%d +%d @@\n", wantLine, gotLine) + if inta, err := a.Int64(); err == nil { + if intb, err := b.Int64(); err == nil { + return inta == intb } - var change bool - for _, line := range c.Added { - change = true - fmt.Fprintf(buf, "+ %s\n", line) + if floatb, err := b.Float64(); err == nil { + return float64(inta) == floatb } - gotLine += len(c.Added) - - for _, line := range c.Deleted { - change = true - fmt.Fprintf(buf, "- %s\n", line) + } else if floata, err := a.Float64(); err == nil { + if intb, err := b.Int64(); err == nil { + return floata == float64(intb) } - wantLine += len(c.Deleted) - - var used int - if change { - used = min(len(c.Equal), u) - for _, line := range c.Equal[:used] { - fmt.Fprintf(buf, " %s\n", line) - } - } - if i < len(chunks)-1 { - next := chunks[i+1] - if len(next.Added) != 0 || len(next.Deleted) != 0 { - off := max(used, len(c.Equal)-u) - if off < len(c.Equal) { - if i == 0 || 2*u < len(c.Equal) { - fmt.Fprintf(buf, "@@ -%d +%d @@\n", wantLine+off, gotLine+off) - } - for _, line := range c.Equal[off:] { - fmt.Fprintf(buf, " %s\n", line) - } - } - } + if floatb, err := b.Float64(); err == nil { + return floata == floatb } - gotLine += len(c.Equal) - wantLine += len(c.Equal) } - return strings.TrimRight(buf.String(), "\n") + return false } -func min(a, b int) int { - if a < b { - return a - } - return b -} +func diffJson(want, got []byte) (string, error) { + opts := jsondiff.DefaultConsoleOptions() + + // Remove colored output. + opts.Added = jsondiff.Tag{} + opts.Removed = jsondiff.Tag{} + opts.Changed = jsondiff.Tag{} + opts.Skipped = jsondiff.Tag{} + + // Configure diff. + opts.SkipMatches = true + opts.CompareNumbers = compareJsonNumbers -func max(a, b int) int { - if a > b { - return a + result, diff := jsondiff.Compare(want, got, &opts) + switch result { + case jsondiff.FirstArgIsInvalidJson, jsondiff.SecondArgIsInvalidJson, jsondiff.BothArgsAreInvalidJson: + return "", errors.New("invalid json") } - return b + return diff, nil } func readExpectedTestResult(testCasePath string, config *testConfig) (*testResult, error) { diff --git a/internal/testrunner/runners/pipeline/test_result_test.go b/internal/testrunner/runners/pipeline/test_result_test.go new file mode 100644 index 0000000000..4f57135938 --- /dev/null +++ b/internal/testrunner/runners/pipeline/test_result_test.go @@ -0,0 +1,45 @@ +// 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 pipeline + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCompareJsonNumber(t *testing.T) { + cases := []struct { + want json.Number + got json.Number + equal bool + }{ + {"0", "0", true}, + {"0.0", "0", true}, + {"0", "0.0", true}, + {"42", "42", true}, + {"42.0", "42", true}, + {"42", "42.0", true}, + {"0.42", "0.42", true}, + {"-10", "-10", true}, + {"-10.0", "-10", true}, + {"6920071768563516000", "6920071768563516000", true}, + {"6920071768563516847", "6920071768563516847", true}, + {"1624617166.182", "1.624617166182E9", true}, + + {"0", "1", false}, + {"0.1", "0", false}, + {"6920071768563516000", "6920071768563516847", false}, + {"1624617166.182", "1.624617166181E9", false}, + } + + for _, c := range cases { + t.Run(c.want.String()+" == "+c.got.String(), func(t *testing.T) { + equal := compareJsonNumbers(c.want, c.got) + assert.Equal(t, c.equal, equal) + }) + } +} diff --git a/test/packages/other/number_formats/changelog.yml b/test/packages/other/number_formats/changelog.yml new file mode 100644 index 0000000000..99a53bd728 --- /dev/null +++ b/test/packages/other/number_formats/changelog.yml @@ -0,0 +1,6 @@ +# newer versions go on top +- version: "0.1.0" + changes: + - description: Initial draft of the package + type: enhancement + link: https://github.com/elastic/integrations/pull/0 # FIXME Replace with the real PR link diff --git a/test/packages/other/number_formats/data_stream/numbers/_dev/test/pipeline/test-example.log b/test/packages/other/number_formats/data_stream/numbers/_dev/test/pipeline/test-example.log new file mode 100644 index 0000000000..5961e9260b --- /dev/null +++ b/test/packages/other/number_formats/data_stream/numbers/_dev/test/pipeline/test-example.log @@ -0,0 +1,9 @@ +0 +0.0 +42 +42.0 +0.42 +-10 +-10.42 +6920071768563516847 +1624617166.182 diff --git a/test/packages/other/number_formats/data_stream/numbers/_dev/test/pipeline/test-example.log-expected.json b/test/packages/other/number_formats/data_stream/numbers/_dev/test/pipeline/test-example.log-expected.json new file mode 100644 index 0000000000..12b401a4c4 --- /dev/null +++ b/test/packages/other/number_formats/data_stream/numbers/_dev/test/pipeline/test-example.log-expected.json @@ -0,0 +1,75 @@ +{ + "expected": [ + { + "example": { + "float": 0, + "float_as_long": 0, + "long": 0, + "long_as_float": 0 + }, + "message": "0" + }, + { + "example": { + "float": 0, + "float_as_long": 0 + }, + "message": "0.0" + }, + { + "example": { + "float": 42, + "float_as_long": 42, + "long": 42, + "long_as_float": 42 + }, + "message": "42" + }, + { + "example": { + "float": 42, + "float_as_long": 42 + }, + "message": "42.0" + }, + { + "example": { + "float": 0.42, + "float_as_long": 0.42 + }, + "message": "0.42" + }, + { + "example": { + "float": -10, + "float_as_long": -10, + "long": -10, + "long_as_float": -10 + }, + "message": "-10" + }, + { + "example": { + "float": -10.42, + "float_as_long": -10.42 + }, + "message": "-10.42" + }, + { + "example": { + "float": 6.9200717685635164E18, + "float_as_long": 6.9200716E18, + "long": 6920071768563516847, + "long_as_float": 6920071768563516847 + }, + "message": "6920071768563516847" + }, + { + "example": { + "float": 1.624617166182E9, + "float_as_long": 1.62461722E9 + }, + "message": "1624617166.182" + } + ] +} \ No newline at end of file diff --git a/test/packages/other/number_formats/data_stream/numbers/agent/stream/stream.yml.hbs b/test/packages/other/number_formats/data_stream/numbers/agent/stream/stream.yml.hbs new file mode 100644 index 0000000000..5845510de8 --- /dev/null +++ b/test/packages/other/number_formats/data_stream/numbers/agent/stream/stream.yml.hbs @@ -0,0 +1,7 @@ +paths: +{{#each paths as |path i|}} + - {{path}} +{{/each}} +exclude_files: [".gz$"] +processors: + - add_locale: ~ diff --git a/test/packages/other/number_formats/data_stream/numbers/elasticsearch/ingest_pipeline/default.yml b/test/packages/other/number_formats/data_stream/numbers/elasticsearch/ingest_pipeline/default.yml new file mode 100644 index 0000000000..dd25bce731 --- /dev/null +++ b/test/packages/other/number_formats/data_stream/numbers/elasticsearch/ingest_pipeline/default.yml @@ -0,0 +1,25 @@ +--- +description: Pipeline for processing sample logs +processors: +- convert: + field: message + target_field: example.long + type: long + ignore_failure: true # Not every number can be converted to long. +- convert: + field: message + target_field: example.float + type: double +- convert: + field: message + target_field: example.float_as_long + type: float +- convert: + field: message + target_field: example.long_as_float + type: long + ignore_failure: true # Not every number can be converted to long. +on_failure: +- set: + field: error.message + value: '{{ _ingest.on_failure_message }}' diff --git a/test/packages/other/number_formats/data_stream/numbers/fields/base-fields.yml b/test/packages/other/number_formats/data_stream/numbers/fields/base-fields.yml new file mode 100644 index 0000000000..28b297d659 --- /dev/null +++ b/test/packages/other/number_formats/data_stream/numbers/fields/base-fields.yml @@ -0,0 +1,14 @@ +- name: data_stream.type + type: constant_keyword + description: Data stream type. +- name: data_stream.dataset + type: constant_keyword + description: Data stream dataset. +- name: data_stream.namespace + type: constant_keyword + description: Data stream namespace. +- name: '@timestamp' + type: date + description: Event timestamp. +- name: 'message' + type: text diff --git a/test/packages/other/number_formats/data_stream/numbers/fields/fields.yml b/test/packages/other/number_formats/data_stream/numbers/fields/fields.yml new file mode 100644 index 0000000000..93930b7560 --- /dev/null +++ b/test/packages/other/number_formats/data_stream/numbers/fields/fields.yml @@ -0,0 +1,21 @@ +- name: example + type: group + fields: + - name: long + type: long + description: Store any number as long. + - name: float + type: double + description: Store any number as double. + - name: string_as_long + type: long + description: Store string representations of numbers as longs. + - name: string_as_float + type: double + description: Store string representations of numbers as float. + - name: float_as_long + type: long + description: Store float as long. + - name: long_as_float + type: float + description: Store long as float. diff --git a/test/packages/other/number_formats/data_stream/numbers/manifest.yml b/test/packages/other/number_formats/data_stream/numbers/manifest.yml new file mode 100644 index 0000000000..df9a1cbebd --- /dev/null +++ b/test/packages/other/number_formats/data_stream/numbers/manifest.yml @@ -0,0 +1,13 @@ +title: "Numbers" +type: logs +streams: + - input: logfile + title: Sample logs + description: Collect sample logs + vars: + - name: paths + type: text + title: Paths + multi: true + default: + - /var/log/*.log diff --git a/test/packages/other/number_formats/docs/README.md b/test/packages/other/number_formats/docs/README.md new file mode 100644 index 0000000000..1e50d9559a --- /dev/null +++ b/test/packages/other/number_formats/docs/README.md @@ -0,0 +1,5 @@ +# Package with documents with different formats of numbers + +This is a new integration created using the [elastic-package](https://github.com/elastic/elastic-package) tool. + +Consider using the README template file `_dev/build/docs/README.md`to generate a list of exported fields or include a sample event. \ No newline at end of file diff --git a/test/packages/other/number_formats/img/sample-logo.svg b/test/packages/other/number_formats/img/sample-logo.svg new file mode 100644 index 0000000000..6268dd88f3 --- /dev/null +++ b/test/packages/other/number_formats/img/sample-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/packages/other/number_formats/img/sample-screenshot.png b/test/packages/other/number_formats/img/sample-screenshot.png new file mode 100644 index 0000000000..d7a56a3ecc Binary files /dev/null and b/test/packages/other/number_formats/img/sample-screenshot.png differ diff --git a/test/packages/other/number_formats/manifest.yml b/test/packages/other/number_formats/manifest.yml new file mode 100644 index 0000000000..bdf566f8c7 --- /dev/null +++ b/test/packages/other/number_formats/manifest.yml @@ -0,0 +1,31 @@ +format_version: 1.0.0 +name: number_formats +title: "Number formats" +version: 0.1.0 +license: basic +description: "Package to tes pipelines with documents with different formats of numbers" +type: integration +categories: + - custom +conditions: + kibana.version: "^8.1.0" +screenshots: + - src: /img/sample-screenshot.png + title: Sample screenshot + size: 600x600 + type: image/png +icons: + - src: /img/sample-logo.svg + title: Sample logo + size: 32x32 + type: image/svg+xml +policy_templates: + - name: sample + title: Sample logs + description: Collect sample logs + inputs: + - type: logfile + title: Collect sample logs from instances + description: Collecting sample logs +owner: + github: elastic/ecosystem