Skip to content
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

release-0.4.0 #54

Merged
merged 34 commits into from
Apr 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a1e9a07
Add coverage to test-macos-spm
finestructure Apr 4, 2019
b8295f8
Try codecov
finestructure Apr 4, 2019
db3796e
Set derived data dir
finestructure Apr 4, 2019
92c5403
Teak build
finestructure Apr 4, 2019
10c2c08
Try -J
finestructure Apr 4, 2019
4cd293f
Cleanup
finestructure Apr 4, 2019
0252214
Fix -D path
finestructure Apr 4, 2019
6ffa98d
Move code to ResterCode to fix coverage reporting
finestructure Apr 5, 2019
a31fa3f
Fix build
finestructure Apr 5, 2019
848e0a3
Reorg build steps, add Xcode build for coverage
finestructure Apr 5, 2019
c13d70f
Fix deploy step
finestructure Apr 5, 2019
d056cfc
Add badge
finestructure Apr 5, 2019
e348262
Rename files
finestructure Apr 5, 2019
70f774f
Merge pull request #46 from finestructure/coverage
finestructure Apr 5, 2019
968eae2
Add twitter badge
finestructure Apr 5, 2019
60319ae
Update docs
finestructure Apr 5, 2019
40513f4
Move console extension
finestructure Apr 5, 2019
9510b81
Add validation error snapshot
finestructure Apr 5, 2019
f9af73d
Merge pull request #47 from finestructure/doc-update
finestructure Apr 5, 2019
75ca924
Test summary pluralisation
finestructure Apr 5, 2019
ea6f3ed
Basic support for looping
finestructure Apr 5, 2019
c1af9a9
Clean up FIXME
finestructure Apr 5, 2019
160cd4d
Handling errors
finestructure Apr 5, 2019
4b1810a
Switch to swift 5 Regex
finestructure Apr 6, 2019
b130833
Merge pull request #48 from finestructure/loop
finestructure Apr 6, 2019
190a0dd
WIP: Switch to official swift:5.0
finestructure Apr 3, 2019
9fb163d
Update runtime libs
finestructure Apr 8, 2019
2199f67
Add credit
finestructure Apr 8, 2019
c790552
Merge pull request #50 from finestructure/apple-swift-5
finestructure Apr 8, 2019
6abbad6
Regex-1.2.0
finestructure Apr 8, 2019
a11ea05
Merge pull request #51 from finestructure/package-update
finestructure Apr 8, 2019
2a4b2b2
Factor out chain
finestructure Apr 9, 2019
af4019f
Add duration parameter
finestructure Apr 9, 2019
9cbae97
Merge pull request #53 from finestructure/run-for-duration
finestructure Apr 9, 2019
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
61 changes: 25 additions & 36 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,45 @@ env:
- secure: "j39yC3GJMPK1/s/Q3VLT7fLuwhkN9lmo9OcRVb5iP8OW7HPrxb4b/e7Yp5Gia2KBjHVai/1zH0YA8UFzQju4VjvZdgLc1F+I7FK4NCXG2Vib3fy76A2wOvNl29qrTMgjYjA6dsfdUigLtZf0EE0yLV8MeVGVzsOa4w2iiJhZtWoNbBY7Xo/cAm9csZvvMJ7W+03tmsWo0VLwV9b1F8gW+WXWNLjg84tOj4KsGPDd+1dniK5xb2OxmmzygcxULm5Sbw/Dityz963LFGHIXlVxPzlQxFnio7iOQn60SA12+dwmRfRWHdUTWp7/pQgvK69kdTCJ2D8K5/QTNuxEJQ+dAT8OEoGISYUa9wS88bHM4NqK+uA9t5XsLkrpSyHMCvWadeacwMyIqxGcc9IwHVJYpMwFX2+ufu3g3JwXV54w+jjj72N/shMvhKQVfMM1V+zUGKyblPMYfbFizywa96/R4UTQFjvBknC95SnsQPOqCEEaiBKYVGtHWiFxXIsiX07lEsbsrbdzczFxBJCgYLPSpkVuydWkXxjpXZ3mo47lZomJy354RW3nRs4pfmz99o5IVjeLPqUiElXA9tkFu4yzRB5L1K+LUxwnLy1SX79BvA06rQBkqXRt5TBidtow3LcxpfrqwP0Eoop6GnoiPhbez3ZUnp3hgskAZovqCKaPzsc="

