Try using nix for running tests on travis and improve nix shell

This commit is contained in:
Greg Hale 2018-06-18 08:17:17 -04:00
parent 1761f87e85
commit c9b0e3051c
23 changed files with 259 additions and 60 deletions

12
.gitmodules vendored
View File

@ -1,12 +0,0 @@
[submodule "deps/http-api-data"]
path = deps/http-api-data
url = https://github.com/fizruk/http-api-data
[submodule "deps/servant"]
path = deps/servant
url = https://github.com/haskell-servant/servant
[submodule "deps/servant-snap"]
path = deps/servant-snap
url = https://github.com/haskell-servant/servant-snap
[submodule "deps/reflex-platform"]
path = deps/reflex-platform
url = https://github.com/reflex-frp/reflex-platform

View File

@ -1,53 +1,22 @@
sudo: required
before_cache:
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar
addons:
apt:
- phantomjs
matrix:
include:
- env: CABALVER=1.24 GHCVER=7.10.3
compiler: ": #GHC 7.10.3"
addons: {apt: {packages: [cabal-install-1.24,ghc-7.10.3], sources: [hvr-ghc]}}
- env: CABALVER=1.24 GHCVER=8.0.1
compiler: ": #GHC 8.0.1"
addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1], sources: [hvr-ghc]}}
language: nix
cache: false
before_install:
- unset CC
- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
- git submodule update --init --recursive
install:
- cabal --version
- BENCH=${BENCH---enable-benchmarks}
- TEST=${TEST---enable-tests}
- echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
- if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ];
then
zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz >
$HOME/.cabal/packages/hackage.haskell.org/00-index.tar;
fi
- travis_retry cabal update -v
- sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
- deps/reflex-platform/work-on ./overrides-ghc.nix ./testserver --command "cd testserver && cabal configure -fExample && cabal build"
- deps/reflex-platform/work-on ghc ./testdriver --command "cd testdriver && cabal configure && cabal build"
- cd testserver && dist/build/back/back -p 8000 &
- sleep 3
- phantomjs --webdriver=127.0.0.1:4444 &
- sleep 3
script:
- git clone https://github.com/reflex-frp/reflex-platform
- cd reflex-platform && sudo echo "Yes" | ./try-reflex --command "exit 0"
- strace nix build -f ../release.nix servant-reflex
- nix build -f ./release.nix servant-reflex --substituters https://cache.nixos.org --substituters https://nixcache.reflex-frp.org
- nix build -f ./release.nix testresults
- git config --global user.email "travis-ci@example.com"
- git config --global user.name "Travis-CI"
- ./build.sh
# - testdriver/dist/build/spec/spec
cache:
directories:

34
default.nix Normal file
View File

@ -0,0 +1,34 @@
{ mkDerivation, aeson, base, bytestring, case-insensitive
, containers, data-default, exceptions, ghcjs-dom, http-api-data
, http-media, jsaddle, mtl, network-uri, reflex, reflex-dom
, reflex-dom-core, safe, scientific, servant, servant-auth, stdenv
, string-conversions, text, transformers
}:
mkDerivation {
pname = "servant-reflex";
version = "0.3.3";
# src = ./.;
src = builtins.filterSource
(path: type:
baseNameOf path != "result"
&& baseNameOf path != "nix"
# baseNameOf (toString path) == "src" ||
# baseNameOf (toString path) == "exec" ||
# baseNameOf (toString path) == "servant-reflex.cabal"
) ./.;
configureFlags = [ "-fexample" ];
isLibrary = true;
isExecutable = true;
libraryHaskellDepends = [
base bytestring case-insensitive containers data-default exceptions
ghcjs-dom http-api-data http-media jsaddle mtl network-uri reflex
reflex-dom-core safe servant servant-auth string-conversions text
transformers
];
executableHaskellDepends = [
aeson base reflex reflex-dom scientific servant text
];
description = "Servant reflex API generator";
license = stdenv.lib.licenses.bsd3;
}

1
deps/http-api-data vendored

@ -1 +0,0 @@
Subproject commit dde6af363d2be6521d1d085ffbab0ea8dbe14f5d

@ -1 +0,0 @@
Subproject commit 1670c5b899658babeda58329d3df6b943cf6aeca

1
deps/servant vendored

@ -1 +0,0 @@
Subproject commit 2a21e14e6e4ec01a7eed2f0c617162adaa803ab7

1
deps/servant-snap vendored

@ -1 +0,0 @@
Subproject commit 31acff4641c228fe5295388166bda485d583295d

3
nix.conf Normal file
View File

@ -0,0 +1,3 @@
substituters = https://cache.nixos.org https://cache.nixos.org https://nixcache.reflex-frp.org
trusted-substituters = https://cache.nixos.org https://cache.nixos.org https://nixcache.reflex-frp.org
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= ryantrinkle.com-1:JJiAKaRv9mWgpVAz8dwewnZe0AzzEAzPkagE9SP5NWI=

