From 2d2288a396ca7b9b8f5155ecdfe808cab6d4eb08 Mon Sep 17 00:00:00 2001 From: Joris Dral Date: Mon, 25 Mar 2024 16:29:04 +0100 Subject: [PATCH] Test that closeIOCtx is idempotent Install io_uring from a package manager in GHA Small unit tests for simple no-op submissions --- .github/workflows/haskell.yml | 16 ++++++++-- System/IO/BlockIO/URingFFI.hsc | 2 +- blockio-uring.cabal | 35 +++++++++++++++++++++- test/Main.hs | 55 ++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 test/Main.hs diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml index 1b4867d..4501cf3 100644 --- a/.github/workflows/haskell.yml +++ b/.github/workflows/haskell.yml @@ -39,6 +39,10 @@ jobs: cabal: "3.10.2.1" os: ubuntu-22.04 liburing: "liburing-2.1" + - ghc: "9.6.4" + cabal: "3.10.2.1" + os: ubuntu-22.04 + liburing: "system" steps: - name: Checkout repository @@ -52,8 +56,9 @@ jobs: cabal-version: ${{ matrix.cabal }} cabal-update: true - - name: Install liburing (on Linux) - id: setup-liburing + - name: Install (specific) liburing from source + id: setup-liburing-source + if: ${{ ! (matrix.liburing == 'system') }} run: | sudo apt-get update sudo apt-get -y install pkg-config @@ -70,6 +75,13 @@ jobs: sudo rm -rf ./tmp pkg-config --modversion liburing + - name: Install (newest) liburing from a package manager + id: setup-liburing-cloned + if: ${{ matrix.liburing == 'system' }} + run: | + sudo apt-get update + sudo apt-get -y install pkg-config liburing-dev + - name: Configure the build run: | cabal configure --enable-test --enable-benchmark --ghc-options="-Werror" --ghc-options="-fno-ignore-asserts" diff --git a/System/IO/BlockIO/URingFFI.hsc b/System/IO/BlockIO/URingFFI.hsc index 070745d..7c552ec 100644 --- a/System/IO/BlockIO/URingFFI.hsc +++ b/System/IO/BlockIO/URingFFI.hsc @@ -42,7 +42,7 @@ foreign import capi unsafe "liburing.h io_uring_sqe_set_data64" #else io_uring_sqe_set_data :: Ptr URingSQE -> CULong -> IO () io_uring_sqe_set_data p user_data = - do #{poke struct io_uring_cqe, user_data} p user_data + do #{poke struct io_uring_sqe, user_data} p user_data #endif foreign import capi unsafe "liburing.h io_uring_prep_read" diff --git a/blockio-uring.cabal b/blockio-uring.cabal index c4197cd..5fa07a3 100644 --- a/blockio-uring.cabal +++ b/blockio-uring.cabal @@ -33,6 +33,19 @@ source-repository head type: git location: https://github.com/well-typed/blockio-uring +common warnings + ghc-options: + -Wall -Wcompat -Wincomplete-uni-patterns + -Wincomplete-record-updates -Wpartial-fields -Widentities + -Wredundant-constraints -Wmissing-export-lists + -Wno-unticked-promoted-constructors -Wunused-packages + +common wno-x-partial + if impl(ghc >=9.8) + -- No errors for x-partial functions. We might remove this in the future if + -- we decide to refactor code that uses partial functions. + ghc-options: -Wno-x-partial + library exposed-modules: System.IO.BlockIO other-modules: @@ -45,7 +58,7 @@ library , primitive ^>=0.9 , unix ^>=2.8 - pkgconfig-depends: liburing >= 2.0 && < 2.7 + pkgconfig-depends: liburing >=2.0 && <2.7 default-language: Haskell2010 ghc-options: -Wall @@ -71,3 +84,23 @@ benchmark bench System.IO.BlockIO.URingFFI ghc-options: -Wall -threaded + +test-suite test + default-language: Haskell2010 + type: exitcode-stdio-1.0 + hs-source-dirs: test . + main-is: Main.hs + build-depends: + , array + , base >=4.16 && <4.20 + , primitive + , tasty + , tasty-hunit + + pkgconfig-depends: liburing + other-modules: + System.IO.BlockIO + System.IO.BlockIO.URing + System.IO.BlockIO.URingFFI + + ghc-options: -threaded -fno-ignore-asserts diff --git a/test/Main.hs b/test/Main.hs new file mode 100644 index 0000000..a17ff50 --- /dev/null +++ b/test/Main.hs @@ -0,0 +1,55 @@ +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TypeApplications #-} + +{-# OPTIONS_GHC -Wno-orphans #-} + +{- HLINT ignore "Use camelCase" -} + +module Main (main) where + +import Control.Exception (SomeException, try) +import Data.Word (Word64) +import System.IO.BlockIO +import System.IO.BlockIO.URing as URing +import Test.Tasty +import Test.Tasty.HUnit + +main :: IO () +main = defaultMain tests + +tests :: TestTree +tests = testGroup "test" [ + testCase "example_simpleNoop 1" $ example_simpleNoop 1 + , testCase "example_simpleNoop maxBound" $ example_simpleNoop maxBound + , testCase "example_initClose" example_initClose + , testCase "example_closeIsIdempotent" example_closeIsIdempotent + ] + +example_simpleNoop :: Word64 -> Assertion +example_simpleNoop n = do + uring <- setupURing (URingParams 1) + prepareNop uring (IOOpId n) + URing.submitIO uring + completion <- awaitIO uring + closeURing uring + IOCompletion (IOOpId n) 0 @=? completion + +deriving instance Eq IOCompletion +deriving instance Show IOCompletion + +example_initClose :: Assertion +example_initClose = do + ctx <- initIOCtx defaultIOCtxParams + closeIOCtx ctx + +example_closeIsIdempotent :: Assertion +example_closeIsIdempotent = do + ctx <- initIOCtx defaultIOCtxParams + closeIOCtx ctx + eith <- try @SomeException (closeIOCtx ctx) + case eith of + Left (e :: SomeException) -> + assertFailure ("Close on a closed context threw an error : " <> show e) + Right () -> + pure ()