Skip to content

Docker and hunit proof-of-concept #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
dist/
*.swp
*.o
*.hi
88 changes: 88 additions & 0 deletions Docker.adoc
Original file line number Diff line number Diff line change
@@ -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
13 changes: 13 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -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
16 changes: 16 additions & 0 deletions Memcached_Test.hs
Original file line number Diff line number Diff line change
@@ -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
21 changes: 21 additions & 0 deletions Network/Memcached/TestUtil.hs
Original file line number Diff line number Diff line change
@@ -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

12 changes: 12 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -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
51 changes: 32 additions & 19 deletions memcached.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -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
5 changes: 5 additions & 0 deletions run_tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh

cabal install --enable-tests
cabal configure --enable-tests
cabal test