9
nix/reflex-platform.nix Normal file
View File

@ -0,0 +1,9 @@
{ fetchFromGitHub }:
import (fetchFromGitHub {
owner = "reflex-frp";
repo = "reflex-platform";
rev = "a4d679629b52f80ecae857864591d79d902a5c5d";
sha256 = "1p34qc3ryar81jh01g4jm0svr05yri83vlswm2jbxiabigy47652";
}) {}

14
nix/servant-reflex.nix Normal file
View File

@ -0,0 +1,14 @@
{ pkgs ? import <nixpkgs> {}, reflexPlatform, compiler ? "ghcjs" }:
let
ghcjsPackages = reflexPlatform.${compiler}.override {
overrides = self: super: {
servant = super.servant;
wai = super.wai;
servant-reflex = pkgs.haskell.lib.appendConfigureFlag
(self.callPackage ../. {}) "-fExample";
};
};
in ghcjsPackages.servant-reflex

3
nix/testdriver.nix Normal file
View File

@ -0,0 +1,3 @@
{ reflexPlatform }:
reflexPlatform.ghc.callPackage ../testdriver/default.nix {}

22
nix/testresults.nix Normal file
View File

@ -0,0 +1,22 @@
{ curl, reflexPlatform, testdriver, testserver, phantomjs }:
reflexPlatform.nixpkgs.pkgs.runCommand "runWebdriveTest.sh" {} ''
echo About to phantom
${phantomjs}/bin/phantomjs --webdriver=127.0.0.1:4444 &
sleep 3
echo About to server
cd ${testserver} && ./back -q --no-access-log --no-error-log &
sleep 3
${curl}/bin/curl localhost:8000
${curl}/bin/curl localhost:8000/runmain.js
echo About to testdrive
${testdriver}/bin/spec
echo Done
mkdir $out
echo Done > $out/out.txt
trap "exit" INT TERM
trap "kill 0" EXIT
''

25
nix/testserver.nix Normal file
View File

