(.module: [library [lux "*" ["_" test {"+" [Test]}] [abstract [monad {"+" [do]}] ["." hash {"+" [Hash]}]] [control ["." io {"+" [IO]}] ["." maybe ("#\." functor)] ["." try ("#\." functor)] [concurrency ["." atom {"+" [Atom]}] ["." async]]] [data ["." product] ["." binary {"+" [Binary]} ("#\." equivalence)] ["." text ["%" format {"+" [format]}]] [collection ["." dictionary {"+" [Dictionary]}] ["." set] ["." list ("#\." mix)]]] [math ["." random {"+" [Random]}] [number ["n" nat]]] [world [net {"+" [URL]} ["." uri {"+" [URI]}] ["." http "_" ["#" client] ["#/." status] ["@#" /]]]]]] ["$." // ["#/" // "_" ["#." package]]] [\\program ["." / [// {"+" [Dependency]} ["." resolution] [// ["." profile] ["." metadata] ["." package {"+" [Package]}] ["." artifact {"+" [Artifact]} ("#\." equivalence) ["#/." type] ["#/." extension]] ["." repository ["." remote]]]]]]) (def: good_upload (@http.Response IO) [http/status.created [#@http.headers (http.headers (list)) #@http.body (function (_ _) (|> [0 (binary.empty 0)] #try.Success io.io))]]) (type: Cache (Atom (Dictionary URL Binary))) (def: (http cache) (-> Cache (http.Client IO)) (implementation (def: (request method url headers input) (do io.monad [_ (: (IO Any) (case [method input] [#@http.Put (#.Some input)] (atom.update! (dictionary.has url input) cache) _ (in [])))] (in (#try.Success ..good_upload)))))) (def: (verify_one expected_deployments address package cache expected_artifact actual_artifact) (-> Nat URL Package (Dictionary URL Binary) Artifact Artifact Bit) (let [url (: (-> URI URL) (|>> (format address))) library_url (url (format (artifact.uri (value@ #artifact.version expected_artifact) expected_artifact) artifact/extension.lux_library)) pom_url (url (format (artifact.uri (value@ #artifact.version expected_artifact) expected_artifact) artifact/extension.pom)) artifact_metadata_url (url (metadata.remote_artifact_uri expected_artifact)) project_metadata_url (url (metadata.remote_project_uri expected_artifact)) expected_library (|> package (value@ #package.library) product.left) expected_pom (|> package (value@ #package.pom) product.right product.left) correct_artifact! (artifact\= expected_artifact actual_artifact) expected_number_of_uploads! (n.= (n.* expected_deployments 8) (dictionary.size cache)) correct_library_upload! (and (|> cache (dictionary.value library_url) (maybe\each (binary\= expected_library)) (maybe.else false)) (dictionary.key? cache (format library_url artifact/extension.sha-1)) (dictionary.key? cache (format library_url artifact/extension.md5))) correct_pom_upload! (and (|> cache (dictionary.value pom_url) (maybe\each (binary\= expected_pom)) (maybe.else false)) (dictionary.key? cache (format pom_url artifact/extension.sha-1)) (dictionary.key? cache (format pom_url artifact/extension.md5))) artifact_metadata_upload! (dictionary.key? cache artifact_metadata_url) project_metadata_upload! (dictionary.key? cache project_metadata_url)] (and correct_artifact! expected_number_of_uploads! correct_library_upload! correct_pom_upload! artifact_metadata_upload! project_metadata_upload!))) (def: bundle (Random [Dependency Artifact Package]) (do random.monad [[profile package] $///package.random .let [artifact (|> profile (value@ #profile.identity) maybe.trusted) dependency (: Dependency [artifact artifact/type.lux_library])]] (in [dependency artifact package]))) (def: .public test Test (<| (_.covering /._) (do [! random.monad] [address (\ ! each (text.suffix uri.separator) (random.ascii/upper 10))] ($_ _.and (do [! random.monad] [[dependency expected_artifact package] ..bundle .let [cache (: Cache (atom.atom (dictionary.empty text.hash))) http (..http cache) repository (repository.async (remote.repository http #.None address))]] (in (do async.monad [?outcome (/.one repository dependency package) cache (async.future (atom.read! cache))] (_.cover' [/.one] (|> ?outcome (try\each (verify_one 1 address package cache expected_artifact)) (try.else false)))))) (do [! random.monad] [.let [hash (: (Hash [Dependency Artifact Package]) (\ hash.functor each (|>> product.right product.left product.left) text.hash))] num_bundles (\ ! each (n.% 10) random.nat) bundles (|> ..bundle (random.set hash num_bundles) (\ ! each set.list)) .let [resolution (list\mix (function (_ [dependency expected_artifact package] resolution) (dictionary.has dependency package resolution)) resolution.empty bundles) cache (: Cache (atom.atom (dictionary.empty text.hash))) http (..http cache) repository (repository.async (remote.repository http #.None address))]] (in (do async.monad [?outcome (/.all repository resolution) cache (async.future (atom.read! cache))] (_.cover' [/.all] (|> ?outcome (try\each (function (_ actual_artifacts) (let [expected_deployments! (n.= num_bundles (set.size actual_artifacts)) every_deployment_was_correct! (list.every? (function (_ [dependency expected_artifact package]) (let [deployed! (set.member? actual_artifacts expected_artifact) deployed_correctly! (verify_one num_bundles address package cache expected_artifact expected_artifact)] (and deployed! deployed_correctly!))) bundles)] (and expected_deployments! every_deployment_was_correct!)))) (try.else false)))))) ))))