ghostflow 0.1.0

Routines which implement various parts of "ghostflow", or the git-hosted workflow.
Documentation
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fs::{self, File};
use std::path::Path;
use std::sync::Arc;

use serde_json::Value;

use crate::actions::test::jobs::*;
use crate::host::{HostedProject, HostingService};
use crate::tests::mock::{MockData, MockMergeRequest, MockService};
use crate::tests::utils::test_workspace_dir;

const REPO_NAME: &str = "base";
const MR_ID: u64 = 1;
const COMMIT: &str = "7189cf557ba2c7c61881ff8669158710b94d8df1";

fn create_test(workspace_path: &Path, service: &Arc<MockService>) -> TestJobs {
    let project = HostedProject {
        name: REPO_NAME.into(),
        service: Arc::clone(service) as Arc<dyn HostingService>,
    };

    TestJobs::new(workspace_path.join("queue"), project).unwrap()
}

fn check_mr_job(path: &Path) {
    let queue = path.join("queue");

    for entry in fs::read_dir(queue).unwrap() {
        let entry = entry.unwrap();

        assert_eq!(entry.path().extension().unwrap(), "json");

        let job = File::open(entry.path()).unwrap();
        let data: Value = serde_json::from_reader(job).unwrap();

        assert_eq!(data, Value::Null);
    }
}

// Testing an update should drop a job file in the queue.
#[test]
fn test_test_updates() {
    let tempdir = test_workspace_dir();
    let service = MockData::builder().service();
    let test = create_test(tempdir.path(), &service);

    test.test_update(Value::Null).unwrap();

    check_mr_job(tempdir.path());

    assert_eq!(service.remaining_data(), 0);
}

// Testing an MR should drop a job file in the queue with the expected contents and comment.
#[test]
fn test_test_mr() {
    let tempdir = test_workspace_dir();
    let base = MockData::repo(REPO_NAME);
    let user = MockData::user("user");
    let service = MockData::builder()
        .add_merge_request(MockMergeRequest::new(MR_ID, &user, COMMIT, &base, None))
        .add_project(base)
        .add_user(user)
        .service();
    let test = create_test(tempdir.path(), &service);

    let mr = service.merge_request(REPO_NAME, MR_ID).unwrap();
    test.test_mr(&mr, Value::Null).unwrap();

    check_mr_job(tempdir.path());

    let mr_comments = service.mr_comments(mr.id);

    assert_eq!(service.remaining_data(), 0);

    assert_eq!(mr_comments.len(), 1);
    assert_eq!(mr_comments[0], "This topic has been queued for testing.");
}

// Testing an MR should drop a job file in the queue with the expected contents.
#[test]
fn test_test_mr_quiet() {
    let tempdir = test_workspace_dir();
    let base = MockData::repo(REPO_NAME);
    let user = MockData::user("user");
    let service = MockData::builder()
        .add_merge_request(MockMergeRequest::new(MR_ID, &user, COMMIT, &base, None))
        .add_project(base)
        .add_user(user)
        .service();
    let mut test = create_test(tempdir.path(), &service);
    test.quiet();

    let mr = service.merge_request(REPO_NAME, MR_ID).unwrap();
    test.test_mr(&mr, Value::Null).unwrap();

    check_mr_job(tempdir.path());

    assert_eq!(service.remaining_data(), 0);
}