Merge branch 'master' into stable

This commit is contained in:
Basti 2022-05-13 19:30:43 +02:00
commit ce5f938938
Signed by: basti
GPG Key ID: 9F88009D31D99C72
18 changed files with 84 additions and 599 deletions

35
.github/workflows/ruby.yml vendored Normal file
View File

@ -0,0 +1,35 @@
name: Tests
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ['2.5', '2.6', '2.7']
redis-version: [4, 5, 6]
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: Start Redis
uses: supercharge/redis-github-action@1.4.0
with:
redis-version: ${{ matrix.redis-version }}
- name: Configure
run: cp config.yml.example.s3 config.yml
- name: Run tests
run: bundle exec rake test

View File

@ -1,27 +0,0 @@
language: ruby
cache: bundler
rvm:
- 2.5
- 2.6
services:
- redis-server
before_script:
- cp config.yml.example.$BACKEND config.yml
- mkdir -p tmp && echo "swifttoken" > tmp/swift_token.txt
script: ruby spec/$BACKEND/*
branches:
only:
- master
- stable
notifications:
email: false
webhooks:
urls:
- http://hook-juggler.herokuapp.com/hooks/travis
on_success: always
on_failure: always
env:
- BACKEND=s3
- BACKEND=swift
# Run on Docker infrastructure
sudo: false

View File

@ -1,93 +0,0 @@
[
{eleveldb, [
{data_root, "/var/lib/riak/leveldb"}
]},
{kernel, [
{inet_dist_listen_max, 7999},
{inet_dist_listen_min, 6000}
]},
{lager, [
{crash_log, "/var/log/riak/crash.log"},
{crash_log_count, 5},
{crash_log_date, "$D0"},
{crash_log_msg_size, 65536},
{crash_log_size, 10485760},
{error_logger_redirect, true},
{handlers, [
{lager_console_backend, info},
{lager_file_backend, [
{"/var/log/riak/console.log", info, 10485760, "$D0", 5},
{"/var/log/riak/error.log", error, 10485760, "$D0", 5}
]}
]}
]},
{merge_index, [
{buffer_rollover_size, 1048576},
{data_root, "/var/lib/riak/merge_index"},
{max_compact_segments, 20}
]},
{riak_api, [
{pb_ip, "127.0.0.1"},
{pb_port, 8087}
]},
{riak_control, [
{admin, true},
{auth, userlist},
{enabled, false},
{userlist, [
{"user", "pass"}
]}
]},
{riak_core, [
{cluster_name, "default"},
{dtrace_support, false},
{handoff_port, 8099},
{http, [{"0.0.0.0", 8098}]},
{platform_bin_dir, "/usr/sbin"},
{platform_data_dir, "/var/lib/riak"},
{platform_etc_dir, "/etc/riak"},
{platform_lib_dir, "/usr/lib/riak"},
{ring_state_dir, "/var/lib/riak/ring"}
]},
{riak_err, [
{fmt_max_bytes, 65536},
{term_max_size, 65536}
]},
{riak_kv, [
{hook_js_vm_count, 2},
{http_url_encoding, on},
{js_max_vm_mem, 8},
{js_thread_stack, 16},
{legacy_keylisting, false},
{map_js_vm_count, 8},
{mapred_2i_pipe, true},
{mapred_name, "mapred"},
{mapred_queue_dir, "/var/lib/riak/mr_queue"},
{mapred_system, pipe},
{raw_name, "riak"},
{reduce_js_vm_count, 6},
{storage_backend, riak_kv_eleveldb_backend},
{vnode_vclocks, true}
]},
{riak_search, [
{enabled, true}
]},
{riak_sysmon, [
{busy_dist_port, true},
{busy_port, true},
{gc_ms_limit, 100},
{heap_word_limit, 40111000},
{port_limit, 2},
{process_limit, 30}
]},
{sasl, [
{errlog_type, error},
{error_logger_mf_dir, "/var/log/riak/sasl"},
{error_logger_mf_maxbytes, 10485760},
{error_logger_mf_maxfiles, 5},
{sasl_error_logger, false}
]},
{service, [
{enabled, false}
]}
].

View File

@ -1,32 +0,0 @@
#!/bin/bash
curl http://apt.basho.com/gpg/basho.apt.key | sudo apt-key add -
sudo bash -c "echo deb http://apt.basho.com $(lsb_release -sc) main > /etc/apt/sources.list.d/basho.list"
sudo apt-get update
sudo apt-get install -o Dpkg::Options::="--force-confnew" -q -y riak=1.4.2-1
sudo apt-get install -q -y riak-cs=1.4.1-1
sudo apt-get install -q -y stanchion=1.4.1-1
sudo bash -c "echo '127.0.0.1 cs.example.com' >> /etc/hosts"
sudo cp .travis/riak.app.config /etc/riak/app.config
sudo cp .travis/riak.vm.args /etc/riak/vm.args
sudo cp .travis/riakcs.app.config /etc/riak-cs/app.config
sudo cp .travis/riakcs.vm.args /etc/riak-cs/vm.args
sudo cp .travis/stanchion.app.config /etc/stanchion/app.config
sudo cp .travis/stanchion.vm.args /etc/stanchion/vm.args
sudo service riak start
sudo service riak-cs start
sudo service stanchion start
sleep 5
curl -H 'Content-Type: application/json' -X POST http://localhost:8080/riak-cs/user --data '{"email":"admin@5apps.com", "name":"admin"}' -o cs_admin_credentials.json
cat cs_admin_credentials.json
curl -H 'Content-Type: application/json' -X POST http://localhost:8080/riak-cs/user --data '{"email":"liquorcabinet@5apps.com", "name":"liquor cabinet"}' -o cs_credentials.json
cat cs_credentials.json
echo "\nFinished"

View File

@ -1,135 +0,0 @@
[
{kernel, [
{inet_dist_listen_max, 7999},
{inet_dist_listen_min, 6000}
]},
{lager, [
{crash_log, "/var/log/riak/crash.log"},
{crash_log_count, 5},
{crash_log_date, "$D0"},
{crash_log_msg_size, 65536},
{crash_log_size, 10485760},
{error_logger_hwm, 100},
{error_logger_redirect, true},
{handlers, [
{lager_file_backend, [
{"/var/log/riak/error.log", error, 10485760, "$D0", 5},
{"/var/log/riak/console.log", info, 10485760, "$D0", 5}
]}
]}
]},
{merge_index, [
{buffer_rollover_size, 1048576},
{data_root, "/var/lib/riak/merge_index"},
{max_compact_segments, 20}
]},
{riak_api, [
{pb, [
{"127.0.0.1", 8087}
]},
{pb_backlog, 128}
]},
{riak_control, [
{admin, true},
{auth, userlist},
{enabled, false},
{userlist, [
{"user", "pass"}
]}
]},
{riak_core, [
{cluster_mgr, {"127.0.0.1", 9085}},
{default_bucket_props, [
{allow_mult, true}
]},
{dtrace_support, false},
{handoff_port, 8099},
{http, [
{"127.0.0.1", 8098}
]},
{platform_bin_dir, "/usr/sbin"},
{platform_data_dir, "/var/lib/riak"},
{platform_etc_dir, "/etc/riak"},
{platform_lib_dir, "/usr/lib/riak"},
{platform_log_dir, "/var/log/riak"},
{ring_creation_size, 64},
{ring_state_dir, "/var/lib/riak/ring"}
]},
{riak_jmx, [
{enabled, false}
]},
{riak_kv, [
{add_paths, [
"/usr/lib/riak-cs/lib/riak_cs-1.4.1/ebin"
]},
{anti_entropy, {on, [
]}},
{anti_entropy_build_limit, {1, 3600000}},
{anti_entropy_concurrency, 2},
{anti_entropy_data_dir, "/var/lib/riak/anti_entropy"},
{anti_entropy_expire, 604800000},
{anti_entropy_leveldb_opts, [
{write_buffer_size, 4194304},
{max_open_files, 20}
]},
{anti_entropy_tick, 15000},
{fsm_limit, 50000},
{hook_js_vm_count, 2},
{http_url_encoding, on},
{js_max_vm_mem, 8},
{js_thread_stack, 16},
{listkeys_backpressure, true},
{map_js_vm_count, 8},
{mapred_2i_pipe, true},
{mapred_name, "mapred"},
{multi_backend, [
{be_default, riak_kv_eleveldb_backend, [
{cache_size, 4194304},
{data_root, "/var/lib/riak/leveldb"},
{max_open_files, 50}
]},
{be_blocks, riak_kv_bitcask_backend, [
{data_root, "/var/lib/riak/bitcask"}
]}
]},
{multi_backend_default, be_default},
{multi_backend_prefix_list, [
{<<"0b:">>, be_blocks}
]},
{object_format, v1},
{reduce_js_vm_count, 6},
{storage_backend, riak_cs_kv_multi_backend},
{vnode_vclocks, true}
]},
{riak_repl, [
{data_root, "/var/lib/riak/riak_repl"}
]},
{riak_search, [
{enabled, false}
]},
{riak_sysmon, [
{busy_dist_port, true},
{busy_port, true},
{gc_ms_limit, 0},
{heap_word_limit, 40111000},
{port_limit, 2},
{process_limit, 30}
]},
{sasl, [
{sasl_error_logger, false}
]},
{snmp, [
{agent, [
{config, [
{dir, "/etc/riak/snmp/agent/conf"},
{force_load, true}
]},
{db_dir, "/var/lib/riak/snmp/agent/db"},
{net_if, [
{options, [
{bind_to, true}
]}
]}
]}
]}
].

View File

@ -1,10 +0,0 @@
+A 64
+K true
+W w
-env ERL_CRASH_DUMP /var/log/riak/erl_crash.dump
-env ERL_FULLSWEEP_AFTER 0
-env ERL_MAX_ETS_TABLES 256000
-env ERL_MAX_PORTS 64000
-name riak@127.0.0.1
-setcookie riak
-smp enable

View File

@ -1,65 +0,0 @@
[
{lager, [
{crash_log, "/var/log/riak-cs/crash.log"},
{crash_log_count, 5},
{crash_log_date, "$D0"},
{crash_log_msg_size, 65536},
{crash_log_size, 10485760},
{error_logger_redirect, true},
{handlers, [
{lager_file_backend, [
{"/var/log/riak-cs/error.log", error, 10485760, "$D0", 5},
{"/var/log/riak-cs/console.log", info, 10485760, "$D0", 5}
]}
]}
]},
{riak_cs, [
{access_archive_period, 3600},
{access_archiver_max_backlog, 2},
{access_log_flush_factor, 1},
{access_log_flush_size, 1000000},
{admin_key, "secret"},
{admin_secret, "secret"},
{anonymous_user_creation, true},
{auth_module, riak_cs_s3_auth},
{connection_pools, [
{bucket_list_pool, {5, 0}},
{request_pool, {128, 0}}
]},
{cs_ip, "127.0.0.1"},
{cs_port, 8080},
{cs_root_host, "cs.example.com"},
{cs_version, 10300},
{dtrace_support, false},
{fold_objects_for_list_keys, false},
{gc_interval, 900},
{gc_retry_interval, 21600},
{leeway_seconds, 86400},
{n_val_1_get_requests, true},
{rewrite_module, riak_cs_s3_rewrite},
{riak_ip, "127.0.0.1"},
{riak_pb_port, 8087},
{stanchion_ip, "127.0.0.1"},
{stanchion_port, 8085},
{stanchion_ssl, false},
{storage_archive_period, 86400},
{storage_schedule, [
]},
{trust_x_forwarded_for, false},
{usage_request_limit, 744}
]},
{sasl, [
{sasl_error_logger, false},
{utc_log, true}
]},
{webmachine, [
{log_handlers, [
{riak_cs_access_log_handler, [
]},
{webmachine_log_handler, [
"/var/log/riak-cs"
]}
]},
{server_name, "Riak CS"}
]}
].

View File

@ -1,8 +0,0 @@
+A 64
+K true
+W w
-env ERL_CRASH_DUMP /var/log/riak-cs/erl_crash.dump
-env ERL_FULLSWEEP_AFTER 0
-env ERL_MAX_PORTS 4096
-name riak-cs@127.0.0.1
-setcookie riak-cs

View File

@ -1,29 +0,0 @@
[
{lager, [
{crash_log, "/var/log/stanchion/crash.log"},
{crash_log_count, 5},
{crash_log_date, "$D0"},
{crash_log_msg_size, 65536},
{crash_log_size, 10485760},
{error_logger_redirect, true},
{handlers, [
{lager_file_backend, [
{"/var/log/stanchion/error.log", error, 10485760, "$D0", 5},
{"/var/log/stanchion/console.log", info, 10485760, "$D0", 5}
]}
]}
]},
{sasl, [
{sasl_error_logger, false},
{utc_log, true}
]},
{stanchion, [
{admin_key, "secret"},
{admin_secret, "secret"},
{auth_bypass, false},
{riak_ip, "127.0.0.1"},
{riak_pb_port, 8087},
{stanchion_ip, "127.0.0.1"},
{stanchion_port, 8085}
]}
].

View File

@ -1,8 +0,0 @@
+A 64
+K true
+W w
-env ERL_CRASH_DUMP /var/log/stanchion/erl_crash.dump
-env ERL_FULLSWEEP_AFTER 0
-env ERL_MAX_PORTS 4096
-name stanchion@127.0.0.1
-setcookie stanchion

10
Gemfile
View File

@ -1,10 +1,10 @@
source "https://rubygems.org"
gem "sinatra"
gem "sinatra-contrib"
gem "activesupport"
gem "rest-client", "~> 2.1.0.rc1" # Fixes a memory leak in Ruby 2.4
gem "redis"
gem "sinatra", "~> 2.2.0"
gem "sinatra-contrib", "~> 2.2.0"
gem "activesupport", "~> 6.0.5"
gem "rest-client", "~> 2.1.0" # Fixes a memory leak in Ruby 2.4
gem "redis", "~> 4.6.0"
# Remove require when we can update to 3.0, which sets the new storage
# format to columnar by default. Increases performance
gem "mime-types"

View File

@ -1,16 +1,15 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (6.0.1)
activesupport (6.0.5)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.2)
addressable (2.7.0)
zeitwerk (~> 2.2, >= 2.2.2)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
backports (3.15.0)
concurrent-ruby (1.1.5)
concurrent-ruby (1.1.10)
crack (0.4.3)
safe_yaml (~> 1.0.0)
domain_name (0.5.20190701)
@ -21,7 +20,7 @@ GEM
http-accept (1.7.0)
http-cookie (1.0.3)
domain_name (~> 0.5)
i18n (1.7.0)
i18n (1.10.0)
concurrent-ruby (~> 1.0)
kgio (2.11.2)
m (1.5.1)
@ -33,15 +32,16 @@ GEM
mime-types-data (3.2019.1009)
minitest (5.13.0)
minitest-stub_any_instance (1.0.2)
multi_json (1.14.1)
multi_json (1.15.0)
multipart-post (2.1.1)
mustermann (1.0.3)
mustermann (1.1.1)
ruby2_keywords (~> 0.0.1)
netrc (0.11.0)
public_suffix (4.0.1)
purdytest (2.0.0)
minitest (~> 5.5)
rack (2.0.8)
rack-protection (2.0.7)
rack (2.2.3)
rack-protection (2.2.0)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
@ -51,30 +51,30 @@ GEM
unicorn (~> 5.1)
raindrops (0.19.0)
rake (13.0.1)
redis (4.1.3)
redis (4.6.0)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
ruby2_keywords (0.0.5)
safe_yaml (1.0.5)
sentry-raven (2.12.3)
faraday (>= 0.7.6, < 1.0)
sinatra (2.0.7)
sinatra (2.2.0)
mustermann (~> 1.0)
rack (~> 2.0)
rack-protection (= 2.0.7)
rack (~> 2.2)
rack-protection (= 2.2.0)
tilt (~> 2.0)
sinatra-contrib (2.0.7)
backports (>= 2.8.2)
sinatra-contrib (2.2.0)
multi_json
mustermann (~> 1.0)
rack-protection (= 2.0.7)
sinatra (= 2.0.7)
rack-protection (= 2.2.0)
sinatra (= 2.2.0)
tilt (~> 2.0)
thread_safe (0.3.6)
tilt (2.0.10)
tzinfo (1.2.5)
tzinfo (1.2.9)
thread_safe (~> 0.1)
unf (0.1.4)
unf_ext
@ -86,13 +86,13 @@ GEM
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
zeitwerk (2.2.1)
zeitwerk (2.5.4)
PLATFORMS
ruby
DEPENDENCIES
activesupport
activesupport (~> 6.0.5)
m
mime-types
minitest-stub_any_instance
@ -100,11 +100,11 @@ DEPENDENCIES
rack-test
rainbows
rake
redis
rest-client (~> 2.1.0.rc1)
redis (~> 4.6.0)
rest-client (~> 2.1.0)
sentry-raven
sinatra
sinatra-contrib
sinatra (~> 2.2.0)
sinatra-contrib (~> 2.2.0)
webmock
BUNDLED WITH

View File

@ -1,4 +1,4 @@
[![Build Status](https://secure.travis-ci.org/5apps/liquor-cabinet.png?branch=master)](http://travis-ci.org/5apps/liquor-cabinet)
[![Build Status](https://github.com/5apps/liquor-cabinet/actions/workflows/ruby.yml/badge.svg)](https://github.com/5apps/liquor-cabinet/actions/workflows/ruby.yml)
# Liquor Cabinet

View File

@ -1,18 +0,0 @@
development: &defaults
maintenance: false
swift: &swift_defaults
host: "https://swift.example.com"
redis:
host: localhost
port: 6379
test:
<<: *defaults
swift:
host: "https://swift.example.com"
staging:
<<: *defaults
production:
<<: *defaults

View File

@ -1,63 +0,0 @@
require "rest_client"
require "active_support/core_ext/time/conversions"
require "active_support/core_ext/numeric/time"
require "active_support/core_ext/hash"
require "remote_storage/rest_provider"
module RemoteStorage
class Swift
include RestProvider
private
# Add quotes around the ETag
def format_etag(etag)
%Q("#{etag}")
end
def base_url
@base_url ||= settings.swift["host"]
end
def container_url_for(user)
"#{base_url}/rs:documents:#{settings.environment.to_s}/#{user}"
end
def default_headers
{"x-auth-token" => swift_token}
end
def reload_swift_token
server.logger.debug "Reloading swift token. Old token: #{settings.swift_token}"
# Remove the line break from the token file. The line break that the
# token script is adding to the file was causing Sentry to reject the
# token field
settings.swift_token = File.read(swift_token_path).rstrip
settings.swift_token_loaded_at = Time.now
server.logger.debug "Reloaded swift token. New token: #{settings.swift_token}"
end
def swift_token_path
"tmp/swift_token.txt"
end
def swift_token
reload_swift_token if Time.now - settings.swift_token_loaded_at > 1800
settings.swift_token
end
def deal_with_unauthorized_requests(&block)
begin
block.call
rescue RestClient::Unauthorized => ex
Raven.capture_exception(
ex,
tags: { swift_token: settings.swift_token[0..19], # send the first 20 characters
swift_token_loaded_at: settings.swift_token_loaded_at }
)
server.halt 500
end
end
end
end

View File

@ -4,7 +4,6 @@ require "json"
require "sinatra/base"
require 'sinatra/config_file'
require "sinatra/reloader"
require "remote_storage/swift"
require "remote_storage/s3"
class LiquorCabinet < Sinatra::Base
@ -20,10 +19,6 @@ class LiquorCabinet < Sinatra::Base
register Sinatra::ConfigFile
set :environments, %w{development test production staging}
config_file 'config.yml'
if settings.respond_to? :swift
set :swift_token, File.read("tmp/swift_token.txt")
set :swift_token_loaded_at, Time.now
end
end
configure :development do
@ -84,6 +79,7 @@ class LiquorCabinet < Sinatra::Base
end
options path do
headers['Access-Control-Max-Age'] = '7200'
halt 200
end
end
@ -130,9 +126,7 @@ class LiquorCabinet < Sinatra::Base
def storage
@storage ||= begin
if settings.respond_to? :swift
RemoteStorage::Swift.new(settings, self)
elsif settings.respond_to? :s3
if settings.respond_to? :s3
RemoteStorage::S3.new(settings, self)
else
puts <<-EOF

View File

@ -1,5 +1,3 @@
require_relative "./spec_helper"
shared_examples_for 'a REST adapter' do
include Rack::Test::Methods
@ -16,6 +14,18 @@ shared_examples_for 'a REST adapter' do
_(last_response.status).must_equal 404
end
describe "OPTIONS requests" do
it "returns CORS headers" do
options "/phil/food/aguacate"
_(last_response.headers["Access-Control-Allow-Origin"]).wont_be_nil
_(last_response.headers["Access-Control-Allow-Methods"]).must_equal "GET, PUT, DELETE"
_(last_response.headers["Access-Control-Max-Age"].to_i).must_be :> , 10
end
end
describe "PUT requests" do
before do
@ -423,8 +433,8 @@ shared_examples_for 'a REST adapter' do
it "returns the required response headers" do
get "/phil/public/shares/example.jpg"
last_response.status.must_equal 200
last_response.headers["Content-Type"].must_equal "image/jpeg"
_(last_response.status).must_equal 200
_(last_response.headers["Content-Type"]).must_equal "image/jpeg"
end
end
@ -442,8 +452,8 @@ JFIFddDuckyA␍⎺␉␊␍
header 'Range', 'bytes=0-16'
get "/phil/public/shares/example_partial.jpg"
last_response.status.must_equal 206
last_response.headers["Content-Type"].must_equal "image/jpeg"
_(last_response.status).must_equal 206
_(last_response.headers["Content-Type"]).must_equal "image/jpeg"
end
end
end

View File

@ -1,66 +0,0 @@
require_relative "../spec_helper"
describe "Swift provider" do
def container_url_for(user)
"#{app.settings.swift["host"]}/rs:documents:test/#{user}"
end
def storage_class
RemoteStorage::Swift
end
before do
stub_request(:put, "#{container_url_for("phil")}/food/aguacate").
to_return(status: 200, headers: { etag: "0815etag", last_modified: "Fri, 04 Mar 2016 12:20:18 GMT" })
# Write new content with an If-Match header (a new Etag is returned)
stub_request(:put, "#{container_url_for("phil")}/food/aguacate").
with(body: "aye").
to_return(status: 200, headers: { etag: "0915etag", last_modified: "Fri, 04 Mar 2016 12:20:18 GMT" })
stub_request(:put, "#{container_url_for("phil")}/public/shares/example.jpg").
to_return(status: 200, headers: { etag: '"0817etag"', content_type: "image/jpeg", last_modified: "Fri, 04 Mar 2016 12:20:18 GMT" })
stub_request(:put, "#{container_url_for("phil")}/public/shares/example_partial.jpg").
to_return(status: 200, headers: { etag: '"0817etag"', content_type: "image/jpeg", last_modified: "Fri, 04 Mar 2016 12:20:18 GMT" })
stub_request(:head, "#{container_url_for("phil")}/food/aguacate").
to_return(status: 200, headers: { last_modified: "Fri, 04 Mar 2016 12:20:18 GMT" })
stub_request(:get, "#{container_url_for("phil")}/food/aguacate").
to_return(status: 200, body: "rootbody", headers: { etag: "0817etag", content_type: "text/plain; charset=utf-8" })
stub_request(:delete, "#{container_url_for("phil")}/food/aguacate").
to_return(status: 200, headers: { etag: "0815etag" })
stub_request(:get, "#{container_url_for("phil")}/public/shares/example.jpg").
to_return(status: 200, body: "", headers: { etag: '"0817etag"', content_type: "image/jpeg" })
stub_request(:get, "#{container_url_for("phil")}/public/shares/example_partial.jpg").
to_return(status: 206, body: "", headers: { etag: '"0817etag"', content_type: "image/jpeg", content_range: "bytes 0-16/128" })
# Write new content to check the metadata in Redis
stub_request(:put, "#{container_url_for("phil")}/food/banano").
with(body: "si").
to_return(status: 200, headers: { etag: "0815etag", last_modified: "Fri, 04 Mar 2016 12:20:18 GMT" })
stub_request(:put, "#{container_url_for("phil")}/food/banano").
with(body: "oh, no").
to_return(status: 200, headers: { etag: "0817etag", last_modified: "Fri, 04 Mar 2016 12:20:20 GMT" })
stub_request(:put, "#{container_url_for("phil")}/food/camaron").
to_return(status: 200, headers: { etag: "0816etag", last_modified: "Fri, 04 Mar 2016 12:20:18 GMT" })
stub_request(:delete, "#{container_url_for("phil")}/food/camaron").
to_return(status: 200, headers: { etag: "0816etag" })
stub_request(:put, "#{container_url_for("phil")}/food/desayunos/bolon").
to_return(status: 200, headers: { etag: "0817etag", last_modified: "Fri, 04 Mar 2016 12:20:18 GMT" })
stub_request(:delete, "#{container_url_for("phil")}/food/desayunos/bolon").
to_return(status: 200, headers: { etag: "0817etag" })
# objects in root dir
stub_request(:put, "#{container_url_for("phil")}/bamboo.txt").
to_return(status: 200, headers: { etag: "0818etag", last_modified: "Fri, 04 Mar 2016 12:20:18 GMT" })
# 404
stub_request(:head, "#{container_url_for("phil")}/food/steak").
to_return(status: 404)
stub_request(:get, "#{container_url_for("phil")}/food/steak").
to_return(status: 404)
stub_request(:delete, "#{container_url_for("phil")}/food/steak").
to_return(status: 404)
end
it_behaves_like 'a REST adapter'
end