Skip to content
Merged
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
56 changes: 52 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,70 @@
name: CI

on: [push, pull_request, workflow_dispatch]
on:
push:
branches: [main]
pull_request:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

permissions:
contents: read

env:
JULIA_VERSION: '1.12.6'

jobs:
cpu:
runs-on: macos-15
package:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: julia-actions/setup-julia@v3
with: {version: '${{ env.JULIA_VERSION }}'}
- uses: julia-actions/cache@v3
- name: Package tests
run: julia --project=. --startup-file=no -e 'using Pkg; Pkg.instantiate(); Pkg.test()'
run: julia --project=. --startup-file=no -e 'using Pkg; Pkg.instantiate(); Pkg.test(; test_args=["--jobs=2", "--verbose"])'

scientific:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: julia-actions/setup-julia@v3
with: {version: '${{ env.JULIA_VERSION }}'}
- uses: julia-actions/cache@v3
- name: Scientific witnesses
run: julia --project=test/scientific_witnesses --startup-file=no -e 'using Pkg; Pkg.develop(path="."); Pkg.instantiate(); include("test/scientific_witnesses/runtests.jl")'

macos-smoke:
runs-on: macos-15
steps:
- uses: actions/checkout@v6
- uses: julia-actions/setup-julia@v3
with: {version: '${{ env.JULIA_VERSION }}'}
- uses: julia-actions/cache@v3
- name: Public API and KernelAbstractions smoke tests
run: julia --project=. --startup-file=no -e 'using Pkg; Pkg.instantiate(); Pkg.test(; test_args=["--jobs=1", "test_public_api", "test_direct_pointwise_stage"])'

macos-package:
if: github.event_name != 'pull_request'
runs-on: macos-15
steps:
- uses: actions/checkout@v6
- uses: julia-actions/setup-julia@v3
with: {version: '${{ env.JULIA_VERSION }}'}
- uses: julia-actions/cache@v3
- name: Complete macOS package tests
run: julia --project=. --startup-file=no -e 'using Pkg; Pkg.instantiate(); Pkg.test(; test_args=["--jobs=2"])'

docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: julia-actions/setup-julia@v3
with: {version: '${{ env.JULIA_VERSION }}'}
- uses: julia-actions/cache@v3
- name: Documentation
run: julia --project=docs --startup-file=no -e 'using Pkg; Pkg.develop(path="."); Pkg.instantiate(); include("docs/make.jl")'

Expand Down
2 changes: 2 additions & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7"
KernelAbstractions = "63c18a36-062a-441e-b654-da1e3ab1ce7c"
LocalMath = "82808884-8acc-4a5c-a056-be440a0fbea1"
ParallelTestRunner = "d3525ed8-44d0-4b2c-a655-542cee43accc"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand All @@ -12,6 +13,7 @@ TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
Aqua = "0.8"
ExplicitImports = "1"
KernelAbstractions = "0.9.42"
ParallelTestRunner = "2.8"
StaticArrays = "1"
Statistics = "1"
Test = "1"
Expand Down
145 changes: 87 additions & 58 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,59 +1,7 @@
using Aqua
using ExplicitImports
using ParallelTestRunner
using Test
import LocalMath

@testset "LocalMath package quality" begin
Aqua.test_all(LocalMath; ambiguities = false)
# These qualified non-public accesses implement the reviewed central
# admission, compiler-identity, storage-alias, and backend-validation
# boundaries. Keep the allowlist exact so new private reliance still fails.
qualified_internal_boundary = (
Symbol("@adapt_structure"),
Symbol("@atomic"),
Symbol("@nospecializeinfer"),
:Argument,
:CodeInfo,
:CodeInstance,
:Compiler,
:Const,
:LLVMPtr,
:MethodInstance,
:PkgId,
:SSAValue,
:SlotNumber,
:Typeof,
:apply_type,
:checked_mul,
:code_typed_by_type,
:datatype_alignment,
:device,
:functional,
:get_world_counter,
:ifelse,
:inferencebarrier,
:invoke_in_world,
:loaded_modules,
:mightalias,
:return_type,
:throw_boundserror,
:throw_inexacterror,
:typename,
:typesof,
:uncompressed_ast,
:unwrap_unionall,
)
ExplicitImports.test_explicit_imports(
LocalMath;
all_qualified_accesses_are_public =
(; ignore = qualified_internal_boundary),
)
@test isempty(Test.detect_ambiguities(
LocalMath, Base; recursive = true
))
end

