Phoenix 1.4.0-dev generated channel test fails with compile error - phoenix-framework

I am developing a web app with the Phoenix framework in a Docker container. Here are the relevant lines in the dockerfile for how phoenix is getting installed:
RUN git clone https://github.com/phoenixframework/phoenix
RUN cd /home/user/phoenix/installer/ && MIX_ENV=prod mix do archive.build, archive.install --force
That all works fine. I can generate a new phoenix project with the command:
mix phx.new hello_phoenix
However, when I generate a new channel with:
mix phx.gen.channel hello_channel
and add this line to the user socket file
channel "hello_channel:lobby", HelloPhoenixWeb.HelloChannelChannel
and then run
mix test
I get the following errors:
warning: Phoenix.ChannelTest.socket/2 is deprecated, please call socket/3 instead
(phoenix) lib/phoenix/test/channel_test.ex:234: Phoenix.ChannelTest."MACRO-socket"/3
(elixir) src/elixir_dispatch.erl:186: :elixir_dispatch.expand_macro_fun/6
(elixir) src/elixir_dispatch.erl:149: :elixir_dispatch.do_expand_import/6
(elixir) src/elixir_dispatch.erl:81: :elixir_dispatch.dispatch_import/5
(elixir) src/elixir_expand.erl:539: :elixir_expand.expand_arg/2
(stdlib) lists.erl:1354: :lists.mapfoldl/3
(elixir) src/elixir_expand.erl:548: :elixir_expand.expand_args/2
(elixir) src/elixir_expand.erl:646: :elixir_expand.expand_remote/7
(elixir) src/elixir_dispatch.erl:207: :elixir_dispatch.expand_quoted/6
(elixir) src/elixir_expand.erl:10: :elixir_expand.expand/2
(elixir) src/elixir_expand.erl:489: :elixir_expand.expand_block/4
(elixir) src/elixir_expand.erl:39: :elixir_expand.expand/2
(elixir) src/elixir_clauses.erl:19: :elixir_clauses.def/2
(elixir) src/elixir_def.erl:146: :elixir_def."-store_definition/10-lc$^0/1-0-"/2
(elixir) src/elixir_def.erl:146: :elixir_def.store_definition/10
test/hello_phoenix_web/channels/hello_channel_channel_test.exs:6: (module)
(elixir) src/elixir_compiler.erl:85: :elixir_compiler.dispatch/6
..
== Compilation error in file test/hello_phoenix_web/channels/hello_channel_channel_test.exs ==
** (CaseClauseError) no case clause matching: [{"/socket", HelloPhoenixWeb.UserSocket, [], [{["socket", "websocket"], {:websocket, HelloPhoenixWeb.UserSocket, [serializer: [{Phoenix.Socket.V1.JSONSerializer, "~> 1.0.0"}, {Phoenix.Socket.V2.JSONSerializer, "~> 2.0.0"}], timeout: 60000, transport_log: false, compress: false]}}]}]
(phoenix) lib/phoenix/test/channel_test.ex:240: Phoenix.ChannelTest.first_socket!/1
(phoenix) lib/phoenix/test/channel_test.ex:213: Phoenix.ChannelTest.build_socket/4
(phoenix) expanding macro: Phoenix.ChannelTest.socket/2
test/hello_phoenix_web/channels/hello_channel_channel_test.exs:8: HelloPhoenixWeb.HelloChannelChannelTest.__ex_unit_setup_1/1
(elixir) expanding macro: Kernel.|>/2
test/hello_phoenix_web/channels/hello_channel_channel_test.exs:9: HelloPhoenixWeb.HelloChannelChannelTest.__ex_unit_setup_1/1
(elixir) lib/code.ex:677: Code.require_file/2
(elixir) lib/kernel/parallel_compiler.ex:201: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6
Here's the code for the channel file that was generated by the mix phx.gen.channel task:
defmodule HelloPhoenixWeb.HelloChannelChannel do
use HelloPhoenixWeb, :channel
def join("hello_channel:lobby", payload, socket) do
if authorized?(payload) do
{:ok, socket}
else
{:error, %{reason: "unauthorized"}}
end
end
# Channels can be used in a request/response fashion
# by sending replies to requests from the client
def handle_in("ping", payload, socket) do
{:reply, {:ok, payload}, socket}
end
# It is also common to receive messages from the client and
# broadcast to everyone in the current topic (hello_channel:lobby).
def handle_in("shout", payload, socket) do
broadcast socket, "shout", payload
{:noreply, socket}
end
# Add authorization logic here as required.
defp authorized?(_payload) do
true
end
end
And here's the code for the test that was generated also:
defmodule HelloPhoenixWeb.HelloChannelChannelTest do
use HelloPhoenixWeb.ChannelCase
alias HelloPhoenixWeb.HelloChannelChannel
setup do
{:ok, _, socket} =
socket("user_id", %{some: :assign})
|> subscribe_and_join(HelloChannelChannel, "hello_channel:lobby")
{:ok, socket: socket}
end
test "ping replies with status ok", %{socket: socket} do
ref = push socket, "ping", %{"hello" => "there"}
assert_reply ref, :ok, %{"hello" => "there"}
end
test "shout broadcasts to hello_channel:lobby", %{socket: socket} do
push socket, "shout", %{"hello" => "all"}
assert_broadcast "shout", %{"hello" => "all"}
end
test "broadcasts are pushed to the client", %{socket: socket} do
broadcast_from! socket, "broadcast", %{"some" => "data"}
assert_push "broadcast", %{"some" => "data"}
end
end
I have this problem with an actual project I'm working on and also with a test project I spun up to isolate the problem.
What is causing the compilation error with the test that the generator made?

