Skip to content

Instantly share code, notes, and snippets.

@Gerg
Last active June 12, 2019 17:22
Show Gist options
  • Save Gerg/af665090efd045e8039f43d627a878c9 to your computer and use it in GitHub Desktop.
Save Gerg/af665090efd045e8039f43d627a878c9 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require 'rspec'
require 'open3'
require 'json'
require 'cgi'
RESOURCE_ENDPOINT = '/v3/routes'
RESOURCE_BODY = {
'host': '<random>',
'relationships': {
'domain': {
'data': { 'guid': 'a2960da2-5c32-409f-b069-2f4e1250752f' }
},
'space': {
'data': { 'guid': '5ac6f371-77b5-4e47-8f42-458413f9d007' }
}
}
}
def to_j(h)
JSON.pretty_generate(h)
end
def to_h(j)
JSON.parse(j, symbolize_names: true)
end
STATUS_REGEX = %r(.*HTTP/1.1 (\d{3}) .*$)
BODY_REGEX = %r(.*mode=block[^\{]*(\{.*\}))m
def execute!(command, print: true)
stdout, _ = Open3.capture2(command)
status_code = stdout.match(STATUS_REGEX)[1].to_i
response_body = to_h(stdout.match(BODY_REGEX)[1])
puts '```'
puts command
puts status_code
puts to_j(response_body)
puts '```'
return status_code, response_body
end
def random_string
rand(36**5).to_s(36)
end
def post_body(metadata)
to_j(RESOURCE_BODY.merge(metadata)).gsub("<random>", random_string)
end
RSpec.describe 'Metadata' do
describe 'Add metadata when creating resource' do
context 'When API client POSTs with a valid body including metadata' do
let(:metadata) do
{
'metadata': {
'labels': {
'potato': 'yam',
'style': 'baked'
},
'annotations': {
'potato': 'idaho',
'style': 'mashed'
}
}
}
end
before do
command = "cf curl -v -X POST #{RESOURCE_ENDPOINT} -d '#{post_body(metadata)}'"
@status_code, @response_body = execute!(command)
end
it 'succeeds and includes metadata in the response' do
expect(@status_code).to eq(201)
expect(@response_body).to include(metadata)
end
end
end
describe 'Add metadata to existing resource' do
context 'When there is a resource with NO metadata' do
let(:metadata) do
{
'metadata': { }
}
end
before do
command = "cf curl -v -X POST #{RESOURCE_ENDPOINT} -d '#{post_body(metadata)}'"
status_code, response_body = execute!(command)
expect(status_code).to eq 201
@resource_guid = response_body[:guid]
end
context 'When API client PATCH with a valid body including metadata' do
let(:updated_metadata) do
{
'metadata': {
'labels': {
'potato': 'yam',
'style': 'baked'
},
'annotations': {
'potato': 'idaho',
'style': 'mashed'
}
}
}
end
before do
command = "cf curl -v -X PATCH #{RESOURCE_ENDPOINT}/#{@resource_guid} -d '#{to_j(updated_metadata)}'"
@status_code, @response_body = execute!(command)
end
it 'succeeds and includes metadata in the response' do
expect(@status_code).to eq(200)
expect(@response_body).to include(updated_metadata)
end
end
context 'When API client PATCH with a body including INVALID metadata' do
let(:updated_metadata) do
{
"metadata": {
"annotations": {
"": "mashed",
"/potato": ".value."
}
}
}
end
before do
command = "cf curl -v -X PATCH #{RESOURCE_ENDPOINT}/#{@resource_guid} -d '#{to_j(updated_metadata)}'"
@status_code, @response_body = execute!(command)
end
it 'fails and returns an error message' do
expect(@status_code).to eq(422)
expect(@response_body[:errors][0][:detail]).to eq('Metadata annotations key cannot be empty string')
end
end
end
context 'When there is a resource with metadata' do
let(:metadata) do
{
'metadata': {
"labels": {
"potato": "yam",
"style": "baked"
},
"annotations": {
"potato": "idaho",
"style": "french"
}
}
}
end
before do
command = "cf curl -v -X POST #{RESOURCE_ENDPOINT} -d '#{post_body(metadata)}'"
status_code, response_body = execute!(command)
expect(status_code).to eq 201
@resource_guid = response_body[:guid]
end
context 'When API client PATCH with a valid body including different metadata' do
let(:updated_metadata) do
{
"metadata": {
"labels": {
"style": "casserole"
},
"annotations": {
"potato": "russet"
}
}
}
end
before do
command = "cf curl -v -X PATCH #{RESOURCE_ENDPOINT}/#{@resource_guid} -d '#{to_j(updated_metadata)}'"
@status_code, @response_body = execute!(command)
end
it 'succeeds and includes the merged metadata in the response' do
expect(@status_code).to eq(200)
merged_metadata = {
"metadata": {
"labels": {
"potato": "yam",
"style": "casserole"
},
"annotations": {
"potato": "russet",
"style": "french"
}
}
}
expect(@response_body).to include(merged_metadata)
end
end
context 'When API client PATCH with a valid body to remove metadata' do
let(:updated_metadata) do
{
"metadata": {
"labels": {
"style": nil
},
"annotations": {
"potato": nil
}
}
}
end
before do
command = "cf curl -v -X PATCH #{RESOURCE_ENDPOINT}/#{@resource_guid} -d '#{to_j(updated_metadata)}'"
@status_code, @response_body = execute!(command)
end
it 'succeeds and includes the merged metadata with the null keys removed' do
expect(@status_code).to eq(200)
merged_metadata = {
"metadata": {
"labels": {
"potato": "yam"
},
"annotations": {
"style": "french"
}
}
}
expect(@response_body).to include(merged_metadata)
end
end
end
end
describe 'filtering on labels' do
context 'when there are a bunch of resources with labels' do
let(:env) { random_string }
let(:animal1) { random_string }
let(:animal2) { random_string }
let(:metadata_a) do
{
"metadata": {
"labels": {
"fruit": "strawberry",
"animal": animal2
}
}
}
end
let(:metadata_b) do
{
"metadata": {
"labels": {
"env": env,
"animal": animal1
}
}
}
end
let(:metadata_c) do
{
"metadata": {
"labels": {
"env": env,
"animal": animal2
}
}
}
end
let(:metadata_d) do
{
"metadata": {
"labels": {
"env": env
}
}
}
end
let(:metadata_e) do
{
"metadata": {
"labels": {
"env": "staging",
"animal": animal1
}
}
}
end
before do
command = "cf curl -v -X POST #{RESOURCE_ENDPOINT} -d '#{post_body(metadata_a)}'"
status_code, response_body = execute!(command)
expect(status_code).to eq 201
@a_guid = response_body[:guid]
command = "cf curl -v -X POST #{RESOURCE_ENDPOINT} -d '#{post_body(metadata_b)}'"
status_code, response_body = execute!(command)
expect(status_code).to eq 201
@b_guid = response_body[:guid]
command = "cf curl -v -X POST #{RESOURCE_ENDPOINT} -d '#{post_body(metadata_c)}'"
status_code, response_body = execute!(command)
expect(status_code).to eq 201
@c_guid = response_body[:guid]
command = "cf curl -v -X POST #{RESOURCE_ENDPOINT} -d '#{post_body(metadata_d)}'"
status_code, response_body = execute!(command)
expect(status_code).to eq 201
@d_guid = response_body[:guid]
command = "cf curl -v -X POST #{RESOURCE_ENDPOINT} -d '#{post_body(metadata_e)}'"
status_code, response_body = execute!(command)
expect(status_code).to eq 201
@e_guid = response_body[:guid]
end
context 'When API client lists resources with a label selector' do
before do
query = CGI.escape("!fruit,env=#{env},animal in (#{animal1},#{animal2})")
command = "cf curl -v #{RESOURCE_ENDPOINT}?label_selector=#{query}"
@status_code, @response_body = execute!(command)
end
it 'returns only the matching resources' do
expect(@status_code).to eq(200)
expect(@response_body[:resources].length).to eq 2
expect(@response_body[:resources].map{ |r| r[:guid] }).to match_array([@b_guid, @c_guid])
end
end
end
end
end
# Copyright 2019 Greg Cobb
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment