From a22044c2c4bd94364fe8869df86810631bf0b66e Mon Sep 17 00:00:00 2001
From: Xiangrong Hao <falood@gmail.com>
Date: Sun, 23 Jul 2017 11:10:05 -0700
Subject: [PATCH] add more test when port stop or crash (#28)

* add more test when port stop or crash

* fix watcher port filter condition
---
 lib/file_system/backends/fs_inotify.ex |  7 +++++++
 lib/file_system/backends/fs_mac.ex     |  7 +++++++
 lib/file_system/backends/fs_windows.ex |  7 +++++++
 lib/file_system/worker.ex              |  3 ++-
 test/file_system_test.exs              | 23 ++++++++++++++++++++++-
 5 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/lib/file_system/backends/fs_inotify.ex b/lib/file_system/backends/fs_inotify.ex
index 141682f..b673b50 100644
--- a/lib/file_system/backends/fs_inotify.ex
+++ b/lib/file_system/backends/fs_inotify.ex
@@ -41,6 +41,8 @@ defmodule FileSystem.Backends.FSInotify do
       {:spawn_executable, to_charlist(find_executable())},
       [:stream, :exit_status, {:line, 16384}, {:args, port_args}, {:cd, System.tmp_dir!()}]
     )
+    Process.link(port)
+    Process.flag(:trap_exit, true)
     {:ok, %{port: port, worker_pid: args[:worker_pid]}}
   end
 
@@ -55,6 +57,11 @@ defmodule FileSystem.Backends.FSInotify do
     {:stop, :normal, state}
   end
 
+  def handle_info({:EXIT, port, _reason}, %{port: port}=state) do
+    send(state.worker_pid, {:backend_file_event, self(), :stop})
+    {:noreply, state}
+  end
+
   def handle_info(_, state) do
     {:noreply, state}
   end
diff --git a/lib/file_system/backends/fs_mac.ex b/lib/file_system/backends/fs_mac.ex
index f816f05..65d39b7 100644
--- a/lib/file_system/backends/fs_mac.ex
+++ b/lib/file_system/backends/fs_mac.ex
@@ -45,6 +45,8 @@ defmodule FileSystem.Backends.FSMac do
       {:spawn_executable, to_charlist(find_executable())},
       [:stream, :exit_status, {:line, 16384}, {:args, port_args}, {:cd, System.tmp_dir!()}]
     )
+    Process.link(port)
+    Process.flag(:trap_exit, true)
     {:ok, %{port: port, worker_pid: args[:worker_pid]}}
   end
 
@@ -59,6 +61,11 @@ defmodule FileSystem.Backends.FSMac do
     {:stop, :normal, state}
   end
 
+  def handle_info({:EXIT, port, _reason}, %{port: port}=state) do
+    send(state.worker_pid, {:backend_file_event, self(), :stop})
+    {:noreply, state}
+  end
+
   def handle_info(_, state) do
     {:noreply, state}
   end
diff --git a/lib/file_system/backends/fs_windows.ex b/lib/file_system/backends/fs_windows.ex
index 1242ebd..89b1ecb 100644
--- a/lib/file_system/backends/fs_windows.ex
+++ b/lib/file_system/backends/fs_windows.ex
@@ -40,6 +40,8 @@ defmodule FileSystem.Backends.FSWindows do
       {:spawn_executable, to_charlist(find_executable())},
       [:stream, :exit_status, {:line, 16384}, {:args, port_args}, {:cd, System.tmp_dir!()}]
     )
+    Process.link(port)
+    Process.flag(:trap_exit, true)
     {:ok, %{port: port, worker_pid: args[:worker_pid]}}
   end
 
@@ -54,6 +56,11 @@ defmodule FileSystem.Backends.FSWindows do
     {:stop, :normal, state}
   end
 
+  def handle_info({:EXIT, port, _reason}, %{port: port}=state) do
+    send(state.worker_pid, {:backend_file_event, self(), :stop})
+    {:noreply, state}
+  end
+
   def handle_info(_, state) do
     {:noreply, state}
   end
diff --git a/lib/file_system/worker.ex b/lib/file_system/worker.ex
index f110770..b771a6c 100644
--- a/lib/file_system/worker.ex
+++ b/lib/file_system/worker.ex
@@ -25,7 +25,8 @@ defmodule FileSystem.Worker do
   end
 
   def handle_info({:DOWN, _pid, _, ref, _reason}, state) do
-    {:noreply, pop_in(state.subscribers[ref])}
+    subscribers = Map.drop(state.subscribers, [ref]) |> IO.inspect
+    {:noreply, %{state | subscribers: subscribers}}
   end
 
   def handle_info(_, state) do
diff --git a/test/file_system_test.exs b/test/file_system_test.exs
index d63d690..750b5d3 100644
--- a/test/file_system_test.exs
+++ b/test/file_system_test.exs
@@ -1,13 +1,34 @@
 defmodule FileSystemTest do
   use ExUnit.Case, async: true
 
-  test "subscribe api" do
+  test "file event api" do
     tmp_dir = System.cmd("mktemp", ["-d"]) |> elem(0) |> String.trim
     {:ok, pid} = FileSystem.start_link(dirs: [tmp_dir])
     FileSystem.subscribe(pid)
+
     :timer.sleep(200)
     File.touch("#{tmp_dir}/a")
     assert_receive {:file_event, ^pid, {_path, _events}}, 5000
+
+    new_subscriber = spawn(fn ->
+      FileSystem.subscribe(pid)
+      :timer.sleep(10000)
+    end)
+    assert Process.alive?(new_subscriber)
+    Process.exit(new_subscriber, :kill)
+    refute Process.alive?(new_subscriber)
+
+    :timer.sleep(200)
+    File.touch("#{tmp_dir}/b")
+    assert_receive {:file_event, ^pid, {_path, _events}}, 5000
+
+    Port.list
+    |> Enum.reject(fn port ->
+      :undefined == port |> Port.info |> Access.get(:os_pid)
+    end)
+    |> Enum.each(&Port.close/1)
+    assert_receive {:file_event, ^pid, :stop}, 5000
+
     File.rm_rf!(tmp_dir)
   end
 end
-- 
GitLab