Skip to content

Commit

Permalink
feat(ci): add dialyzer and improve workflows (elixir-grpc#248)
Browse files Browse the repository at this point in the history
* feat: improve ci and add dialyzer

* fix: mix_env=test for dialyzer

* fix: ci

* fix: dialyzeR

* chore: run fewer rounds for interop

* fix: scope plt cache by otp/elixir version

* fix: fallback key
  • Loading branch information
polvalente authored Jul 23, 2022
1 parent 8db5727 commit 0585e1f
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 68 deletions.
143 changes: 102 additions & 41 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: CI
on:
pull_request:
branches:
- '**'
- "**"
push:
branches:
- master
Expand All @@ -18,6 +18,12 @@ jobs:
with:
otp-version: 24
elixir-version: 1.13.1
- name: Retrieve dependencies cache
uses: actions/cache@v1
id: mix-cache # id to use in retrieve action
with:
path: deps
key: v1-${{ matrix.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
- name: Install Dependencies
run: |
mix local.rebar --force
Expand All @@ -40,39 +46,51 @@ jobs:
elixir: 1.12.x
needs: check_format
steps:
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: ${{matrix.otp}}
elixir-version: ${{matrix.elixir}}
- name: Install Dependencies
run: |
mix local.rebar --force
mix local.hex --force
mix deps.get
- name: Run Tests
run: mix test
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: ${{matrix.otp}}
elixir-version: ${{matrix.elixir}}
- name: Retrieve dependencies cache
uses: actions/cache@v1
id: mix-cache # id to use in retrieve action
with:
path: deps
key: v1-${{ matrix.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
- name: Install Dependencies
run: |
mix local.rebar --force
mix local.hex --force
mix deps.get
- name: Run Tests
run: mix test

interop-tests:
runs-on: ubuntu-latest
name: Interop tests
needs: check_format
if: ${{ github.ref != 'refs/heads/master' }}
steps:
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: 25.x
elixir-version: 1.13.x
- name: Install Dependencies
run: |
mix local.rebar --force
mix local.hex --force
mix deps.get
working-directory: ./interop
- name: Run interop tests
run: mix run script/run.exs
working-directory: ./interop
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: 25.x
elixir-version: 1.13.x
- name: Retrieve dependencies cache
uses: actions/cache@v1
id: mix-cache # id to use in retrieve action
with:
path: deps
key: v1-${{ matrix.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
- name: Install Dependencies
run: |
mix local.rebar --force
mix local.hex --force
mix deps.get
working-directory: ./interop
- name: Run interop tests
run: mix run script/run.exs --rounds 64
working-directory: ./interop

interop-tests-all:
runs-on: ubuntu-latest
Expand All @@ -89,20 +107,57 @@ jobs:
- otp: 25.x
elixir: 1.12.x
steps:
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: 25.x
elixir-version: 1.13.x
- name: Install Dependencies
run: |
mix local.rebar --force
mix local.hex --force
mix deps.get
working-directory: ./interop
- name: Run interop tests
run: mix run script/run.exs
working-directory: ./interop
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: 25.x
elixir-version: 1.13.x
- name: Retrieve dependencies cache
uses: actions/cache@v1
id: mix-cache # id to use in retrieve action
with:
path: deps
key: v1-${{ matrix.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
- name: Install Dependencies
run: |
mix local.rebar --force
mix local.hex --force
mix deps.get
working-directory: ./interop
- name: Run interop tests
run: mix run script/run.exs --rounds 64
working-directory: ./interop

dialyzer:
name: Dialyzer
runs-on: ubuntu-latest
strategy:
matrix:
otp: [24.x, 25.x]
elixir: [1.13.x]
env:
MIX_ENV: test
steps:
- uses: actions/checkout@v2
- id: set_vars
run: |
mix_hash="${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}"
echo "::set-output name=mix_hash::$mix_hash"
- id: cache-plt
uses: actions/cache@v2
with:
path: |
_build/test/plts/dialyzer.plt
_build/test/plts/dialyzer.plt.hash
key: plt-cache-${{ matrix.otp }}-${{ matrix.elixir }}-${{ steps.set_vars.outputs.mix_hash }}
restore-keys: |
plt-cache-${{ matrix.otp }}-${{ matrix.elixir }}-
- uses: erlef/setup-beam@v1
with:
otp-version: ${{matrix.otp}}
elixir-version: ${{matrix.elixir}}
- run: mix deps.get
- run: mix dialyzer --format short

check_release:
runs-on: ubuntu-latest
Expand All @@ -114,6 +169,12 @@ jobs:
with:
otp-version: 24
elixir-version: 1.13.1
- name: Retrieve dependencies cache
uses: actions/cache@v1
id: mix-cache # id to use in retrieve action
with:
path: deps
key: v1-${{ matrix.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
- name: Install Dependencies
run: |
mix local.rebar --force
Expand Down
2 changes: 2 additions & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
elixir 1.13.3-otp-25
erlang 25.0.3
36 changes: 19 additions & 17 deletions interop/lib/interop/client.ex
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
defmodule Interop.Client do
import ExUnit.Assertions, only: [refute: 1]

require Logger

def connect(host, port, opts \\ []) do
{:ok, ch} = GRPC.Stub.connect(host, port, opts)
ch
end

def empty_unary!(ch) do
IO.puts("Run empty_unary!")
Logger.info("Run empty_unary!")
empty = Grpc.Testing.Empty.new()
{:ok, ^empty} = Grpc.Testing.TestService.Stub.empty_call(ch, empty)
end
Expand All @@ -17,21 +19,21 @@ defmodule Interop.Client do
end

def large_unary!(ch) do
IO.puts("Run large_unary!")
Logger.info("Run large_unary!")
req = Grpc.Testing.SimpleRequest.new(response_size: 314_159, payload: payload(271_828))
reply = Grpc.Testing.SimpleResponse.new(payload: payload(314_159))
{:ok, ^reply} = Grpc.Testing.TestService.Stub.unary_call(ch, req)
end

def large_unary2!(ch) do
IO.puts("Run large_unary2!")
Logger.info("Run large_unary2!")
req = Grpc.Testing.SimpleRequest.new(response_size: 1024*1024*8, payload: payload(1024*1024*8))
reply = Grpc.Testing.SimpleResponse.new(payload: payload(1024*1024*8))
{:ok, ^reply} = Grpc.Testing.TestService.Stub.unary_call(ch, req)
end

def client_compressed_unary!(ch) do
IO.puts("Run client_compressed_unary!")
Logger.info("Run client_compressed_unary!")
# "Client calls UnaryCall with the feature probe, an uncompressed message" is not supported

req = Grpc.Testing.SimpleRequest.new(expect_compressed: %{value: true}, response_size: 314_159, payload: payload(271_828))
Expand All @@ -44,7 +46,7 @@ defmodule Interop.Client do
end

def server_compressed_unary!(ch) do
IO.puts("Run server_compressed_unary!")
Logger.info("Run server_compressed_unary!")

req = Grpc.Testing.SimpleRequest.new(response_compressed: %{value: true}, response_size: 314_159, payload: payload(271_828))
reply = Grpc.Testing.SimpleResponse.new(payload: payload(314_159))
Expand All @@ -57,7 +59,7 @@ defmodule Interop.Client do
end

def client_streaming!(ch) do
IO.puts("Run client_streaming!")
Logger.info("Run client_streaming!")

stream =
ch
Expand All @@ -79,7 +81,7 @@ defmodule Interop.Client do
end

def client_compressed_streaming!(ch) do
IO.puts("Run client_compressed_streaming!")
Logger.info("Run client_compressed_streaming!")

# INVALID_ARGUMENT testing is not supported

Expand All @@ -97,7 +99,7 @@ defmodule Interop.Client do
end

def server_streaming!(ch) do
IO.puts("Run server_streaming!")
Logger.info("Run server_streaming!")
params = Enum.map([31415, 9, 2653, 58979], &res_param(&1))
req = Grpc.Testing.StreamingOutputCallRequest.new(response_parameters: params)
{:ok, res_enum} = ch |> Grpc.Testing.TestService.Stub.streaming_output_call(req)
Expand All @@ -110,7 +112,7 @@ defmodule Interop.Client do
end

def server_compressed_streaming!(ch) do
IO.puts("Run server_compressed_streaming!")
Logger.info("Run server_compressed_streaming!")
req = Grpc.Testing.StreamingOutputCallRequest.new(response_parameters: [
%{compressed: %{value: true},
size: 31415},
Expand All @@ -127,7 +129,7 @@ defmodule Interop.Client do
end

def ping_pong!(ch) do
IO.puts("Run ping_pong!")
Logger.info("Run ping_pong!")
stream = Grpc.Testing.TestService.Stub.full_duplex_call(ch)

req = fn size1, size2 ->
Expand Down Expand Up @@ -156,7 +158,7 @@ defmodule Interop.Client do
end

def empty_stream!(ch) do
IO.puts("Run empty_stream!")
Logger.info("Run empty_stream!")

{:ok, res_enum} =
ch
Expand All @@ -168,7 +170,7 @@ defmodule Interop.Client do
end

def custom_metadata!(ch) do
IO.puts("Run custom_metadata!")
Logger.info("Run custom_metadata!")
# UnaryCall
req = Grpc.Testing.SimpleRequest.new(response_size: 314_159, payload: payload(271_828))
reply = Grpc.Testing.SimpleResponse.new(payload: payload(314_159))
Expand Down Expand Up @@ -205,7 +207,7 @@ defmodule Interop.Client do
end

def status_code_and_message!(ch) do
IO.puts("Run status_code_and_message!")
Logger.info("Run status_code_and_message!")

code = 2
msg = "test status message"
Expand All @@ -227,23 +229,23 @@ defmodule Interop.Client do
end

def unimplemented_service!(ch) do
IO.puts("Run unimplemented_service!")
Logger.info("Run unimplemented_service!")
req = Grpc.Testing.Empty.new()

{:error, %GRPC.RPCError{status: 12}} =
Grpc.Testing.TestService.Stub.unimplemented_call(ch, req)
end

def cancel_after_begin!(ch) do
IO.puts("Run cancel_after_begin!")
Logger.info("Run cancel_after_begin!")
stream = Grpc.Testing.TestService.Stub.streaming_input_call(ch)
stream = GRPC.Stub.cancel(stream)
error = GRPC.RPCError.exception(1, "The operation was cancelled")
{:error, ^error} = GRPC.Stub.recv(stream)
end

def cancel_after_first_response!(ch) do
IO.puts("Run cancel_after_first_response!")
Logger.info("Run cancel_after_first_response!")

req =
Grpc.Testing.StreamingOutputCallRequest.new(
Expand All @@ -264,7 +266,7 @@ defmodule Interop.Client do
end

def timeout_on_sleeping_server!(ch) do
IO.puts("Run timeout_on_sleeping_server!")
Logger.info("Run timeout_on_sleeping_server!")

req =
Grpc.Testing.StreamingOutputCallRequest.new(
Expand Down
21 changes: 13 additions & 8 deletions interop/script/run.exs
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
{options, _, _} = OptionParser.parse(System.argv(), strict: [rounds: :integer, concurrency: :integer, port: :integer])
rounds = Keyword.get(options, :rounds) || 100
max_concurrency = System.schedulers_online() |> div(2) |> min(1)
max_concurrency = System.schedulers_online()
concurrency = Keyword.get(options, :concurrency) || max_concurrency
port = Keyword.get(options, :port) || 0
level = Keyword.get(options, :log_level) || "warn"
level = String.to_existing_atom(level)

IO.puts "Rounds: #{rounds}; concurrency: #{concurrency}; port: #{port}"
IO.puts ""
require Logger

Logger.configure(level: level)

Logger.warn("Rounds: #{rounds}; concurrency: #{concurrency}; port: #{port}")

alias Interop.Client

{:ok, _pid, port} = GRPC.Server.start_endpoint(Interop.Endpoint, port)

stream = Task.async_stream(1..concurrency, fn cli ->
stream = Task.async_stream(1..concurrency, fn _cli ->
ch = Client.connect("127.0.0.1", port, interceptors: [GRPCPrometheus.ClientInterceptor, GRPC.Logger.Client])
run = fn(i) ->
IO.puts("Client##{cli}, Round #{i}")

for _ <- 1..rounds do
Client.empty_unary!(ch)
Client.cacheable_unary!(ch)
Client.large_unary!(ch)
Expand All @@ -33,7 +39,6 @@ stream = Task.async_stream(1..concurrency, fn cli ->
Client.cancel_after_first_response!(ch)
Client.timeout_on_sleeping_server!(ch)
end
Enum.each(1..rounds, run)
:ok
end, max_concurrency: concurrency, ordered: false, timeout: :infinity)

Expand All @@ -55,5 +60,5 @@ end)
# end
# Helper.flush()

IO.puts("Succeed!")
Logger.warn("Succeed!")
:ok = GRPC.Server.stop_endpoint(Interop.Endpoint)
Loading

0 comments on commit 0585e1f

Please sign in to comment.