add openhack files

This commit is contained in:
Ryan Peters
2022-11-03 16:41:13 -04:00
commit b2c9f7e29f
920 changed files with 118861 additions and 0 deletions

View File

@ -0,0 +1 @@
node_modules

View File

@ -0,0 +1,2 @@
coverage
templates

View File

@ -0,0 +1,25 @@
{
"rules": {
"indent": [
2,
4
],
"quotes": [
2,
"single"
],
"linebreak-style": [
2,
"unix"
],
"semi": [
2,
"always"
]
},
"env": {
"es6": true,
"node": true
},
"extends": "eslint:recommended"
}

5
apis/userprofile/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.xml
coverage
.nyc_output
reports
reports-tmp

View File

@ -0,0 +1,51 @@
# Automatically ignored per:
# https://www.npmjs.org/doc/developers.html#Keeping-files-out-of-your-package
#
# .*.swp
# ._*
# .DS_Store
# .git
# .hg
# .lock-wscript
# .svn
# .wafpickle-*
# CVS
# npm-debug.log
# node_modules
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
*.orig
work
build
test
pids
logs
results
coverage
lib-cov
html-report
xunit.xml
.project
.idea
.settings
.iml
*.sublime-workspace
*.sublime-project
ehthumbs.db
Icon?
Thumbs.db
.AppleDouble
.LSOverride
.Spotlight-V100
.Trashes
test/temp

View File

@ -0,0 +1,19 @@
FROM node:12-alpine
COPY . /app
WORKDIR /app
EXPOSE 8080
# docker build argument
# This can be specified during the docker build step by adding " --build-arg build_version=<value>"
# App version can be accessed via the uri path /api/version/user
# https://vsupalov.com/docker-build-pass-environment-variables/
ARG build_version="userprofile default"
ENV APP_VERSION=$build_version
RUN npm install
CMD npm start

View File

@ -0,0 +1,35 @@
# Overview
This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub.
This api uses node 12.x and express as the server and c
## Install modules
To install modules, run:
```shell
npm install
```
## Running the server
To run the server, run:
```shell
npm start
```
### To view the Swagger UI interface
```shell
open http://localhost:8080/api/docs/user
```
### To execute the unit tests
```shell
npm run test
```
There will be a junit formatted report file called userprofile-report.xml under the current userprofile directory `/reports` subfolder.

View File

@ -0,0 +1,7 @@
#!/bin/bash
# install dependencies
npm install
# run tests
npm run test

View File

@ -0,0 +1,15 @@
const sqlConfig = {
userName: process.env.SQL_USER || '',
password: process.env.SQL_PASSWORD || '',
server: process.env.SQL_SERVER || '', // You can use 'localhost\\instance' to connect to named instance
options: {
encrypt: true, // Use this if you're on Windows Azure
database: process.env.SQL_DBNAME || 'mydrivingdb',
MultipleActiveResultSets: false,
TrustServerCertificate: false,
rowCollectionOnDone: true
// Persist Security Info=False;Connection Timeout=30
}
};
exports = module.exports = sqlConfig;

View File

