From e3d6c70c8828a76a64f5536a922f277e4d59317c Mon Sep 17 00:00:00 2001 From: Darren Klein Date: Wed, 25 Sep 2019 11:33:57 -0400 Subject: [PATCH] Add instructions for running integration tests against local DDB, make sure to delete test tables after running integration, version bump to 2.2.2 --- .gitignore | 3 ++ README.md | 33 +++++++++++++++++++++ config/config.exs | 40 +------------------------- config/dev.exs | 7 +++++ config/test_options.exs | 2 ++ mix.exs | 2 +- test/lib/dynamo/integration_test.exs | 43 ++++++++++++++-------------- test/support/ddb_local.ex | 16 +++++++++++ 8 files changed, 85 insertions(+), 61 deletions(-) create mode 100644 config/dev.exs create mode 100644 test/support/ddb_local.ex diff --git a/.gitignore b/.gitignore index 12179ea..75dcd56 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ erl_crash.dump # Also ignore archive artifacts (built via "mix archive.build"). *.ez + +# Ignore config/test.exs to avoid unintentionally interfering with a user's local DDB instance. See README. +config/test.exs diff --git a/README.md b/README.md index f8f8b6e..228edb9 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,39 @@ config :ex_aws, :dynamodb, decode_sets: true ``` +## Local testing + +This application supports three test commands: + +* `mix test` - run the normal test suite +* `mix test.options` - run the test suite with options enabled (see `config/test_options.exs`) +* `mix test.all` - run `mix test` and `mix test.options` sequentially + +### Integration tests (optional) + +The tests in `test/lib/dynamo/integration_test.exs` will attempt to run against a running local instance of DynamoDB - in order to run these tests, you will need both a running local instance of DynamoDB as well as a `config/test.exs` file (currently gitignored) formatted like so: + +`config/test.exs` +```elixir +use Mix.Config + +config :ex_aws, :dynamodb, + scheme: "http://", + host: "localhost", + port: CHOOSE_YOUR_TEST_PORT, + region: "us-east-1" + +config :ex_aws, + debug_requests: true, + access_key_id: "abcd", + secret_access_key: "1234", + region: "us-east-1" +``` + +Before setting the `port`, be aware that `integration_test.exs` will create and delete tables with the names `"TestUsers", Test.User, "TestSeveralUsers", TestFoo, "test_books", "TestUsersWithRange"` - be careful when setting the port, as these operations may interfere with your current tables if they share any of those names. + +If you do not have a running local instance of DynamoDB and/or you don't provide a `config/test.exs` file, the integration tests will hang for a few seconds before returning `invalid` - this will not interfere with the successful execution of other tests. + ## License The MIT License (MIT) diff --git a/config/config.exs b/config/config.exs index 91d0805..c9c59bb 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,41 +1,3 @@ -# This file is responsible for configuring your application -# and its dependencies with the aid of the Mix.Config module. use Mix.Config -config :ex_aws, :dynamodb, - scheme: "http://", - host: "localhost", - port: 8000, - region: "us-east-1" - -case Mix.env do - :test_options -> import_config "test_options.exs" - _ -> nil -end - -# This configuration is loaded before any dependency and is restricted -# to this project. If another project depends on this project, this -# file won't be loaded nor affect the parent project. For this reason, -# if you want to provide default values for your application for -# 3rd-party users, it should be done in your "mix.exs" file. - -# You can configure your application as: -# -# config :ex_aws_dynamo, key: :value -# -# and access this configuration in your application as: -# -# Application.get_env(:ex_aws_dynamo, :key) -# -# You can also configure a 3rd-party app: -# -# config :logger, level: :info -# - -# It is also possible to import configuration files, relative to this -# directory. For example, you can emulate configuration per environment -# by uncommenting the line below and defining dev.exs, test.exs and such. -# Configuration from the imported file will override the ones defined -# here (which is why it is important to import them last). -# -# import_config "#{Mix.env}.exs" +import_config "#{Mix.env}.exs" diff --git a/config/dev.exs b/config/dev.exs new file mode 100644 index 0000000..699a109 --- /dev/null +++ b/config/dev.exs @@ -0,0 +1,7 @@ +use Mix.Config + +config :ex_aws, :dynamodb, + scheme: "http://", + host: "localhost", + port: 8000, + region: "us-east-1" diff --git a/config/test_options.exs b/config/test_options.exs index 2b0229b..eb8ba0b 100644 --- a/config/test_options.exs +++ b/config/test_options.exs @@ -3,3 +3,5 @@ require Logger config :ex_aws, :dynamodb, decode_sets: true + +import_config "test.exs" diff --git a/mix.exs b/mix.exs index e7f0b98..9d6b9a8 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule ExAws.Dynamo.Mixfile do use Mix.Project - @version "2.2.1" + @version "2.2.2" @service "dynamo" @url "https://github.com/ex-aws/ex_aws_#{@service}" @name __MODULE__ |> Module.split() |> Enum.take(2) |> Enum.join(".") diff --git a/test/lib/dynamo/integration_test.exs b/test/lib/dynamo/integration_test.exs index 2ccb6cf..90e7590 100644 --- a/test/lib/dynamo/integration_test.exs +++ b/test/lib/dynamo/integration_test.exs @@ -12,12 +12,13 @@ defmodule ExAws.DynamoIntegrationTest do @moduletag :dynamo setup_all do - Dynamo.delete_table("Users") |> ExAws.request() - Dynamo.delete_table(Test.User) |> ExAws.request() - Dynamo.delete_table("SeveralUsers") |> ExAws.request() - Dynamo.delete_table(Foo) |> ExAws.request() - Dynamo.delete_table("books") |> ExAws.request() - :ok + tables = [ "TestUsers", Test.User, "TestSeveralUsers", TestFoo, "test_books", "TestUsersWithRange" ] + + DDBLocal.delete_test_tables(tables) + + on_exit(fn -> + DDBLocal.delete_test_tables(tables) + end) end test "#list_tables" do @@ -25,13 +26,13 @@ defmodule ExAws.DynamoIntegrationTest do end test "#create and destroy table" do - assert {:ok, %{"TableDescription" => %{"TableName" => "Elixir.Foo"}}} = - Dynamo.create_table(Foo, :shard_id, [shard_id: :string], 1, 1) |> ExAws.request() + assert {:ok, %{"TableDescription" => %{"TableName" => "Elixir.TestFoo"}}} = + Dynamo.create_table(TestFoo, :shard_id, [shard_id: :string], 1, 1) |> ExAws.request() end test "#create table with range" do assert Dynamo.create_table( - "UsersWithRange", + "TestUsersWithRange", [email: :hash, age: :range], [email: :string, age: :number], 1, @@ -63,7 +64,7 @@ defmodule ExAws.DynamoIntegrationTest do test "put and get several items with map values work" do {:ok, _} = - Dynamo.create_table("SeveralUsers", :email, [email: :string], 1, 1) |> ExAws.request() + Dynamo.create_table("TestSeveralUsers", :email, [email: :string], 1, 1) |> ExAws.request() user1 = %Test.User{ email: "foo@bar.com", @@ -79,11 +80,11 @@ defmodule ExAws.DynamoIntegrationTest do admin: true } - assert {:ok, _} = Dynamo.put_item("SeveralUsers", user1) |> ExAws.request() - assert {:ok, _} = Dynamo.put_item("SeveralUsers", user2) |> ExAws.request() + assert {:ok, _} = Dynamo.put_item("TestSeveralUsers", user1) |> ExAws.request() + assert {:ok, _} = Dynamo.put_item("TestSeveralUsers", user2) |> ExAws.request() items = - Dynamo.scan("SeveralUsers", limit: 2) + Dynamo.scan("TestSeveralUsers", limit: 2) |> ExAws.request!() |> Dynamo.decode_item(as: Test.User) @@ -92,7 +93,7 @@ defmodule ExAws.DynamoIntegrationTest do end test "stream scan" do - {:ok, _} = Dynamo.create_table("Users", :email, [email: :string], 1, 1) |> ExAws.request() + {:ok, _} = Dynamo.create_table("TestUsers", :email, [email: :string], 1, 1) |> ExAws.request() user = %Test.User{ email: "foo@bar.com", @@ -101,7 +102,7 @@ defmodule ExAws.DynamoIntegrationTest do admin: false } - assert {:ok, _} = Dynamo.put_item("Users", user) |> ExAws.request() + assert {:ok, _} = Dynamo.put_item("TestUsers", user) |> ExAws.request() user = %Test.User{ email: "bar@bar.com", @@ -110,7 +111,7 @@ defmodule ExAws.DynamoIntegrationTest do admin: false } - assert {:ok, _} = Dynamo.put_item("Users", user) |> ExAws.request() + assert {:ok, _} = Dynamo.put_item("TestUsers", user) |> ExAws.request() user = %Test.User{ email: "baz@bar.com", @@ -119,9 +120,9 @@ defmodule ExAws.DynamoIntegrationTest do admin: false } - assert {:ok, _} = Dynamo.put_item("Users", user) |> ExAws.request() + assert {:ok, _} = Dynamo.put_item("TestUsers", user) |> ExAws.request() - assert Dynamo.scan("Users", limit: 1) + assert Dynamo.scan("TestUsers", limit: 1) |> ExAws.stream!() |> Enum.count() == 3 end @@ -129,7 +130,7 @@ defmodule ExAws.DynamoIntegrationTest do test "batch_write_item works" do {:ok, _} = Dynamo.create_table( - "books", + "test_books", [title: "hash", format: "range"], [title: :string, format: :string], 1, @@ -142,13 +143,13 @@ defmodule ExAws.DynamoIntegrationTest do [put_request: [item: %{title: "Tale of Two Cities", format: "softcover", price: 10.00}]] ] - assert {:ok, _} = Dynamo.batch_write_item(%{"books" => requests}) |> ExAws.request() + assert {:ok, _} = Dynamo.batch_write_item(%{"test_books" => requests}) |> ExAws.request() delete_requests = [ [delete_request: [key: %{title: "Tale of Two Cities", format: "hardcover"}]], [delete_request: [key: %{title: "Tale of Two Cities", format: "softcover"}]] ] - assert {:ok, _} = Dynamo.batch_write_item(%{"books" => delete_requests}) |> ExAws.request() + assert {:ok, _} = Dynamo.batch_write_item(%{"test_books" => delete_requests}) |> ExAws.request() end end diff --git a/test/support/ddb_local.ex b/test/support/ddb_local.ex new file mode 100644 index 0000000..ce67607 --- /dev/null +++ b/test/support/ddb_local.ex @@ -0,0 +1,16 @@ +defmodule DDBLocal do + @moduledoc """ + Helper methods for working with local DynamoDB during testing. + """ + + alias ExAws.Dynamo + + @doc """ + Delete tables created while running tests. + """ + def delete_test_tables(tables) do + tables + |> Enum.each(fn table -> Dynamo.delete_table(table) |> ExAws.request() end) + :ok + end +end