1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use http::StatusCode;
use wiremock::ResponseTemplate;
use wiremock::{Request, Respond};

use crate::{GitlabRunnerMock, MockJobState};

pub(crate) struct JobTraceResponder {
    mock: GitlabRunnerMock,
}

impl JobTraceResponder {
    pub(crate) fn new(mock: GitlabRunnerMock) -> Self {
        Self { mock }
    }
}

impl Respond for JobTraceResponder {
    fn respond(&self, request: &Request) -> ResponseTemplate {
        /* api/v4/jobs/<id>/trace */
        let id = request
            .url
            .path_segments()
            .unwrap()
            .nth_back(1)
            .unwrap()
            .parse()
            .unwrap();

        let token = if let Some(header) = request.headers.get("JOB-TOKEN") {
            header.to_str().expect("Invalid JOB-TOKEN value")
        } else {
            return ResponseTemplate::new(StatusCode::FORBIDDEN);
        };

        let (start, end) = if let Some(range) = request.headers.get("Content-Range") {
            let mut split = range
                .to_str()
                .expect("Invalid Content-Range value")
                .splitn(2, '-');
            let start = split.next().unwrap().parse().unwrap();
            let end = split.next().unwrap().parse().unwrap();
            (start, end)
        } else {
            return ResponseTemplate::new(StatusCode::BAD_REQUEST);
        };

        if let Some(job) = self.mock.get_job(id) {
            if token != job.token() {
                ResponseTemplate::new(StatusCode::FORBIDDEN)
            } else if job.state() != MockJobState::Running {
                ResponseTemplate::new(StatusCode::FORBIDDEN)
                    .insert_header("Job-Status", &*job.state().to_string())
            } else {
                match job.append_log(request.body.clone(), start, end) {
                    Ok(()) => ResponseTemplate::new(StatusCode::ACCEPTED)
                        .insert_header(
                            "X-GitLab-Trace-Update-Interval",
                            &*self.mock.update_interval().to_string(),
                        )
                        .insert_header("Job-Status", &*job.state().to_string()),
                    Err(e) => ResponseTemplate::new(StatusCode::RANGE_NOT_SATISFIABLE)
                        .set_body_string(format!("{:?}", e)),
                }
            }
        } else {
            ResponseTemplate::new(StatusCode::NOT_FOUND)
        }
    }
}