@ -0,0 +1,25 @@
{ servant-reflex, reflexPlatform }:
let
ghcPackages = reflexPlatform.ghc.override {
overrides = self: super: {
snap = reflexPlatform.lib.doJailbreak (self.callCabal2nix "snap" ../../snap {});
hspec-snap = reflexPlatform.lib.doJailbreak (super.hspec-snap);
servant-snap = reflexPlatform.lib.doJailbreak (super.servant-snap);
skylighting = reflexPlatform.lib.dontCheck super.skylighting;
testserver = (self.callPackage ../testserver/default.nix {}).overrideDerivation (old:
{ postInstall = ''
echo "SOURCE IS: $src"
echo "ls IS: $ls"
echo "EXAMPLE IS: ${servant-reflex}"
cp dist/build/back/back $out/back
mkdir $out/static
cp ${servant-reflex}/bin/example.jsexe/* $out/static/
'';
}
);
heist = reflexPlatform.lib.doJailbreak super.heist;
};
};
in ghcPackages.testserver

27
release.nix Normal file
View File

@ -0,0 +1,27 @@
{ pkgs ? import <nixpkgs> {}, compiler ? "ghcjs" }:
let
reflexPlatform =
import ./nix/reflex-platform.nix {
fetchFromGitHub = pkgs.fetchFromGitHub;
};
in rec {
servant-reflex = import ./nix/servant-reflex.nix {
reflexPlatform = reflexPlatform;
compiler = compiler;
};
testserver = import ./nix/testserver.nix
{ reflexPlatform = reflexPlatform;
servant-reflex = servant-reflex ;
};
testdriver = import ./nix/testdriver.nix
{ reflexPlatform = reflexPlatform;
};
testresults = import ./nix/testresults.nix
{ inherit reflexPlatform testserver testdriver;
inherit (pkgs) curl;
phantomjs = pkgs.phantomjs2;
};
}

3
shell.nix Normal file
View File

@ -0,0 +1,3 @@
{ compiler ? "ghcjs" }:
(import ./release.nix { inherit compiler; }).servant-reflex.env

16
testdriver/default.nix Normal file
View File

@ -0,0 +1,16 @@
{ mkDerivation, base, hspec, hspec-webdriver, stdenv, text
, webdriver
}:
mkDerivation {
pname = "testdriver";
version = "0.2";
src = ./.;
isLibrary = false;
isExecutable = true;
executableHaskellDepends = [
base hspec hspec-webdriver text webdriver
];
description = "Selenium test driver for Servant reflex";
license = stdenv.lib.licenses.bsd3;
hydraPlatforms = stdenv.lib.platforms.none;
}

1
testdriver/shell.nix Normal file
View File

@ -0,0 +1 @@
(import ../release3.nix {}).testdriver.env

View File

@ -28,7 +28,7 @@ spec :: Spec
spec = do
describe "servant-reflex tests" $ do
session "test page" $ using Chrome $ do
session "test page" $ using [chromeCaps] $ do
it "opens the page" $ runWD $
openPage "http://localhost:8000"

View File

@ -1 +0,0 @@
../exec/API.hs

69
testserver/API.hs Normal file
View File

@ -0,0 +1,69 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
module API where
import Data.Aeson
import Data.Aeson.Types (typeMismatch)
import Data.Text (Text)
import Servant.API
newtype Question = Question { unQuestion :: Text } deriving (Show)
instance ToJSON Question where
toJSON (Question txt) = object ["question" .= txt]
instance FromJSON Question where
parseJSON (Object v) = Question <$> v .: "question"
parseJSON x = typeMismatch "Couldn't find key 'question'" x
newtype Answer = Answer { unAnswer :: Text } deriving (Show)
instance ToJSON Answer where
toJSON (Answer txt) = object ["answer" .= txt]
instance FromJSON Answer where
parseJSON (Object v) = Answer <$> v .: "answer"
parseJSON x = typeMismatch "Couldn't find key 'answer'" x
-- | API spec for server, client, and docs
type API = "getunit" :> Get '[JSON] ()
:<|> "getint" :> Get '[JSON] Int
:<|> "sayhi" :> QueryParam "username" Text
:> QueryParams "greetings" Text
:> QueryFlag "gusto"
:> Get '[JSON] Text
:<|> "double" :> ReqBody '[JSON] Double
:> Post '[JSON] Double
:<|> "a" :> "b" :> QueryFlag "gusto" :> Get '[JSON] Text
:<|> "qna" :> ReqBody '[JSON] Question
:> Post '[JSON] Answer
:<|> "secret" :> BasicAuth "realm" () :> Get '[JSON] Int
:<|> Raw
type GET = Get '[JSON] ()
-- Imported the comprehensive API example for testing.
-- https://github.com/haskell-servant/servant/blob/master/servant/src/Servant/API/Internal/Test/ComprehensiveAPI.hs
type ComprehensiveAPI =
GET :<|>
Get '[JSON] Int :<|>
Capture "foo" Int :> GET :<|>
Header "foo" Int :> GET :<|>
HttpVersion :> GET :<|>
IsSecure :> GET :<|>
QueryParam "foo" Int :> GET :<|>
QueryParams "foo" Int :> GET :<|>
QueryFlag "foo" :> GET :<|>
-- Raw :<|>
RemoteHost :> GET :<|>
ReqBody '[JSON] Int :> GET :<|>
Get '[JSON] (Headers '[Header "foo" Int] ()) :<|>
"foo" :> GET :<|>
Vault :> GET :<|>
Verb 'POST 204 '[JSON] () :<|>
Verb 'POST 204 '[JSON] Int
-- This one isn't in scope
-- :<|> WithNamedContext "foo" '[] GET

View File

@ -18,12 +18,12 @@ import Data.Text hiding (head, length, map,
import qualified Data.Text as T
import qualified Data.Text.IO as T
import GHC.Generics
import Servant.Server.Internal.SnapShims
import Snap.Core
import Snap.Http.Server
import Servant
import Servant.Server
import Servant.Server ()
import System.Directory
-- import Snap.Util.FileServe
import API
import Snap
@ -85,6 +85,8 @@ test = serveSnapWithContext testApi
initApp :: SnapletInit App App
initApp = makeSnaplet "myapp" "example" Nothing $ do
liftIO $ print =<< listDirectory "."
liftIO $ print =<< listDirectory "static"
addRoutes [("", test)
,("", serveDirectory "static")
]
@ -92,4 +94,7 @@ initApp = makeSnaplet "myapp" "example" Nothing $ do
-- Put this all to work!
main :: IO ()
main = serveSnaplet mempty initApp
main = commandLineConfig emptyConfig >>= \cfg -> print cfg >> serveSnaplet cfg initApp
-- main = serveSnaplet (defaultConfig { accessLog = "/tmp/log/testserver-access.log"
-- , errorLog = "/tmp/log/testserver-error.log"
-- }) initApp

14
testserver/default.nix Normal file
View File

@ -0,0 +1,14 @@
{ mkDerivation, aeson, base, servant, servant-snap, snap, snap-core
, snap-server, stdenv, text
}:
mkDerivation {
pname = "testserver";
version = "0.1.0.0";
src = ./.;
isLibrary = false;
isExecutable = true;
executableHaskellDepends = [
aeson base servant servant-snap snap snap-core snap-server text
];
license = stdenv.lib.licenses.bsd3;
}

1
testserver/shell.nix Normal file
View File

@ -0,0 +1 @@
(import ../release2.nix {}).testserver.env

View File

@ -21,6 +21,7 @@ executable back
-- other-extensions:
build-depends: aeson >= 0.9 && < 1.4
, base >=4.8 && <4.11
, directory >= 1.2 && < 1.4
, snap >= 1.0 && < 1.2
, snap-server >= 1.0 && < 1.1
, snap-core >= 1.0 && < 1.1