Skip to content

Commit

Permalink
Merge pull request #54 from finestructure/develop
Browse files Browse the repository at this point in the history
release-0.4.0
  • Loading branch information
finestructure authored Apr 9, 2019
2 parents a524ae5 + 9cbae97 commit 4a5aaf6
Show file tree
Hide file tree
Showing 31 changed files with 384 additions and 196 deletions.
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

0 comments on commit 4a5aaf6

Please sign in to comment.