A batteries included HTTP/1.1 client in OCaml
at main 136 lines 5.3 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(** Tests for Auth module *) 7 8module Auth = Requests.Auth 9module Headers = Requests.Headers 10 11(** {1 requires_https Tests} *) 12 13let test_requires_https_none () = 14 Alcotest.(check bool) 15 "none does not require https" false 16 (Auth.requires_https Auth.none) 17 18let test_requires_https_basic () = 19 let auth = Auth.basic ~username:"user" ~password:"pass" in 20 Alcotest.(check bool) "basic requires https" true (Auth.requires_https auth) 21 22let test_requires_https_bearer () = 23 let auth = Auth.bearer ~token:"tok" in 24 Alcotest.(check bool) "bearer requires https" true (Auth.requires_https auth) 25 26let test_requires_https_digest () = 27 let auth = Auth.digest ~username:"user" ~password:"pass" in 28 Alcotest.(check bool) "digest requires https" true (Auth.requires_https auth) 29 30(** {1 is_digest Tests} *) 31 32let test_is_digest_true () = 33 let auth = Auth.digest ~username:"user" ~password:"pass" in 34 Alcotest.(check bool) "digest is_digest" true (Auth.is_digest auth) 35 36let test_is_digest_false_none () = 37 Alcotest.(check bool) "none is not digest" false (Auth.is_digest Auth.none) 38 39let test_is_digest_false_basic () = 40 let auth = Auth.basic ~username:"user" ~password:"pass" in 41 Alcotest.(check bool) "basic is not digest" false (Auth.is_digest auth) 42 43(** {1 apply Tests} *) 44 45let test_apply_basic () = 46 let auth = Auth.basic ~username:"user" ~password:"pass" in 47 let headers = Auth.apply auth Headers.empty in 48 let v = Headers.string "authorization" headers in 49 match v with 50 | Some s -> 51 Alcotest.(check bool) 52 "basic auth starts with Basic" true 53 (String.length s > 6 && String.sub s 0 6 = "Basic ") 54 | None -> Alcotest.fail "Expected Authorization header" 55 56let test_apply_bearer () = 57 let auth = Auth.bearer ~token:"mytoken" in 58 let headers = Auth.apply auth Headers.empty in 59 let v = Headers.string "authorization" headers in 60 Alcotest.(check (option string)) 61 "bearer auth header" (Some "Bearer mytoken") v 62 63let test_apply_none () = 64 let headers = Auth.apply Auth.none Headers.empty in 65 let v = Headers.string "authorization" headers in 66 Alcotest.(check (option string)) "no auth header" None v 67 68(** {1 digest_credentials Tests} *) 69 70let test_get_digest_credentials_some () = 71 let auth = Auth.digest ~username:"alice" ~password:"secret" in 72 let creds = Auth.digest_credentials auth in 73 Alcotest.(check (option (pair string string))) 74 "digest credentials" 75 (Some ("alice", "secret")) 76 creds 77 78let test_get_digest_credentials_none () = 79 let auth = Auth.basic ~username:"alice" ~password:"secret" in 80 let creds = Auth.digest_credentials auth in 81 Alcotest.(check (option (pair string string))) 82 "non-digest has no credentials" None creds 83 84let test_digest_credentials_none () = 85 let creds = Auth.digest_credentials Auth.none in 86 Alcotest.(check (option (pair string string))) 87 "none has no credentials" None creds 88 89(** {1 parse_www_authenticate Tests} *) 90 91let test_parse_www_authenticate_digest () = 92 let header = 93 "Digest realm=\"example.com\", nonce=\"abc123\", qop=\"auth\", \ 94 algorithm=SHA-256" 95 in 96 match Auth.parse_www_authenticate header with 97 | Some challenge -> 98 Alcotest.(check string) "realm" "example.com" challenge.realm; 99 Alcotest.(check string) "nonce" "abc123" challenge.nonce; 100 Alcotest.(check (option string)) "qop" (Some "auth") challenge.qop; 101 Alcotest.(check string) "algorithm" "SHA-256" challenge.algorithm 102 | None -> Alcotest.fail "Expected parsed digest challenge" 103 104let parse_www_auth_not_digest () = 105 let header = "Basic realm=\"example.com\"" in 106 let result = Auth.parse_www_authenticate header in 107 Alcotest.(check bool) "not a digest challenge" true (Option.is_none result) 108 109(** {1 Test Suite} *) 110 111let suite = 112 ( "auth", 113 [ 114 Alcotest.test_case "requires_https none" `Quick test_requires_https_none; 115 Alcotest.test_case "requires_https basic" `Quick test_requires_https_basic; 116 Alcotest.test_case "requires_https bearer" `Quick 117 test_requires_https_bearer; 118 Alcotest.test_case "requires_https digest" `Quick 119 test_requires_https_digest; 120 Alcotest.test_case "is_digest true" `Quick test_is_digest_true; 121 Alcotest.test_case "is_digest false none" `Quick test_is_digest_false_none; 122 Alcotest.test_case "is_digest false basic" `Quick 123 test_is_digest_false_basic; 124 Alcotest.test_case "apply basic" `Quick test_apply_basic; 125 Alcotest.test_case "apply bearer" `Quick test_apply_bearer; 126 Alcotest.test_case "apply none" `Quick test_apply_none; 127 Alcotest.test_case "digest credentials some" `Quick 128 test_get_digest_credentials_some; 129 Alcotest.test_case "digest credentials none" `Quick 130 test_get_digest_credentials_none; 131 Alcotest.test_case "digest credentials none auth" `Quick 132 test_digest_credentials_none; 133 Alcotest.test_case "parse www-authenticate" `Quick 134 test_parse_www_authenticate_digest; 135 Alcotest.test_case "parse non-digest" `Quick parse_www_auth_not_digest; 136 ] )