github.com/magnusbaeck/logstash-filter-verifier/v2@v2.0.0-pre.1/logstash/parallel_process_test.go (about)

     1  // Copyright (c) 2016-2018 Magnus Bäck <magnus@noun.se>
     2  
     3  package logstash
     4  
     5  import (
     6  	"errors"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"reflect"
    11  	"testing"
    12  	"time"
    13  
    14  	semver "github.com/Masterminds/semver/v3"
    15  )
    16  
    17  func TestParallelProcess(t *testing.T) {
    18  	const testLine = "test line\n"
    19  
    20  	fs := FieldSet{}
    21  	ts, err := NewTestStream("Codec", fs, 5*time.Second)
    22  	if err != nil {
    23  		t.Fatalf("Unable to create TestStream: %s", err)
    24  	}
    25  	defer CleanupTestStreams([]*TestStream{ts})
    26  
    27  	file, err := ioutil.TempFile("", "")
    28  	if err != nil {
    29  		t.Fatalf("Failed to create temporary config file: %s", err)
    30  	}
    31  	configPaths := []string{file.Name()}
    32  
    33  	// Pretend it's an old Logstash; if NewInvocation() is called
    34  	// for 5.0 or newer it'll try to copy configuration files so
    35  	// we'd have to generate such files too.
    36  	v, err := semver.NewVersion("2.4.0")
    37  	if err != nil {
    38  		t.Fatalf("Unable to parse version number: %s", err)
    39  	}
    40  
    41  	inv, err := NewInvocation(os.Args[0], []string{}, v, configPaths...)
    42  	if err != nil {
    43  		t.Fatalf("Unable to create Invocation: %s", err)
    44  	}
    45  	defer inv.Release()
    46  	p, err := NewParallelProcess(inv, []*TestStream{ts}, []string{})
    47  	if err != nil {
    48  		t.Fatalf("Unable to create ParallelProcess: %s", err)
    49  	}
    50  	defer p.Release()
    51  
    52  	p.child.Env = append(os.Environ(), "TEST_MAIN=logstash-mock", "TEST_SOCKET="+ts.senderPath)
    53  
    54  	if err = p.Start(); err != nil {
    55  		t.Fatalf("Unable to start ParallelProcess: %s", err)
    56  	}
    57  
    58  	_, err = ts.Write([]byte(testLine))
    59  	if err != nil {
    60  		t.Fatalf("Unable to write to TestStream: %s", err)
    61  	}
    62  	if err = ts.Close(); err != nil {
    63  		t.Fatalf("Unable to close TestStream: %s", err)
    64  	}
    65  
    66  	result, err := p.Wait()
    67  	if err != nil {
    68  		t.Fatalf("Error while waiting for ParallelProcess to finish: %s", err)
    69  	}
    70  	if result.Output != testLine {
    71  		t.Errorf("Unexpected return from ParallelProcess, expected: %s, got: %s", testLine, result.Output)
    72  	}
    73  }
    74  
    75  func TestGetSocketInOutPlugins(t *testing.T) {
    76  	// Create a single temporary file that all test cases can use.
    77  	receiver, err := newDeletedTempFile("", "")
    78  	if err != nil {
    79  		t.Fatalf("Unable to create temporary file: %s", err)
    80  	}
    81  	defer receiver.Close()
    82  
    83  	cases := []struct {
    84  		streams         []*TestStream
    85  		expectedInputs  []string
    86  		expectedOutputs []string
    87  		err             error
    88  	}{
    89  		// Single TestStream struct.
    90  		{
    91  			[]*TestStream{
    92  				{
    93  					senderPath: "/tmp/foo",
    94  					inputCodec: "any_codec",
    95  					fields:     FieldSet{},
    96  					receiver:   receiver,
    97  				},
    98  			},
    99  			[]string{
   100  				"unix { mode => \"client\" path => \"/tmp/foo\" codec => any_codec " +
   101  					"add_field => { \"[@metadata][__lfv_testcase]\" => \"0\" } }",
   102  			},
   103  			[]string{
   104  				fmt.Sprintf("if [@metadata][__lfv_testcase] == \"0\" { file { path => %q codec => \"json_lines\" } }", receiver.Name()),
   105  			},
   106  			nil,
   107  		},
   108  		// Multiple TestStream structs.
   109  		{
   110  			[]*TestStream{
   111  				{
   112  					senderPath: "/tmp/foo",
   113  					inputCodec: "any_codec",
   114  					fields:     FieldSet{},
   115  					receiver:   receiver,
   116  				},
   117  				{
   118  					senderPath: "/tmp/bar",
   119  					inputCodec: "other_codec",
   120  					fields:     FieldSet{},
   121  					receiver:   receiver,
   122  				},
   123  			},
   124  			[]string{
   125  				"unix { mode => \"client\" path => \"/tmp/foo\" codec => any_codec " +
   126  					"add_field => { \"[@metadata][__lfv_testcase]\" => \"0\" } }",
   127  				"unix { mode => \"client\" path => \"/tmp/bar\" codec => other_codec " +
   128  					"add_field => { \"[@metadata][__lfv_testcase]\" => \"1\" } }",
   129  			},
   130  			[]string{
   131  				fmt.Sprintf("if [@metadata][__lfv_testcase] == \"0\" { file { path => %q codec => \"json_lines\" } }", receiver.Name()),
   132  				fmt.Sprintf("if [@metadata][__lfv_testcase] == \"1\" { file { path => %q codec => \"json_lines\" } }", receiver.Name()),
   133  			},
   134  			nil,
   135  		},
   136  		// Single TestStream struct with additional fields set.
   137  		{
   138  			[]*TestStream{
   139  				{
   140  					senderPath: "/tmp/foo",
   141  					inputCodec: "any_codec",
   142  					fields: FieldSet{
   143  						"@metadata": map[string]interface{}{
   144  							"foo": "bar",
   145  						},
   146  					},
   147  					receiver: receiver,
   148  				},
   149  			},
   150  			[]string{
   151  				"unix { mode => \"client\" path => \"/tmp/foo\" codec => any_codec " +
   152  					"add_field => { \"[@metadata][__lfv_testcase]\" => \"0\" \"[@metadata][foo]\" => \"bar\" } }",
   153  			},
   154  			[]string{
   155  				fmt.Sprintf("if [@metadata][__lfv_testcase] == \"0\" { file { path => %q codec => \"json_lines\" } }", receiver.Name()),
   156  			},
   157  			nil,
   158  		},
   159  		// Single TestStream struct with a non-map @metadata
   160  		// field should result in an error.
   161  		{
   162  			[]*TestStream{
   163  				{
   164  					senderPath: "/tmp/foo",
   165  					inputCodec: "any_codec",
   166  					fields: FieldSet{
   167  						"@metadata": "foo",
   168  					},
   169  					receiver: receiver,
   170  				},
   171  			},
   172  			nil,
   173  			nil,
   174  			errors.New("the supplied contents of the @metadata field must be a hash (found string instead)"),
   175  		},
   176  	}
   177  	for i, c := range cases {
   178  		inputs, outputs, err := getSocketInOutPlugins(c.streams)
   179  
   180  		if err == nil && c.err != nil {
   181  			t.Errorf("Test %d: Expected failure, got success.", i)
   182  		} else if err != nil && c.err == nil {
   183  			t.Errorf("Test %d: Expected success, got this error instead: %#v", i, err)
   184  		} else if err != nil && c.err != nil && err.Error() != c.err.Error() {
   185  			t.Errorf("Test %d: Didn't get the expected error.\nExpected:\n%s\nGot:\n%s", i, c.err, err)
   186  		} else {
   187  			if !reflect.DeepEqual(c.expectedInputs, inputs) {
   188  				t.Errorf("Test %d:\nExpected:\n%#v\nGot:\n%#v", i, c.expectedInputs, inputs)
   189  			}
   190  			if !reflect.DeepEqual(c.expectedOutputs, outputs) {
   191  				t.Errorf("Test %d:\nExpected:\n%#v\nGot:\n%#v", i, c.expectedOutputs, outputs)
   192  			}
   193  		}
   194  	}
   195  }