Skip to content

Commit 9ead331

Browse files
nkzouci.datadog-api-spec
and
ci.datadog-api-spec
authored
Enable test running in CI (#43)
Co-authored-by: ci.datadog-api-spec <[email protected]>
1 parent e7d5fe1 commit 9ead331

File tree

92 files changed

+24261
-3637
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+24261
-3637
lines changed

Diff for: .generator/src/generator/templates/api.j2

+92-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
use reqwest;
33
use serde::{Serialize, Deserialize};
44
use crate::datadog::*;
5+
use reqwest::header::{HeaderMap, HeaderValue};
56
{%- for _, _, operation in operations if "x-pagination" in operation %}
67
{%- if loop.first %}
78
use async_stream::try_stream;
@@ -13,6 +14,12 @@ use futures_core::stream::Stream;
1314
use log::warn;
1415
{%- endif %}
1516
{%- endfor %}
17+
{%- for _, _, operation in operations if operation.requestBody is defined and not operation|form_parameter %}
18+
{%- if loop.first %}
19+
use std::io::Write;
20+
use flate2::{write::{GzEncoder, ZlibEncoder}, Compression};
21+
{%- endif %}
22+
{%- endfor %}
1623

1724
{%- set structName = name.replace(" ", "")+"API" %}
1825
{% for path, method, operation in operations|sort(attribute="2.operationId", case_sensitive=true) %}
@@ -300,18 +307,50 @@ impl {{ structName }} {
300307
{%- endif %}
301308
{%- endfor %}
302309

310+
// build headers
311+
let mut headers = HeaderMap::new();
312+
{%- if operation.requestBody %}
313+
{%- set contentTypeHeaders = operation.requestBody.content.keys()|list %}
314+
{%- if contentTypeHeaders %}
315+
{%- if "application/json" in contentTypeHeaders %}
316+
headers.insert("Content-Type", HeaderValue::from_static("application/json"));
317+
{%- else %}
318+
headers.insert("Content-Type", HeaderValue::from_static("{{ contentTypeHeaders[0] }}"));
319+
{%- endif %}
320+
{%- endif %}
321+
{%- endif %}
322+
{%- if operation.responses %}
323+
{%- set acceptHeaders = operation|accept_headers %}
324+
{%- if acceptHeaders %}
325+
{%- if "application/json" in acceptHeaders %}
326+
headers.insert("Accept", HeaderValue::from_static("application/json"));
327+
{%- else %}
328+
headers.insert("Accept", HeaderValue::from_static("{{ acceptHeaders|join(",") }}"));
329+
{%- endif %}
330+
{%- endif %}
331+
{%- endif %}
332+
303333
{% for name, parameter in operation|parameters if parameter.in == "header" %}
304334
{%- if not parameter.required %}
305335
if let Some(ref local) = {{name|variable_name}} {
306-
local_req_builder = local_req_builder.header("{{name}}", &local.to_string());
307-
};
336+
headers.insert("{{name}}", local.to_string().parse().expect("failed to parse {{name}} header"));
337+
}
308338
{%- else %}
309-
local_req_builder = local_req_builder.header("{{name}}", &{{name|variable_name}}.to_string());
339+
headers.insert("{{name}}", {{name|variable_name}}.to_string().parse().expect("failed to parse {{name}} header"));
310340
{%- endif %}
311341
{%- endfor %}
312342

313343
// build user agent
314-
local_req_builder = local_req_builder.header(reqwest::header::USER_AGENT, local_configuration.user_agent.clone());
344+
match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
345+
Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
346+
Err(e) => {
347+
log::warn!("Failed to parse user agent header: {e}, falling back to default");
348+
headers.insert(
349+
reqwest::header::USER_AGENT,
350+
HeaderValue::from_static(configuration::DEFAULT_USER_AGENT.as_str()),
351+
)
352+
}
353+
};
315354

