@@ -6,15 +6,16 @@ use crate::db::{Pool, PoolClient};
6
6
use crate :: error:: Result ;
7
7
use crate :: repositories:: RepositoryStatsUpdater ;
8
8
use crate :: storage:: { Storage , StorageKind } ;
9
- use crate :: web:: Server ;
9
+ use crate :: web:: { cache , Server } ;
10
10
use crate :: { BuildQueue , Config , Context , Index , Metrics } ;
11
11
use anyhow:: Context as _;
12
12
use fn_error_context:: context;
13
+ use iron:: headers:: CacheControl ;
13
14
use log:: error;
14
15
use once_cell:: unsync:: OnceCell ;
15
16
use postgres:: Client as Connection ;
16
17
use reqwest:: {
17
- blocking:: { Client , ClientBuilder , RequestBuilder } ,
18
+ blocking:: { Client , ClientBuilder , RequestBuilder , Response } ,
18
19
Method ,
19
20
} ;
20
21
use std:: { fs, net:: SocketAddr , panic, sync:: Arc , time:: Duration } ;
@@ -43,21 +44,74 @@ pub(crate) fn wrapper(f: impl FnOnce(&TestEnvironment) -> Result<()>) {
43
44
}
44
45
}
45
46
47
+ /// check a request if the cache control header matches NoCache
48
+ pub ( crate ) fn assert_no_cache ( res : & Response ) {
49
+ assert_eq ! (
50
+ res. headers( )
51
+ . get( "Cache-Control" )
52
+ . expect( "missing cache-control header" ) ,
53
+ cache:: NO_CACHE ,
54
+ ) ;
55
+ }
56
+
57
+ /// check a request if the cache control header matches the given cache config.
58
+ pub ( crate ) fn assert_cache_control (
59
+ res : & Response ,
60
+ cache_policy : cache:: CachePolicy ,
61
+ config : & Config ,
62
+ ) {
63
+ assert ! ( config. cache_control_stale_while_revalidate. is_some( ) ) ;
64
+ assert_eq ! (
65
+ res. headers( )
66
+ . get( "Cache-Control" )
67
+ . expect( "missing cache-control header" ) ,
68
+ & CacheControl ( cache_policy. render( config) ) . to_string( )
69
+ ) ;
70
+ }
71
+
46
72
/// Make sure that a URL returns a status code between 200-299
47
73
pub ( crate ) fn assert_success ( path : & str , web : & TestFrontend ) -> Result < ( ) > {
48
74
let status = web. get ( path) . send ( ) ?. status ( ) ;
49
75
assert ! ( status. is_success( ) , "failed to GET {}: {}" , path, status) ;
50
76
Ok ( ( ) )
51
77
}
52
78
79
+ /// Make sure that a URL returns a status code between 200-299,
80
+ /// also check the cache-control headers.
81
+ pub ( crate ) fn assert_success_cached (
82
+ path : & str ,
83
+ web : & TestFrontend ,
84
+ cache_policy : cache:: CachePolicy ,
85
+ config : & Config ,
86
+ ) -> Result < ( ) > {
87
+ let response = web. get ( path) . send ( ) ?;
88
+ assert_cache_control ( & response, cache_policy, config) ;
89
+ let status = response. status ( ) ;
90
+ assert ! ( status. is_success( ) , "failed to GET {}: {}" , path, status) ;
91
+ Ok ( ( ) )
92
+ }
93
+
53
94
/// Make sure that a URL returns a 404
54
95
pub ( crate ) fn assert_not_found ( path : & str , web : & TestFrontend ) -> Result < ( ) > {
55
- let status = web. get ( path) . send ( ) ?. status ( ) ;
56
- assert_eq ! ( status, 404 , "GET {} should have been a 404" , path) ;
96
+ let response = web. get ( path) . send ( ) ?;
97
+
98
+ // for now, 404s should always have `no-cache`
99
+ assert_no_cache ( & response) ;
100
+
101
+ assert_eq ! (
102
+ response. status( ) ,
103
+ 404 ,
104
+ "GET {} should have been a 404" ,
105
+ path
106
+ ) ;
57
107
Ok ( ( ) )
58
108
}
59
109
60
- fn assert_redirect_common ( path : & str , expected_target : & str , web : & TestFrontend ) -> Result < ( ) > {
110
+ fn assert_redirect_common (
111
+ path : & str ,
112
+ expected_target : & str ,
113
+ web : & TestFrontend ,
114
+ ) -> Result < Response > {
61
115
let response = web. get_no_redirect ( path) . send ( ) ?;
62
116
let status = response. status ( ) ;
63
117
if !status. is_redirection ( ) {
@@ -84,7 +138,7 @@ fn assert_redirect_common(path: &str, expected_target: &str, web: &TestFrontend)
84
138
anyhow:: bail!( "got redirect to {redirect_target}" ) ;
85
139
}
86
140
87
- Ok ( ( ) )
141
+ Ok ( response )
88
142
}
89
143
90
144
/// Makes sure that a URL redirects to a specific page, but doesn't check that the target exists
@@ -94,7 +148,7 @@ pub(crate) fn assert_redirect_unchecked(
94
148
expected_target : & str ,
95
149
web : & TestFrontend ,
96
150
) -> Result < ( ) > {
97
- assert_redirect_common ( path, expected_target, web)
151
+ assert_redirect_common ( path, expected_target, web) . map ( |_| ( ) )
98
152
}
99
153
100
154
/// Make sure that a URL redirects to a specific page, and that the target exists and is not another redirect
@@ -111,6 +165,27 @@ pub(crate) fn assert_redirect(path: &str, expected_target: &str, web: &TestFront
111
165
Ok ( ( ) )
112
166
}
113
167
168
+ /// Make sure that a URL redirects to a specific page, and that the target exists and is not another redirect
169
+ #[ context( "expected redirect from {path} to {expected_target}" ) ]
170
+ pub ( crate ) fn assert_redirect_cached (
171
+ path : & str ,
172
+ expected_target : & str ,
173
+ cache_policy : cache:: CachePolicy ,
174
+ web : & TestFrontend ,
175
+ config : & Config ,
176
+ ) -> Result < ( ) > {
177
+ let redirect_response = assert_redirect_common ( path, expected_target, web) ?;
178
+ assert_cache_control ( & redirect_response, cache_policy, config) ;
179
+
180
+ let response = web. get_no_redirect ( expected_target) . send ( ) ?;
181
+ let status = response. status ( ) ;
182
+ if !status. is_success ( ) {
183
+ anyhow:: bail!( "failed to GET {expected_target}: {status}" ) ;
184
+ }
185
+
186
+ Ok ( ( ) )
187
+ }
188
+
114
189
pub ( crate ) struct TestEnvironment {
115
190
build_queue : OnceCell < Arc < BuildQueue > > ,
116
191
config : OnceCell < Arc < Config > > ,
@@ -188,6 +263,10 @@ impl TestEnvironment {
188
263
config. local_archive_cache_path =
189
264
std:: env:: temp_dir ( ) . join ( format ! ( "docsrs-test-index-{}" , rand:: random:: <u64 >( ) ) ) ;
190
265
266
+ // set stale content serving so Cache::ForeverOnlyInCdn and Cache::ForeverInCdnAndStaleInBrowser
267
+ // are actually different.
268
+ config. cache_control_stale_while_revalidate = Some ( 86400 ) ;
269
+
191
270
config
192
271
}
193
272
0 commit comments