|
@@ -18,7 +18,9 @@ import (
|
|
"github.com/lf-edge/ekuiper/internal/conf"
|
|
"github.com/lf-edge/ekuiper/internal/conf"
|
|
"github.com/lf-edge/ekuiper/internal/topo/context"
|
|
"github.com/lf-edge/ekuiper/internal/topo/context"
|
|
"github.com/lf-edge/ekuiper/internal/topo/transform"
|
|
"github.com/lf-edge/ekuiper/internal/topo/transform"
|
|
|
|
+ "github.com/lf-edge/ekuiper/pkg/message"
|
|
"os"
|
|
"os"
|
|
|
|
+ "reflect"
|
|
"testing"
|
|
"testing"
|
|
)
|
|
)
|
|
|
|
|
|
@@ -47,77 +49,101 @@ func TestConfigure(t *testing.T) {
|
|
if err == nil {
|
|
if err == nil {
|
|
t.Errorf("Configure() error = %v, wantErr not nil", err)
|
|
t.Errorf("Configure() error = %v, wantErr not nil", err)
|
|
}
|
|
}
|
|
|
|
+ err = m.Configure(map[string]interface{}{"fileType": "csv2"})
|
|
|
|
+ if err == nil {
|
|
|
|
+ t.Errorf("Configure() error = %v, wantErr not nil", err)
|
|
|
|
+ }
|
|
|
|
+ err = m.Configure(map[string]interface{}{"interval": 500,
|
|
|
|
+ "path": "test",
|
|
|
|
+ "fileType": "csv"})
|
|
|
|
+ if err == nil {
|
|
|
|
+ t.Errorf("Configure() error = %v, wantErr not nil", err)
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
func TestFileSink_Configure(t *testing.T) {
|
|
func TestFileSink_Configure(t *testing.T) {
|
|
tests := []struct {
|
|
tests := []struct {
|
|
- name string
|
|
|
|
- c *sinkConf
|
|
|
|
- p map[string]interface{}
|
|
|
|
- wantErr bool
|
|
|
|
|
|
+ name string
|
|
|
|
+ c *sinkConf
|
|
|
|
+ p map[string]interface{}
|
|
}{
|
|
}{
|
|
{
|
|
{
|
|
- name: "valid configuration",
|
|
|
|
|
|
+ name: "default configurations",
|
|
c: &sinkConf{
|
|
c: &sinkConf{
|
|
Interval: 1000,
|
|
Interval: 1000,
|
|
Path: "cache",
|
|
Path: "cache",
|
|
|
|
+ FileType: LINES_TYPE,
|
|
},
|
|
},
|
|
- p: map[string]interface{}{
|
|
|
|
- "interval": 500,
|
|
|
|
- "path": "test",
|
|
|
|
- },
|
|
|
|
- wantErr: false,
|
|
|
|
|
|
+ p: map[string]interface{}{},
|
|
},
|
|
},
|
|
{
|
|
{
|
|
- name: "invalid interval",
|
|
|
|
-
|
|
|
|
|
|
+ name: "previous setting",
|
|
c: &sinkConf{
|
|
c: &sinkConf{
|
|
- Interval: 1000,
|
|
|
|
- Path: "cache",
|
|
|
|
|
|
+ Interval: 500,
|
|
|
|
+ Path: "test",
|
|
|
|
+ FileType: LINES_TYPE,
|
|
},
|
|
},
|
|
|
|
|
|
p: map[string]interface{}{
|
|
p: map[string]interface{}{
|
|
- "interval": -500,
|
|
|
|
|
|
+ "interval": 500,
|
|
"path": "test",
|
|
"path": "test",
|
|
},
|
|
},
|
|
- wantErr: true,
|
|
|
|
},
|
|
},
|
|
{
|
|
{
|
|
- name: "empty path",
|
|
|
|
-
|
|
|
|
|
|
+ name: "new props",
|
|
c: &sinkConf{
|
|
c: &sinkConf{
|
|
- Interval: 1000,
|
|
|
|
- Path: "cache",
|
|
|
|
|
|
+ Interval: 500,
|
|
|
|
+ Path: "test",
|
|
|
|
+ FileType: CSV_TYPE,
|
|
|
|
+ Format: message.FormatDelimited,
|
|
|
|
+ Delimiter: ",",
|
|
},
|
|
},
|
|
-
|
|
|
|
p: map[string]interface{}{
|
|
p: map[string]interface{}{
|
|
"interval": 500,
|
|
"interval": 500,
|
|
- "path": "",
|
|
|
|
|
|
+ "path": "test",
|
|
|
|
+ "fileType": "csv",
|
|
|
|
+ "format": message.FormatDelimited,
|
|
},
|
|
},
|
|
-
|
|
|
|
- wantErr: true,
|
|
|
|
},
|
|
},
|
|
}
|
|
}
|
|
for _, tt := range tests {
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
m := &fileSink{}
|
|
m := &fileSink{}
|
|
- if err := m.Configure(tt.p); (err != nil) != tt.wantErr {
|
|
|
|
- t.Errorf("fileSink.Configure() error = %v, wantErr %v", err, tt.wantErr)
|
|
|
|
|
|
+ if err := m.Configure(tt.p); err != nil {
|
|
|
|
+ t.Errorf("fileSink.Configure() error = %v", err)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ if !reflect.DeepEqual(m.c, tt.c) {
|
|
|
|
+ t.Errorf("fileSink.Configure() = %v, want %v", m.c, tt.c)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func TestFileSink_Collect(t *testing.T) {
|
|
func TestFileSink_Collect(t *testing.T) {
|
|
- // Create a temporary file for testing
|
|
|
|
- tmpfile, err := os.CreateTemp("", "test")
|
|
|
|
- if err != nil {
|
|
|
|
- t.Fatal(err)
|
|
|
|
|
|
+ tests := []struct {
|
|
|
|
+ name string
|
|
|
|
+ ft FileType
|
|
|
|
+ fname string
|
|
|
|
+ content []byte
|
|
|
|
+ }{
|
|
|
|
+ {
|
|
|
|
+ name: "lines",
|
|
|
|
+ ft: LINES_TYPE,
|
|
|
|
+ fname: "test_lines",
|
|
|
|
+ content: []byte("{\"key\":\"value1\"}\n{\"key\":\"value2\"}"),
|
|
|
|
+ }, {
|
|
|
|
+ name: "json",
|
|
|
|
+ ft: JSON_TYPE,
|
|
|
|
+ fname: "test_json",
|
|
|
|
+ content: []byte(`[{"key":"value1"}{"key":"value2"}]`),
|
|
|
|
+ }, {
|
|
|
|
+ name: "csv",
|
|
|
|
+ ft: CSV_TYPE,
|
|
|
|
+ fname: "test_csv",
|
|
|
|
+ content: []byte("key\n{\"key\":\"value1\"}\n{\"key\":\"value2\"}"),
|
|
|
|
+ },
|
|
}
|
|
}
|
|
- defer os.Remove(tmpfile.Name())
|
|
|
|
-
|
|
|
|
- // Create a file sink with the temporary file path
|
|
|
|
- sink := &fileSink{c: &sinkConf{Path: tmpfile.Name()}}
|
|
|
|
|
|
|
|
// Create a stream context for testing
|
|
// Create a stream context for testing
|
|
contextLogger := conf.Log.WithField("rule", "test2")
|
|
contextLogger := conf.Log.WithField("rule", "test2")
|
|
@@ -125,38 +151,41 @@ func TestFileSink_Collect(t *testing.T) {
|
|
|
|
|
|
tf, _ := transform.GenTransform("", "json", "", "")
|
|
tf, _ := transform.GenTransform("", "json", "", "")
|
|
vCtx := context.WithValue(ctx, context.TransKey, tf)
|
|
vCtx := context.WithValue(ctx, context.TransKey, tf)
|
|
- sink.Open(ctx)
|
|
|
|
-
|
|
|
|
- // Test collecting a string item
|
|
|
|
- str := "test string"
|
|
|
|
- if err := sink.Collect(vCtx, str); err != nil {
|
|
|
|
- t.Errorf("unexpected error: %s", err)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Test collecting a map item
|
|
|
|
- m := map[string]interface{}{"key": "value"}
|
|
|
|
- if err := sink.Collect(ctx, m); err != nil {
|
|
|
|
- t.Errorf("unexpected error: %s", err)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Test collecting an invalid item
|
|
|
|
- invalid := make(chan int)
|
|
|
|
- if err := sink.Collect(ctx, invalid); err == nil {
|
|
|
|
- t.Error("expected error but got nil")
|
|
|
|
- }
|
|
|
|
|
|
|
|
- // Close the file sink
|
|
|
|
- if err := sink.Close(ctx); err != nil {
|
|
|
|
- t.Errorf("unexpected error: %s", err)
|
|
|
|
- }
|
|
|
|
|
|
+ for _, tt := range tests {
|
|
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
|
|
+ // Create a temporary file for testing
|
|
|
|
+ tmpfile, err := os.CreateTemp("", tt.fname)
|
|
|
|
+ if err != nil {
|
|
|
|
+ t.Fatal(err)
|
|
|
|
+ }
|
|
|
|
+ defer os.Remove(tmpfile.Name())
|
|
|
|
+ // Create a file sink with the temporary file path
|
|
|
|
+ sink := &fileSink{c: &sinkConf{Path: tmpfile.Name(), FileType: tt.ft, HasHeader: true}}
|
|
|
|
+ sink.Open(ctx)
|
|
|
|
+
|
|
|
|
+ // Test collecting a map item
|
|
|
|
+ m := map[string]interface{}{"key": "value1"}
|
|
|
|
+ if err := sink.Collect(vCtx, m); err != nil {
|
|
|
|
+ t.Errorf("unexpected error: %s", err)
|
|
|
|
+ }
|
|
|
|
|
|
- // Read the contents of the temporary file and check if they match the collected items
|
|
|
|
- contents, err := os.ReadFile(tmpfile.Name())
|
|
|
|
- if err != nil {
|
|
|
|
- t.Fatal(err)
|
|
|
|
- }
|
|
|
|
- expected := "\"test string\"\n{\"key\":\"value\"}\n"
|
|
|
|
- if string(contents) != expected {
|
|
|
|
- t.Errorf("expected %q but got %q", expected, string(contents))
|
|
|
|
|
|
+ // Test collecting another map item
|
|
|
|
+ m = map[string]interface{}{"key": "value2"}
|
|
|
|
+ if err := sink.Collect(ctx, m); err != nil {
|
|
|
|
+ t.Errorf("unexpected error: %s", err)
|
|
|
|
+ }
|
|
|
|
+ if err = sink.Close(ctx); err != nil {
|
|
|
|
+ t.Errorf("unexpected close error: %s", err)
|
|
|
|
+ }
|
|
|
|
+ // Read the contents of the temporary file and check if they match the collected items
|
|
|
|
+ contents, err := os.ReadFile(tmpfile.Name())
|
|
|
|
+ if err != nil {
|
|
|
|
+ t.Fatal(err)
|
|
|
|
+ }
|
|
|
|
+ if !reflect.DeepEqual(contents, tt.content) {
|
|
|
|
+ t.Errorf("expected %q but got %q", tt.content, string(contents))
|
|
|
|
+ }
|
|
|
|
+ })
|
|
}
|
|
}
|
|
}
|
|
}
|