Skip to content

Test improvements, conversions to using the new API #1546

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Nov 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
322 changes: 3 additions & 319 deletions src/tests/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ use flate2::Compression;
use cargo_registry::{models, schema, views};
use util::{Bad, RequestHelper, TestApp};

use models::{Crate, CrateDownload, CrateOwner, Dependency, Keyword, Team, User, Version};
use models::{NewCategory, NewCrate, NewTeam, NewUser, NewVersion};
use models::{Crate, CrateOwner, Dependency, Team, User, Version};
use models::{NewCategory, NewTeam, NewUser, NewVersion};
use schema::*;
use views::krate_publish as u;
use views::{EncodableCrate, EncodableKeyword, EncodableVersion};
Expand Down Expand Up @@ -82,6 +82,7 @@ macro_rules! bad_resp {
}

mod badge;
mod builders;
mod categories;
mod category;
mod git;
Expand Down Expand Up @@ -266,231 +267,6 @@ fn add_team_to_crate(t: &Team, krate: &Crate, u: &User, conn: &PgConnection) ->

use cargo_registry::util::CargoResult;

struct VersionBuilder<'a> {
num: semver::Version,
license: Option<&'a str>,
license_file: Option<&'a str>,
features: HashMap<String, Vec<String>>,
dependencies: Vec<(i32, Option<&'static str>)>,
yanked: bool,
}

impl<'a> VersionBuilder<'a> {
fn new(num: &str) -> Self {
let num = semver::Version::parse(num).unwrap_or_else(|e| {
panic!("The version {} is not valid: {}", num, e);
});

VersionBuilder {
num,
license: None,
license_file: None,
features: HashMap::new(),
dependencies: Vec::new(),
yanked: false,
}
}

fn license(mut self, license: Option<&'a str>) -> Self {
self.license = license;
self
}

fn dependency(mut self, dependency: &Crate, target: Option<&'static str>) -> Self {
self.dependencies.push((dependency.id, target));
self
}

fn yanked(self, yanked: bool) -> Self {
Self { yanked, ..self }
}

fn build(self, crate_id: i32, connection: &PgConnection) -> CargoResult<Version> {
use diesel::{insert_into, update};

let license = match self.license {
Some(license) => Some(license.to_owned()),
None => None,
};

let mut vers = NewVersion::new(
crate_id,
&self.num,
&self.features,
license,
self.license_file,
None,
)?.save(connection, &[])?;

if self.yanked {
vers = update(&vers)
.set(versions::yanked.eq(true))
.get_result(connection)?;
}

let new_deps = self
.dependencies
.into_iter()
.map(|(crate_id, target)| {
(
dependencies::version_id.eq(vers.id),
dependencies::req.eq(">= 0"),
dependencies::crate_id.eq(crate_id),
dependencies::target.eq(target),
dependencies::optional.eq(false),
dependencies::default_features.eq(false),
dependencies::features.eq(Vec::<String>::new()),
)
}).collect::<Vec<_>>();
insert_into(dependencies::table)
.values(&new_deps)
.execute(connection)?;

Ok(vers)
}
}

impl<'a> From<&'a str> for VersionBuilder<'a> {
fn from(num: &'a str) -> Self {
VersionBuilder::new(num)
}
}

struct CrateBuilder<'a> {
owner_id: i32,
krate: NewCrate<'a>,
downloads: Option<i32>,
recent_downloads: Option<i32>,
versions: Vec<VersionBuilder<'a>>,
keywords: Vec<&'a str>,
}

impl<'a> CrateBuilder<'a> {
fn new(name: &str, owner_id: i32) -> CrateBuilder<'_> {
CrateBuilder {
owner_id,
krate: NewCrate {
name,
..NewCrate::default()
},
downloads: None,
recent_downloads: None,
versions: Vec::new(),
keywords: Vec::new(),
}
}

fn description(mut self, description: &'a str) -> Self {
self.krate.description = Some(description);
self
}

fn documentation(mut self, documentation: &'a str) -> Self {
self.krate.documentation = Some(documentation);
self
}

fn homepage(mut self, homepage: &'a str) -> Self {
self.krate.homepage = Some(homepage);
self
}

fn readme(mut self, readme: &'a str) -> Self {
self.krate.readme = Some(readme);
self
}

fn max_upload_size(mut self, max_upload_size: i32) -> Self {
self.krate.max_upload_size = Some(max_upload_size);
self
}

fn downloads(mut self, downloads: i32) -> Self {
self.downloads = Some(downloads);
self
}

fn recent_downloads(mut self, recent_downloads: i32) -> Self {
self.recent_downloads = Some(recent_downloads);
self
}

fn version<T: Into<VersionBuilder<'a>>>(mut self, version: T) -> Self {
self.versions.push(version.into());
self
}

fn keyword(mut self, keyword: &'a str) -> Self {
self.keywords.push(keyword);
self
}

