package org.jooby.filewatcher;
import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertEquals;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchService;
import java.util.List;
import java.util.Map;
import org.jooby.Env;
import org.jooby.test.MockUnit;
import org.jooby.test.MockUnit.Block;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Binder;
import com.google.inject.binder.AnnotatedBindingBuilder;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.multibindings.Multibinder;
import com.typesafe.config.Config;
@RunWith(PowerMockRunner.class)
@PrepareForTest({FileWatcher.class, Multibinder.class, FileSystems.class, FileEventOptions.class,
Paths.class })
public class FileWatcherTest {
@SuppressWarnings({"rawtypes", "unchecked" })
private Block watcher = unit -> {
WatchService watcher = unit.get(WatchService.class);
FileSystem fs = unit.get(FileSystem.class);
expect(fs.newWatchService()).andReturn(watcher);
unit.mockStatic(FileSystems.class);
expect(FileSystems.getDefault()).andReturn(fs);
AnnotatedBindingBuilder abbws = unit.mock(AnnotatedBindingBuilder.class);
abbws.toInstance(watcher);
Binder binder = unit.get(Binder.class);
expect(binder.bind(WatchService.class)).andReturn(abbws);
};
@SuppressWarnings({"rawtypes", "unchecked" })
private Block filemonitor = unit -> {
AnnotatedBindingBuilder aab = unit.mock(AnnotatedBindingBuilder.class);
aab.asEagerSingleton();
Binder binder = unit.get(Binder.class);
expect(binder.bind(FileMonitor.class)).andReturn(aab);
};
@Test
public void newModule() throws Exception {
new MockUnit(Env.class, Config.class, Binder.class, WatchService.class, FileSystem.class)
.expect(watcher)
.expect(filewatcherProp(false))
.expect(filemonitor)
.run(unit -> {
new FileWatcher()
.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
});
}
@Test
public void registerPath() throws Exception {
new MockUnit(Env.class, Config.class, Binder.class, WatchService.class, FileSystem.class,
Path.class)
.expect(watcher)
.expect(filewatcherProp(false))
.expect(filemonitor)
.expect(fileeventoptions(FileEventHandler.class))
.run(unit -> {
FileWatcher watcher = new FileWatcher();
watcher.register(unit.get(Path.class), FileEventHandler.class)
.configure(unit.get(Env.class), unit.get(Config.class),
unit.get(Binder.class));
});
}
@Test
public void registerPathInstance() throws Exception {
FileEventHandler handler = (k, p) -> {
};
new MockUnit(Env.class, Config.class, Binder.class, WatchService.class, FileSystem.class,
Path.class)
.expect(watcher)
.expect(filewatcherProp(false))
.expect(filemonitor)
.expect(fileeventoptions(handler))
.run(unit -> {
FileWatcher watcher = new FileWatcher();
watcher.register(unit.get(Path.class), handler)
.configure(unit.get(Env.class), unit.get(Config.class),
unit.get(Binder.class));
});
}
@Test
public void registerPathInstanceCallback() throws Exception {
FileEventHandler handler = (k, p) -> {
};
new MockUnit(Env.class, Config.class, Binder.class, WatchService.class, FileSystem.class,
Path.class)
.expect(watcher)
.expect(filewatcherProp(false))
.expect(filemonitor)
.expect(fileeventoptions(handler))
.expect(unit -> {
FileEventOptions options = unit.get(FileEventOptions.class);
expect(options.recursive(true)).andReturn(options);
})
.run(unit -> {
FileWatcher watcher = new FileWatcher();
watcher.register(unit.get(Path.class), handler, options -> {
options.recursive(true);
})
.configure(unit.get(Env.class), unit.get(Config.class),
unit.get(Binder.class));
});
}
@SuppressWarnings({"unchecked", "rawtypes" })
@Test
public void registerFromConf() throws Exception {
new MockUnit(Env.class, Config.class, Binder.class, WatchService.class, FileSystem.class,
Path.class)
.expect(watcher)
.expect(filewatcherProp(true))
.expect(unit -> {
Config conf = unit.get(Config.class);
Map<String, Object> options = ImmutableMap.<String, Object> builder()
.put("path", "target")
.put("handler", FileEventHandler.class.getName())
.put("kind", ImmutableList.of("ENTRY_CREATE", "ENTRY_MODIFY"))
.put("recursive", false)
.put("includes", "*.cp")
.put("modifier", "LOW")
.build();
expect(conf.getAnyRef("filewatcher.register")).andReturn(options);
unit.mockStatic(Paths.class);
expect(Paths.get("target")).andReturn(unit.get(Path.class));
})
.expect(filemonitor)
.expect(fileeventoptions(FileEventHandler.class))
.expect(unit -> {
FileEventOptions options = unit.get(FileEventOptions.class);
expect(options.kind(unit.capture(WatchEvent.Kind.class))).andReturn(options);
expect(options.kind(unit.capture(WatchEvent.Kind.class))).andReturn(options);
expect(options.recursive(false)).andReturn(options);
expect(options.includes("*.cp")).andReturn(options);
expect(options.modifier(unit.capture(WatchEvent.Modifier.class))).andReturn(options);
})
.run(unit -> {
FileWatcher watcher = new FileWatcher();
watcher.configure(unit.get(Env.class), unit.get(Config.class),
unit.get(Binder.class));
}, unit -> {
List<Kind> kinds = unit.captured(WatchEvent.Kind.class);
assertEquals("ENTRY_CREATE", kinds.get(0).name());
assertEquals("ENTRY_MODIFY", kinds.get(1).name());
assertEquals("LOW", unit.captured(WatchEvent.Modifier.class).get(0).name());
});
}
@Test
public void registerPropPath() throws Exception {
new MockUnit(Env.class, Config.class, Binder.class, WatchService.class, FileSystem.class,
Path.class)
.expect(watcher)
.expect(filewatcherProp(false))
.expect(pathprop("property"))
.expect(filemonitor)
.expect(fileeventoptions(FileEventHandler.class))
.run(unit -> {
FileWatcher watcher = new FileWatcher();
watcher.register("property", FileEventHandler.class)
.configure(unit.get(Env.class), unit.get(Config.class),
unit.get(Binder.class));
});
}
@Test
public void registerPropPathInstance() throws Exception {
FileEventHandler handler = (k, p) -> {
};
new MockUnit(Env.class, Config.class, Binder.class, WatchService.class, FileSystem.class,
Path.class)
.expect(watcher)
.expect(filewatcherProp(false))
.expect(pathprop("property"))
.expect(filemonitor)
.expect(fileeventoptions(handler))
.run(unit -> {
FileWatcher watcher = new FileWatcher();
watcher.register("property", handler)
.configure(unit.get(Env.class), unit.get(Config.class),
unit.get(Binder.class));
});
}
@Test
public void registerPropPathInstanceOptions() throws Exception {
FileEventHandler handler = (k, p) -> {
};
new MockUnit(Env.class, Config.class, Binder.class, WatchService.class, FileSystem.class,
Path.class)
.expect(watcher)
.expect(filewatcherProp(false))
.expect(pathprop("property"))
.expect(filemonitor)
.expect(fileeventoptions(handler))
.expect(unit -> {
FileEventOptions options = unit.get(FileEventOptions.class);
expect(options.kind(StandardWatchEventKinds.ENTRY_CREATE)).andReturn(options);
})
.run(unit -> {
FileWatcher watcher = new FileWatcher();
watcher.register("property", handler, options -> {
options.kind(StandardWatchEventKinds.ENTRY_CREATE);
}).configure(unit.get(Env.class), unit.get(Config.class),
unit.get(Binder.class));
});
}
@Test
public void registerPropPathWithOptions() throws Exception {
new MockUnit(Env.class, Config.class, Binder.class, WatchService.class, FileSystem.class,
Path.class)
.expect(watcher)
.expect(filewatcherProp(false))
.expect(pathprop("prop"))
.expect(filemonitor)
.expect(fileeventoptions(FileEventHandler.class))
.expect(unit -> {
FileEventOptions options = unit.get(FileEventOptions.class);
expect(options.kind(StandardWatchEventKinds.ENTRY_CREATE)).andReturn(options);
})
.run(unit -> {
FileWatcher watcher = new FileWatcher();
watcher.register("prop", FileEventHandler.class, options -> {
options.kind(StandardWatchEventKinds.ENTRY_CREATE);
}).configure(unit.get(Env.class), unit.get(Config.class),
unit.get(Binder.class));
});
}
@Test
public void registerPathWithOptions() throws Exception {
new MockUnit(Env.class, Config.class, Binder.class, WatchService.class, FileSystem.class,
Path.class)
.expect(watcher)
.expect(filewatcherProp(false))
.expect(filemonitor)
.expect(fileeventoptions(FileEventHandler.class))
.expect(unit -> {
FileEventOptions options = unit.get(FileEventOptions.class);
expect(options.kind(StandardWatchEventKinds.ENTRY_CREATE)).andReturn(options);
})
.run(unit -> {
FileWatcher watcher = new FileWatcher();
watcher.register(unit.get(Path.class), FileEventHandler.class, options -> {
options.kind(StandardWatchEventKinds.ENTRY_CREATE);
}).configure(unit.get(Env.class), unit.get(Config.class),
unit.get(Binder.class));
});
}
@SuppressWarnings({"rawtypes", "unchecked" })
private Block fileeventoptions(final Object handler) {
return unit -> {
Binder binder = unit.get(Binder.class);
FileEventOptions options;
if (handler instanceof FileEventHandler) {
options = unit.constructor(FileEventOptions.class)
.args(Path.class, FileEventHandler.class)
.build(unit.get(Path.class), handler);
} else {
options = unit.constructor(FileEventOptions.class)
.args(Path.class, Class.class)
.build(unit.get(Path.class), handler);
}
unit.registerMock(FileEventOptions.class, options);
LinkedBindingBuilder lbb = unit.mock(LinkedBindingBuilder.class);
lbb.toInstance(options);
Multibinder mbinder = unit.mock(Multibinder.class);
unit.mockStatic(Multibinder.class);
expect(Multibinder.newSetBinder(binder, FileEventOptions.class)).andReturn(mbinder);
expect(mbinder.addBinding()).andReturn(lbb);
};
}
private Block filewatcherProp(final boolean b) {
return unit -> {
Config config = unit.get(Config.class);
expect(config.hasPath("filewatcher.register")).andReturn(b);
};
}
private Block pathprop(final String name) {
return unit -> {
Config conf = unit.get(Config.class);
expect(conf.getString(name)).andReturn("target");
unit.mockStatic(Paths.class);
expect(Paths.get("target")).andReturn(unit.get(Path.class));
};
}
}