Phoenix framework 1.4 is still in development state so bugs are pretty much not surprising. Phoenix framwork 1.3.x is current stable version, you should use that. And if you know what your are doing with 1.4-dev build than you should raise a issue on Phoenix Framework github repo.

Related

How to raise timeout error in unittesting

This is first time i am touching ruby, so no sure about correct terminology. I have tried searching for mulitple things, but couldn't find a solution.
I have this code block
domain_response = MyDomain::Api::MyApi::Api.new(parameters: message.to_domain_object, timeout: 1000)
# :nocov:
case (response = domain_response.response)
when MyDomain::Api::MyApi::SuccessResponse
## do something
when Domain::ErrorResponses::TimeoutResponse
## do something.
now i am trying to testing TimeoutResponse, I have written(tried) this
it "when api call timesout" do
expect(MyDomain::Api::MyApi::Api).to{
receive(:new)
} raise_error(MyDomain::ErrorResponses::TimeoutResponse)
end
this gave me error that unexpected identifier.
I have also tried by not providing receive, and it gave me error that block is expected.
Whats the proper way to raise an error that i can test?
Update:
Here is where i am stuck now
it "when api call timesout" do
# 1
expect(MyDomain::Api::MyApi::Api).to(
receive(:new),
).and_return(domain_api_instance)
# 2
expect(domain_api_instance.response).to receive(:response).and_raise(Domain::ErrorResponses::TimeoutResponse)
expect(domain_api_instance.response).to eq(ApiError::Timeout)
end
But with this code i am getting this error
1) Rpc::Package::SubPackage::V1::PackageService#first_test testing when api call timesout
Failure/Error: expect(domain_api_instance.response).to receive(:response).and_raise(Domain::ErrorResponses::TimeoutResponse)
#<InstanceDouble(MyDomain::Api::MyApi::Api) (anonymous)> received unexpected message :response with (no args)

How to get devcards working with shadow-cljs

My devcards used to work with Figwheel. However I can't get them to display with shadow-cljs.
Shadow emits this message:
shadow-cljs - HTTP server for :cards available at http://localhost:3450
The namespace cards.card-ui is just a series of requires.
I have a println message in cards.card-ui that is being displayed.
In shadow-cljs.edn I have two :builds. This is the second one:
:cards {:target :browser
:output-dir "resources/public/js/cards"
:asset-path "js/cards"
:modules {:main {:entries [cards.card-ui]}}
:compiler-options {:static-fns false}
:devtools {:http-root "resources/public"
:http-resource-root "resources/public"
:http-port 3450
:http-handler shadow.http.push-state/handle
:push-state/index "cards.html"
:preloads [devtools.preload
default-db-format.preload]}
:dev {:compiler-options {:devcards true}}
}
cards.html has a body tag that has a div tag that has id "app". I take the browser to http://localhost:3450/cards.html and just get a blank page. My best theory is that the cards.card-ui namespace is not being mounted at app.
Currently the only way to get an example Fulcro application that uses shadow-cljs rather than Figwheel is via the lein template. So at the command prompt:
lein new fulcro app shadow-cljs
Here app is any name you choose and shadow-cljs is an option. After studying the resultant application I realised that the namespace cards.card-ui should not just be a list of requires, but needs to have these lines as well:
(devcards.core/start-devcard-ui!)
(defn refresh []
(println "In cards.card-ui that starts the ui"))
The :cards build in shadow-cljs.edn becomes a bit simpler:
:cards {:target :browser
:output-dir "resources/public/js/cards"
:asset-path "js/cards"
:compiler-options {:devcards true}
:modules {:main
{:entries [cards.card-ui]}}
:devtools {:after-load cards.card-ui/refresh
:http-root "resources/public"
:http-port 3450}
}
Another thing I had wrong was the HTML (cards.html). Here is just the body tag of the markup:
<body>
<div id="app"></div>
<script src="js/cards/main.js"></script>
</body>
Some import pointers from the Devcards site: https://github.com/bhauman/devcards#usage-without-figwheel
The lein template project: https://github.com/fulcrologic/fulcro-lein-template

