Skip to content

Commit

Permalink
test: migrate voting tests to cucumber
Browse files Browse the repository at this point in the history
  • Loading branch information
Zoe Spellman committed Feb 21, 2024
1 parent d47dd21 commit f9598ed
Show file tree
Hide file tree
Showing 26 changed files with 1,179 additions and 646 deletions.
620 changes: 578 additions & 42 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,10 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }

[build-dependencies]
tonic-build = { version = "0.11", features = ["prost"] }

[dev-dependencies]
cucumber = { version = "0.20.2", features = ["libtest", "tracing"] }

[[test]]
name = "voting"
harness = false
46 changes: 44 additions & 2 deletions src/features/common/entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ const INSUFFICIENT_VOTES_QUANTITY: i64 = 25;

/// A descriptive mapping of a number of ratings to a general indicator of "how good"
/// an app can be said to be.
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[allow(missing_docs)]
pub enum RatingsBand {
VeryGood = 0,
Good = 1,
Neutral = 2,
Poor = 3,
VeryPoor = 4,
#[default]
InsufficientVotes = 5,
}

Expand Down Expand Up @@ -45,10 +47,38 @@ impl RatingsBand {
}
}

impl PartialOrd for RatingsBand {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if matches!(self, RatingsBand::InsufficientVotes)
|| matches!(other, RatingsBand::InsufficientVotes)
{
None
} else {
// The ratings bad values are actually backwards from an ordering perspective,
// so flip them
let max = Self::InsufficientVotes as u8;
(max - (*self as u8)).partial_cmp(&(max - (*other as u8)))
}
}
}

impl From<crate::features::pb::common::RatingsBand> for RatingsBand {
fn from(value: crate::features::pb::common::RatingsBand) -> Self {
match value {
pb::RatingsBand::VeryGood => Self::VeryGood,
pb::RatingsBand::Good => Self::Good,
pb::RatingsBand::Neutral => Self::Neutral,
pb::RatingsBand::Poor => Self::Poor,
pb::RatingsBand::VeryPoor => Self::VeryPoor,
pb::RatingsBand::InsufficientVotes => Self::InsufficientVotes,
}
}
}

/// A descriptive rating object, usually used converted and transferred over the wire.
/// This is an aggregated rating for a snap without holding every raw value, as determined
/// by [`RatingsBand`].
#[derive(Debug, Clone, FromRow)]
#[derive(Debug, Clone, FromRow, Default)]
pub struct Rating {
/// The ID of the snap this rating is for
pub snap_id: String,
Expand Down Expand Up @@ -81,6 +111,18 @@ impl Rating {
}
}

impl From<crate::features::pb::common::Rating> for Rating {
fn from(value: crate::features::pb::common::Rating) -> Self {
Self {
snap_id: value.snap_id,
total_votes: value.total_votes,
ratings_band: crate::features::pb::common::RatingsBand::try_from(value.ratings_band)
.unwrap()
.into(),
}
}
}

/// A summary of votes for a given snap, this is then aggregated before transfer.
#[derive(Debug, Clone, FromRow)]
pub struct VoteSummary {
Expand Down
3 changes: 1 addition & 2 deletions src/features/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//! Contains various feature implementations for the ratings backend.
pub mod chart;
pub mod common;
pub mod pb;
pub mod rating;
pub mod user;

mod common;
118 changes: 0 additions & 118 deletions tests/app_tests/lifecycle_test.rs

This file was deleted.

22 changes: 14 additions & 8 deletions tests/chart_tests/category.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use ratings::{
use crate::{
clear_test_snap,
helpers::{
self, client_app::AppClient, client_chart::ChartClient, client_user::UserClient,
test_data::TestData, vote_generator::generate_votes, with_lifecycle::with_lifecycle,
self, client_app::*, client_chart::*, client_user::*, test_data::TestData,
vote_generator::generate_votes, with_lifecycle::with_lifecycle,
},
CLEAR_TEST_SNAP,
};
Expand All @@ -35,13 +35,13 @@ async fn category_chart_filtering() -> Result<(), Box<dyn std::error::Error>> {
CLEAR_TEST_SNAP.get_or_init(clear_test_snap).await;

let data = TestData {
user_client: Some(UserClient::new(&config.socket())),
user_client: Some(UserClient::new(config.socket())),
app_ctx,
id: None,
token: None,
app_client: Some(AppClient::new(&config.socket())),
app_client: Some(AppClient::new(config.socket())),
snap_id: Some(TESTING_SNAP_ID.to_string()),
chart_client: Some(ChartClient::new(&config.socket())),
chart_client: Some(ChartClient::new(config.socket())),
categories: Some(TESTING_SNAP_CATEGORIES.iter().cloned().collect()),
};

Expand Down Expand Up @@ -86,9 +86,15 @@ async fn vote(mut data: TestData) -> TestData {
// Does an app voted against multiple times appear correctly in the chart?
pub async fn multiple_votes(data: TestData) -> TestData {
// This should rank our snap_id at the top of the chart, but only for our category
generate_votes(&data.snap_id.clone().unwrap(), 111, true, 50, data.clone())
.await
.expect("Votes should succeed");
generate_votes(
&data.snap_id.clone().unwrap(),
111,
true,
50,
data.user_client.as_ref().unwrap(),
)
.await
.expect("Votes should succeed");

data
}
Expand Down
28 changes: 17 additions & 11 deletions tests/chart_tests/lifecycle_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ use ratings::{

use super::super::helpers::with_lifecycle::with_lifecycle;
use crate::helpers::vote_generator::generate_votes;
use crate::helpers::{self, client_app::AppClient};
use crate::helpers::{client_chart::ChartClient, test_data::TestData};
use crate::helpers::{client_user::UserClient, data_faker};
use crate::helpers::{self, client_app::*};
use crate::helpers::{client_chart::*, test_data::TestData};
use crate::helpers::{client_user::*, data_faker};

#[tokio::test]
async fn chart_lifecycle_test() -> Result<(), Box<dyn std::error::Error>> {
Expand All @@ -22,13 +22,13 @@ async fn chart_lifecycle_test() -> Result<(), Box<dyn std::error::Error>> {
let app_ctx = AppContext::new(&config, infra);

let data = TestData {
user_client: Some(UserClient::new(&config.socket())),
user_client: Some(UserClient::new(config.socket())),
app_ctx,
id: None,
token: None,
app_client: Some(AppClient::new(&config.socket())),
app_client: Some(AppClient::new(config.socket())),
snap_id: Some(data_faker::rnd_id()),
chart_client: Some(ChartClient::new(&config.socket())),
chart_client: Some(ChartClient::new(config.socket())),
categories: None,
};

Expand All @@ -48,9 +48,15 @@ async fn vote_once(mut data: TestData) -> TestData {

// Fill up chart with other votes so ours doesn't appear
for _ in 0..20 {
generate_votes(&data_faker::rnd_id(), 111, vote_up, 25, data.clone())
.await
.expect("Votes should succeed");
generate_votes(
&data_faker::rnd_id(),
111,
vote_up,
25,
data.user_client.as_ref().unwrap(),
)
.await
.expect("Votes should succeed");
}

let vote_up = true;
Expand All @@ -60,7 +66,7 @@ async fn vote_once(mut data: TestData) -> TestData {
111,
vote_up,
1,
data.clone(),
data.user_client.as_ref().unwrap(),
)
.await
.expect("Votes should succeed");
Expand Down Expand Up @@ -115,7 +121,7 @@ async fn multiple_votes(mut data: TestData) -> TestData {
111,
vote_up,
100,
data.clone(),
data.user_client.as_ref().unwrap(),
)
.await
.expect("Votes should succeed");
Expand Down
22 changes: 22 additions & 0 deletions tests/features/voting.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Feature: User voting
Background:
Given a Snap named "chu-chu-garden" has already accumulated 5 votes and 3 upvotes

Scenario: Amy upvotes a snap she hasn't voted for in the past
When Amy casts an upvote
Then the total number of votes strictly increases
And the ratings band monotonically increases

Rule: Votes that a user updates do not change the total vote count

Scenario Outline: Sonic changes his vote between downvote and upvote because "chu-chu-garden" got better/worse
Given Sonic originally voted <original>
When Sonic changes his vote to <after>
Then the ratings band <direction>
But the total number of votes stays constant

Examples:
| original | after | direction |
| upvote | downvote | monotonically increases |
| downvote | upvote | monotonically decreases |

33 changes: 33 additions & 0 deletions tests/helpers/client/app.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use tonic::async_trait;
use tonic::{metadata::MetadataValue, transport::Endpoint, Request, Response, Status};

use ratings::features::pb::app::{GetRatingRequest, GetRatingResponse};

use ratings::features::pb::app::app_client as pb;

use super::Client;

#[async_trait]
pub trait AppClient: Client {
async fn get_rating(
&self,
token: &str,
id: &str,
) -> Result<Response<GetRatingResponse>, Status> {
let channel = Endpoint::from_shared(self.url().to_string())
.unwrap()
.connect()
.await
.unwrap();
let mut client = pb::AppClient::with_interceptor(channel, move |mut req: Request<()>| {
let header: MetadataValue<_> = format!("Bearer {token}").parse().unwrap();
req.metadata_mut().insert("authorization", header);
Ok(req)
});
client
.get_rating(GetRatingRequest {
snap_id: id.to_string(),
})
.await
}
}
Loading

0 comments on commit f9598ed

Please sign in to comment.