Skip to content

Commit

Permalink
Fix bug if no instance_name/resource_name is given upload does not work
Browse files Browse the repository at this point in the history
Fixes a bug that if an upload is attempted but no instance_name is
configured it will error out.
  • Loading branch information
allada committed Oct 17, 2022
1 parent a2be6f5 commit b010b4b
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 14 deletions.
10 changes: 10 additions & 0 deletions util/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,16 @@ rust_library(
visibility = ["//visibility:public"],
)

rust_test(
name = "resource_info_test",
srcs = ["tests/resource_info_test.rs"],
deps = [
"//third_party:pretty_assertions",
"//third_party:tokio",
":resource_info",
],
)

rust_test(
name = "fastcdc_test",
srcs = ["tests/fastcdc_test.rs"],
Expand Down
39 changes: 25 additions & 14 deletions util/resource_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,35 +24,46 @@ pub struct ResourceInfo<'a> {

impl<'a> ResourceInfo<'a> {
pub fn new(resource_name: &'a str) -> Result<ResourceInfo<'a>, Error> {
let mut parts = resource_name.splitn(6, '/');
let mut parts = resource_name.splitn(6, '/').peekable();
const ERROR_MSG: &str = concat!(
"Expected resource_name to be of pattern ",
"'{instance_name}/uploads/{uuid}/blobs/{hash}/{size}' or ",
"'{instance_name}/blobs/{hash}/{size}'",
"'{?instance_name/}uploads/{uuid}/blobs/{hash}/{size}' or ",
"'{?instance_name/}blobs/{hash}/{size}'",
);
let instance_name = &parts.next().err_tip(|| ERROR_MSG)?;
let mut blobs_or_uploads: &str = parts.next().err_tip(|| ERROR_MSG)?;

let mut instance_name = "";
let maybe_instance_name = parts.next().err_tip(|| ERROR_MSG)?;
let peek_next = parts.peek().err_tip(|| ERROR_MSG)?;
let blobs_or_uploads = if *peek_next == "uploads" || *peek_next == "blobs" {
instance_name = maybe_instance_name;
// We do have an instance_name, so set blobs_or_uploads to the peek_next and consume it.
parts.next().err_tip(|| ERROR_MSG)?
} else {
// We don't have an instance_name, so use our first item as blobs_or_uploads.
maybe_instance_name
};
let mut uuid = None;
if &blobs_or_uploads == &"uploads" {
if blobs_or_uploads == "uploads" {
uuid = Some(parts.next().err_tip(|| ERROR_MSG)?);
blobs_or_uploads = parts.next().err_tip(|| ERROR_MSG)?;
let blobs = parts.next().err_tip(|| ERROR_MSG)?;
error_if!(
blobs != "blobs",
"Expected resource_name to have 'blobs' here. Got: {}",
blobs_or_uploads
);
}

error_if!(
&blobs_or_uploads != &"blobs",
"Element 2 or 4 of resource_name should have been 'blobs'. Got: {}",
blobs_or_uploads
);
let hash = &parts.next().err_tip(|| ERROR_MSG)?;
let hash = parts.next().err_tip(|| ERROR_MSG)?;
let raw_digest_size = parts.next().err_tip(|| ERROR_MSG)?;
let expected_size = raw_digest_size.parse::<usize>().err_tip(|| {
format!(
"Digest size_bytes was not convertible to usize. Got: {}",
raw_digest_size
)
})?;

Ok(ResourceInfo {
instance_name: instance_name,
instance_name,
uuid,
hash,
expected_size,
Expand Down
73 changes: 73 additions & 0 deletions util/tests/resource_info_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2022 The Turbo Cache Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use resource_info::ResourceInfo;

#[cfg(test)]
mod resource_info_tests {
use super::*;
use pretty_assertions::assert_eq; // Must be declared in every module.

#[tokio::test]
async fn with_resource_name_blobs_test() -> Result<(), Box<dyn std::error::Error>> {
const RESOURCE_NAME: &str = "foo_bar/blobs/HASH-HERE/12345";
let resource_info = ResourceInfo::new(RESOURCE_NAME)?;

assert_eq!(resource_info.instance_name, "foo_bar");
assert_eq!(resource_info.uuid, None);
assert_eq!(resource_info.hash, "HASH-HERE");
assert_eq!(resource_info.expected_size, 12345);

Ok(())
}

#[tokio::test]
async fn with_resource_name_uploads_test() -> Result<(), Box<dyn std::error::Error>> {
const RESOURCE_NAME: &str = "foo_bar/uploads/UUID-HERE/blobs/HASH-HERE/12345";
let resource_info = ResourceInfo::new(RESOURCE_NAME)?;

assert_eq!(resource_info.instance_name, "foo_bar");
assert_eq!(resource_info.uuid, Some("UUID-HERE"));
assert_eq!(resource_info.hash, "HASH-HERE");
assert_eq!(resource_info.expected_size, 12345);

Ok(())
}

#[tokio::test]
async fn without_resource_name_blobs_test() -> Result<(), Box<dyn std::error::Error>> {
const RESOURCE_NAME: &str = "blobs/HASH-HERE/12345";
let resource_info = ResourceInfo::new(RESOURCE_NAME)?;

assert_eq!(resource_info.instance_name, "");
assert_eq!(resource_info.uuid, None);
assert_eq!(resource_info.hash, "HASH-HERE");
assert_eq!(resource_info.expected_size, 12345);

Ok(())
}

#[tokio::test]
async fn without_resource_name_uploads_test() -> Result<(), Box<dyn std::error::Error>> {
const RESOURCE_NAME: &str = "uploads/UUID-HERE/blobs/HASH-HERE/12345";
let resource_info = ResourceInfo::new(RESOURCE_NAME)?;

assert_eq!(resource_info.instance_name, "");
assert_eq!(resource_info.uuid, Some("UUID-HERE"));
assert_eq!(resource_info.hash, "HASH-HERE");
assert_eq!(resource_info.expected_size, 12345);

Ok(())
}
}

0 comments on commit b010b4b

Please sign in to comment.