stages:
- build base image
- build app image
- test


install:
- if [[ $TRAVIS_OS_NAME == "linux" ]]; then
eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)";
fi
- deploy


jobs:
include:
- os: linux
dist: trusty
- os: osx

- name: macos spm test
stage: test
os: osx
osx_image: xcode10.2
script: make test-macos-spm

- stage: build base image
- name: macos xcode test
stage: test
os: osx
osx_image: xcode10.2
script: make test-macos-xcode
after_success:
# upload coverage data
- bash <(curl -s https://codecov.io/bash) -J '^ResterCore$' -D .build/derivedData

- name: docker spm test
stage: test
os: linux
dist: trusty
script: |
set -e

# login
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin

# build
VERSION=${TRAVIS_TAG:-$TRAVIS_COMMIT}
IMG=finestructure/rester:base-$VERSION
docker build --pull -t $IMG -f Dockerfile.base .

# push
docker push $IMG
IMAGE=finestructure/rester:base-$VERSION
docker build --pull -t $IMAGE -f Dockerfile.base .
docker run --rm -e GITHUB_TOKEN=$GITHUB_TOKEN $IMAGE swift test
docker push $IMAGE

- stage: build app image
- name: push app image
stage: deploy
os: linux
dist: trusty
script: |
set -e

Expand All @@ -64,17 +67,3 @@ jobs:
# tag and push latest
docker tag $IMG finestructure/rester:latest
docker push finestructure/rester:latest

- stage: test
name: swift test
script: swift test

- stage: test
name: docker swift test
os: linux
script: |
set -e
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
VERSION=${TRAVIS_TAG:-$TRAVIS_COMMIT}
IMAGE=finestructure/rester:base-$VERSION
docker run --rm -e GITHUB_TOKEN=$GITHUB_TOKEN $IMAGE swift test
12 changes: 7 additions & 5 deletions Dockerfile.app
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# based on https://github.com/vapor/api-template/blob/b5573ace9632e2d28362cd278cdaac43ff9a00ea/web.Dockerfile

# base image

ARG VERSION=${VERSION}
Expand All @@ -6,17 +8,17 @@ FROM finestructure/rester:base-${VERSION} as build
# add VERSION to binary
RUN make version

RUN mkdir -p /build/lib && cp -R /usr/lib/swift/linux/*.so /build/lib && cp -R /usr/lib/swift/linux/*.so.* /build/lib
RUN mkdir -p /build/lib && cp -R /usr/lib/swift/linux/*.so* /build/lib
RUN swift build -c release && mv `swift build -c release --show-bin-path` /build/bin

# deployment image

ARG VERSION=${VERSION}
FROM ubuntu:16.04
FROM ubuntu:18.04

RUN apt-get -qq update && apt-get install -y \
libicu55 libxml2 libbsd0 libcurl3 libatomic1 \
tzdata \
# DEBIAN_FRONTEND=noninteractive for automatic UTC configuration in tzdata
RUN apt-get -qq update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
libatomic1 libicu60 libxml2 libcurl4 libz-dev libbsd0 tzdata \
&& rm -r /var/lib/apt/lists/*

WORKDIR /app
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.base
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM finestructure/swift:5.0
FROM swift:5.0

WORKDIR /package

Expand Down
14 changes: 9 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,23 @@ build-docker-app: build-docker-base
docker tag rester-base finestructure/rester:base-$(VERSION)
docker build --tag rester:$(VERSION) -f Dockerfile.app --build-arg VERSION=$(VERSION) .

test-linux: build-docker-base
test-linux-spm: build-docker-base
docker run --rm rester-base swift test

test-macos: xcodeproj
test-macos-xcode: xcodeproj
set -o pipefail && \
xcodebuild test \
-scheme Rester \
-destination platform="macOS" \
-enableCodeCoverage YES \
-derivedDataPath .build/derivedData

test-swift:
swift test
test-macos-spm: BUILD_DIR=$(shell swift build --show-bin-path)
test-macos-spm:
swift test --enable-code-coverage
xcrun llvm-cov report -ignore-filename-regex=".build/*" -instr-profile $(BUILD_DIR)/codecov/default.profdata $(BUILD_DIR)/rester

test-all: test-linux test-macos
test-all: test-linux-spm test-macos-spm test-macos-xcode

magic:
sourcery --templates ./.sourcery --sources Tests --args testimports='@testable import '"ResterTests" --output Tests/LinuxMain.swift
Expand Down
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@
"repositoryURL": "https://github.com/crossroadlabs/Regex.git",
"state": {
"branch": null,
"revision": "f144250678e4c13f1d820ffa265a8326b25bcd86",
"version": "1.1.0"
"revision": "166728756082a9cac6e4aed3ebbce8e41cb3a945",
"version": "1.2.0"
}
},
{
Expand Down
6 changes: 3 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ let package = Package(
.executable(name: "rester", targets: ["Rester"])
],
dependencies: [
.package(url: "https://github.com/crossroadlabs/Regex.git", from: "1.0.0"),
.package(url: "https://github.com/crossroadlabs/Regex.git", from: "1.2.0"),
.package(url: "https://github.com/finestructure/ValueCodable", from: "0.0.2"),
.package(url: "https://github.com/jpsim/Yams.git", from: "1.0.0"),
.package(url: "https://github.com/kylef/Commander.git", from: "0.8.0"),
Expand All @@ -23,10 +23,10 @@ let package = Package(
targets: [
.target(
name: "Rester",
dependencies: ["Commander", "Rainbow", "ResterCore"]),
dependencies: ["ResterCore"]),
.target(
name: "ResterCore",
dependencies: ["LegibleError", "PMKFoundation", "Path", "PromiseKit", "Rainbow", "Regex", "ValueCodable", "Yams"]),
dependencies: ["Commander", "LegibleError", "PMKFoundation", "Path", "PromiseKit", "Rainbow", "Regex", "ValueCodable", "Yams"]),
.testTarget(
name: "ResterTests",
dependencies: ["ResterCore", "SnapshotTesting"]),
Expand Down
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
# Rester

![](https://img.shields.io/badge/Swift-5-blue.svg) [![Build Status](https://travis-ci.org/finestructure/Rester.svg?branch=develop)](https://travis-ci.org/finestructure/Rester)
![Swift 5](https://img.shields.io/badge/Swift-5-blue.svg)
[![Build Status](https://travis-ci.org/finestructure/Rester.svg?branch=develop)](https://travis-ci.org/finestructure/Rester)
[![codecov](https://codecov.io/gh/finestructure/Rester/branch/develop/graph/badge.svg)](https://codecov.io/gh/finestructure/Rester)
[![Twitter: @_sa_s](https://img.shields.io/badge/twitter-@_sa_s-blue.svg?style=flat)](https://twitter.com/_sa_s)

Rester is a command line tool to test HTTP APIs. It takes a request description like the following:

Rester is a command line tool to test HTTP APIs. It processes declaratively written request descriptions as a test script, executing and validating the requests as specified.

For instance, a description like the following:

```
# basic.yml
Expand All @@ -13,7 +19,7 @@ requests:
status: 200
```

and processes it
is processed as follows:

[![asciicast](https://asciinema.org/a/237892.svg)](https://asciinema.org/a/237892)

Expand All @@ -29,6 +35,7 @@ Rester currently supports:
- Sending headers
- Using response values as substitution variables
- Batch file processing
- Uploading and downloading of files
- Delay between requests

See [Upcoming Features](https://github.com/finestructure/Rester/issues/28) for a list of what is planned for future releases.
Expand Down Expand Up @@ -68,8 +75,15 @@ Result:

[![asciicast](https://asciinema.org/a/237894.svg)](https://asciinema.org/a/237894)

## More examples

The [examples directory](examples) demonstrates further uses of rester. You can also find the output these examples generate in the [test snapshot directory](Tests/ResterTests/__Snapshots__/ExampleTests/).

A few noteworthy examples for common tasks are

- [`github.yml`](examples/github.yml): Use the Github API to fetch and print the latest release version of `rester`. Demonstrates the use of response variables and how to index into response arrays and objects as well as how to log responses.
- [`multipart.yml`](examples/multipart.yml): Performs a multipart upload of an image.

## Running `rester`

The easiest way to run `rester` is via docker:
Expand Down
108 changes: 1 addition & 107 deletions Sources/Rester/main.swift
Original file line number Diff line number Diff line change
@@ -1,109 +1,3 @@
import Commander
import Foundation
import LegibleError
import Path
import PromiseKit
import Rainbow
import ResterCore
import Yams


extension Console {
func display(variables: [Key: Value]) {
guard variables.count > 0 else { return }
Current.console.display(verbose: "Defined variables:")
for v in variables.keys {
Current.console.display(verbose: " - \(v)")
}
Current.console.display(verbose: "")
}
}


func before(name: Request.Name) {
Current.console.display("🎬 \(name.blue) started ...\n")
}


func after(name: Request.Name, response: Response, result: ValidationResult) -> Bool {
switch result {
case .valid:
let duration = format(response.elapsed).map { " (\($0)s)" } ?? ""
Current.console.display("✅ \(name.blue) \("PASSED".green.bold)\(duration)\n")
return true
case let .invalid(message):
Current.console.display(verbose: "Response:".bold)
Current.console.display(verbose: "\(response)\n")
Current.console.display("❌ \(name.blue) \("FAILED".red.bold) : \(message.red)\n")
return false
}
}


let main = command(
Flag("verbose", flag: "v", description: "Verbose output"),
Option<String>("workdir", default: "", flag: "w", description: "Working directory (for the purpose of resolving relative paths in Restfiles)"),
Option<TimeInterval>("timeout", default: 10, flag: "t", description: "Request timeout"),
Flag("insecure", default: false, description: "do not validate SSL certificate (macOS only)"),
Argument<String>("filename", description: "A Restfile")
) { verbose, wdir, timeout, insecure, filename in

#if !os(macOS)
if insecure {
Current.console.display("--insecure flag currently only supported on macOS")
exit(1)
}
#endif

Current.console.display("🚀 Resting \(filename.bold) ...\n")

let restfilePath = Path(filename) ?? Path.cwd/filename
Current.workDir = getWorkDir(input: wdir) ?? (restfilePath).parent

if verbose {
Current.console.display(verbose: "Restfile path: \(restfilePath)")
Current.console.display(verbose: "Working directory: \(Current.workDir)\n")
}

if timeout != Request.defaultTimeout {
Current.console.display(verbose: "Request timeout: \(timeout)s\n")
}

let rester: Rester
do {
rester = try Rester(path: restfilePath, workDir: Current.workDir)
} catch {
Current.console.display(error)
exit(1)
}

if verbose {
Current.console.display(variables: rester.allVariables)
}

guard rester.requestCount > 0 else {
Current.console.display("⚠️ no requests defined in \(filename.bold)!")
exit(0)
}

rester.test(before: before, after: after, timeout: timeout, validateCertificate: !insecure)
.done { results in
let failureCount = results.filter { !$0 }.count
let failureMsg = failureCount == 0 ? "0".green.bold : failureCount.description.red.bold
Current.console.display("Executed \(results.count.description.bold) tests, with \(failureMsg) failures")
if failureCount > 0 {
exit(1)
} else {
exit(0)
}
}.catch { error in
Current.console.display(error)
exit(1)
}

RunLoop.main.run()

}


main.run(ResterVersion)
app.run(ResterVersion)
Loading