fn build(mut self, connection: &PgConnection) -> CargoResult<Crate> {
use diesel::{insert_into, select, update};

let mut krate = self
.krate
.create_or_update(connection, None, self.owner_id)?;

// Since we are using `NewCrate`, we can't set all the
// crate properties in a single DB call.

let old_downloads = self.downloads.unwrap_or(0) - self.recent_downloads.unwrap_or(0);
let now = Utc::now();
let old_date = now.naive_utc().date() - chrono::Duration::days(91);

if let Some(downloads) = self.downloads {
let crate_download = CrateDownload {
crate_id: krate.id,
downloads: old_downloads,
date: old_date,
};

insert_into(crate_downloads::table)
.values(&crate_download)
.execute(connection)?;
krate.downloads = downloads;
update(&krate).set(&krate).execute(connection)?;
}

if self.recent_downloads.is_some() {
let crate_download = CrateDownload {
crate_id: krate.id,
downloads: self.recent_downloads.unwrap(),
date: now.naive_utc().date(),
};

insert_into(crate_downloads::table)
.values(&crate_download)
.execute(connection)?;

no_arg_sql_function!(refresh_recent_crate_downloads, ());
select(refresh_recent_crate_downloads).execute(connection)?;
}

if self.versions.is_empty() {
self.versions.push(VersionBuilder::new("0.99.0"));
}

for version_builder in self.versions {
version_builder.build(krate.id, connection)?;
}

if !self.keywords.is_empty() {
Keyword::update_crate(connection, &krate, &self.keywords)?;
}

Ok(krate)
}

fn expect_build(self, connection: &PgConnection) -> Crate {
let name = self.krate.name;
self.build(connection).unwrap_or_else(|e| {
panic!("Unable to create crate {}: {:?}", name, e);
})
}
}

fn new_version(crate_id: i32, num: &str, crate_size: Option<i32>) -> NewVersion {
let num = semver::Version::parse(num).unwrap();
NewVersion::new(crate_id, &num, &HashMap::new(), None, None, crate_size).unwrap()
Expand Down Expand Up @@ -745,95 +521,3 @@ fn new_crate_to_body_with_tarball(new_crate: &u::NewCrate, tarball: &[u8]) -> Ve
body.extend(tarball);
body
}

lazy_static! {
static ref EMPTY_TARBALL_BYTES: Vec<u8> = {
let mut empty_tarball = vec![];
{
let mut ar =
tar::Builder::new(GzEncoder::new(&mut empty_tarball, Compression::default()));
t!(ar.finish());
}
empty_tarball
};
}

/// A builder for constructing a crate for the purposes of testing publishing. If you only need
/// a crate to exist and don't need to test behavior caused by the publish request, inserting
/// a crate into the database directly by using CrateBuilder will be faster.
pub struct PublishBuilder {
pub krate_name: String,
version: semver::Version,
tarball: Vec<u8>,
}

impl PublishBuilder {
/// Create a request to publish a crate with the given name, version 1.0.0, and no files
/// in its tarball.
fn new(krate_name: &str) -> Self {
PublishBuilder {
krate_name: krate_name.into(),
version: semver::Version::parse("1.0.0").unwrap(),
tarball: EMPTY_TARBALL_BYTES.to_vec(),
}
}

/// Set the version of the crate being published to something other than the default of 1.0.0.
fn version(mut self, version: &str) -> Self {
self.version = semver::Version::parse(version).unwrap();
self
}

/// Set the files in the crate's tarball.
fn files(mut self, files: &[(&str, &[u8])]) -> Self {
let mut slices = files.iter().map(|p| p.1).collect::<Vec<_>>();
let files = files
.iter()
.zip(&mut slices)
.map(|(&(name, _), data)| {
let len = data.len() as u64;
(name, data as &mut Read, len)
}).collect::<Vec<_>>();

let mut tarball = Vec::new();
{
let mut ar = tar::Builder::new(GzEncoder::new(&mut tarball, Compression::default()));
for (name, ref mut data, size) in files {
let mut header = tar::Header::new_gnu();
t!(header.set_path(name));
header.set_size(size);
header.set_cksum();
t!(ar.append(&header, data));
}
t!(ar.finish());
}

self.tarball = tarball;
self
}

/// Consume this builder to make the Put request body
fn body(self) -> Vec<u8> {
let new_crate = u::NewCrate {
name: u::CrateName(self.krate_name.clone()),
vers: u::CrateVersion(self.version),
features: HashMap::new(),
deps: Vec::new(),
authors: vec!["foo".to_string()],
description: Some("description".to_string()),
homepage: None,
documentation: None,
readme: None,
readme_file: None,
keywords: Some(u::KeywordList(Vec::new())),
categories: Some(u::CategoryList(Vec::new())),
license: Some("MIT".to_string()),
license_file: None,
repository: None,
badges: Some(HashMap::new()),
links: None,
};

::new_crate_to_body_with_tarball(&new_crate, &self.tarball)
}
}
3 changes: 2 additions & 1 deletion src/tests/badge.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::collections::HashMap;

use builders::CrateBuilder;
use models::{Badge, Crate, MaintenanceStatus};
use {app, new_user, util::DieselConnection, CrateBuilder};
use {app, new_user, util::DieselConnection};

struct BadgeRef {
appveyor: Badge,
Expand Down
Loading