Elixir: Nebulex (Caching library) error

I'm new to Elixir, trying to use Nebulex for making a simple local cache (Panda.Cache). I followed its tutorial but finally, by doing these commands:
data = %{id: 1, text: "hello"}
Mycache.set(data[:id], data)
I get this error:
** (ArgumentError) argument error
(stdlib) :ets.lookup_element(Panda.Cache, :metadata, 2)
(nebulex) lib/nebulex/adapters/local/metadata.ex:19: Nebulex.Adapters.Local.Metadata.get/1
(nebulex) lib/nebulex/adapters/local.ex:177: Nebulex.Adapters.Local.set/4
(panda) lib/panda/cache.ex:2: Panda.Cache.execute/2
Panda is the name of my Elixir app and Panda.Cache the name of the cache I'm trying to make.
Any help or solution would be appreciated. Thank you in advance.
Update:
Project folders and files are like:
panda
config
config.exs
lib
panda.ex
panda
application.ex
cache.ex
config.exs file:
use Mix.Config
config :panda, Panda.Cache,
adapter: Nebulex.Adapters.Local,
gc_interval: 86_400 # 24 hrs
cache.ex file:
defmodule Panda.Cache do
use Nebulex.Cache, otp_app: :panda
end
application.ex file:
defmodule Panda.Application do
use Application
def start(_type, _args) do
import Supervisor.Spec
children = [
supervisor(Panda.Cache, [])
]
opts = [strategy: :one_for_one, name: Panda.Supervisor]
Supervisor.start_link(children, opts)
end
end
And, how I tried to use the cache in my code:
defmodule Panda do
def mytest do
data = %{id: 1, text: "hello"}
Panda.Cache.set(data[:id], data)
end
end
According to your code in GitHub (https://github.com/ab00zar/FirstElixirCode), in the mix.exs file you are missing the app module, currently it is like this:
def application do
[
extra_applications: [:logger]
]
end
But it should be like this:
def application do
[
extra_applications: [:logger],
mod: {Panda.Application, []}
]
end
Because of this, your app (and supervision tree) it is not being started and the cache (Nebulex) is started as part of your supervision tree. Let me know if that works for you.
I tried the code you posted, but I cannot replicate the error.
When something like this happens I often do the following:
mix deps.clean --all
mix clean
mix deps.get
mix deps.compile
mix compile
and then I try again.
I hope this helps :)

** (Mix) Could not start application rumbl: Rumbl.start(:normal, [])

