• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gripmock / grpctestify-rust / 24266242389

10 Apr 2026 10:03PM UTC coverage: 73.488% (-0.6%) from 74.127%
24266242389

Pull #32

github

web-flow
Merge 0d81fbf98 into 65f4b1f6e
Pull Request #32: multi requests

1053 of 1709 new or added lines in 10 files covered. (61.61%)

85 existing lines in 6 files now uncovered.

14899 of 20274 relevant lines covered (73.49%)

2114.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

24.38
/src/execution/workflow_graph.rs
1
// Workflow graph builder - builds execution graph from GCTF document
2

3
use crate::parser::ast::{Section, SectionContent, SectionType};
4

5
/// Workflow step in the execution graph
6
#[derive(Debug, Clone)]
7
pub struct WorkflowStep {
8
    pub step_number: usize,
9
    pub step_type: WorkflowStepType,
10
    pub section_line: usize,
11
    pub description: String,
12
}
13

14
/// Type of workflow step
15
#[derive(Debug, Clone)]
16
pub enum WorkflowStepType {
17
    Connect,
18
    SendRequest { request_index: usize },
19
    ReceiveResponse { response_index: usize },
20
    ReceiveError { error_index: usize },
21
    ValidateResponse { validation_index: usize },
22
    ValidateError { validation_index: usize },
23
    Extract { extraction_index: usize },
24
    Assert { assertion_index: usize },
25
}
26

27
impl WorkflowStep {
UNCOV
28
    pub fn format(&self) -> String {
×
UNCOV
29
        match &self.step_type {
×
UNCOV
30
            WorkflowStepType::Connect => format!("{}. Connect", self.step_number),
×
UNCOV
31
            WorkflowStepType::SendRequest { request_index } => {
×
UNCOV
32
                format!("{}. Send Request #{}", self.step_number, request_index)
×
33
            }
UNCOV
34
            WorkflowStepType::ReceiveResponse { response_index } => {
×
UNCOV
35
                format!("{}. Receive Response #{}", self.step_number, response_index)
×
36
            }
37
            WorkflowStepType::ReceiveError { error_index } => {
×
38
                format!("{}. Receive gRPC Error #{}", self.step_number, error_index)
×
39
            }
UNCOV
40
            WorkflowStepType::ValidateResponse { validation_index } => {
×
UNCOV
41
                format!(
×
42
                    "{}. Validate Response #{}",
43
                    self.step_number, validation_index
44
                )
45
            }
46
            WorkflowStepType::ValidateError { validation_index } => {
×
47
                format!("{}. Validate Error #{}", self.step_number, validation_index)
×
48
            }
49
            WorkflowStepType::Extract { extraction_index } => {
×
50
                format!(
×
51
                    "{}. Extract Variables #{}",
52
                    self.step_number, extraction_index
53
                )
54
            }
55
            WorkflowStepType::Assert { assertion_index } => {
×
56
                format!("{}. Run Assertions #{}", self.step_number, assertion_index)
×
57
            }
58
        }
UNCOV
59
    }
×
60
}
61

