Skip to content

Commit 4a9c49e

Browse files
committed
tests: add basic unit tests for compute-static
fix: remame compute-static build target to wasip1 fix: pin toolchain to 1.90 due to https://www.fastlystatus.com/incident/378001 tweak: handle version-downloads URL path with/without trailing slash in the same way without permanent redirects refactor: move request/response log collection to log_line to facilitate testing
1 parent b0a9e28 commit 4a9c49e

File tree

6 files changed

+232
-116
lines changed

6 files changed

+232
-116
lines changed
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
[build]
2-
target = "wasm32-wasi"
2+
target = "wasm32-wasip1"
3+
4+
[target.wasm32-wasip1]
5+
runner = "viceroy run -C fastly.toml -- "

terragrunt/modules/crates-io/compute-static/Cargo.lock

Lines changed: 48 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

terragrunt/modules/crates-io/compute-static/README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,33 @@ responses.
88

99
## Development
1010

11-
Build the function:
11+
Install the Fastly CLI from [here](https://www.fastly.com/documentation/reference/tools/cli/#installing).
12+
13+
Then, build the function:
1214

1315
```shell
1416
cd compute-static
1517
fastly compute build
1618
```
1719

20+
## Testing
21+
22+
Testing requires [cargo-nextest](https://nexte.st/docs/installation/pre-built-binaries/), as specified in the [Fastly documentation](https://www.fastly.com/documentation/guides/compute/developer-guides/rust/). You can install it from source with binstall:
23+
```shell
24+
cargo install cargo-binstall
25+
cargo binstall cargo-nextest --secure
26+
```
27+
28+
Then, install [Viceroy](https://github.com/fastly/Viceroy) to run the edge function locally:
29+
```shell
30+
cargo install --locked viceroy
31+
```
32+
33+
Now you can run the tests with:
34+
```shell
35+
cargo nextest run
36+
```
37+
1838
## Deployment
1939

2040
Terraform uses an [external data source] to build the function as part of its
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[toolchain]
2-
channel = "stable"
2+
channel = "1.90"
33
targets = ["wasm32-wasip1"]

terragrunt/modules/crates-io/compute-static/src/log_line.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1+
use std::env::var;
12
use std::net::IpAddr;
23

4+
use crate::config::Config;
5+
use crate::http_version_to_string;
36
use derive_builder::Builder;
7+
use fastly::{Error, Request, Response};
48
use serde::Serialize;
59
use time::OffsetDateTime;
610

11+
const DATADOG_APP: &str = "crates.io";
12+
const DATADOG_SERVICE: &str = "static.crates.io";
13+
714
#[derive(Debug, Serialize)]
815
#[serde(tag = "version")]
916
pub enum LogLine {
@@ -33,6 +40,65 @@ pub struct LogLineV1 {
3340
url: String,
3441
}
3542

43+
impl LogLineV1 {
44+
/// Collect data for the logs from the request
45+
pub fn collect_request(config: &Config, request: &Request) -> LogLineV1Builder {
46+
let http_details = HttpDetailsBuilder::default()
47+
.protocol(http_version_to_string(request.get_version()))
48+
.referer(
49+
request
50+
.get_header("Referer")
51+
.and_then(|s| s.to_str().ok())
52+
.map(|s| s.to_string()),
53+
)
54+
.useragent(
55+
request
56+
.get_header("User-Agent")
57+
.and_then(|s| s.to_str().ok())
58+
.map(|s| s.to_string()),
59+
)
60+
.build()
61+
.ok();
62+
63+
let tls_details = TlsDetailsBuilder::default()
64+
.cipher(request.get_tls_cipher_openssl_name())
65+
.protocol(request.get_tls_protocol())
66+
.build()
67+
.ok();
68+
69+
let log_line = LogLineV1Builder::default()
70+
.ddtags(format!("app:{},env:{}", DATADOG_APP, config.datadog_env))
71+
.service(DATADOG_SERVICE)
72+
.date_time(OffsetDateTime::now_utc())
73+
.edge_location(var("FASTLY_POP").ok())
74+
.host(request.get_url().host().map(|s| s.to_string()))
75+
.http(http_details)
76+
.ip(request.get_client_ip_addr())
77+
.method(Some(request.get_method().to_string()))
78+
.url(request.get_url_str().into())
79+
.tls(tls_details)
80+
.to_owned();
81+
82+
log_line
83+
}
84+
85+
/// Collect data for the logs from the response
86+
pub fn collect_response(
87+
log_line: &mut LogLineV1Builder,
88+
response: &Result<Response, Error>,
89+
) -> LogLineV1Builder {
90+
if let Ok(response) = response {
91+
log_line
92+
.bytes(response.get_content_length())
93+
.content_type(response.get_content_type().map(|s| s.to_string()))
94+
.status(Some(response.get_status().as_u16()))
95+
.to_owned()
96+
} else {
97+
log_line.status(Some(500)).to_owned()
98+
}
99+
}
100+
}
101+
36102
fn default_source() -> &'static str {
37103
"fastly"
38104
}
@@ -49,3 +115,43 @@ pub struct TlsDetails {
49115
cipher: Option<&'static str>,
50116
protocol: Option<&'static str>,
51117
}
118+
119+
#[cfg(test)]
120+
mod tests {
121+
use super::*;
122+
123+
/// Verifies whether the log collector can correctly build a log line from a request/response pair.
124+
#[test]
125+
fn test_log_collector() {
126+
let client_req = Request::get("https://crates.io/crates/syn"); // Arbitrary crate with no meaning
127+
let config = Config {
128+
primary_host: "test_backend".to_string(),
129+
fallback_host: "fallback_host".to_string(),
130+
static_ttl: 0,
131+
cloudfront_url: "cloudfront_url".to_string(),
132+
datadog_env: "datadog_env".to_string(),
133+
datadog_host: "datadog_host".to_string(),
134+
datadog_request_logs_endpoint: "datadog_request_logs_endpoint".to_string(),
135+
s3_request_logs_endpoint: "s3_request_logs_endpoint".to_string(),
136+
s3_service_logs_endpoint: "s3_service_logs_endpoint".to_string(),
137+
};
138+
let mut log = LogLineV1::collect_request(&config, &client_req);
139+
let log = LogLineV1::collect_response(
140+
&mut log,
141+
&Ok(Response::temporary_redirect("https://crates.io/")),
142+
);
143+
let log = log.build().unwrap();
144+
assert_eq!(log.ddsource, "fastly");
145+
assert_eq!(
146+
log.ddtags,
147+
format!("app:crates.io,env:{}", config.datadog_env)
148+
);
149+
assert_eq!(log.service, "static.crates.io");
150+
assert_eq!(
151+
log.host,
152+
Some(client_req.get_url().host().unwrap().to_string())
153+
);
154+
assert_eq!(log.url, client_req.get_url_str());
155+
assert_eq!(log.method, Some(client_req.get_method().to_string()));
156+
}
157+
}

0 commit comments

Comments
 (0)