github.com/observiq/carbon@v0.9.11-0.20200820160507-1b872e368a5e/pipeline/pipeline_test.go (about)

     1  package pipeline
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/observiq/carbon/operator"
     7  	"github.com/observiq/carbon/testutil"
     8  	"github.com/stretchr/testify/mock"
     9  	"github.com/stretchr/testify/require"
    10  	"gonum.org/v1/gonum/graph"
    11  	"gonum.org/v1/gonum/graph/simple"
    12  	"gonum.org/v1/gonum/graph/topo"
    13  )
    14  
    15  func TestUnorderableToCycles(t *testing.T) {
    16  	t.Run("SingleCycle", func(t *testing.T) {
    17  		mockOperator1 := testutil.NewMockOperator("operator1")
    18  		mockOperator2 := testutil.NewMockOperator("operator2")
    19  		mockOperator3 := testutil.NewMockOperator("operator3")
    20  		mockOperator1.On("Outputs").Return([]operator.Operator{mockOperator2})
    21  		mockOperator2.On("Outputs").Return([]operator.Operator{mockOperator3})
    22  		mockOperator3.On("Outputs").Return([]operator.Operator{mockOperator1})
    23  
    24  		err := topo.Unorderable([][]graph.Node{{
    25  			createOperatorNode(mockOperator1),
    26  			createOperatorNode(mockOperator2),
    27  			createOperatorNode(mockOperator3),
    28  		}})
    29  
    30  		output := unorderableToCycles(err)
    31  		expected := `(operator1 -> operator2 -> operator3 -> operator1)`
    32  
    33  		require.Equal(t, expected, output)
    34  	})
    35  
    36  	t.Run("MultipleCycles", func(t *testing.T) {
    37  		mockOperator1 := testutil.NewMockOperator("operator1")
    38  		mockOperator2 := testutil.NewMockOperator("operator2")
    39  		mockOperator3 := testutil.NewMockOperator("operator3")
    40  		mockOperator1.On("Outputs").Return([]operator.Operator{mockOperator2})
    41  		mockOperator2.On("Outputs").Return([]operator.Operator{mockOperator3})
    42  		mockOperator3.On("Outputs").Return([]operator.Operator{mockOperator1})
    43  
    44  		mockOperator4 := testutil.NewMockOperator("operator4")
    45  		mockOperator5 := testutil.NewMockOperator("operator5")
    46  		mockOperator6 := testutil.NewMockOperator("operator6")
    47  		mockOperator4.On("Outputs").Return([]operator.Operator{mockOperator5})
    48  		mockOperator5.On("Outputs").Return([]operator.Operator{mockOperator6})
    49  		mockOperator6.On("Outputs").Return([]operator.Operator{mockOperator4})
    50  
    51  		err := topo.Unorderable([][]graph.Node{{
    52  			createOperatorNode(mockOperator1),
    53  			createOperatorNode(mockOperator2),
    54  			createOperatorNode(mockOperator3),
    55  		}, {
    56  			createOperatorNode(mockOperator4),
    57  			createOperatorNode(mockOperator5),
    58  			createOperatorNode(mockOperator6),
    59  		}})
    60  
    61  		output := unorderableToCycles(err)
    62  		expected := `(operator1 -> operator2 -> operator3 -> operator1),(operator4 -> operator5 -> operator6 -> operator4)`
    63  
    64  		require.Equal(t, expected, output)
    65  	})
    66  }
    67  
    68  func TestPipeline(t *testing.T) {
    69  	t.Run("MultipleStart", func(t *testing.T) {
    70  		pipeline, err := NewPipeline([]operator.Operator{})
    71  		require.NoError(t, err)
    72  
    73  		err = pipeline.Start()
    74  		require.NoError(t, err)
    75  
    76  		err = pipeline.Start()
    77  		require.NoError(t, err)
    78  
    79  		pipeline.Stop()
    80  	})
    81  
    82  	t.Run("MultipleStop", func(t *testing.T) {
    83  		pipeline, err := NewPipeline([]operator.Operator{})
    84  		require.NoError(t, err)
    85  
    86  		err = pipeline.Start()
    87  		require.NoError(t, err)
    88  
    89  		pipeline.Stop()
    90  		pipeline.Stop()
    91  	})
    92  
    93  	t.Run("DuplicateNodeIDs", func(t *testing.T) {
    94  		operator1 := testutil.NewMockOperator("operator1")
    95  		operator1.On("SetOutputs", mock.Anything).Return(nil)
    96  		operator1.On("Outputs").Return(nil)
    97  		operator2 := testutil.NewMockOperator("operator1")
    98  		operator2.On("SetOutputs", mock.Anything).Return(nil)
    99  		operator2.On("Outputs").Return(nil)
   100  
   101  		_, err := NewPipeline([]operator.Operator{operator1, operator2})
   102  		require.Error(t, err)
   103  		require.Contains(t, err.Error(), "already exists")
   104  	})
   105  
   106  	t.Run("OutputNotExist", func(t *testing.T) {
   107  		operator1 := testutil.NewMockOperator("operator1")
   108  		operator1.On("SetOutputs", mock.Anything).Return(nil)
   109  		operator1.On("Outputs").Return()
   110  
   111  		operator2 := testutil.NewMockOperator("operator2")
   112  		operator2.On("SetOutputs", mock.Anything).Return(nil)
   113  		operator2.On("Outputs").Return([]operator.Operator{operator1})
   114  
   115  		_, err := NewPipeline([]operator.Operator{operator2})
   116  		require.Error(t, err)
   117  		require.Contains(t, err.Error(), "does not exist")
   118  	})
   119  
   120  	t.Run("OutputNotProcessor", func(t *testing.T) {
   121  		operator1 := &testutil.Operator{}
   122  		operator1.On("ID").Return("operator1")
   123  		operator1.On("CanProcess").Return(false)
   124  		operator1.On("CanOutput").Return(true)
   125  		operator1.On("SetOutputs", mock.Anything).Return(nil)
   126  		operator1.On("Outputs").Return(nil)
   127  
   128  		operator2 := testutil.NewMockOperator("operator2")
   129  		operator2.On("SetOutputs", mock.Anything).Return(nil)
   130  		operator2.On("Outputs").Return([]operator.Operator{operator1})
   131  
   132  		_, err := NewPipeline([]operator.Operator{operator1, operator2})
   133  		require.Error(t, err)
   134  		require.Contains(t, err.Error(), "can not process")
   135  	})
   136  
   137  	t.Run("DuplicateEdges", func(t *testing.T) {
   138  		operator1 := testutil.NewMockOperator("operator1")
   139  		operator1.On("SetOutputs", mock.Anything).Return(nil)
   140  		operator1.On("Outputs").Return(nil)
   141  
   142  		operator2 := testutil.NewMockOperator("operator2")
   143  		operator2.On("SetOutputs", mock.Anything).Return(nil)
   144  		operator2.On("Outputs").Return([]operator.Operator{operator1, operator1})
   145  
   146  		node1 := createOperatorNode(operator1)
   147  		node2 := createOperatorNode(operator2)
   148  
   149  		graph := simple.NewDirectedGraph()
   150  		graph.AddNode(node1)
   151  		graph.AddNode(node2)
   152  		edge := graph.NewEdge(node2, node1)
   153  		graph.SetEdge(edge)
   154  
   155  		err := connectNode(graph, node2)
   156  		require.Error(t, err)
   157  		require.Contains(t, err.Error(), "connection already exists")
   158  	})
   159  
   160  	t.Run("Cyclical", func(t *testing.T) {
   161  		mockOperator1 := testutil.NewMockOperator("operator1")
   162  		mockOperator2 := testutil.NewMockOperator("operator2")
   163  		mockOperator3 := testutil.NewMockOperator("operator3")
   164  		mockOperator1.On("Outputs").Return([]operator.Operator{mockOperator2})
   165  		mockOperator1.On("SetOutputs", mock.Anything).Return(nil)
   166  		mockOperator2.On("Outputs").Return([]operator.Operator{mockOperator3})
   167  		mockOperator2.On("SetOutputs", mock.Anything).Return(nil)
   168  		mockOperator3.On("Outputs").Return([]operator.Operator{mockOperator1})
   169  		mockOperator3.On("SetOutputs", mock.Anything).Return(nil)
   170  
   171  		_, err := NewPipeline([]operator.Operator{mockOperator1, mockOperator2, mockOperator3})
   172  		require.Error(t, err)
   173  		require.Contains(t, err.Error(), "circular dependency")
   174  	})
   175  }