From 36c84bbfe4d570bccd4f84d97ab108d2bd298063 Mon Sep 17 00:00:00 2001 From: Steve Jones Date: Sat, 5 Dec 2015 17:38:12 -0500 Subject: [PATCH] Docker setup and hunit tests --- .gitignore | 3 ++ Docker.adoc | 88 +++++++++++++++++++++++++++++++++++ Dockerfile | 13 ++++++ Memcached_Test.hs | 16 +++++++ Network/Memcached/TestUtil.hs | 21 +++++++++ docker-compose.yml | 12 +++++ memcached.cabal | 51 ++++++++++++-------- run_tests | 5 ++ 8 files changed, 190 insertions(+), 19 deletions(-) create mode 100644 Docker.adoc create mode 100644 Dockerfile create mode 100644 Memcached_Test.hs create mode 100644 Network/Memcached/TestUtil.hs create mode 100644 docker-compose.yml create mode 100755 run_tests diff --git a/.gitignore b/.gitignore index 849ddff..afbeee8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ dist/ +*.swp +*.o +*.hi diff --git a/Docker.adoc b/Docker.adoc new file mode 100644 index 0000000..0468f90 --- /dev/null +++ b/Docker.adoc @@ -0,0 +1,88 @@ += Using Docker to Develop and Test the Haskell Memcached API + +== Why do I want this? + +* Enforces build consistency +* Isolates and encapsulates dependencies and dev environment +* No need to provision individual dev machines +* Easily target the production architecture (no cross-compilation) +* Provides ephemeral infrastructure (memached server, in this case) +* Build once -- facilitates continuous delivery and/or deployment + +== And what *is* this, exactly? + +Included here is an automated container definition of the development environment and a minimal application runtime for testing. + +== Requirements + +On a reasonably up-to-date linux box you will need to install: + +* docker-engine +* docker-compose + +Other operating systems will require the above and `docker-machine` besides. It is recommended to install Docker Toolbox, which should include all that is needed. + +Specific installation for a variety of platforms may be found at http://docs.docker.com/engine/installation/ + +== Putting Docker to work + +`docker-compose` is a tool to 'compose' applications from individual Docker containers. To bring everything up, run + + $ docker-compose up -d + +This will pull images, build the build the dev image and create and run the containers. + +NOTE: Pulling and building are only invoked initially (or when an image is invalidated). They will be locally available subsequently. + +Do: + $ docker ps + +to see the newly created containers: + + CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES + 9e75930c2023 haskellmemcached_haskell:latest "/bin/sh -c '$SHELL 45 seconds ago Up 44 seconds haskellmemcached_haskell_1 + 9fb03ced9663 memcached:latest "/entrypoint.sh memc 5 minutes ago Up 5 minutes 11211/tcp haskellmemcached_memcached_1 + +haskellmemcached_haskell_1:: + + This container is the development environment. + +haskellmemcached_memcached_1:: + + This provides the memcached server. + +=== Development + +To run a minimal interactive development environment, execute: + + $ docker-compose run haskell + +You will find yourself in a shell within a container (specifically, `haskellmemcached_haskell_1`) in this current directory, which will have been effectively 'mounted' there from the host machine. If you are a tmux/vim user, you should be happy to begin with this (a bare emacs is also provided). If you require more, it is also possible to edit in a separate window directly from the host box. + +NOTE: The actual build environment is isolated within the container. Certain IDE interoperability and build commends, etc., may not work as expected in this mode of work. + +It is expected that the Dockerfile be tweaked and also extended to meet whatever additional requirements there may be. + + +=== Automated tests + +There are a few `hunit` tests included that may be run: + + $ docker-compose run haskell sh -l ./run_tests + +Note that these are *not* proper unit tests in that they involve actual infrastructure; they will be run against a real memcached server. + +It is also possible to run them manually, while interactively developing. + +Run the container, as described above: + + $ docker-compose run haskell + +within this shell do: + + $ cabal install --enable-tests + $ cabal configure --enable-tests + $ runhaskell Memcached_Test.hs + + +TODO: trigger this testframe with travis diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2b64beb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ + +from sjfloat/haskell_7.10.2 + +user root +run apt-get update && apt-get install -y telnet + +# TODO cleanup! + +workdir /home/dev/work + +user $USER + +cmd $SHELL -l diff --git a/Memcached_Test.hs b/Memcached_Test.hs new file mode 100644 index 0000000..e881f01 --- /dev/null +++ b/Memcached_Test.hs @@ -0,0 +1,16 @@ +module Main (main) where + +import Network.Memcached.TestUtil as TstUtl +import Test.Framework as TstFrm +import Test.Framework.Providers.HUnit as TstFrmHUnit +import Test.HUnit as HUnit + +tests = TstFrmHUnit.hUnitTestToTests $ HUnit.TestList [ + TestCase ( TstUtl.setAndGet (42 :: Int) ) + ,TestCase ( TstUtl.setAndGet "blah" ) + ,TestCase ( TstUtl.setAndGet 'c' ) + ,TestCase ( TstUtl.setAndGet '0' ) + ] + +main :: IO () +main = TstFrm.defaultMain tests diff --git a/Network/Memcached/TestUtil.hs b/Network/Memcached/TestUtil.hs new file mode 100644 index 0000000..c05ee0a --- /dev/null +++ b/Network/Memcached/TestUtil.hs @@ -0,0 +1,21 @@ +module Network.Memcached.TestUtil (setAndGet) where + +import Network.Memcached.Memcached as Cache +import Network.Memcached.Protocol as Proto +import Network.Memcached.Serializable as Ser +import Network.Memcached.Server as Srv +import Test.HUnit as HUnit + +setAndGet :: (Ser.Serializable a, Eq a, Show a) => a -> IO () +setAndGet theFacts = do + let host = "memcached" + port = Nothing -- default: 11211 + expiry = Proto.Never + flags = Nothing + + conn <- Srv.connect (configure expiry flags) host port + status <- Cache.set conn "_setAndGet_" theFacts + assertBool "set was successful" status + ma'am <- Cache.get conn "_setAndGet_" + assertEqual "Tell us what happened" (Just theFacts) ma'am + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2d6c06a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,12 @@ +memcached: + image: memcached + +haskell: + build: . + tty: true + stdin_open: true + links: + - memcached + volumes: + - .:/home/dev/work + working_dir: /home/dev/work diff --git a/memcached.cabal b/memcached.cabal index 47c9113..c7a3814 100644 --- a/memcached.cabal +++ b/memcached.cabal @@ -13,25 +13,38 @@ build-type: Simple tested-with: GHC==7.10.2 -build-depends: - base >3 && <5, - network, - time >=1 && <2, - bytestring >=0.9 && <0.11, - utf8-light >=0.4 && <1.0 +Library + build-depends: + base >3 && <5, + network, + time >=1 && <2, + bytestring >=0.9 && <0.11, + utf8-light >=0.4 && <1.0 -extra-source-files: - Setup.hs + extra-source-files: + Setup.hs -exposed-modules: - Network.Memcached, - Network.Memcached.Server, - Network.Memcached.Memcached, - Network.Memcached.Protocol, - Network.Memcached.Serializable, - Network.Memcached.Key, - Network.Memcached.Cluster, - Network.Memcached.Helpers + exposed-modules: + Network.Memcached, + Network.Memcached.Server, + Network.Memcached.Memcached, + Network.Memcached.Protocol, + Network.Memcached.Serializable, + Network.Memcached.Key, + Network.Memcached.Cluster, + Network.Memcached.Helpers + + ghc-options: -Wall + ghc-prof-options: -prof -auto-all + +Test-Suite hunit + type: exitcode-stdio-1.0 + main-is: Memcached_Test.hs + build-depends: base, + regex-posix, + test-framework, + test-framework-hunit, + HUnit + default-language: Haskell2010 + ghc-options: -Wall -ghc-options: -Wall -ghc-prof-options: -prof -auto-all diff --git a/run_tests b/run_tests new file mode 100755 index 0000000..11c75e7 --- /dev/null +++ b/run_tests @@ -0,0 +1,5 @@ +#!/bin/sh + +cabal install --enable-tests +cabal configure --enable-tests +cabal test