316355
// build auth
317356
{%- set authMethods = operation.security if "security" in operation else openapi.security %}
@@ -321,7 +360,7 @@ impl {{ structName }} {
321360
{%- set schema = openapi.components.securitySchemes[name] %}
322361
{%- if schema.type == "apiKey" and schema.in != "cookie" %}
323362
if let Some(local_key) = local_configuration.auth_keys.get("{{ name }}") {
324-
local_req_builder = local_req_builder.header("{{schema.name}}", &local_key.key);
363+
headers.insert("{{schema.name}}", HeaderValue::from_str(local_key.key.as_str()).expect("failed to parse {{schema.name}} header"));
325364
};
326365
{%- endif %}
327366
{%- endfor %}
@@ -333,11 +372,13 @@ impl {{ structName }} {
333372
{%- if formParameter.required %}
334373
let mut local_form = reqwest::multipart::Form::new();
335374
local_form = local_form.part("{{formParameter.name}}", reqwest::multipart::Part::bytes({{formParameter.name}}).file_name("{{formParameter.name}}"));
375+
headers.insert("Content-Type", format!("multipart/form-data; boundary={}", local_form.boundary()).parse().unwrap());
336376
local_req_builder = local_req_builder.multipart(local_form);
337377
{%- else %}
338378
if let Some({{formParameter.name}}) = {{formParameter.name}} {
339379
let mut local_form = reqwest::multipart::Form::new();
340380
local_form = local_form.part("{{formParameter.name}}", reqwest::multipart::Part::bytes({{formParameter.name}}).file_name("{{formParameter.name}}"));
381+
headers.insert("Content-Type", format!("multipart/form-data; boundary={}", local_form.boundary()).parse().unwrap());
341382
local_req_builder = local_req_builder.multipart(local_form);
342383
};
343384
{%- endif %}
@@ -348,10 +389,55 @@ impl {{ structName }} {
348389
let output = Vec::new();
349390
let mut ser = serde_json::Serializer::with_formatter(output, DDFormatter);
350391
if {{operation.get("x-codegen-request-body-name", "body")|variable_name}}.serialize(&mut ser).is_ok() {
351-
local_req_builder = local_req_builder.body(ser.into_inner());
392+
if let Some(content_encoding) = headers.get("Content-Encoding") {
393+
match content_encoding.to_str().unwrap_or_default() {
394+
"gzip" => {
395+
let mut enc = GzEncoder::new(
396+
Vec::new(),
397+
Compression::default(),
398+
);
399+
let _ = enc.write_all(ser.into_inner().as_slice());
400+
match enc.finish() {
401+
Ok(buf) => {
402+
local_req_builder = local_req_builder.body(buf);
403+
}
404+
Err(e) => return Err(Error::Io(e)),
405+
}
406+
}
407+
"deflate" => {
408+
let mut enc = ZlibEncoder::new(
409+
Vec::new(),
410+
Compression::default(),
411+
);
412+
let _ = enc.write_all(ser.into_inner().as_slice());
413+
match enc.finish() {
414+
Ok(buf) => {
415+
local_req_builder = local_req_builder.body(buf);
416+
}
417+
Err(e) => return Err(Error::Io(e)),
418+
}
419+
}
420+
"zstd1" => {
421+
let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap();
422+
let _ = enc.write_all(ser.into_inner().as_slice());
423+
match enc.finish() {
424+
Ok(buf) => {
425+
local_req_builder = local_req_builder.body(buf);
426+
}
427+
Err(e) => return Err(Error::Io(e)),
428+
}
429+
}
430+
_ => {
431+
local_req_builder = local_req_builder.body(ser.into_inner());
432+
},
433+
}
434+
} else {
435+
local_req_builder = local_req_builder.body(ser.into_inner());
436+
}
352437
}
353438
{%- endif %}
354439

440+
local_req_builder = local_req_builder.headers(headers);
355441
let local_req = local_req_builder.build()?;
356442
let local_resp = local_client.execute(local_req).await?;
357443

Diff for: .generator/src/generator/templates/configuration.j2

+8-8
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,6 @@ impl Configuration {
118118

119119
impl Default for Configuration {
120120
fn default() -> Self {
121-
let user_agent = format!(
122-
"datadog-api-client-rust/{} (rust {}; os {}; arch {})",
123-
option_env!("CARGO_PKG_VERSION").unwrap_or("?"),
124-
option_env!("DD_RUSTC_VERSION").unwrap_or("?"),
125-
env::consts::OS,
126-
env::consts::ARCH,
127-
);
128121
let unstable_operations = HashMap::from([
129122
{%- for version, api in apis.items() %}
130123
{%- for operations in api.values() %}
@@ -156,7 +149,7 @@ impl Default for Configuration {
156149
{%- endif %}
157150

158151
Self {
159-
user_agent,
152+
user_agent: DEFAULT_USER_AGENT.clone(),
160153
unstable_operations,
161154
auth_keys,
162155
server_index: 0,
@@ -192,6 +185,13 @@ ServerConfiguration {
192185
{%- endmacro %}
193186

194187
lazy_static! {
188+
pub static ref DEFAULT_USER_AGENT: String = format!(
189+
"datadog-api-client-rust/{} (rust {}; os {}; arch {})",
190+
option_env!("CARGO_PKG_VERSION").unwrap_or("?"),
191+
option_env!("DD_RUSTC_VERSION").unwrap_or("?"),
192+
env::consts::OS,
193+
env::consts::ARCH,
194+
);
195195
static ref SERVERS: Vec<ServerConfiguration> = {
196196
vec![
197197
{%- for server in openapi.servers %}

Diff for: .generator/src/generator/templates/function_mappings.j2

+4-4
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,14 @@ fn test_{{version}}_{{ operation['operationId'] | snake_case }}(world: &mut Data
6464
{%- set schema = parameter[1] | parameter_schema %}
6565
{%- if parameter[1].required %}
6666
{%- if schema | is_primitive and schema.get("format") == "binary" -%}
67-
let {{ parameter[0] | variable_name }} = _parameters.get("{{ parameter[0] }}").unwrap().as_str().unwrap().as_bytes().to_vec();
67+
let {{ parameter[0] | variable_name }} = std::fs::read(format!("tests/scenarios/features/v{}/{}", world.api_version, _parameters.get("{{ parameter[0] }}").unwrap().as_str().unwrap())).unwrap();
6868
{%- else -%}
6969
let {{ parameter[0] | variable_name }} = serde_json::from_value(_parameters.get("{{ parameter[0] }}").unwrap().clone()).unwrap();
7070
{%- endif -%}
7171
{%- else %}
7272
let {{ parameter[0] | variable_name }} = _parameters.get("{{ parameter[0] }}").and_then(|param|
7373
{%- if schema | is_primitive and schema.get("format") == "binary" -%}
74-
Some(param.as_str().unwrap().as_bytes().to_vec())
74+
std::fs::read(format!("tests/scenarios/features/v{}/{}", world.api_version, param.as_str().unwrap())).ok()
7575
{%- else -%}
7676
Some(serde_json::from_value(param.clone()).unwrap())
7777
{%- endif -%}
@@ -113,14 +113,14 @@ fn test_{{version}}_{{ operation['operationId'] | snake_case }}_with_pagination(
113113
{%- set schema = parameter[1] | parameter_schema %}
114114
{%- if parameter[1].required %}
115115
{%- if schema | is_primitive and schema.get("format") == "binary" -%}
116-
let {{ parameter[0] | variable_name }} = _parameters.get("{{ parameter[0] }}").unwrap().as_str().unwrap().as_bytes().to_vec();
116+
let {{ parameter[0] | variable_name }} = std::fs::read(_parameters.get("{{ parameter[0] }}").unwrap().as_str().unwrap()).unwrap();
117117
{%- else -%}
118118
let {{ parameter[0] | variable_name }} = serde_json::from_value(_parameters.get("{{ parameter[0] }}").unwrap().clone()).unwrap();
119119
{%- endif -%}
120120
{%- else %}
121121
let {{ parameter[0] | variable_name }} = _parameters.get("{{ parameter[0] }}").and_then(|param|
122122
{%- if schema | is_primitive and schema.get("format") == "binary" -%}
123-
Some(param.as_str().unwrap().as_bytes().to_vec())
123+
std::fs::read(param.as_str().unwrap()).ok()
124124
{%- else -%}
125125
Some(serde_json::from_value(param.clone()).unwrap())
126126
{%- endif -%}

Diff for: .github/workflows/test.yml

+7-4
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ on:
88
pull_request:
99
branches:
1010
- master
11-
# schedule:
12-
# - cron: "0 1 * * *"
11+
schedule:
12+
- cron: "0 6 * * *"
1313

1414
concurrency:
1515
group: unit-${{ github.head_ref }}
@@ -25,11 +25,14 @@ jobs:
2525
github.event_name == 'schedule'
2626
steps:
2727
- name: Get GitHub App token
28+
if: github.event_name == 'pull_request'
2829
id: get_token
29-
uses: tibdex/github-app-token@v1
30+
uses: tibdex/github-app-token@v2.1.0
3031
with:
3132
app_id: ${{ secrets.PIPELINE_GITHUB_APP_ID }}
3233
private_key: ${{ secrets.PIPELINE_GITHUB_APP_PRIVATE_KEY }}
34+
installation_retrieval_mode: repository
35+
installation_retrieval_payload: DataDog/datadog-api-spec
3336
- uses: actions/checkout@v3
3437
with:
3538
fetch-depth: 0
@@ -84,7 +87,7 @@ jobs:
8487
toolchain: ${{ matrix.rust-version }}
8588
- uses: Swatinem/rust-cache@v2
8689
- name: Test
87-
run: cargo build
90+
run: ./run-tests.sh
8891

8992
examples:
9093
runs-on: ubuntu-latest

Diff for: .github/workflows/test_integration.yml

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
name: Run Integration Tests
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- master
7+
types:
8+
- opened
9+
- reopened
10+
- ready_for_review
11+
- synchronize
12+
- labeled
13+
- unlabeled
14+
schedule:
15+
- cron: "0 5 * * *"
16+
17+
concurrency:
18+
group: integration-${{ github.head_ref }}
19+
cancel-in-progress: true
20+
21+
jobs:
22+
integration_tests:
23+
runs-on: ubuntu-latest
24+
if: >
25+
(github.event_name == 'pull_request' &&
26+
github.event.pull_request.draft == false &&
27+
!contains(github.event.pull_request.labels.*.name, 'ci/skip') &&
28+
!contains(github.event.pull_request.head.ref, 'datadog-api-spec/test/') &&
29+
contains(github.event.pull_request.labels.*.name, 'ci/integrations')) ||
30+
github.event_name == 'schedule'
31+
services:
32+
datadog-agent:
33+
image: gcr.io/datadoghq/agent:latest
34+
ports:
35+
- 8126:8126
36+
env:
37+
DD_API_KEY: ${{ secrets.DD_API_KEY }}
38+
DD_HOSTNAME: "none"
39+
DD_INSIDE_CI: "true"
40+
steps:
41+
- name: Get GitHub App token
42+
if: github.event_name == 'pull_request'
43+
id: get_token
44+
uses: tibdex/[email protected]
45+
with:
46+
app_id: ${{ secrets.PIPELINE_GITHUB_APP_ID }}
47+
private_key: ${{ secrets.PIPELINE_GITHUB_APP_PRIVATE_KEY }}
48+
installation_retrieval_mode: repository
49+
installation_retrieval_payload: DataDog/datadog-api-spec
50+
- name: Checkout code
51+
uses: actions/checkout@v3
52+
- name: Post pending status check
53+
if: github.event_name == 'pull_request' && contains(github.event.pull_request.head.ref, 'datadog-api-spec/generated/')
54+
uses: DataDog/github-actions/post-status-check@v2
55+
with:
56+
github-token: ${{ steps.get_token.outputs.token }}
57+
repo: datadog-api-spec
58+
status: pending
59+
context: integration
60+
- name: Install Rust
61+
uses: dtolnay/rust-toolchain@v1
62+
with:
63+
toolchain: "stable"
64+
- uses: Swatinem/rust-cache@v2
65+
- name: Run integration tests
66+
shell: bash
67+
run: ./run-tests.sh
68+
env:
69+
CI: "true"
70+
DD_AGENT_HOST: localhost
71+
DD_ENV: prod
72+
DD_SERVICE: datadog-api-client-rust
73+
DD_TAGS: "team:integrations-tools-and-libraries"
74+
DD_TEST_CLIENT_API_KEY: ${{ secrets.DD_CLIENT_API_KEY }}
75+
DD_TEST_CLIENT_APP_KEY: ${{ secrets.DD_CLIENT_APP_KEY }}
76+
RECORD: "none"
77+
- name: Post failure status check
78+
if: failure() && github.event_name == 'pull_request' && contains(github.event.pull_request.head.ref, 'datadog-api-spec/generated/')
79+
uses: DataDog/github-actions/post-status-check@v2
80+
with:
81+
github-token: ${{ steps.get_token.outputs.token }}
82+
repo: datadog-api-spec
83+
status: failure
84+
context: integration
85+
- name: Post success status check
86+
if: "!failure() && github.event_name == 'pull_request' && contains(github.event.pull_request.head.ref, 'datadog-api-spec/generated/')"
87+
uses: DataDog/github-actions/post-status-check@v2
88+
with:
89+
github-token: ${{ steps.get_token.outputs.token }}
90+
repo: datadog-api-spec
91+
status: success
92+
context: integration

Diff for: Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ version = "0.0.1"
3131

3232
[dependencies]
3333
async-stream = "0.3.5"
34+
flate2 = "1.0.28"
3435
futures-core = "0.3.30"
3536
lazy_static = "1.4.0"
3637
log = "0.4.20"
@@ -40,6 +41,7 @@ serde = { version = "1.0.197", features = ["derive"] }
4041
serde_json = "1.0.114"
4142
serde_with = "3.6.1"
4243
url = "2.5.0"
44+
zstd = "0.13.0"
4345

4446
[build-dependencies]
4547
rustc_version = "0.4.0"

Diff for: LICENSE-3rdparty.csv

+5
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ bytes,https://github.com/tokio-rs/bytes,MIT,"Carl Lerche <[email protected]>, Se
1414
cfg-if,https://github.com/alexcrichton/cfg-if,MIT OR Apache-2.0,Alex Crichton <[email protected]>
1515
chrono,https://github.com/chronotope/chrono,MIT OR Apache-2.0,The chrono Authors
1616
core-foundation,https://github.com/servo/core-foundation-rs,MIT OR Apache-2.0,The Servo Project Developers
17+
crc32fast,https://github.com/srijs/rust-crc32fast,MIT OR Apache-2.0,"Sam Rijs <[email protected]>, Alex Crichton <[email protected]>"
1718
darling,https://github.com/TedDriggs/darling,MIT,Ted Driggs <[email protected]>
1819
deranged,https://github.com/jhpratt/deranged,MIT OR Apache-2.0,Jacob Pratt <[email protected]>
1920
encoding_rs,https://github.com/hsivonen/encoding_rs,(Apache-2.0 OR MIT) AND BSD-3-Clause,Henri Sivonen <[email protected]>
2021
equivalent,https://github.com/cuviper/equivalent,Apache-2.0 OR MIT,The equivalent Authors
2122
errno,https://github.com/lambda-fairy/rust-errno,MIT OR Apache-2.0,Chris Wong <[email protected]>
2223
fastrand,https://github.com/smol-rs/fastrand,Apache-2.0 OR MIT,Stjepan Glavina <[email protected]>
24+
flate2,https://github.com/rust-lang/flate2-rs,MIT OR Apache-2.0,"Alex Crichton <[email protected]>, Josh Triplett <[email protected]>"
2325
fnv,https://github.com/servo/rust-fnv,Apache-2.0 OR MIT,Alex Crichton <[email protected]>
2426
foreign-types,https://github.com/sfackler/foreign-types,MIT OR Apache-2.0,Steven Fackler <[email protected]>
2527
futures,https://github.com/rust-lang/futures-rs,MIT OR Apache-2.0,The futures Authors
@@ -131,3 +133,6 @@ windows_x86_64_gnu,https://github.com/microsoft/windows-rs,MIT OR Apache-2.0,Mic
131133
windows_x86_64_gnullvm,https://github.com/microsoft/windows-rs,MIT OR Apache-2.0,Microsoft
132134
windows_x86_64_msvc,https://github.com/microsoft/windows-rs,MIT OR Apache-2.0,Microsoft
133135
winreg,https://github.com/gentoo90/winreg-rs,MIT,Igor Shaula <[email protected]>
136+
zstd,https://github.com/gyscos/zstd-rs,MIT,Alexandre Bury <[email protected]>
137+
zstd-safe,https://github.com/gyscos/zstd-rs,MIT OR Apache-2.0,Alexandre Bury <[email protected]>
138+
zstd-sys,https://github.com/gyscos/zstd-rs,MIT OR Apache-2.0,Alexandre Bury <[email protected]>

Diff for: generate.sh

-1
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,3 @@ rm -rf src/*
2727
pre_commit_wrapper generator
2828
pre_commit_wrapper format
2929
pre_commit_wrapper lint
30-
pre_commit_wrapper license-check

0 commit comments

Comments
 (0)