packages feed

tmp-proc 0.5.0.0 → 0.5.0.1

raw patch · 5 files changed

+261/−33 lines, 5 filesdep ~basedep ~bytestringdep ~textnew-component:exe:readme

Dependency ranges changed: base, bytestring, text, wai, warp, warp-tls

Files

ChangeLog.md view
@@ -2,6 +2,12 @@  `tmp-proc` uses [PVP Versioning][1]. +## 0.5.0.1 -- 2021-09-30++* Fix use of packaged data in tests+* Introduce some build flags to control how the package builds in CI environments++ ## 0.5.0.0 -- 2021-09-28  * Initial release to hackage
+ README.lhs view
@@ -0,0 +1,192 @@+# tmp-proc++[![Hackage](https://img.shields.io/hackage/v/tmp-proc.svg)](https://hackage.haskell.org/package/tmp-proc)+[![GitHub CI](https://github.com/adetokunbo/tmp-proc/actions/workflows/test.yml/badge.svg)](https://github.com/adetokunbo/tmp-proc/actions)+[![BSD-3.0 license](https://img.shields.io/badge/license-BSD--3.0-blue.svg)](https://github.com/adetokunbo/tmp-proc/blob/master/tmp-proc/LICENSE)++`tmp-proc` is a small library designed to simplify integration tests that use+services running on docker.++This README contains a _How to_ tutorial on using this library. This tutorial+explains step by step how to specify a docker image as a `tmp proc` and use it in+a test.++__N.B.__ It assumes that docker is installed.++All code below can be compiled and run with the following commands:++```shell+# At the moment (30/09/2021), this is does not consistently run when using cabal+$ stack build tmp-proc+$ stack run readme+```++## Preamble: imports and language extensions++Since this is a literate haskell file, we need to specify all our language+extensions and imports up front.++```haskell+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE LambdaCase          #-}+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications    #-}+{-# LANGUAGE TypeFamilies        #-}++import           Test.Hspec++import qualified Data.ByteString.Char8 as C8+import           Data.List             (foldl')+import           Data.Proxy            (Proxy (..))+import           Data.Text             (Text)+import qualified Data.Text             as Text+import           Network.HTTP.Req++import           System.TmpProc        (HList (..), HandlesOf, HostIpAddress,+                                        Pinged (..), Proc (..), ProcHandle (..),+                                        SvcURI, manyNamed, startupAll, toPinged,+                                        (&:), ixPing, nameOf, terminateAll)++```+++## Specify a Proc instance++In `tmp-proc`, docker instances are specified by making new instances of the+`Proc` typeclass.++For this tutorial, we'll test the famous [http-bin](https://httpbin.org)+service. Although it's an online service in it's own right, it is also available+as a docker image.+++```haskell+data HttpBinLhs = HttpBinLhs++instance Proc HttpBinLhs where+  type Image HttpBinLhs = "kennethreitz/httpbin"+  type Name HttpBinLhs = "http-bin-lhs"++  uriOf ip = "http://" <> C8.pack (Text.unpack ip) <> "/"+  runArgs = []+  reset _ = pure ()+  ping = pingImpl++```++A `Proc` instance specifies both an `Image` and `Name`.+- The `Image` corresponds to the docker image that needs to be run+- The `Name` is a label that needs to be unique; it is used an alternate index for the Proc instance.++The instance also specifies a number of useful typeclass functions; only `ping`+will be covered in this tutorial, but the others all have important roles.+++```haskell++pingImpl :: ProcHandle a -> IO Pinged+pingImpl handle = toPinged @HttpException Proxy $ do+  gotStatus <- runReq defaultHttpConfig $ do+    r <- req GET (handleUrl handle "/status/200") NoReqBody ignoreResponse $ mempty+    pure $ responseStatusCode r+  if (gotStatus == 200) then pure OK else pure NotOK+++handleUrl :: ProcHandle a -> Text -> Url 'Http+handleUrl handle urlPath = foldl' (/:) (http $ hAddr handle)+  $ Text.splitOn "/" $ Text.dropWhile (== '/') urlPath+++```++The `pingImpl` used by the `Proc` instance above is implemented next.++Each `Proc` instance must provide a valid `ping` implementation, `tmp-proc` uses+`ping` to determine when the `Proc's` service is ready for use in the test.++## Using the Proc+++```haskell++spec :: Spec+spec = describe ("Tmp.Proc: " ++ Text.unpack (nameOf HttpBinLhs)) $ do+  beforeAll (startupAll $ HttpBinLhs &: HNil) $ afterAll terminateAll $ do+    context "When accessing the services in the list of test tmp procs" $ do++      context "ixPing" $ do++        it "should succeed when accessing a Proc by name" $ \handles+          -> ixPing @"http-bin-lhs" Proxy handles `shouldReturn` OK++        it "should succeed when accessing a Proc by type" $ \handles+          -> ixPing @HttpBinLhs Proxy handles `shouldReturn` OK++```++With just this, it's now possible to write a simple test showing various+features of `tmp-proc`.  E.g,++- `hspec` launches `Procs` during test setup++   - this results in an `HList` of `ProcHandle` types being passed to each test.++     - (In this example, the HList has only one `Proc`. `startupAll` allows for+       many `Procs` to started, each of different type. This is possible because+       `startupAll` acts on and returns a heteregenous list (or `HList`) rather+       than the usual `List` type.++   - `startupAll` takes an `HList` of `Procs` and returns an `HList` of+     corresponding `ProcHandle` types, first ensuring that all the corresponding+     docker services start up ok++- once setup succeeds, each test is passed the `ProcHandles` created by+  `startupAll`++   - this is powered by a feature of [hspec][2], it's through use of `hspec's`+     `beforeAll` hook that enables this++    - `startupAll` is just one example of a `tmp-proc` combinator meshing well with+    the test frameworks' combinators.++        - the `startAll` and `terminateAll` functions used here also work with+          `tasty's` [withResource][6]++        - `tmp-proc` provides other functions that work with other hooks in [hspec][1]++- the test cases here show the way that `tmp-proc` functions work with an+  `HList` of `ProcHandles`++    - `ixPing` uses [TypeApplications][7] with an index type to identify the+        'ProcHandle' to ping++    - `tmp-proc` provides similar functions that enable access to attributes+        of one or many `ProcHandle`.++    - Though not shown here, as well as accessing a `ProcHandle's` attributes,+      test code may also to access the corresponding service using a+      `Connection` type specific to that service.++    - __N.B.__ these test cases are completely unrealistic; there should be no+      reason to use `ixPing` in a normal test case! For slightly more realism,+      please take a look at the [example package][4].+++## Run the Spec++```haskell++main :: IO ()+main = hspec spec++```+++[1]: https://hackage.haskell.org/package/wai+[2]: https://hspec.github.io+[3]: https://hackage.haskell.org/package/tasty+[4]: https://github.com/adetokunbo/tmp-proc/tree/master/tmp-proc-example+[5]: https://github.com/adetokunbo/tmp-proc/tree/master/tmp-proc+[6]: https://hackage.haskell.org/package/tasty-1.4.2/docs/Test-Tasty.html#v:withResource+[7]: https://typeclasses.com/ghc/type-applications
test/Test/SimpleServer.hs view
@@ -22,7 +22,17 @@ import qualified Network.Wai.Handler.Warp    as Warp import qualified Network.Wai.Handler.WarpTLS as Warp +import           Paths_tmp_proc              (getDataFileName) ++-- | The settings used in the integration tests+defaultTLSSettings :: IO Warp.TLSSettings+defaultTLSSettings =+  Warp.tlsSettings+ <$> (getDataFileName "test_certs/certificate.pem")+ <*> (getDataFileName "test_certs/key.pem")++ -- | Determine the status from a Get on localhost. statusOfGet :: Warp.Port -> Text -> IO Int statusOfGet p path = runReq defaultHttpConfig $ do@@ -46,10 +56,6 @@ localHttpsUrl :: Text -> Url 'Https localHttpsUrl p = foldl' (/:) (https "localhost")   $ Text.splitOn "/" $ Text.dropWhile (== '/') p---defaultTLSSettings :: Warp.TLSSettings-defaultTLSSettings = Warp.tlsSettings "test_certs/certificate.pem" "test_certs/key.pem"   mkSimpleTLSManager :: IO HC.Manager
test/Test/System/TmpProc/WarpSpec.hs view
@@ -47,8 +47,11 @@ setupBeforeAll :: IO (ServerHandle '[HttpBinTest]) setupBeforeAll = runServer testProcs testApp + setupBeforeAllTls :: IO (ServerHandle '[HttpBinTest])-setupBeforeAllTls = runTLSServer defaultTLSSettings testProcs testApp+setupBeforeAllTls = do+  tls <- defaultTLSSettings+  runTLSServer tls testProcs testApp   suffixAround, suffixBeforeAll, prefixHttp, prefixHttps :: String@@ -83,7 +86,9 @@   setupAroundTls :: ((HandlesOf '[HttpBinTest], Int) -> IO a) -> IO a-setupAroundTls = testWithTLSApplication defaultTLSSettings testProcs testApp+setupAroundTls cont = do+  tls <- defaultTLSSettings+  testWithTLSApplication tls testProcs testApp cont   aroundSpec :: Spec
tmp-proc.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               tmp-proc-version:            0.5.0.0+version:            0.5.0.1 synopsis:           Run 'tmp' processes in integration tests description:   @tmp-proc@ runs services in docker containers for use in integration tests.@@ -27,11 +27,13 @@ maintainer:         adetokunbo@users.noreply.github.com category:           testing, docker bug-reports:        https://github.com/adetokunbo/tmp-proc/issues+homepage:           https://github.com/adetokunbo/tmp-proc/tree/master/tmp-proc#tmp-proc build-type:         Simple-extra-source-files:-  ChangeLog.md+data-files:   test_certs/*.csr   test_certs/*.pem+extra-source-files:+  ChangeLog.md tested-with:   GHC == 8.10.5 @@ -67,6 +69,8 @@ test-suite integration-test   type:             exitcode-stdio-1.0   main-is:          Spec.hs+  autogen-modules:  Paths_tmp_proc+   other-modules:     Test.Hspec.TmpProc     Test.HttpBin@@ -74,6 +78,7 @@     Test.System.TmpProc.Hspec     Test.System.TmpProc.HttpBinSpec     Test.System.TmpProc.WarpSpec+    Paths_tmp_proc    hs-source-dirs:   test   build-depends:@@ -96,7 +101,15 @@   ghc-options:     -threaded -rtsopts -with-rtsopts=-N -fno-ignore-asserts -Wall +Flag use-doc-tests+  description: Include the doctests in the package tests+  default:     False+ test-suite doctests+  if flag(use-doc-tests)+     buildable:     True+  else+     buildable:     False   type:             exitcode-stdio-1.0   main-is:          Main.hs   build-depends:@@ -108,28 +121,34 @@   default-language: Haskell2010   ghc-options:      -threaded --- This is not currently working in the nix build environment.------ executable readme---   if os(windows)---     buildable: False ---   build-tool-depends: markdown-unlit:markdown-unlit---   ghc-options:        -pgmL markdown-unlit---   main-is:            README.lhs---   default-language:   Haskell2010---   build-depends:---     , base---     , bytestring---     , connection---     , data-default---     , hspec---     , http-client---     , http-client-tls---     , http-types---     , req---     , text---     , tmp-proc---     , wai---     , warp---     , warp-tls+Flag build-the-readme+  description: Allow the readme to build+  default:     False+++executable readme+  if os(windows) || !flag(build-the-readme)+    buildable: False+  else+    buildable: True++  build-tool-depends: markdown-unlit:markdown-unlit+  ghc-options:        -pgmL markdown-unlit -threaded -rtsopts -with-rtsopts=-N+  main-is:            README.lhs+  default-language:   Haskell2010+  build-depends:+    , base+    , bytestring+    , connection+    , data-default+    , hspec+    , http-client+    , http-client-tls+    , http-types+    , req+    , text+    , tmp-proc+    , wai+    , warp+    , warp-tls