@ -0,0 +1,326 @@
{
"swagger": "2.0",
"info": {
"description": "API for the user profile in the My Driving example app. https://github.com/Azure-Samples/openhack-devops",
"version": "0.1.0",
"title": "My Driving User Profile API"
},
"basePath": "/api",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/healthcheck/user": {
"x-swagger-router-controller": "healthcheck",
"get": {
"description": "Returns healthcheck for systems looking to ensure API is up and operational",
"responses": {
"200": {
"description": "Service is healthy",
"schema": {
"$ref": "#/definitions/Healthcheck"
}
},
"default": {
"description": "An error occurred",
"schema": {
"$ref": "#/definitions/DefaultResponse"
}
}
},
"tags": [ "User Profile" ]
}
},
"/version/user": {
"x-swagger-router-controller": "version",
"get": {
"description": "Returns APP_VERSION environment variable to ensure API is running with a specific version",
"responses": {
"200": {
"description": "Build Version",
"schema": {
"$ref": "#/definitions/Version"
}
},
"default": {
"description": "An error occurred",
"schema": {
"$ref": "#/definitions/DefaultErrorResponse"
}
}
}
}
},
"/user": {
"get": {
"description": "List all user profiles",
"operationId": "getAllUsers",
"parameters": [],
"responses": {
"200": {
"description": "List of all users",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Profile"
}
}
},
"default": {
"description": "An error occurred",
"schema": {
"$ref": "#/definitions/DefaultResponse"
}
}
},
"x-swagger-router-controller": "user",
"tags": [ "User Profile" ]
}
},
"/user/{userID}": {
"parameters": [
{
"name": "userID",
"in": "path",
"description": "User's unique ID",
"type": "string",
"required": true
}
],
"get": {
"description": "Get a User Profile by ID",
"operationId": "userGET",
"responses": {
"200": {
"description": "List of profiles",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Profile"
}
}
},
"default": {
"description": "An error occurred",
"schema": {
"$ref": "#/definitions/DefaultResponse"
}
}
},
"x-swagger-router-controller": "user",
"tags": [ "User Profile" ]
},
"post": {
"description": "Declares and creates a new profile",
"operationId": "userPOST",
"parameters": [
{
"in": "body",
"name": "_profile",
"description": "Details of the profile",
"required": true,
"schema": {
"$ref": "#/definitions/Profile"
}
}
],
"responses": {
"201": {
"description": "Creation successful",
"schema": {
"$ref": "#/definitions/Profile"
},
"headers": {
"location": {
"type": "string"
}
}
},
"default": {
"description": "An error occurred",
"schema": {
"$ref": "#/definitions/DefaultResponse"
}
}
},
"x-swagger-router-controller": "user",
"tags": [ "User Profile" ]
},
"patch": {
"description": "Update User",
"operationId": "updateUser",
"responses": {
"200": {
"description": "User Updated",
"schema": {
"$ref": "#/definitions/Profile"
}
},
"404": {
"description": "User profile not found"
},
"default": {
"description": "Unknown Error",
"schema": {
"$ref": "#/definitions/DefaultResponse"
}
}
},
"tags": [ "User Profile" ]
},
"delete": {
"description": "Delete User By ID",
"operationId": "userDELETE",
"responses": {
"204": {
"description": "User Deleted"
},
"404": {
"description": "User not found"
},
"default": {
"description": "Unknown Error",
"schema": {
"$ref": "#/definitions/DefaultResponse"
}
}
},
"tags": [ "User Profile" ]
}
}
},
"definitions": {
"Healthcheck": {
"type": "object",
"properties": {
"message": {
"type": "string",
"description": ""
},
"status": {
"type": "string",
"description": ""
}
}
},
"Version": {
"type": "string"
},
"Profile": {
"type": "object",
"properties": {
"Id": {
"type": "string",
"description": "User's unique identity"
},
"FirstName": {
"type": "string",
"minLength": 0,
"maxLength": 50,
"pattern": "^[A-Za-z \u0000-][a-zA-Z \u0000-]*$"
},
"LastName": {
"type": "string",
"minLength": 0,
"maxLength": 80,
"pattern": "^[A-Za-z \u0000-][a-zA-Z \u0000-]*$"
},
"UserId": {
"type": "string",
"description": "User's identity"
},
"ProfilePictureUri": {
"type": "string",
"format": "binary",
"description": "User's Profile picture"
},
"Rating": {
"type": "integer",
"description": "User's rating"
},
"Ranking": {
"type": "integer",
"description": "User's ranking"
},
"TotalDistance": {
"type": "number",
"format": "float",
"description": "User's total distance traveled"
},
"TotalTrips": {
"type": "integer",
"format": "long",
"description": "User's total number of trips"
},
"TotalTime": {
"type": "integer",
"format": "long",
"description": "User's total driving time"
},
"HardStops": {
"type": "integer",
"format": "long",
"description": "User's total number of hard stops"
},
"HardAccelerations": {
"type": "integer",
"format": "long",
"description": "User's total number of hard accelerations"
},
"FuelConsumption": {
"type": "number",
"format": "float",
"description": "User's amount of fuel consumed"
},
"MaxSpeed": {
"type": "number",
"format": "float",
"description": "User's maximum speed"
},
"CreatedAt": {
"type": "string",
"format": "date"
},
"UpdatedAt": {
"type": "string",
"format": "date"
},
"Deleted": {
"type": "boolean",
"description": "Whether the user has been deleted or not."
}
}
},
"DefaultErrorResponse": {
"type": "object",
"properties": {
"status": {
"description": "Error code (if available)",
"type": "integer",
"format": "int32"
},
"message": {
"description": "Error Message",
"type": "string"
}
}
},
"DefaultResponse": {
"type": "object",
"properties": {
"status": {
"description": "Error code (if available)",
"type": "integer",
"format": "int32"
},
"message": {
"description": "Error Message",
"type": "string"
}
}
}
}
}

View File

@ -0,0 +1,35 @@
'use strict';
var Mockgen = require('../mockgen.js');
/**
* Operations on /healthcheck/user
*/
module.exports = {
/**
* summary:
* description: Returns healthcheck for systems looking to ensure API is up and operational
* parameters:
* produces:
* responses: 200, default
* operationId:
*/
get: {
200: function (req, res, callback) {
res.json({
message: 'Userprofile Service Healthcheck',
status: 'healthy'
});
callback;
},
default: function (req, res, callback) {
/**
* Using mock data generator module.
* Replace this by actual data for the api.
*/
Mockgen().responses({
path: '/healthcheck/user',
operation: 'get',
response: 'default'
}, callback);
}
}
};

View File

@ -0,0 +1,13 @@
'use strict';
var Swagmock = require('swagmock');
var Path = require('path');
var apiPath = Path.resolve(__dirname, '../config/swagger.json');
var mockgen;
module.exports = function () {
/**
* Cached mock generator
*/
mockgen = mockgen || Swagmock(apiPath);
return mockgen;
};

View File

@ -0,0 +1,66 @@
exports.INSERT_USER_PROFILE =
`INSERT INTO userprofiles \
(\
Id,\
FirstName,\
LastName,\
UserId,\
ProfilePictureUri,\
Rating,\
Ranking,\
TotalDistance,\
TotalTrips,\
TotalTime,\
HardStops,\
HardAccelerations,\
FuelConsumption,\
MaxSpeed,\
CreatedAt,\
UpdatedAt,\
Deleted\
) \
SELECT \
Id,\
FirstName,\
LastName,\
UserId,\
ProfilePictureUri,\
Rating,\
Ranking,\
TotalDistance,\
TotalTrips,\
TotalTime,\
HardStops,\
HardAccelerations,\
FuelConsumption,\
MaxSpeed,\
GETDATE(),\
GETDATE(),\
Deleted \
FROM OPENJSON(@UserProfileJson) \
WITH (
Id nvarchar(128),\
FirstName nvarchar(max),\
LastName nvarchar(max),\
UserId nvarchar(max),\
ProfilePictureUri nvarchar(max),\
Rating int,\
Ranking int,\
TotalDistance float(53),\
TotalTrips bigint,\
TotalTime bigint,\
HardStops bigint,\
HardAccelerations bigint,\
FuelConsumption float(53),\
MaxSpeed float(53),\
Deleted bit\
) AS JSON`;
exports.SELECT_USER_PROFILE_BY_ID=
'select * from userprofiles where id = @user_profile_id FOR JSON PATH';
exports.SELECT_USER_PROFILES=
'select * FROM userprofiles FOR JSON PATH';
exports.DELETE_USER_PROFILE=
'UPDATE userprofiles SET Deleted = 1 WHERE id = @user_profile_id';

View File

@ -0,0 +1,33 @@
'use strict';
var Mockgen = require('./mockgen.js');
var queries = require('./queries');
/**
* Operations on /user
*/
module.exports = {
/**
* summary:
* description: List all user profiles
* parameters:
* produces:
* responses: 200, default
* operationId: getAllUsers
*/
get: {
200: function (req, res, callback) {
req.sql(queries.SELECT_USER_PROFILES)
.into(res);
callback;
},
default: function (req, res, callback) {
Mockgen().responses({
path: '/user',
operation: 'get',
response: 'default'
}, callback);
}
}
};

View File

@ -0,0 +1,149 @@
'use strict';
var Mockgen = require('../mockgen.js');
var TYPES = require('tedious').TYPES;
var queries = require('../queries');
/**
* Operations on /user/{userID}
*/
module.exports = {
/**
* summary:
* description: Get a User Profile by ID
* parameters:
* produces:
* responses: 200, default
* operationId: userGET
*/
get: {
200: function (req, res, callback) {
req.sql(queries.SELECT_USER_PROFILE_BY_ID)
.param('user_profile_id', req.params.userID, TYPES.NVarChar)
.into(res, '{}');
callback;
},
default: function (req, res, callback) {
/**
* Using mock data generator module.
* Replace this by factual data for the api.
*/
Mockgen().responses({
path: '/user/{userID}',
operation: 'get',
response: 'default'
}, callback);
}
},
/**
* summary:
* description: Declares and creates a new profile
* parameters: _profile
* produces:
* responses: 201, default
* operationId: userPOST
*/
post: {
201: function (req, res, callback) {
req.sql(queries.INSERT_USER_PROFILE)
.param('UserProfileJson', req.body, TYPES.NVarChar)
.exec(res);
callback;
},
default: function (req, res, callback) {
/**
* Using mock data generator module.
* Replace this by actual data for the api.
*/
Mockgen().responses({
path: '/user/{userID}',
operation: 'post',
response: 'default'
}, callback);
}
},
/**
* summary:
* description: Update User
* parameters:
* produces:
* responses: 200, 404, default
* operationId: updateUser
*/
patch: {
200: function (req, res, callback) {
req.sql('EXEC UpdateProductFromJson @id, @json')
.param('json', req.body, TYPES.NVarChar)
.param('id', req.params.id, TYPES.Int)
.exec(res);
callback;
},
404: function (req, res, callback) {
/**
* Using mock data generator module.
* Replace this by actual data for the api.
*/
Mockgen().responses({
path: '/user/{userID}',
operation: 'patch',
response: '404'
}, callback);
},
default: function (req, res, callback) {
/**
* Using mock data generator module.
* Replace this by actual data for the api.
*/
Mockgen().responses({
path: '/user/{userID}',
operation: 'patch',
response: 'default'
}, callback);
}
},
/**
* summary:
* description: Delete User By ID
* parameters:
* produces:
* responses: 204, 404, default
* operationId: userDELETE
*/
delete: {
204: function (req, res, callback) {
var tempmessage = '';
var resmessage = tempmessage.concat('User profile ',req.params.userID,' deleted');
req.sql(queries.DELETE_USER_PROFILE)
.param('user_profile_id', req.params.userID, TYPES.NVarChar)
.into(res, resmessage);
callback;
},
404: function (req, res, callback) {
/**
* Using mock data generator module.
* Replace this by actual data for the api.
*/
Mockgen().responses({
path: '/user/{userID}',
operation: 'delete',
response: '404'
}, callback);
},
default: function (req, res, callback) {
/**
* Using mock data generator module.
* Replace this by actual data for the api.
*/
Mockgen().responses({
path: '/user/{userID}',
operation: 'delete',
response: 'default'
}, callback);
}
}
};

View File

@ -0,0 +1,29 @@
'use strict';
var dataProvider = require('../../data/healthcheck/user.js');
/**
* Operations on /healthcheck/user
*/
module.exports = {
/**
* summary:
* description: Returns healthcheck for systems looking to ensure API is up and operational
* parameters:
* produces:
* responses: 200, default
*/
get: function (req, res, next) {
/**
* Get the data for response 200
* For response `default` status 200 is used.
*/
var status = 200;
var provider = dataProvider['get']['200'];
provider(req, res, function (err, data) {
if (err) {
next(err);
return;
}
res.status(status).send(data && data.responses);
});
}
};

View File

@ -0,0 +1,29 @@
'use strict';
var dataProvider = require('../data/user.js');
/**
* Operations on /user
*/
module.exports = {
/**
* summary:
* description: List all user profiles
* parameters:
* produces:
* responses: 200, default
*/
get: function getAllUsers(req, res, next) {
/**
* Get the data for response 200
* For response `default` status 200 is used.
*/
var status = 200;
var provider = dataProvider['get']['200'];
provider(req, res, function (err, data) {
if (err) {
next(err);
return;
}
res.status(status).send(data && data.responses);
});
}
};

View File

@ -0,0 +1,95 @@
'use strict';
var dataProvider = require('../../data/user/{userID}.js');
/**
* Operations on /user/{userID}
*/
module.exports = {
/**
* summary:
* description: Get a User Profile by ID
* parameters:
* produces:
* responses: 200, default
*/
get: function userGET(req, res, next) {
/**
* Get the data for response 200
* For response `default` status 200 is used.
*/
var status = 200;
var provider = dataProvider['get']['200'];
provider(req, res, function (err, data) {
if (err) {
next(err);
return;
}
res.status(status).send(data && data.responses);
});
},
/**
* summary:
* description: Declares and creates a new profile
* parameters: _profile
* produces:
* responses: 201, default
*/
post: function userPOST(req, res, next) {
/**
* Get the data for response 201
* For response `default` status 200 is used.
*/
var status = 201;
var provider = dataProvider['post']['201'];
provider(req, res, function (err, data) {
if (err) {
next(err);
return;
}
res.status(status).send(data && data.responses);
});
},
/**
* summary:
* description: Update User
* parameters:
* produces:
* responses: 200, 404, default
*/
patch: function updateUser(req, res, next) {
/**
* Get the data for response 200
* For response `default` status 200 is used.
*/
var status = 200;
var provider = dataProvider['patch']['200'];
provider(req, res, function (err, data) {
if (err) {
next(err);
return;
}
res.status(status).send(data && data.responses);
});
},
/**
* summary:
* description: Delete User By ID
* parameters:
* produces:
* responses: 204, 404, default
*/
delete: function userDELETE(req, res, next) {
/**
* Get the data for response 204
* For response `default` status 200 is used.
*/
var status = 204;
var provider = dataProvider['delete']['204'];
provider(req, res, function (err, data) {
if (err) {
next(err);
return;
}
res.status(status).send(data && data.responses);
});
}
};

View File

@ -0,0 +1,20 @@
'use strict';
/**
* Operations on /version/user
*/
module.exports = {
/**
* summary:
* description: Returns healthcheck for systems looking to ensure API is up and operational
* parameters:
* produces:
* responses: 200, default
*/
get: function (req, res, next) {
let status = 200;
let version = process.env.APP_VERSION;
res.set('Content-Type', 'text/plain');
res.status(status).send(version);
}
};

3752
apis/userprofile/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,60 @@
{
"name": "mydriving-user-api",
"description": "This is the User API for the MyDriving service",
"version": "1.0.0",
"repository": {
"type": "git",
"url": "git://github.com/Azure-Samples/openhack-devops-team.git"
},
"bugs": "http://github.com/Azure-Samples/openhack-devops-team/issues",
"dependencies": {
"body-parser": "^1.18.3",
"dotenv": "^8.2.0",
"express": "^4.16.3",
"express4-tedious": "^0.3.0",
"morgan": "^1.9.0",
"swagger-ui-express": "^3.0.10",
"swaggerize-express": "^4.0.5",
"swagmock": "1.0.0",
"tedious": "^2.6.4",
"trim": "^1.0.1"
},
"devDependencies": {
"eslint": "6.8.0",
"is-my-json-valid": "2.20.0",
"js-yaml": "3.13.1",
"nyc": "15.0.1",
"supertest": "4.0.2",
"swagger-parser": "9.0.1",
"tap-junit": "^5.0.1",
"tape": "5.0.0"
},
"nyc": {
"check-coverage": true,
"per-file": false,
"lines": 25,
"statements": 8,
"functions": 9,
"branches": 1,
"reporter": [
"cobertura",
"html"
],
"require": [],
"cache": true,
"all": true,
"temp-directory": "./reports-tmp",
"report-dir": "./reports"
},
"scripts": {
"test": "tape 'tests/**/*.js' | tap-junit --output reports --name userprofile-report",
"test-noreport": "tape 'tests/**/*.js'",
"cover": "nyc tape -- 'tests/**/*.js' --cov",
"lint": "eslint .",
"regenerate": "yo swaggerize:test --framework express --apiPath './config/swagger.json'"
},
"generator-swaggerize": {
"version": "4.1.0"
},
"main": "./server"
}

View File

@ -0,0 +1,46 @@
'use strict';
require('dotenv').config()
var Http = require('http');
var Express = require('express');
var BodyParser = require('body-parser');
var Swaggerize = require('swaggerize-express');
var Path = require('path');
var tediousExpress = require('express4-tedious');
var sqlConfig = require('./config/sqlConfig');
var morgan = require('morgan');
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./config/swagger.json');
var App = Express();
var Server = Http.createServer(App);
var logger = morgan(':remote-addr [:date[web]] :method :url HTTP/:http-version :status :res[content-length] :referrer :user-agent :response-time ms');
App.use(logger);
App.use(function (req, res, next) {
req.sql = tediousExpress(sqlConfig);
next();
});
App.use(BodyParser.json());
App.use(BodyParser.urlencoded({
extended: true
}));
App.use(Swaggerize({
api: Path.resolve('./config/swagger.json'),
handlers: Path.resolve('./handlers')
}));
App.use('/api/docs/user', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
Server.listen(8080, function () {
App.swagger.api.host = this.address().address + ':' + this.address().port;
/* eslint-disable no-console */
console.log('App running on %s:%d', this.address().address, this.address().port);
/* eslint-disable no-console */
});

View File

@ -0,0 +1,227 @@
---
swagger: "2.0"
info:
description: "API for the user profile in the My Driving example app. https://github.com/Azure-Samples/openhack-devops-team"
version: "0.1.0"
title: "My Driving User Profile API"
basePath: "/api"
schemes:
- "http"
consumes:
- "application/json"
produces:
- "application/json"
paths:
/healthcheck/user:
x-swagger-router-controller: healthcheck
get:
description: "Returns healthcheck for systems looking to ensure API is up and operational"
responses:
200:
description: "Service is healthy"
schema:
$ref: "#/definitions/Healthcheck"
default:
description: "An error occurred"
schema:
$ref: "#/definitions/error_response_default"
/version/user:
x-swagger-router-controller: version
get:
description: "Returns APP_VERSION environment variable to ensure API is running with a specific versionl"
responses:
200:
description: "BuildVersion"
schema:
$ref: "#/definitions/Version"
default:
description: "An error occurred"
schema:
$ref: "#/definitions/error_response_default"
/user:
get:
description: "List all user profiles"
operationId: "getAllUsers"
parameters: []
responses:
200:
description: "List of all users"
schema:
type: "array"
items:
$ref: "#/definitions/Profile"
default:
description: "An error occurred"
schema:
$ref: "#/definitions/inline_response_default"
x-swagger-router-controller: "user"
/user/{userID}:
parameters:
-
name: "userID"
in: "path"
description: "User's unique ID"
type: "string"
required: true
get:
description: "Get a User Profile by ID"
operationId: "userGET"
responses:
200:
description: "List of profiles"
schema:
type: "array"
items:
$ref: "#/definitions/Profile"
default:
description: "An error occurred"
schema:
$ref: "#/definitions/inline_response_default"
x-swagger-router-controller: "user"
post:
description: "Declares and creates a new profile"
operationId: "userPOST"
parameters:
- in: "body"
name: "_profile"
description: "Details of the profile"
required: true
schema:
$ref: "#/definitions/Profile"
responses:
201:
description: "Creation successful"
schema:
$ref: "#/definitions/Profile"
headers:
location:
type: "string"
default:
description: "An error occurred"
schema:
$ref: "#/definitions/inline_response_default"
x-swagger-router-controller: "user"
patch:
description: "Update User"
operationId: "updateUser"
responses:
200:
description: "User Updated"
schema:
$ref: "#/definitions/Profile"
404:
description: "User profile not found"
default:
description: "Unknown Error"
schema:
$ref: "#/definitions/error_response_default"
delete:
description: "Delete User By ID"
operationId: "userDELETE"
responses:
204:
description: "User Deleted"
404:
description: "User not found"
default:
description: "Unknown Error"
schema:
$ref: "#/definitions/error_response_default"
definitions:
Healthcheck:
type: "object"
properties:
message:
type: "string"
description: ""
status:
type: "string"
description: ""
Version:
type: "string"
Profile:
type: "object"
properties:
Id:
type: "string"
description: "User's unique identity"
FirstName:
type: "string"
minLength: 0
maxLength: 50
pattern: "^[A-Za-z \0-\x7f][a-zA-Z \0-\x7f]*$"
LastName:
type: "string"
minLength: 0
maxLength: 80
pattern: "^[A-Za-z \0-\x7f][a-zA-Z \0-\x7f]*$"
UserId:
type: "string"
description: "User's identity"
ProfilePictureUri:
type: "string"
format: "binary"
description: "User's Profile picture"
Rating:
type: "integer"
description: "User's rating"
Ranking:
type: "integer"
description: "User's ranking"
TotalDistance:
type: "number"
format: "float"
description: "User's total distance traveled"
TotalTrips:
type: "integer"
format: "long"
description: "User's total number of trips"
TotalTime:
type: "integer"
format: "long"
description: "User's total driving time"
HardStops:
type: "integer"
format: "long"
description: "User's total number of hard stops"
HardAccelerations:
type: "integer"
format: "long"
description: "User's total number of hard accelerations"
FuelConsumption:
type: "number"
format: "float"
description: "User's amount of fuel consumed"
MaxSpeed:
type: "number"
format: "float"
description: "User's maximum speed"
CreatedAt:
type: "string"
format: "date"
UpdatedAt:
type: "string"
format: "date"
Deleted:
type: "boolean"
description: "Whether the user has been deleted or not."
error_response_default:
type: "object"
properties:
status:
description: "Error code (if available)"
type: "integer"
format: "int32"
message:
description: "Error Message"
type: "string"
inline_response_default:
required:
- "message"
- "status"
properties:
status:
type: "integer"
format: "int32"
message:
type: "string"

View File

@ -0,0 +1,78 @@
'use strict';
var Test = require('tape');
var Express = require('express');
var BodyParser = require('body-parser');
var Swaggerize = require('swaggerize-express');
var Path = require('path');
var Request = require('supertest');
var Mockgen = require('../../data/mockgen.js');
var Parser = require('swagger-parser');
/**
* Test for /healthcheck/user
*/
Test('/healthcheck/user', function (t) {
var apiPath = Path.resolve(__dirname, '../../config/swagger.json');
var App = Express();
App.use(BodyParser.json());
App.use(BodyParser.urlencoded({
extended: true
}));
App.use(Swaggerize({
api: apiPath,
handlers: Path.resolve(__dirname, '../../handlers')
}));
Parser.validate(apiPath, function (err, api) {
t.error(err, 'No parse error');
t.ok(api, 'Valid swagger api');
/**
* summary:
* description: Returns healthcheck for systems looking to ensure API is up and operational
* parameters:
* produces:
* responses: 200, default
*/
t.test('test get operation', function (t) {
Mockgen().requests({
path: '/healthcheck/user',
operation: 'get'
}, function (err, mock) {
var request;
t.error(err);
t.ok(mock);
t.ok(mock.request);
//Get the resolved path from mock request
//Mock request Path templates({}) are resolved using path parameters
request = Request(App)
.get('/api' + mock.request.path);
if (mock.request.body) {
//Send the request body
request = request.send(mock.request.body);
} else if (mock.request.formData){
//Send the request form data
request = request.send(mock.request.formData);
//Set the Content-Type as application/x-www-form-urlencoded
request = request.set('Content-Type', 'application/x-www-form-urlencoded');
}
// If headers are present, set the headers.
if (mock.request.headers && mock.request.headers.length > 0) {
Object.keys(mock.request.headers).forEach(function (headerName) {
request = request.set(headerName, mock.request.headers[headerName]);
});
}
request.end(function (err, res) {
t.error(err, 'No error');
t.ok(res.statusCode === 200, 'Ok response status');
var Validator = require('is-my-json-valid');
var validate = Validator(api.paths['/healthcheck/user']['get']['responses']['200']['schema']);
var response = res.body;
if (Object.keys(response).length <= 0) {
response = res.text;
}
t.ok(validate(response), 'Valid response');
t.error(validate.errors, 'No validation errors');
t.end();
});
});
});
});
});

View File

@ -0,0 +1,78 @@
'use strict';
var Test = require('tape');
var Express = require('express');
var BodyParser = require('body-parser');
var Swaggerize = require('swaggerize-express');
var Path = require('path');
var Request = require('supertest');
var Mockgen = require('../data/mockgen.js');
var Parser = require('swagger-parser');
/**
* Test for /user
*/
Test('/user', function (t) {
var apiPath = Path.resolve(__dirname, '../config/swagger.json');
var App = Express();
App.use(BodyParser.json());
App.use(BodyParser.urlencoded({
extended: true
}));
App.use(Swaggerize({
api: apiPath,
handlers: Path.resolve(__dirname, '../handlers')
}));
Parser.validate(apiPath, function (err, api) {
t.error(err, 'No parse error');
t.ok(api, 'Valid swagger api');
/**
* summary:
* description: List all user profiles
* parameters:
* produces:
* responses: 200, default
*/
t.test('test getAllUsers get operation', function (t) {
Mockgen().requests({
path: '/user',
operation: 'get'
}, function (err, mock) {
var request;
t.error(err);
t.ok(mock);
t.ok(mock.request);
//Get the resolved path from mock request
//Mock request Path templates({}) are resolved using path parameters
request = Request(App)
.get('/api' + mock.request.path);
if (mock.request.body) {
//Send the request body
request = request.send(mock.request.body);
} else if (mock.request.formData){
//Send the request form data
request = request.send(mock.request.formData);
//Set the Content-Type as application/x-www-form-urlencoded
request = request.set('Content-Type', 'application/x-www-form-urlencoded');
}
// If headers are present, set the headers.
if (mock.request.headers && mock.request.headers.length > 0) {
Object.keys(mock.request.headers).forEach(function (headerName) {
request = request.set(headerName, mock.request.headers[headerName]);
});
}
request.end(function (err, res) {
t.error(err, 'No error');
t.ok(res.statusCode === 200, 'Ok response status');
var Validator = require('is-my-json-valid');
var validate = Validator(api.paths['/user']['get']['responses']['200']['schema']);
var response = res.body;
if (Object.keys(response).length <= 0) {
response = res.text;
}
t.ok(validate(response), 'Valid response');
t.error(validate.errors, 'No validation errors');
t.end();
});
});
});
});
});

View File

@ -0,0 +1,217 @@
'use strict';
var Test = require('tape');
var Express = require('express');
var BodyParser = require('body-parser');
var Swaggerize = require('swaggerize-express');
var Path = require('path');
var Request = require('supertest');
var Mockgen = require('../../data/mockgen.js');
var Parser = require('swagger-parser');
/**
* Test for /user/{userID}
*/
Test('/user/{userID}', function (t) {
var apiPath = Path.resolve(__dirname, '../../config/swagger.json');
var App = Express();
App.use(BodyParser.json());
App.use(BodyParser.urlencoded({
extended: true
}));
App.use(Swaggerize({
api: apiPath,
handlers: Path.resolve(__dirname, '../../handlers')
}));
Parser.validate(apiPath, function (err, api) {
t.error(err, 'No parse error');
t.ok(api, 'Valid swagger api');
/**
* summary:
* description: Get a User Profile by ID
* parameters:
* produces:
* responses: 200, default
*/
t.test('test userGET get operation', function (t) {
Mockgen().requests({
path: '/user/{userID}',
operation: 'get'
}, function (err, mock) {
var request;
t.error(err);
t.ok(mock);
t.ok(mock.request);
//Get the resolved path from mock request
//Mock request Path templates({}) are resolved using path parameters
request = Request(App)
.get('/api' + mock.request.path);
if (mock.request.body) {
//Send the request body
request = request.send(mock.request.body);
} else if (mock.request.formData){
//Send the request form data
request = request.send(mock.request.formData);
//Set the Content-Type as application/x-www-form-urlencoded
request = request.set('Content-Type', 'application/x-www-form-urlencoded');
}
// If headers are present, set the headers.
if (mock.request.headers && mock.request.headers.length > 0) {
Object.keys(mock.request.headers).forEach(function (headerName) {
request = request.set(headerName, mock.request.headers[headerName]);
});
}
request.end(function (err, res) {
t.error(err, 'No error');
t.ok(res.statusCode === 200, 'Ok response status');
var Validator = require('is-my-json-valid');
var validate = Validator(api.paths['/user/{userID}']['get']['responses']['200']['schema']);
var response = res.body;
if (Object.keys(response).length <= 0) {
response = res.text;
}
t.ok(validate(response), 'Valid response');
t.error(validate.errors, 'No validation errors');
t.end();
});
});
});/**
* summary:
* description: Declares and creates a new profile
* parameters: _profile
* produces:
* responses: 201, default
*/
t.test('test userPOST post operation', function (t) {
Mockgen().requests({
path: '/user/{userID}',
operation: 'post'
}, function (err, mock) {
var request;
t.error(err);
t.ok(mock);
t.ok(mock.request);
//Get the resolved path from mock request
//Mock request Path templates({}) are resolved using path parameters
request = Request(App)
.post('/api' + mock.request.path);
if (mock.request.body) {
//Send the request body
request = request.send(mock.request.body);
} else if (mock.request.formData){
//Send the request form data
request = request.send(mock.request.formData);
//Set the Content-Type as application/x-www-form-urlencoded
request = request.set('Content-Type', 'application/x-www-form-urlencoded');
}
// If headers are present, set the headers.
if (mock.request.headers && mock.request.headers.length > 0) {
Object.keys(mock.request.headers).forEach(function (headerName) {
request = request.set(headerName, mock.request.headers[headerName]);
});
}
request.end(function (err, res) {
t.error(err, 'No error');
t.ok(res.statusCode === 201, 'Ok response status');
var Validator = require('is-my-json-valid');
var validate = Validator(api.paths['/user/{userID}']['post']['responses']['201']['schema']);
var response = res.body;
if (Object.keys(response).length <= 0) {
response = res.text;
}
t.ok(validate(response), 'Valid response');
t.error(validate.errors, 'No validation errors');
t.end();
});
});
});/**
* summary:
* description: Update User
* parameters:
* produces:
* responses: 200, 404, default
*/
t.test('test updateUser patch operation', function (t) {
Mockgen().requests({
path: '/user/{userID}',
operation: 'patch'
}, function (err, mock) {
var request;
t.error(err);
t.ok(mock);
t.ok(mock.request);
//Get the resolved path from mock request
//Mock request Path templates({}) are resolved using path parameters
request = Request(App)
.patch('/api' + mock.request.path);
if (mock.request.body) {
//Send the request body
request = request.send(mock.request.body);
} else if (mock.request.formData){
//Send the request form data
request = request.send(mock.request.formData);
//Set the Content-Type as application/x-www-form-urlencoded
request = request.set('Content-Type', 'application/x-www-form-urlencoded');
}
// If headers are present, set the headers.
if (mock.request.headers && mock.request.headers.length > 0) {
Object.keys(mock.request.headers).forEach(function (headerName) {
request = request.set(headerName, mock.request.headers[headerName]);
});
}
request.end(function (err, res) {
t.error(err, 'No error');
t.ok(res.statusCode === 200, 'Ok response status');
var Validator = require('is-my-json-valid');
var validate = Validator(api.paths['/user/{userID}']['patch']['responses']['200']['schema']);
var response = res.body;
if (Object.keys(response).length <= 0) {
response = res.text;
}
t.ok(validate(response), 'Valid response');
t.error(validate.errors, 'No validation errors');
t.end();
});
});
});/**
* summary:
* description: Delete User By ID
* parameters:
* produces:
* responses: 204, 404, default
*/
t.test('test userDELETE delete operation', function (t) {
Mockgen().requests({
path: '/user/{userID}',
operation: 'delete'
}, function (err, mock) {
var request;
t.error(err);
t.ok(mock);
t.ok(mock.request);
//Get the resolved path from mock request
//Mock request Path templates({}) are resolved using path parameters
request = Request(App)
.delete('/api' + mock.request.path);
if (mock.request.body) {
//Send the request body
request = request.send(mock.request.body);
} else if (mock.request.formData){
//Send the request form data
request = request.send(mock.request.formData);
//Set the Content-Type as application/x-www-form-urlencoded
request = request.set('Content-Type', 'application/x-www-form-urlencoded');
}
// If headers are present, set the headers.
if (mock.request.headers && mock.request.headers.length > 0) {
Object.keys(mock.request.headers).forEach(function (headerName) {
request = request.set(headerName, mock.request.headers[headerName]);
});
}
request.end(function (err, res) {
t.error(err, 'No error');
t.ok(res.statusCode === 204, 'Ok response status');
t.end();
});
});
});
});
});