1 package watch
2
3 import (
4 "bytes"
5 "context"
6 "fmt"
7 "testing"
8 "time"
9
10 "k8s.io/apimachinery/pkg/watch"
11
12 "github.com/fsnotify/fsnotify"
13
14 "github.com/redhat-developer/odo/pkg/dev"
15 odocontext "github.com/redhat-developer/odo/pkg/odo/context"
16 )
17
18 func evaluateChangesHandler(events []fsnotify.Event, path string, fileIgnores []string, watcher *fsnotify.Watcher) ([]string, []string) {
19 var changedFiles []string
20 var deletedPaths []string
21
22 for _, event := range events {
23 for _, file := range fileIgnores {
24
25 if event.Name == file {
26 continue
27 }
28 }
29
30 if event.Op&fsnotify.Remove == fsnotify.Remove || event.Op&fsnotify.Rename == fsnotify.Rename {
31
32 _ = watcher.Remove(event.Name)
33
34 deletedPaths = append(deletedPaths, event.Name)
35 continue
36 }
37
38 if event.Op&fsnotify.Remove != fsnotify.Remove {
39 changedFiles = append(changedFiles, event.Name)
40 }
41 }
42 return changedFiles, deletedPaths
43 }
44
45 func processEventsHandler(ctx context.Context, params WatchParameters, changedFiles, deletedPaths []string, componentStatus *ComponentStatus) error {
46 fmt.Fprintf(params.StartOptions.Out, "changedFiles %s deletedPaths %s\n", changedFiles, deletedPaths)
47 return nil
48 }
49
50 type fakeWatcher struct{}
51
52 func (o fakeWatcher) Stop() {
53 }
54
55 func (o fakeWatcher) ResultChan() <-chan watch.Event {
56 return make(chan watch.Event, 1)
57 }
58
59 func Test_eventWatcher(t *testing.T) {
60 type args struct {
61 parameters WatchParameters
62 }
63 tests := []struct {
64 name string
65 args args
66 wantOut string
67 wantErr bool
68 watcherEvents []fsnotify.Event
69 watcherError error
70 }{
71 {
72 name: "Case 1: Multiple events, no errors",
73 args: args{
74 parameters: WatchParameters{},
75 },
76 wantOut: "Pushing files...\n\nchangedFiles [file1 file2] deletedPaths []\n",
77 wantErr: false,
78 watcherEvents: []fsnotify.Event{{Name: "file1", Op: fsnotify.Create}, {Name: "file2", Op: fsnotify.Write}},
79 watcherError: nil,
80 },
81 {
82 name: "Case 2: Multiple events, one error",
83 args: args{
84 parameters: WatchParameters{},
85 },
86 wantOut: "",
87 wantErr: true,
88 watcherEvents: []fsnotify.Event{{Name: "file1", Op: fsnotify.Create}, {Name: "file2", Op: fsnotify.Write}},
89 watcherError: fmt.Errorf("error"),
90 },
91 {
92 name: "Case 3: Delete file, no error",
93 args: args{
94 parameters: WatchParameters{
95 StartOptions: dev.StartOptions{
96 IgnorePaths: []string{"file1"},
97 },
98 },
99 },
100 wantOut: "Pushing files...\n\nchangedFiles [] deletedPaths [file1 file2]\n",
101 wantErr: false,
102 watcherEvents: []fsnotify.Event{{Name: "file1", Op: fsnotify.Remove}, {Name: "file2", Op: fsnotify.Rename}},
103 watcherError: nil,
104 },
105 {
106 name: "Case 4: Only errors",
107 args: args{
108 parameters: WatchParameters{},
109 },
110 wantOut: "",
111 wantErr: true,
112 watcherEvents: nil,
113 watcherError: fmt.Errorf("error1"),
114 },
115 }
116 for _, tt := range tests {
117 t.Run(tt.name, func(t *testing.T) {
118 watcher, _ := fsnotify.NewWatcher()
119 fileWatcher, _ := fsnotify.NewWatcher()
120 var cancel context.CancelFunc
121 ctx, cancel := context.WithCancel(context.Background())
122 ctx = odocontext.WithDevfilePath(ctx, "/path/to/devfile")
123 ctx = odocontext.WithApplication(ctx, "odo")
124 ctx = odocontext.WithComponentName(ctx, "my-component")
125 out := &bytes.Buffer{}
126
127 go func() {
128 for _, event := range tt.watcherEvents {
129 watcher.Events <- event
130 }
131
132 if tt.watcherError != nil {
133 watcher.Errors <- tt.watcherError
134 }
135 <-time.After(500 * time.Millisecond)
136 cancel()
137 }()
138
139 componentStatus := ComponentStatus{}
140 componentStatus.SetState(StateReady)
141
142 o := WatchClient{
143 sourcesWatcher: watcher,
144 deploymentWatcher: fakeWatcher{},
145 podWatcher: fakeWatcher{},
146 warningsWatcher: fakeWatcher{},
147 devfileWatcher: fileWatcher,
148 keyWatcher: make(chan byte),
149 }
150 tt.args.parameters.StartOptions.Out = out
151
152 err := o.eventWatcher(ctx, tt.args.parameters, evaluateChangesHandler, processEventsHandler, componentStatus)
153 if (err != nil) != tt.wantErr {
154 t.Errorf("eventWatcher() error = %v, wantErr %v", err, tt.wantErr)
155 return
156 }
157
158 if gotOut := out.String(); gotOut != tt.wantOut {
159 t.Errorf("eventWatcher() gotOut = %v, want %v", gotOut, tt.wantOut)
160 }
161 })
162 }
163 }
164
View as plain text