If you have the next error in your terminal:
(Mix) Could not start application rumbl: Rumbl.start(:normal, []) returned an error: shutdown: failed to start child: Rumbl.Repo
(EXIT) an exception was raised:
(UndefinedFunctionError) undefined function Rumbl.Repo.start_link/0
(rumbl) Rumbl.Repo.start_link()
(stdlib) supervisor.erl:358: :supervisor.do_start_child/2
(stdlib) supervisor.erl:341: :supervisor.start_children/3
(stdlib) supervisor.erl:307: :supervisor.init_children/2
(stdlib) gen_server.erl:328: :gen_server.init_it/6
(stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Just add this before last end, in your repo.ex file:
def start_link do
{:ok, self}
end
In lib/rumbl.ex, comment out the line that starts the repository:
# Start the Ecto repository
# supervisor(Rumbl.Repo, []),

cucumber ActiveRecord::ConnectionNotEstablished

The exception I am getting is "ActiveRecord::ConnectionNotEstablished: No connection pool for ActiveRecord::Base". I am really on the deep end of the pool (no pun intended) with this one. I really don't understand the connection and connection pool handling, even as much as I have studied this problem. I'm assuming this might be scope related inside of Cucumber, but I do not know. Any and all assistance is appreciated.
Here are the details:
The exception occurs when I perform a count from a Then clause:
WorkTable.where('? is not null',col['COLUMN_NAME']).count
It does not occur if I send the sql directly through the connection:
WorkTable.connection.select_all(st.encode('utf-8')).first['nulls']
My scenario reads as follows:
Scenario: CompanyMaster test for null value
Given table dbo.base_table in stage
Then these columns are expected to be not null
| COLUMN_NAME | nulls |
| id | 0 |
| company_name | 0 |
I establish my class in my env.rb:
class WorkTable < ActiveRecord::Base
end
ActiveRecord::Base.configurations = YAML.load_file(yaml) # yaml is database.yml file name
I establish my connection in a Given clause:
Given(/^table (\w+)\.?([\w_]+) in (\w+)(?: as (\w+))?$/) do |schema,name,env,id|
#sc_name = schema_file_name(schema,name)
WorkTable.logger.info title_line("* Active table(#{#sc_name}) *")
case id
# ActiveRecord::Base.configurations[env]
...
else
WorkTable.table_name = #sc_name
WorkTable.establish_connection(env.to_sym)
# ary = get_tables(WorkTable,schema:schema)
# expect( ary.any?{|s| s.casecmp(name)==0 } ).to eq(true)
end
end
I execute my test in a Then clause:
Then(/^these columns are expected to be not null$/) do |columns|
# expected is an instance of Cucumber::Ast::Table
WorkTable.logger.info title_line('Columns cannot be null')
results = []
columns.hashes.each {|col|
results << {
'COLUMN_NAME' => col['COLUMN_NAME'],
'nulls' => WorkTable.where('? is not null',col['COLUMN_NAME']).count.to_s
}
}
columns.diff!(results,surplus_row: false)
end
It is the WorkTable.where that throws the "ActiveRecord::ConnectionNotEstablished: No connection pool for ActiveRecord::Base". Again, if I use the WorkTable.connection method, I do not get it. Also, it executes fine if I copy all the function code to single ruby script.
I see the following when I "pp WorkTable.connection":
#<ActiveRecord::ConnectionAdapters::SQLServerAdapter version: 4.2.2, mode: dblib, azure: false>
And I see the following when I "pp WorkTable.connection_pool":
#<ActiveRecord::ConnectionAdapters::ConnectionPool:0x42f5238
#automatic_reconnect=true,
#available=
#<ActiveRecord::ConnectionAdapters::ConnectionPool::Queue:0x42f4f20
#cond=
#<MonitorMixin::ConditionVariable:0x42f4ed8
#cond=
#<ConditionVariable:0x42f4de8
#waiters=[],
#waiters_mutex=#<Mutex:0x42f4d58>>,
#monitor=
#<ActiveRecord::ConnectionAdapters::ConnectionPool:0x42f5238 ...>>,
#lock=#<ActiveRecord::ConnectionAdapters::ConnectionPool:0x42f5238 ...>,
#num_waiting=0,
#queue=[]>,
#checkout_timeout=5,
#connections=
[#<ActiveRecord::ConnectionAdapters::SQLServerAdapter version: 4.2.2, mode: dblib, azure: false>],
#mon_count=0,
#mon_mutex=#<Mutex:0x42f51c0>,
#mon_owner=nil,
#reaper=
#<ActiveRecord::ConnectionAdapters::ConnectionPool::Reaper:0x42f51a8
#frequency=nil,
#pool=#<ActiveRecord::ConnectionAdapters::ConnectionPool:0x42f5238 ...>>,
#reserved_connections=
#<ThreadSafe::Cache:0x42f4fc8
#backend=
{16931712=>
#<ActiveRecord::ConnectionAdapters::SQLServerAdapter version: 4.2.2, mode: dblib, azure: false>},
#default_proc=nil>,
#size=5,
#spec=
#<ActiveRecord::ConnectionAdapters::ConnectionSpecification:0x42f55c8
#adapter_method="sqlserver_connection",
#config=
{:host=>"server_name",
:database=>"mssb_stg",
:encoding=>"utf-8",
:adapter=>"sqlserver",
:timeout=>5000}>>
Ruby 1.9.3, activerecord (4.2.0), activerecord-sqlserver-adapter (4.2.2), and cucumber (1.3.18). And sql server 2014 [this has been a bugger for me].
Thank you for you time and consideration.
dvn
== Additional detail ==
Ignore the sql-server reference. I get the same exception when I reconfigure to work with SqLite. So it is not related to db platform.
Check your env.rb, conf in supports, it seems you are making connections in steps, ideally you should do it in before_scenario or before feature file rather than per steps.
It could be possible after steps your connection is not working properly.

Resources