62
/// Build workflow graph from document sections
UNCOV
63
pub fn build_workflow_graph(sections: &[Section]) -> Vec<WorkflowStep> {
×
UNCOV
64
    let mut steps = Vec::new();
×
UNCOV
65
    let mut step_number = 1;
×
66

67
    // Always start with Connect
UNCOV
68
    if let Some(first_section) = sections.first() {
×
UNCOV
69
        steps.push(WorkflowStep {
×
UNCOV
70
            step_number,
×
UNCOV
71
            step_type: WorkflowStepType::Connect,
×
UNCOV
72
            section_line: first_section.start_line,
×
UNCOV
73
            description: "Connect to gRPC server".to_string(),
×
UNCOV
74
        });
×
UNCOV
75
        step_number += 1;
×
UNCOV
76
    }
×
77

78
    // Track indices for each section type
UNCOV
79
    let mut request_index = 0;
×
UNCOV
80
    let mut response_index = 0;
×
UNCOV
81
    let mut error_index = 0;
×
UNCOV
82
    let mut validation_index = 0;
×
UNCOV
83
    let mut extraction_index = 0;
×
UNCOV
84
    let mut assertion_index = 0;
×
85

86
    // Process sections in order
UNCOV
87
    for section in sections {
×
UNCOV
88
        match section.section_type {
×
UNCOV
89
            SectionType::Request => {
×
UNCOV
90
                request_index += 1;
×
UNCOV
91
                steps.push(WorkflowStep {
×
UNCOV
92
                    step_number,
×
UNCOV
93
                    step_type: WorkflowStepType::SendRequest { request_index },
×
UNCOV
94
                    section_line: section.start_line,
×
UNCOV
95
                    description: format!("Send request #{}", request_index),
×
UNCOV
96
                });
×
UNCOV
97
                step_number += 1;
×
UNCOV
98
            }
×
99
            SectionType::Response => {
UNCOV
100
                response_index += 1;
×
UNCOV
101
                steps.push(WorkflowStep {
×
UNCOV
102
                    step_number,
×
UNCOV
103
                    step_type: WorkflowStepType::ReceiveResponse { response_index },
×
UNCOV
104
                    section_line: section.start_line,
×
UNCOV
105
                    description: format!("Receive response #{}", response_index),
×
UNCOV
106
                });
×
UNCOV
107
                step_number += 1;
×
108

109
                // Add validation step if response has content or with_asserts
UNCOV
110
                if section.inline_options.with_asserts
×
111
                    || matches!(
×
UNCOV
112
                        &section.content,
×
113
                        SectionContent::Json(_) | SectionContent::JsonLines(_)
114
                    )
UNCOV
115
                {
×
UNCOV
116
                    validation_index += 1;
×
UNCOV
117
                    steps.push(WorkflowStep {
×
UNCOV
118
                        step_number,
×
UNCOV
119
                        step_type: WorkflowStepType::ValidateResponse { validation_index },
×
UNCOV
120
                        section_line: section.start_line,
×
UNCOV
121
                        description: format!("Validate response #{}", validation_index),
×
UNCOV
122
                    });
×
UNCOV
123
                    step_number += 1;
×
UNCOV
124
                }
×
125
            }
126
            SectionType::Error => {
×
127
                error_index += 1;
×
128
                steps.push(WorkflowStep {
×
129
                    step_number,
×
130
                    step_type: WorkflowStepType::ReceiveError { error_index },
×
131
                    section_line: section.start_line,
×
132
                    description: format!("Receive gRPC error #{}", error_index),
×
133
                });
×
134
                step_number += 1;
×
135

×
136
                // Add validation step for error
×
137
                validation_index += 1;
×
138
                steps.push(WorkflowStep {
×
139
                    step_number,
×
140
                    step_type: WorkflowStepType::ValidateError { validation_index },
×
141
                    section_line: section.start_line,
×
142
                    description: format!("Validate error #{}", validation_index),
×
143
                });
×
144
                step_number += 1;
×
145
            }
×
146
            SectionType::Extract => {
147
                if let SectionContent::Extract(extractions) = &section.content
×
148
                    && !extractions.is_empty()
×
149
                {
×
150
                    extraction_index += 1;
×
151
                    steps.push(WorkflowStep {
×
152
                        step_number,
×
153
                        step_type: WorkflowStepType::Extract { extraction_index },
×
154
                        section_line: section.start_line,
×
155
                        description: format!("Extract variables #{}", extraction_index),
×
156
                    });
×
157
                    step_number += 1;
×
158
                }
×
159
            }
160
            SectionType::Asserts => {
161
                if let SectionContent::Assertions(assertions) = &section.content
×
162
                    && !assertions.is_empty()
×
163
                {
×
164
                    assertion_index += 1;
×
165
                    steps.push(WorkflowStep {
×
166
                        step_number,
×
167
                        step_type: WorkflowStepType::Assert { assertion_index },
×
168
                        section_line: section.start_line,
×
169
                        description: format!("Run assertions #{}", assertion_index),
×
170
                    });
×
171
                    step_number += 1;
×
172
                }
×
173
            }
UNCOV
174
            _ => {}
×
175
        }
176
    }
177

UNCOV
178
    steps
×
UNCOV
179
}
×
180

181
/// Get workflow summary statistics
182
pub struct WorkflowSummary {
183
    pub total_requests: usize,
184
    pub total_responses: usize,
185
    pub total_errors: usize,
186
    pub total_extractions: usize,
187
    pub total_assertions: usize,
188
    pub has_streaming: bool,
189
}
190

191
pub fn get_workflow_summary(sections: &[Section]) -> WorkflowSummary {
1✔
192
    let total_requests = sections
1✔
193
        .iter()
1✔
194
        .filter(|s| s.section_type == SectionType::Request)
4✔
195
        .count();
1✔
196
    let total_responses = sections
1✔
197
        .iter()
1✔
198
        .filter(|s| s.section_type == SectionType::Response)
4✔
199
        .count();
1✔
200
    let total_errors = sections
1✔
201
        .iter()
1✔
202
        .filter(|s| s.section_type == SectionType::Error)
4✔
203
        .count();
1✔
204
    let total_extractions = sections
1✔
205
        .iter()
1✔
206
        .filter(|s| s.section_type == SectionType::Extract)
4✔
207
        .count();
1✔
208
    let total_assertions = sections
1✔
209
        .iter()
1✔
210
        .filter(|s| s.section_type == SectionType::Asserts)
4✔
211
        .count();
1✔
212

213
    // Detect streaming based on multiple requests/responses
214
    let has_streaming = total_requests > 1 || total_responses > 1;
1✔
215

216
    WorkflowSummary {
1✔
217
        total_requests,
1✔
218
        total_responses,
1✔
219
        total_errors,
1✔
220
        total_extractions,
1✔
221
        total_assertions,
1✔
222
        has_streaming,
1✔
223
    }
1✔
224
}
1✔
225

226
/// Get call type description based on workflow
227
pub fn get_call_type(summary: &WorkflowSummary) -> &'static str {
1✔
228
    if summary.total_errors > 0 && summary.total_requests == 1 && summary.total_responses == 0 {
1✔
229
        "Unary Call Expecting Error"
×
230
    } else if summary.total_requests == 1 && summary.total_responses > 1 {
1✔
231
        "Server Streaming Call"
×
232
    } else if summary.total_requests > 1 && summary.total_responses == 1 {
1✔
233
        "Client Streaming Call"
×
234
    } else if summary.total_requests > 1 && summary.total_responses > 1 {
1✔
235
        "Bidirectional Streaming Call"
×
236
    } else if summary.total_requests == 1 && summary.total_responses == 1 {
1✔
237
        "Standard Unary Call"
1✔
238
    } else {
239
        "Multi-Step Workflow"
×
240
    }
241
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc