Skip to content

Commit

Permalink
Add inital tests (#1)
Browse files Browse the repository at this point in the history
* Add tck tests for "Format" and "File Structure" spec sections

* Add more tck tests

AsyncAPI Object
AsyncAPI Version String
Contact Object
Identifier
Info Object
License Object
Servers Object

* Add more tck tests

Server Object
Server Variable Object
Channels Object

* Add more tck tests

Channel Item Object
Operation Object
Operation Trait Object

* Add more tck tests

Channel Bindings Object
Message Bindings Object
Operation Bindings Object
Parameter Object
Parameters Object
Server Bindings Object

* Add more tck tests

Message Object

* Add more tck tests. Extend existing ones.

External Documentation Object
Message Trait Object
Tag Object

* Add Components Object tests. Rename few tests.

* Add Reference Object tck tests

* Add tck tests for Schema Object

* Add more tck tests

Correlation ID Object
Security Requirement Object
Security Scheme Object
Specification Extensions

* Add tests for fields types

* Finish adding tests for fields types

* Implement manifest gen. Generate manifest

* Port initial version of tck runner

* Use .yml extension for reffered files

* Fix tck file issue

* Add/fix js runners code

* Add development note

* Add gen-manifest note to contrib

* Add more tests to address initial notes

* Add gh actions workflow to publish to gh-pages

* Rework GH Actions workflow to use SSH

* Address initial PR review notes

* Reduce some tests size

* Delete invalid test

#1 (comment)

Co-authored-by: Artem Kostiuk <[email protected]>
  • Loading branch information
jstoiko and postatum authored Mar 19, 2020
1 parent db9e506 commit fb062a4
Show file tree
Hide file tree
Showing 410 changed files with 10,889 additions and 1 deletion.
28 changes: 28 additions & 0 deletions .github/workflows/publish-gh-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Publish Github Pages

on:
push:
branches:
- add_tck_tests

jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Build tck runner reports
run: make
working-directory: ./runner
- name: Create .nojekyll file
run: touch runner/reports/html/.nojekyll
- name: Install SSH Client
uses: webfactory/[email protected]
with:
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
- name: Deploy to Github Pages
uses: JamesIves/github-pages-deploy-action@releases/v3
with:
SSH: true
BRANCH: gh-pages # The branch the action should deploy to.
FOLDER: runner/reports/html/ # The folder the action should deploy.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
18 changes: 18 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Contributing

Each test case should contain the following files:
* A valid `*valid*.yaml` file showcasing valid use of the feature under test
* An invalid `*invalid*.yaml` files showcasing invalid use of the feature under test

Please place new tests in one of `tests/asyncapi-2.0` sub-folders. Name of the target folder should correspond to the name of the feature your tests test. E.g. if your new `.yaml` tests `Info Object`, place it in `tests/asyncapi-2.0/Info Object`.

Non-AsyncAPI files (libraries, extensions, etc.) must have a `.yml` extension instead of `.yaml`.

After adding/moving/deleting tck files, manifest has to be regenerated with:
```sh
npm run gen-manifest
```

## Running tests

We've created a separate project called [tck runner](./runner) to run all the tests contained in the AsyncAPI TCK. By following the instructions on that directory, you should be able to test any new test case that you may want to contribute against the different projects that this runner covers.
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,18 @@
# tck
# AsyncAPI tck

AsyncAPI's Test Compatibility Kit (AsyncAPI TCK) provides a way for any AsyncAPI processor to test its compliance with the AsyncAPI 2.0 Spec. AsyncAPI TCK contains a set of AsyncAPI documents meant to be used to test correct and incorrect usage of each AsyncAPI feature.

## Naming convention

- `*valid*.yaml`: valid AsyncAPI file expected to be successfully processed
- `*invalid*.yaml`: invalid AsyncAPI file with syntax/semantic/spec error(s), expected to be unsuccessfully processed (error or exit code returned)

Note that this repository contains a [manifest file](./manifest.json) that lists all tests in the order their respective tested features appear in the AsyncAPI 2.0 Specification.

Names of folders' tests reside in correspond to AsyncAPI 2.0 Specification sections names.

Non-AsyncAPI files (libraries, extensions, etc.) must have a `.yml` extension instead of `.yaml`.

## Contributing

We welcome contributions! If you have a new test case in mind, feel free to submit a pull request. More info on how to do that [here](./CONTRIBUTING.md).
155 changes: 155 additions & 0 deletions genmanifest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
const path = require('path')
const fs = require('fs')
const walk = require('walk')

// Features listed in order they appear in the spec spec.
const FEATURES_PRIORITY = [
'Format',
'File Structure',
'AsyncAPI Object',
'AsyncAPI Version String',
'Identifier',
'Info Object',
'Contact Object',
'License Object',
'Servers Object',
'Server Object',
'Server Variable Object',
'Channels Object',
'Channel Item Object',
'Operation Object',
'Operation Trait Object',
'Message Object',
'Message Trait Object',
'Tags Object',
'Tag Object',
'External Documentation Object',
'Components Object',
'Reference Object',
'Schema Object',
'Security Scheme Object',
'Security Requirement Object',
'Parameters Object',
'Parameter Object',
'Server Bindings Object',
'Channel Bindings Object',
'Operation Bindings Object',
'Message Bindings Object',
'Correlation ID Object',
'Specification Extensions'
]

const EXT = '.yaml'

function main () {
const projRoot = path.resolve(__dirname)
const inputRoot = getInputDirPath()
let filesPaths = listFiles(inputRoot)
filesPaths = sortFilesPaths(inputRoot, filesPaths)
filesPaths = makePathsRelative(projRoot, filesPaths)
generateManifest(projRoot, filesPaths)
}

// Gets absolute path of input folder
function getInputDirPath () {
let dirPath = process.argv[2]

if (!fs.existsSync(dirPath)) {
console.error(`'${dirPath}' not found`)
return
}

dirPath = path.resolve(dirPath)
if (!fs.lstatSync(dirPath).isDirectory()) {
console.error(`'${dirPath}' is not a directory`)
return
}
return dirPath
}

// Lists files with a particular extension under directory path
function listFiles (dirPath) {
let files = []
const options = {
listeners: {
file: (root, fileStats, next) => {
if (fileStats.name.indexOf(EXT) >= 0) {
files.push(path.join(root, fileStats.name))
}
next()
}
}
}
walk.walkSync(dirPath, options)
return files
}

// Sorts string filesPaths according to features definition order in a spec
function sortFilesPaths (filesRoot, filesPaths) {
const pathObjs = extendWithPriority(
filesRoot, filesPaths, FEATURES_PRIORITY.slice())
const sortedPathObjs = pathObjs.sort((obj1, obj2) => {
return obj1.priority - obj2.priority
})
return sortedPathObjs.map((obj) => {
return obj.path
})
}

// Makes fiels paths relative to a directory
function makePathsRelative (dirPath, filesPaths) {
return filesPaths.map((pth) => {
return path.relative(dirPath, pth)
})
}

// Turns plain file paths into objects of type {priority: INT, path: STRING}
// E.g.:
// > let featuresPriority = ['methodresponses', 'overlays']
// > extendWithPriority('/foo/bar', '/foo/bar/Overlays/some/file.ext')
// > {priority: 2, path: '/foo/bar/Overlays/some/file.ext'}
// > extendWithPriority('/foo/bar', '/foo/bar/qweqwe/some/file.ext')
// > {priority: 3, path: '/foo/bar/qweqwe/some/file.ext'}
//
// Override this to change logic of picking priority.
function extendWithPriority (filesRoot, filesPaths, featuresPriority) {
featuresPriority = featuresPriority.map(x => x.toLowerCase())
return filesPaths.map((pth) => {
const piece = getFirstPathPiece(filesRoot, pth).toLowerCase()
let priority = featuresPriority.findIndex(el => el === piece)

// Feature name not found. Adding it to the list allows sorting not
// found features.
if (priority === -1) {
featuresPriority.push(piece)
priority = featuresPriority.length - 1
}
priority += 1 // Make 1-based
return {path: pth, priority: priority}
})
}

// Gets relative folder 'root' name of files file path.
// E.g.:
// > const filesRoot = '/foo/bar'
// > const fielPath = '/foo/bar/MethodResponses/some/file.ext'
// > getFirstPathPiece(filesRoot, fielPath)
// > 'methodresponses'
function getFirstPathPiece (filesRoot, fielPath) {
const relPath = path.relative(filesRoot, fielPath)
return relPath.split(path.sep)[0].toLowerCase()
}

// Generates and writes manifest file
function generateManifest (dirPath, filesPaths) {
const data = {
description: 'Files listed in order corresponding AsyncAPI ' +
'feature appears in AsyncAPI 2.0 Specification',
filePaths: filesPaths
}
const manifestPath = path.join(dirPath, 'manifest.json')
console.log(`Writing manifest file to ${manifestPath}`)
fs.writeFileSync(manifestPath, JSON.stringify(data, null, 4))
}

main()
Loading

0 comments on commit fb062a4

Please sign in to comment.