Elixir

2015-07-30 17 views
5

में पर्यवेक्षकों का परीक्षण करने के लिए सबसे अच्छा अभ्यास मैंने एक उचित बिट के आसपास गुगल किया है और विषय पर कुछ भी ढूंढने में असमर्थ हूं - या तो एलिक्सीर बहुत छोटी भाषा है या मैं गलत शर्तों से खोज रहा हूं।Elixir

मैं जोस वैलीम के इलीक्सिर पोर्टल ट्यूटोरियल (https://howistart.org/posts/elixir/1) के माध्यम से काम कर रहा हूं और अभ्यास के लिए परीक्षण तैयार कर रहा हूं (मैंने सभी कार्यक्षमताएं बनाई हैं)। ट्यूटोरियल के

भाग Portal.Door मॉड्यूल दोष सहिष्णु बनाने के लिए एक पर्यवेक्षक बनाने जा रहा है।

मैं (अगर यह अनुचित तरीके से बंद है जैसे कि पर्यवेक्षक के पुनः प्रारंभ Portal.Door उदाहरण) दोष सहिष्णुता परीक्षण करने के लिए निम्न कोड

defmodule PortalTest do 
    use ExUnit.Case, async: true 

    ... 

    test "supervisor restarts doors" do 
    {:ok, pid} = Portal.shoot(:third) 
    Process.unlink(pid) 
    Process.exit(pid, :shutdown) 
    assert Portal.Door.get(:third) == [] #new doors initialize with an empty array 
    end 

end 

का उपयोग कर कोशिश कर रहा हूँ लेकिन जब मैं चलाने मैं इस त्रुटि प्राप्त हो रही परीक्षण:

1) test supervisor restarts doors (PortalTest) 
    test/portal_test.exs:35 
    ** (exit) exited in: GenServer.call(:third, {:get, #Function<3.47016826/1 in Portal.Door.get/1>}, 5000) 
     ** (EXIT) shutdown 
    stacktrace: 
     (elixir) lib/gen_server.ex:356: GenServer.call/3 
     test/portal_test.exs:39 

तो, मुझे आश्चर्य है कि ऐसा करने का कोई बेहतर तरीका है या मेरा कोड बस खराब है।

उत्तर

1

Process.exit/1 एक निकास संकेत भेजता है लेकिन के लिए प्रक्रिया को रोकने के लिए इंतजार नहीं करता। आपके त्रुटि आउटपुट के आधार पर, ऐसा लगता है कि Portal.Door.get/1 तब विफल रहता है, क्योंकि gen_server प्रक्रिया कॉल संदेश प्राप्त करने से पहले समाप्त हो जाती है।

इस पर काबू पाने के लिए, आप बंद करने के लिए प्रक्रिया के लिए प्रतीक्षा करने, और फिर पुन: प्रारंभ करने की जरूरत है। एक्जिट सिग्नल जारी करने के बाद :timer.sleep/1 के माध्यम से एक साधारण उपाय एक संक्षिप्त नींद (100ms कहें) हो सकता है।

प्रक्रिया में समाप्त होने की प्रतीक्षा करने के लिए एक और अधिक शामिल दृष्टिकोण है, और फिर पुनरारंभ किया जाना चाहिए। पहले भाग को आसानी से एक मॉनिटर (Process.monitor/1 के माध्यम से) की स्थापना के द्वारा किया जा सकता है और इसी :DOWN संदेश के लिए प्रतीक्षा करें। ऐसा करके, आप यह भी सत्यापित करते हैं कि लक्ष्य प्रक्रिया वास्तव में समाप्त हो गई है।

तो आप के लिए प्रक्रिया को फिर से पुन: प्रारंभ करने प्रतीक्षा करने की आवश्यकता है, तो आप एक अनुरोध जारी कर सकते हैं। यह मुश्किल हो सकता है, और थोड़े समय के लिए सोना शायद सबसे आसान विकल्प है। या फिर, यदि प्रक्रिया एक स्थानीय उर्फ ​​तहत पंजीकृत है, तो आप Process.whereis/1 साथ मतदान जब तक आप एक गैर शून्य मूल्य है, जो बिंदु पर आप जानते हैं कि प्रक्रिया को फिर से चलाता है मिल सकता है।

+0

वास्तव में मैं अपना मूल विवरण वापस लेता हूं। ऐसा लगता है कि जब मैं कुछ डीबगिंग करने के लिए IO.inspect का उपयोग करता हूं तो यह देरी का कारण बनता है जो प्रक्रिया को पुनरारंभ करने के लिए काफी लंबा होता है। इसके बिना प्रक्रिया का इंतजार करने के लिए उपयोग करने के लिए रिकर्सन। कहीं भी/1 शून्य मूल्य के अलावा कुछ और लौटने के लिए काम नहीं लगता है (संभवतः मेरी गलती)। तो, मैं इसके साथ जा रहा हूं: timer.sleep/1 अभी के लिए। – user2577226

0

यहां एक कामकाजी कोड उदाहरण है, जो कि @sasajuric प्रदान की गई युक्तियों पर आधारित है।

defmodule Namer.Worker.Test do 
    use ExUnit.Case 

    test "supervisor restarts worker on server crash" do 
    pid = Process.whereis(Namer.Worker) 
    ref = Process.monitor(pid) 
    Process.exit(pid, :kill) 
    receive do 
     {:DOWN, ^ref, :process, ^pid, :killed} -> 
     :timer.sleep 1 
     assert is_pid(Process.whereis(Namer.Worker)) 
    after 
     1000 -> 
     raise :timeout 
    end 
    end 
end