| Copyright | (c) 2020-2021 Tim Emiola |
|---|---|
| License | BSD3 |
| Maintainer | Tim Emiola <[email protected]> |
| Safe Haskell | Safe-Inferred |
| Language | Haskell2010 |
System.TmpProc.Docker
Description
Provides the core datatypes and combinators used to launch temporary (tmp) processes (procs) using docker.
tmp-proc helps launch services used by integration tests on docker. It aims to
simplify writing those kind of tests, by providing combinators that
- launch services on docker
- provide references to the launched services
- clean up these services after the test completes
It achieves this through its typeclasses, datatypes and combinators:
- A datatype implements the
Proctypeclass to specify a docker image that provides a service startupstarts aProc; using adocker runcommand generated from metadata encoded in theProc's implementation- Additionally, a
Procdatatype may implement theToRunCmdtypeclass to customize the arguments of thedocker runcommand that launches the service. Invoking
startupconstructs aProcHandleon successful launch of a service specifed by aProc- It provides combinators for accessing the service, and for eventually shutting it down
Multiple services are launched by specifying distinct
Procsin anHListstartupAllconstructs anHListof the correspondingProcHandleon successful launch of the specified services.
Support for additional features that might prove useful in integration tests is available by implementing additional supporting typeclasses:
Use Connectable when there is a specific Connection datatype used to
access a service. It provides a combinator to construct an instance of that
datatype that accesses the launched service
Use Preparer to allow customization and cleanup of the docker container
used to launch the service
Synopsis
- class (KnownSymbol (Image a), KnownSymbol (Name a)) => Proc a where
- startup :: ProcPlus a prepared => a -> IO (ProcHandle a)
- nameOf :: forall a. Proc a => a -> Text
- uriOf' :: forall a. Proc a => a -> HostIpAddress -> SvcURI
- runArgs' :: forall a. Proc a => a -> [Text]
- data Pinged
- = OK
- | NotOK
- | PingFailed Text
- toPinged :: forall e a. Exception e => Proxy e -> IO a -> IO Pinged
- class AreProcs as
- class Preparer a prepared => ToRunCmd a prepared where
- toRunCmd :: a -> prepared -> [Text]
- class Preparer a prepared | a -> prepared where
- prepare :: [SlimHandle] -> a -> IO prepared
- tidy :: a -> prepared -> IO ()
- type ProcPlus a prepared = (Proc a, ToRunCmd a prepared, Preparer a prepared)
- startupAll :: AreProcs procs => HList procs -> IO (HandlesOf procs)
- terminateAll :: AreProcs procs => HandlesOf procs -> IO ()
- withTmpProcs :: AreProcs procs => HList procs -> (HandlesOf procs -> IO b) -> IO b
- startupAll' :: AreProcs procs => Maybe Text -> HList procs -> IO (NetworkHandlesOf procs)
- netwTerminateAll :: AreProcs procs => NetworkHandlesOf procs -> IO ()
- netwStartupAll :: AreProcs procs => HList procs -> IO (NetworkHandlesOf procs)
- data ProcHandle a where
- pattern ProcHandle :: a -> String -> SvcURI -> HostIpAddress -> ProcHandle a
- handleOf :: HandleOf a procs b => Proxy a -> HandlesOf procs -> ProcHandle b
- data SlimHandle = SlimHandle {
- shName :: Text
- shIpAddress :: HostIpAddress
- shPid :: String
- shUri :: SvcURI
- slim :: Proc a => ProcHandle a -> SlimHandle
- type family Proc2Handle (as :: [Type]) = (handleTys :: [Type]) | handleTys -> as where ...
- type HasHandle aProc procs = (Proc aProc, AreProcs procs, IsInProof (ProcHandle aProc) (Proc2Handle procs))
- type HasNamedHandle name a procs = (name ~ Name a, Proc a, AreProcs procs, MemberKV name (ProcHandle a) (Handle2KV (Proc2Handle procs)))
- type HandlesOf procs = HList (Proc2Handle procs)
- ixReset :: IxReset a procs => Proxy a -> HandlesOf procs -> IO ()
- ixPing :: IxPing a procs => Proxy a -> HandlesOf procs -> IO Pinged
- ixUriOf :: IxUriOf a procs => Proxy a -> HandlesOf procs -> SvcURI
- manyNamed :: SomeNamedHandles names namedProcs someProcs sortedProcs => Proxy names -> HandlesOf someProcs -> HandlesOf namedProcs
- mapSlim :: AreProcs procs => HandlesOf procs -> [SlimHandle]
- type SomeNamedHandles names procs someProcs sortedProcs = (names ~ Proc2Name procs, ManyMemberKV (SortSymbols names) (SortHandles (Proc2Handle procs)) (Handle2KV (Proc2Handle sortedProcs)), ReorderH (SortHandles (Proc2Handle procs)) (Proc2Handle procs), ReorderH (Proc2Handle someProcs) (Proc2Handle sortedProcs), AreProcs sortedProcs, SortHandles (Proc2Handle someProcs) ~ Proc2Handle sortedProcs)
- type NetworkHandlesOf procs = (Text, HandlesOf procs)
- class Proc a => Connectable a where
- withTmpConn :: Connectable a => ProcHandle a -> (Conn a -> IO b) -> IO b
- openAll :: Connectables xs => HandlesOf xs -> IO (HList (ConnsOf xs))
- closeAll :: Connectables procs => HList (ConnsOf procs) -> IO ()
- withConns :: Connectables procs => HandlesOf procs -> (HList (ConnsOf procs) -> IO b) -> IO b
- withConnOf :: (HandleOf idx procs namedConn, Connectable namedConn) => Proxy idx -> HandlesOf procs -> (Conn namedConn -> IO b) -> IO b
- withKnownConns :: (AreProcs someProcs, Connectables conns, ReorderH (Proc2Handle someProcs) (Proc2Handle conns)) => HandlesOf someProcs -> (HList (ConnsOf conns) -> IO b) -> IO b
- withNamedConns :: (SomeNamedHandles names namedConns someProcs sortedProcs, Connectables namedConns) => Proxy names -> HandlesOf someProcs -> (HList (ConnsOf namedConns) -> IO b) -> IO b
- class Connectables as
- hasDocker :: IO Bool
- genNetworkName :: IO Text
- type HostIpAddress = Text
- type SvcURI = ByteString
- type family SortSymbols (xs :: [Symbol]) :: [Symbol] where ...
- type family HalfOf (n :: Nat) :: Nat where ...
- type family LengthOf (xs :: [k]) :: Nat where ...
- type family Drop (xs :: [k]) (n :: Nat) :: [k] where ...
- type family Take (xs :: [k]) (n :: Nat) :: [k] where ...
- class IsInProof t (tys :: [Type])
- class ReorderH xs ys where
- class ManyMemberKV (ks :: [Symbol]) (ts :: [Type]) (kvs :: [Type])
- class MemberKV (k :: Symbol) (t :: Type) (xs :: [Type])
- type family IsAbsent e r :: Constraint where ...
- data KV :: Symbol -> Type -> Type where
- data HList :: [Type] -> Type where
- hHead :: HList (a ': as) -> a
- hOf :: forall y xs. IsInProof y xs => Proxy y -> HList xs -> y
- (&:) :: x -> HList xs -> HList (x ': xs)
- both :: x -> y -> HList '[x, y]
- (&:&) :: x -> y -> HList '[x, y]
- only :: x -> HList '[x]
- select :: forall k t xs. MemberKV k t xs => HList xs -> t
- selectMany :: forall ks ts xs. ManyMemberKV ks ts xs => HList xs -> HList ts
define tmp procs
class (KnownSymbol (Image a), KnownSymbol (Name a)) => Proc a where Source #
Specifies how to launch a temporary process using Docker.
Associated Types
type Image a :: Symbol Source #
The image name of the docker image, e.g, postgres:10.6
type Name a = (labelName :: Symbol) | labelName -> a Source #
A label used to refer to the running tmp proc created from this image, e.g, a-postgres-db
Methods
Additional arguments to the docker command that launches the tmp proc.
uriOf :: HostIpAddress -> SvcURI Source #
Determines the service URI of the tmp proc, when applicable.
reset :: ProcHandle a -> IO () Source #
Resets some state in a tmp proc service.
ping :: ProcHandle a -> IO Pinged Source #
Checks if the tmp proc started correctly.
Maximum number of pings to perform during startup.
Number of milliseconds between pings.
startup :: ProcPlus a prepared => a -> IO (ProcHandle a) Source #
Starts a Proc.
It uses ping to determine if the Proc started up ok, and will fail by
throwing an exception if it did not.
Returns the ProcHandle used to access and control the Proc once a ping has
succeeded.
Indicates the result of pinging a Proc.
If the ping succeeds, ping should return OK.
ping should catch any exceptions that are expected when the service
is not available and return ProcsNotOK.
startupAll uses PingFailed to report any unexpected exceptions that escape
ping.
Constructors
| OK | The service is running OK. |
| NotOK | The service is not running. |
| PingFailed Text | Contact to the service failed unexpectedly. |
toPinged :: forall e a. Exception e => Proxy e -> IO a -> IO Pinged Source #
Use an action that might throw an exception as a ping.
Declares a proof that a list of types only contains .Procs
Minimal complete definition
procProof
customize proc setup
class Preparer a prepared => ToRunCmd a prepared where Source #
Allow customization of the docker command that launches a Proc
The docker launch command is `docker run -d optional-args --name $(name a) $(imageText a)`
A Proc datatype should declare an instance of ToRunCmd to control
optional-args
This module provides an Overlappable fallback instance with default behaviour
that matches all , so this typeclass is only needed when a Proc
datatypes actually needs additional argumentsProc
class Preparer a prepared | a -> prepared where Source #
Prepare resources for use by a Proc
Preparation occurs before the docker container is a launched; once the
resources are set up, they are located using the prepared datatype.
Usually, this means it will be used by toRunCmd to provide additional
arguments to the docker run command
This module provides an Overlappable fallback instance that matches all
, so this typeclass is only needed when a Proc datatype actually
requires preparatory setup.Proc
The first argument to prepare is a [ that gives access to
other SlimHandle]tmp-procs previously launched in the same test, to allow prepare to
setup links to them when necessary
type ProcPlus a prepared = (Proc a, ToRunCmd a prepared, Preparer a prepared) Source #
A Constraint that combines and its supporting typeclassesProc
start/stop many procs
startupAll :: AreProcs procs => HList procs -> IO (HandlesOf procs) Source #
Start up processes for each Proc type
the processes' are able to communicate via a docker network with a unique generated name
terminateAll :: AreProcs procs => HandlesOf procs -> IO () Source #
Terminate all processes owned by some .ProcHandles
withTmpProcs :: AreProcs procs => HList procs -> (HandlesOf procs -> IO b) -> IO b Source #
Set up some , run an action that uses them, then terminate them.Procs
startupAll' :: AreProcs procs => Maybe Text -> HList procs -> IO (NetworkHandlesOf procs) Source #
Deprecated: since v0.7 this is no longer needed and will be removed, use startupAll instead; it always generates a named docker network
Start up processes for each Proc type.
netwTerminateAll :: AreProcs procs => NetworkHandlesOf procs -> IO () Source #
Deprecated: since v0.7 this is no longer needed and will be removed, use terminateAll instead
Like terminateAll, but also removes the docker network connecting the
processes.
netwStartupAll :: AreProcs procs => HList procs -> IO (NetworkHandlesOf procs) Source #
Deprecated: since v0.7 this is no longer needed and will be removed, use startupAll instead
Like startupAll, but reveals the generated network name via the
deprecated NetworkHandlesOf
access running procs
data ProcHandle a where Source #
Provides access to a Proc that has been started.
Bundled Patterns
| pattern ProcHandle | A The selectors are readonly, i.e they only match in a pattern context since
|
Fields
| |
handleOf :: HandleOf a procs b => Proxy a -> HandlesOf procs -> ProcHandle b Source #
Obtain the handle matching the given type from a of HList.ProcHandle
data SlimHandle Source #
Provides an untyped view of the data in a ProcHandle
Constructors
| SlimHandle | |
Fields
| |
Instances
| Show SlimHandle Source # | |
Defined in System.TmpProc.Docker | |
| Eq SlimHandle Source # | |
Defined in System.TmpProc.Docker Methods (==) :: SlimHandle -> SlimHandle -> Bool Source # (/=) :: SlimHandle -> SlimHandle -> Bool Source # | |
slim :: Proc a => ProcHandle a -> SlimHandle Source #
Obtain the SlimHandle.
type family Proc2Handle (as :: [Type]) = (handleTys :: [Type]) | handleTys -> as where ... Source #
Converts list of types to the corresponding types.ProcHandle
Equations
| Proc2Handle '[] = '[] | |
| Proc2Handle (a ': as) = ProcHandle a ': Proc2Handle as |
type HasHandle aProc procs = (Proc aProc, AreProcs procs, IsInProof (ProcHandle aProc) (Proc2Handle procs)) Source #
Constraint alias used to constrain types where proxy of a Proc type looks up
a value in an HList of ProcHandle.
type HasNamedHandle name a procs = (name ~ Name a, Proc a, AreProcs procs, MemberKV name (ProcHandle a) (Handle2KV (Proc2Handle procs))) Source #
Constraint alias used to constrain types where a Name looks up
a type in an HList of ProcHandle.
access many started procs
type HandlesOf procs = HList (Proc2Handle procs) Source #
A list of values.ProcHandle
ixReset :: IxReset a procs => Proxy a -> HandlesOf procs -> IO () Source #
Resets the handle whose index is specified by the proxy type.
ixPing :: IxPing a procs => Proxy a -> HandlesOf procs -> IO Pinged Source #
Pings the handle whose index is specified by the proxy type.
ixUriOf :: IxUriOf a procs => Proxy a -> HandlesOf procs -> SvcURI Source #
Obtains the service URI of the handle whose index is specified by the proxy type.
manyNamed :: SomeNamedHandles names namedProcs someProcs sortedProcs => Proxy names -> HandlesOf someProcs -> HandlesOf namedProcs Source #
Select the named from an ProcHandlesHList of .ProcHandle
mapSlim :: AreProcs procs => HandlesOf procs -> [SlimHandle] Source #
Obtain the SlimHandle of several Procs
type SomeNamedHandles names procs someProcs sortedProcs = (names ~ Proc2Name procs, ManyMemberKV (SortSymbols names) (SortHandles (Proc2Handle procs)) (Handle2KV (Proc2Handle sortedProcs)), ReorderH (SortHandles (Proc2Handle procs)) (Proc2Handle procs), ReorderH (Proc2Handle someProcs) (Proc2Handle sortedProcs), AreProcs sortedProcs, SortHandles (Proc2Handle someProcs) ~ Proc2Handle sortedProcs) Source #
Constraint alias when several are used to find matching
types in an NamesHList of ProcHandle.
type NetworkHandlesOf procs = (Text, HandlesOf procs) Source #
Deprecated: since v0.7 this is no longer necessary and will be removed
A list of values of different types with the name of the
docker network connecting their processesProcHandle
access via a known connection type
class Proc a => Connectable a where Source #
Specifies how to construct a connection datatype for accessing the launched
service specified by a Proc.
Minimal complete definition
withTmpConn :: Connectable a => ProcHandle a -> (Conn a -> IO b) -> IO b Source #
Run an action on a Connectable handle as a callback on its Conn
openAll :: Connectables xs => HandlesOf xs -> IO (HList (ConnsOf xs)) Source #
Open all the Connectable types to corresponding Conn types.
closeAll :: Connectables procs => HList (ConnsOf procs) -> IO () Source #
Close some Connectable types.
withConns :: Connectables procs => HandlesOf procs -> (HList (ConnsOf procs) -> IO b) -> IO b Source #
Open some connections, use them in an action; close them.
withConnOf :: (HandleOf idx procs namedConn, Connectable namedConn) => Proxy idx -> HandlesOf procs -> (Conn namedConn -> IO b) -> IO b Source #
Builds on handleOf; gives the Conn of the ProcHandle to a callback.
withKnownConns :: (AreProcs someProcs, Connectables conns, ReorderH (Proc2Handle someProcs) (Proc2Handle conns)) => HandlesOf someProcs -> (HList (ConnsOf conns) -> IO b) -> IO b Source #
Open all known connections; use them in an action; close them.
withNamedConns :: (SomeNamedHandles names namedConns someProcs sortedProcs, Connectables namedConns) => Proxy names -> HandlesOf someProcs -> (HList (ConnsOf namedConns) -> IO b) -> IO b Source #
Open the named connections; use them in an action; close them.
class Connectables as Source #
Declares a proof that a list of types only contains .Connectables
Minimal complete definition
connProof
Instances
| Connectables ('[] :: [Type]) Source # | |
Defined in System.TmpProc.Docker Methods connProof :: Uniquely Connectable Connectables '[] | |
| (Connectable a, Connectables as, IsAbsent a as) => Connectables (a ': as) Source # | |
Defined in System.TmpProc.Docker Methods connProof :: Uniquely Connectable Connectables (a ': as) | |
Docker status
genNetworkName :: IO Text Source #
Deprecated: since v0.7 this is no longer needs to be exported and will be hidden in later releases
generate a random network name
Aliases
type HostIpAddress = Text Source #
The IP address of the docker host.
Re-exports
type family SortSymbols (xs :: [Symbol]) :: [Symbol] where ... Source #
Sort a list of type-level symbols using merge sort.
Examples
>>>:kind! SortSymbols '["xyz", "def", "abc"]SortSymbols '["xyz", "def", "abc"] :: [Symbol] = '["abc", "def", "xyz"]
Equations
| SortSymbols '[] = '[] | |
| SortSymbols '[x] = '[x] | |
| SortSymbols '[x, y] = MergeSymbols '[x] '[y] | |
| SortSymbols xs = SortSymbolsStep xs (HalfOf (LengthOf xs)) |
type family HalfOf (n :: Nat) :: Nat where ... Source #
Computes the midpoint of a number.
N.B: maximum value that this works for depends on the reduction limit of the type-checker.
Examples
>>>:kind! CmpNat 49 (HalfOf 99)CmpNat 49 (HalfOf 99) :: Ordering = 'EQ
>>>:kind! CmpNat 50 (HalfOf 100)CmpNat 50 (HalfOf 100) :: Ordering = 'EQ
type family LengthOf (xs :: [k]) :: Nat where ... Source #
Counts a list, 1 element at a time.
Examples
>>>:kind! CmpNat 4 (LengthOf '[1, 2, 3, 4])CmpNat 4 (LengthOf '[1, 2, 3, 4]) :: Ordering = 'EQ
type family Drop (xs :: [k]) (n :: Nat) :: [k] where ... Source #
Drops 1 element at a time until the the dropped target is reached.
Examples
>>>:kind! Drop '["a", "b", "c", "d"] 2Drop '["a", "b", "c", "d"] 2 :: [Symbol] = '["c", "d"]
>>>:kind! Drop '["a"] 2Drop '["a"] 2 :: [Symbol] = '[]
type family Take (xs :: [k]) (n :: Nat) :: [k] where ... Source #
Takes 1 element at a time from a list until the desired length is reached.
Examples
>>>:kind! Take '["a", "b", "c", "d"] 2Take '["a", "b", "c", "d"] 2 :: [Symbol] = '["a", "b"]
class IsInProof t (tys :: [Type]) Source #
Generate proof instances of IsIn.
Minimal complete definition
provedIsIn
Instances
| IsInProof t tys => IsInProof t (a ': tys) Source # | |
Defined in System.TmpProc.TypeLevel Methods provedIsIn :: IsIn t (a ': tys) | |
| IsInProof t (t ': tys) Source # | |
Defined in System.TmpProc.TypeLevel Methods provedIsIn :: IsIn t (t ': tys) | |
class ReorderH xs ys where Source #
Allows reordering of similar .HLists
Examples
>>>hReorder @_ @'[Bool, Int] ('c' &: (3 :: Int) &: True &: (3.1 :: Double) &: HNil)True &: 3 &: HNil
>>>hReorder @_ @'[Double, Bool, Int] ('c' &: (3 :: Int) &: True &: (3.1 :: Double) &: HNil)3.1 &: True &: 3 &: HNil
class ManyMemberKV (ks :: [Symbol]) (ts :: [Type]) (kvs :: [Type]) Source #
Generate proof instances of LookupMany.
Minimal complete definition
Instances
| ManyMemberKV ks ts kvs => ManyMemberKV ks ts (KV ok ot ': kvs) Source # | |
Defined in System.TmpProc.TypeLevel | |
| ManyMemberKV '[k] '[t] (KV k t ': ks) Source # | |
Defined in System.TmpProc.TypeLevel | |
| ManyMemberKV ks ts kvs => ManyMemberKV (k ': ks) (t ': ts) (KV k t ': kvs) Source # | |
Defined in System.TmpProc.TypeLevel | |
class MemberKV (k :: Symbol) (t :: Type) (xs :: [Type]) Source #
Generate proof instances of LookupKV.
Minimal complete definition
Instances
| MemberKV k t '[KV k t] Source # | |
Defined in System.TmpProc.TypeLevel Methods lookupProof :: LookupKV k t '[KV k t] Source # | |
| MemberKV k t (KV k t ': kvs) Source # | |
Defined in System.TmpProc.TypeLevel Methods lookupProof :: LookupKV k t (KV k t ': kvs) Source # | |
| MemberKV k t kvs => MemberKV k t (KV ok ot ': kvs) Source # | |
Defined in System.TmpProc.TypeLevel Methods lookupProof :: LookupKV k t (KV ok ot ': kvs) Source # | |
type family IsAbsent e r :: Constraint where ... Source #
A constraint that confirms that a type is not present in a type-level list.
data KV :: Symbol -> Type -> Type where Source #
Use a type-level symbol as key type that indexes a value type.
Instances
| ManyMemberKV ks ts kvs => ManyMemberKV ks ts (KV ok ot ': kvs) Source # | |
Defined in System.TmpProc.TypeLevel | |
| MemberKV k t '[KV k t] Source # | |
Defined in System.TmpProc.TypeLevel Methods lookupProof :: LookupKV k t '[KV k t] Source # | |
| MemberKV k t (KV k t ': kvs) Source # | |
Defined in System.TmpProc.TypeLevel Methods lookupProof :: LookupKV k t (KV k t ': kvs) Source # | |
| MemberKV k t kvs => MemberKV k t (KV ok ot ': kvs) Source # | |
Defined in System.TmpProc.TypeLevel Methods lookupProof :: LookupKV k t (KV ok ot ': kvs) Source # | |
| ManyMemberKV '[k] '[t] (KV k t ': ks) Source # | |
Defined in System.TmpProc.TypeLevel | |
| ManyMemberKV ks ts kvs => ManyMemberKV (k ': ks) (t ': ts) (KV k t ': kvs) Source # | |
Defined in System.TmpProc.TypeLevel | |
data HList :: [Type] -> Type where Source #
Defines a Heterogenous list.
hOf :: forall y xs. IsInProof y xs => Proxy y -> HList xs -> y Source #
Get an item in an HList given its type.
selectMany :: forall ks ts xs. ManyMemberKV ks ts xs => HList xs -> HList ts Source #
Select items with specified keys from an of HList by key.KVs
N.B. this this is an internal function.
The keys must be provided in the same order as they occur in the HList, any other order will likely result in an compiler error.
Examples
>>>selectMany @'["b"] @'[Bool] @'[KV "b" Bool, KV "d" Double] (V True &: V (3.1 :: Double) &: HNil)True &: HNil