include("support.jl")
const LOCALMATH_INCLUDED_TESTS = (
"test_public_api.jl",
"test_spatial_model.jl",
Expand Down Expand Up @@ -91,10 +39,91 @@ const LOCALMATH_INCLUDED_TESTS = (
"test_semantic_oracles.jl",
)

@testset "LocalMath test runner inventory" begin
discovered = sort(filter(name ->
startswith(name, "test_") && endswith(name, ".jl"), readdir(@__DIR__)))
@test sort(collect(LOCALMATH_INCLUDED_TESTS)) == discovered
const LOCALMATH_TEST_SUITE = Dict{String, Expr}(
"package_quality" => quote
using Aqua
using ExplicitImports

@testset "LocalMath package quality" begin
Aqua.test_all(LocalMath; ambiguities = false)
# These qualified non-public accesses implement the reviewed
# central admission, compiler-identity, storage-alias, and
# backend-validation boundaries. Keep the allowlist exact so new
# private reliance still fails.
qualified_internal_boundary = (
Symbol("@adapt_structure"),
Symbol("@atomic"),
Symbol("@nospecializeinfer"),
:Argument,
:CodeInfo,
:CodeInstance,
:Compiler,
:Const,
:LLVMPtr,
:MethodInstance,
:PkgId,
:SSAValue,
:SlotNumber,
:Typeof,
:apply_type,
:checked_mul,
:code_typed_by_type,
:datatype_alignment,
:device,
:functional,
:get_world_counter,
:ifelse,
:inferencebarrier,
:invoke_in_world,
:loaded_modules,
:mightalias,
:return_type,
:throw_boundserror,
:throw_inexacterror,
:typename,
:typesof,
:uncompressed_ast,
:unwrap_unionall,
)
ExplicitImports.test_explicit_imports(
LocalMath;
all_qualified_accesses_are_public =
(; ignore = qualified_internal_boundary),
)
@test isempty(Test.detect_ambiguities(
LocalMath, Base; recursive = true
))
end
end,
"test_runner_inventory" => quote
@testset "LocalMath test runner inventory" begin
discovered = sort(filter(
name -> startswith(name, "test_") && endswith(name, ".jl"),
readdir(@__DIR__),
))
@test sort(collect($LOCALMATH_INCLUDED_TESTS)) == discovered
end
end,
)

for test_file in LOCALMATH_INCLUDED_TESTS
test_name = first(splitext(test_file))
LOCALMATH_TEST_SUITE[test_name] = quote
include($(joinpath(@__DIR__, "support.jl")))
include($(joinpath(@__DIR__, test_file)))
end
end

const LOCALMATH_TEST_INITIALIZATION = quote
using Test
import KernelAbstractions
import LocalMath
end

foreach(include, LOCALMATH_INCLUDED_TESTS)
ParallelTestRunner.runtests(
LocalMath,
ARGS;
testsuite = LOCALMATH_TEST_SUITE,
init_code = LOCALMATH_TEST_INITIALIZATION,
serial = ["package_quality", "test_runner_inventory"],
)
31 changes: 31 additions & 0 deletions test/support.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,34 @@ function _test_stage_admission(bound; backend, index::Integer = 1)
1 <= index <= length(entries) || throw(BoundsError(entries, index))
return entries[index].admission
end

struct ReceiptTestNode end
struct ReceiptTestEvaluator{T}
value::T
end

@inline (evaluator::ReceiptTestEvaluator)(item::Int32, reads, parameters) =
(value = LM.UniqueValue(evaluator.value + item),)

function _receipt_test_preparation(value::Int32;
dependency_arity::Int = 0, lease_capacity::Int = 1,
evaluator = ReceiptTestEvaluator(value))
space = LM.Space(ReceiptTestNode, 2)
output = LM.Field(space, Int32)
relation = LM.IdentityRelation(space)
publication = LM.Publication((LM.FieldPublication(
output, relation, LM.PublicationValue(:value)),),
LM.Unique(Int32))
stage = LM.Stage(space, NamedTuple(), (publication,),
LM.Evaluator(evaluator), LM.Control(),
LM.SourceOrigin(:execution_receipt_test, 1))
storage = fill(Int32(-1), 2)
bound = LM._bind_law(LM.LocalLaw(stage),
LM._StructuralBinding(
(LM._field_storage_binding(output, storage),),
(LM._relation_storage_binding(relation),)))
backend = LM.KernelAbstractions.get_backend(storage)
prepared = LM.prepare(LM.plan(bound; backend);
dependency_arity, lease_capacity)
return prepared, storage
end
29 changes: 0 additions & 29 deletions test/test_execution_receipts.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,13 @@ using Test
import LocalMath
const LWER = LocalMath

struct ReceiptTestNode end
struct ReceiptTestEvaluator{T}
value::T
end
@inline (evaluator::ReceiptTestEvaluator)(item::Int32, reads, parameters) =
(value = LWER.UniqueValue(evaluator.value + item),)
struct ReceiptProviderFailureEvaluator end
@inline function (::ReceiptProviderFailureEvaluator)(
item::Int32, reads, parameters)
item == Int32(0) && return (value = LWER.UniqueValue(item),)
error("intentional provider execution failure")
end

function _receipt_test_preparation(value::Int32;
dependency_arity::Int = 0, lease_capacity::Int = 1,
evaluator = ReceiptTestEvaluator(value))
space = LWER.Space(ReceiptTestNode, 2)
output = LWER.Field(space, Int32)
relation = LWER.IdentityRelation(space)
publication = LWER.Publication((LWER.FieldPublication(
output, relation, LWER.PublicationValue(:value)),),
LWER.Unique(Int32))
stage = LWER.Stage(space, NamedTuple(), (publication,),
LWER.Evaluator(evaluator), LWER.Control(),
LWER.SourceOrigin(:execution_receipt_test, 1))
storage = fill(Int32(-1), 2)
bound = LWER._bind_law(LWER.LocalLaw(stage),
LWER._StructuralBinding(
(LWER._field_storage_binding(output, storage),),
(LWER._relation_storage_binding(relation),)))
backend = LWER.KernelAbstractions.get_backend(storage)
prepared = LWER.prepare(LWER.plan(bound; backend);
dependency_arity, lease_capacity)
return prepared, storage
end

function _receipt_test_conflict_preparation(; dependency_arity::Int = 0)
source = LWER.Space(ReceiptTestNode, 2)
destination = LWER.Space(ReceiptTestNode, 1)
Expand Down