You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@openwhisk.apache.org by GitBox <gi...@apache.org> on 2018/08/03 13:07:43 UTC

[GitHub] markusthoemmes closed pull request #3878: Validate the Controller Swagger spec matches the impl

markusthoemmes closed pull request #3878: Validate the Controller Swagger spec matches the impl
URL: https://github.com/apache/incubator-openwhisk/pull/3878
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/core/controller/src/main/resources/apiv1swagger.json b/core/controller/src/main/resources/apiv1swagger.json
index 80eefbbfd1..989c5fa843 100644
--- a/core/controller/src/main/resources/apiv1swagger.json
+++ b/core/controller/src/main/resources/apiv1swagger.json
@@ -9,6 +9,16 @@
         "application/json"
     ],
     "basePath": "/api/v1",
+    "securityDefinitions": {
+        "basicAuth": {
+            "type": "basic"
+        }
+    },
+    "security": [
+        {
+            "basicAuth": []
+        }
+    ],
     "tags": [
         {
             "name": "Actions"
@@ -100,7 +110,7 @@
                         "schema": {
                             "type": "array",
                             "items": {
-                                "$ref": "#/definitions/EntityBrief"
+                                "$ref": "#/definitions/Action"
                             }
                         }
                     },
@@ -114,6 +124,22 @@
             }
         },
         "/namespaces/{namespace}/actions/{actionName}": {
+            "parameters": [
+                {
+                    "name": "namespace",
+                    "in": "path",
+                    "description": "The entity namespace",
+                    "required": true,
+                    "type": "string"
+                },
+                {
+                    "name": "actionName",
+                    "in": "path",
+                    "description": "Name of action to fetch",
+                    "required": true,
+                    "type": "string"
+                }
+            ],
             "get": {
                 "tags": [
                     "Actions"
@@ -122,20 +148,6 @@
                 "description": "Get action information.",
                 "operationId": "getActionByName",
                 "parameters": [
-                    {
-                        "name": "namespace",
-                        "in": "path",
-                        "description": "The entity namespace",
-                        "required": true,
-                        "type": "string"
-                    },
-                    {
-                        "name": "actionName",
-                        "in": "path",
-                        "description": "Name of action to fetch",
-                        "required": true,
-                        "type": "string"
-                    },
                     {
                         "name": "code",
                         "in": "query",
@@ -157,6 +169,9 @@
                     "401": {
                         "$ref": "#/responses/UnauthorizedRequest"
                     },
+                    "403": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
                     "404": {
                         "$ref": "#/responses/ItemNotFound"
                     },
@@ -173,20 +188,6 @@
                 "summary": "Create or update an action",
                 "operationId": "updateAction",
                 "parameters": [
-                    {
-                        "name": "namespace",
-                        "in": "path",
-                        "description": "The entity namespace",
-                        "required": true,
-                        "type": "string"
-                    },
-                    {
-                        "name": "actionName",
-                        "in": "path",
-                        "description": "Name of action",
-                        "required": true,
-                        "type": "string"
-                    },
                     {
                         "name": "overwrite",
                         "in": "query",
@@ -216,7 +217,10 @@
                 ],
                 "responses": {
                     "200": {
-                        "$ref": "#/responses/UpdatedItem"
+                        "description": "Updated Action",
+                        "schema": {
+                            "$ref": "#/definitions/Action"
+                        }
                     },
                     "400": {
                         "$ref": "#/responses/BadRequest"
@@ -224,6 +228,9 @@
                     "401": {
                         "$ref": "#/responses/UnauthorizedRequest"
                     },
+                    "403": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
                     "409": {
                         "$ref": "#/responses/Conflict"
                     },
@@ -242,29 +249,167 @@
                 "description": "Delete an action",
                 "summary": "Delete an action",
                 "operationId": "deleteAction",
+                "responses": {
+                    "200": {
+                        "$ref": "#/responses/DeletedItem"
+                    },
+                    "400": {
+                        "$ref": "#/responses/BadRequest"
+                    },
+                    "401": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
+                    "403": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
+                    "404": {
+                        "$ref": "#/responses/ItemNotFound"
+                    },
+                    "409": {
+                        "$ref": "#/responses/Conflict"
+                    },
+                    "500": {
+                        "$ref": "#/responses/ServerError"
+                    }
+                }
+            },
+            "post": {
+                "tags": [
+                    "Actions"
+                ],
+                "description": "Invoke an action",
+                "summary": "Invoke an action",
+                "operationId": "invokeAction",
                 "parameters": [
                     {
-                        "name": "namespace",
-                        "in": "path",
-                        "description": "The entity namespace",
-                        "required": true,
-                        "type": "string"
+                        "name": "blocking",
+                        "in": "query",
+                        "description": "Blocking or non-blocking invocation. Default is non-blocking.",
+                        "required": false,
+                        "type": "string",
+                        "enum": [
+                            "true",
+                            "false"
+                        ]
                     },
                     {
-                        "name": "actionName",
-                        "in": "path",
-                        "description": "Name of action",
-                        "required": true,
-                        "type": "string"
+                        "name": "result",
+                        "in": "query",
+                        "description": "Return only the result of a blocking activation. Default is false.",
+                        "required": false,
+                        "type": "string",
+                        "enum": [
+                            "true",
+                            "false"
+                        ]
+                    },
+                    {
+                        "name": "timeout",
+                        "in": "query",
+                        "description": "Wait no more than specified duration in milliseconds for a blocking response. Default value and max allowed timeout are 60000.",
+                        "required": false,
+                        "type": "integer"
+                    },
+                    {
+                        "name": "payload",
+                        "in": "body",
+                        "description": "The parameters for the action being invoked",
+                        "required": false,
+                        "schema": {
+                            "type": "object"
+                        }
                     }
                 ],
+                "consumes": [
+                    "application/json"
+                ],
                 "responses": {
                     "200": {
-                        "$ref": "#/responses/DeletedItem"
+                        "description": "Successful activation"
+                    },
+                    "202": {
+                        "$ref": "#/responses/AcceptedActivation"
+                    },
+                    "401": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
+                    "403": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
+                    "404": {
+                        "$ref": "#/responses/ItemNotFound"
+                    },
+                    "408": {
+                        "$ref": "#/responses/Timeout"
+                    },
+                    "429": {
+                        "$ref": "#/responses/TooManyRequsts"
+                    },
+                    "500": {
+                        "$ref": "#/responses/ServerError"
+                    },
+                    "502": {
+                        "description": "Activation produced an application error"
+                    }
+                }
+            }
+        },
+        "/namespaces/{namespace}/actions/{packageName}/{actionName}": {
+            "parameters": [
+                {
+                    "name": "namespace",
+                    "in": "path",
+                    "description": "The entity namespace",
+                    "required": true,
+                    "type": "string"
+                },
+                {
+                    "name": "packageName",
+                    "in": "path",
+                    "description": "Name of package that contains action",
+                    "required": true,
+                    "type": "string"
+                },
+                {
+                    "name": "actionName",
+                    "in": "path",
+                    "description": "Name of action to fetch",
+                    "required": true,
+                    "type": "string"
+                }
+            ],
+            "get": {
+                "tags": [
+                    "Actions"
+                ],
+                "summary": "Get action information",
+                "description": "Get action information.",
+                "operationId": "getActionInPackageByName",
+                "parameters": [
+                    {
+                        "name": "code",
+                        "in": "query",
+                        "description": "Include action code in the result",
+                        "required": false,
+                        "type": "boolean"
+                    }
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Returned action",
+                        "schema": {
+                            "$ref": "#/definitions/Action"
+                        }
                     },
                     "401": {
                         "$ref": "#/responses/UnauthorizedRequest"
                     },
+                    "403": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
                     "404": {
                         "$ref": "#/responses/ItemNotFound"
                     },
@@ -273,28 +418,107 @@
                     }
                 }
             },
-            "post": {
+            "put": {
                 "tags": [
                     "Actions"
                 ],
-                "description": "Invoke an action",
-                "summary": "Invoke an action",
-                "operationId": "invokeAction",
+                "description": "Create or update an action",
+                "summary": "Create or update an action",
+                "operationId": "updateActionInPackage",
                 "parameters": [
                     {
-                        "name": "namespace",
-                        "in": "path",
-                        "description": "The entity namespace",
-                        "required": true,
-                        "type": "string"
+                        "name": "overwrite",
+                        "in": "query",
+                        "description": "Overwrite item if it exists. Default is false.",
+                        "required": false,
+                        "type": "string",
+                        "enum": [
+                            "true",
+                            "false"
+                        ]
                     },
                     {
-                        "name": "actionName",
-                        "in": "path",
-                        "description": "Name of action",
+                        "name": "action",
+                        "in": "body",
+                        "description": "The action being updated",
                         "required": true,
-                        "type": "string"
+                        "schema": {
+                            "$ref": "#/definitions/ActionPut"
+                        }
+                    }
+                ],
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Updated Action",
+                        "schema": {
+                            "$ref": "#/definitions/Action"
+                        }
+                    },
+                    "400": {
+                        "$ref": "#/responses/BadRequest"
+                    },
+                    "401": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
+                    "403": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
+                    "409": {
+                        "$ref": "#/responses/Conflict"
+                    },
+                    "413": {
+                        "$ref": "#/responses/RequestEntityTooLarge"
                     },
+                    "500": {
+                        "$ref": "#/responses/ServerError"
+                    }
+                }
+            },
+            "delete": {
+                "tags": [
+                    "Actions"
+                ],
+                "description": "Delete an action",
+                "summary": "Delete an action",
+                "operationId": "deleteActionInPackage",
+                "responses": {
+                    "200": {
+                        "$ref": "#/responses/DeletedItem"
+                    },
+                    "400": {
+                        "$ref": "#/responses/BadRequest"
+                    },
+                    "401": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
+                    "403": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
+                    "404": {
+                        "$ref": "#/responses/ItemNotFound"
+                    },
+                    "409": {
+                        "$ref": "#/responses/Conflict"
+                    },
+                    "500": {
+                        "$ref": "#/responses/ServerError"
+                    }
+                }
+            },
+            "post": {
+                "tags": [
+                    "Actions"
+                ],
+                "description": "Invoke an action",
+                "summary": "Invoke an action",
+                "operationId": "invokeActionInPackage",
+                "parameters": [
                     {
                         "name": "blocking",
                         "in": "query",
@@ -328,39 +552,125 @@
                         "name": "payload",
                         "in": "body",
                         "description": "The parameters for the action being invoked",
-                        "required": true,
+                        "required": false,
+                        "schema": {
+                            "type": "object"
+                        }
+                    }
+                ],
+                "consumes": [
+                    "application/json"
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful activation"
+                    },
+                    "202": {
+                        "$ref": "#/responses/AcceptedActivation"
+                    },
+                    "401": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
+                    "403": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
+                    "404": {
+                        "$ref": "#/responses/ItemNotFound"
+                    },
+                    "408": {
+                        "$ref": "#/responses/Timeout"
+                    },
+                    "429": {
+                        "$ref": "#/responses/TooManyRequsts"
+                    },
+                    "500": {
+                        "$ref": "#/responses/ServerError"
+                    },
+                    "502": {
+                        "description": "Activation produced an application error"
+                    }
+                }
+            }
+        },
+        "/web/{namespace}/{packageName}/{actionName}.{extension}": {
+            "parameters": [
+                {
+                    "name": "namespace",
+                    "type": "string",
+                    "in": "path",
+                    "required": true
+                },
+                {
+                    "name": "packageName",
+                    "type": "string",
+                    "in": "path",
+                    "required": true
+                },
+                {
+                    "name": "actionName",
+                    "type": "string",
+                    "in": "path",
+                    "required": true
+                },
+                {
+                    "name": "extension",
+                    "type": "string",
+                    "in": "path",
+                    "required": true
+                }
+            ],
+            "get": {
+                "tags": [
+                    "Actions"
+                ],
+                "responses": {
+                    "default": {
+                        "description": "any response",
+                        "schema": {}
+                    }
+                }
+            },
+            "put": {
+                "tags": [
+                    "Actions"
+                ],
+                "responses": {
+                    "default": {
+                        "description": "any response",
+                        "schema": {}
+                    }
+                }
+            },
+            "delete": {
+                "tags": [
+                    "Actions"
+                ],
+                "responses": {
+                    "default": {
+                        "description": "any response",
+                        "schema": {}
+                    }
+                }
+            },
+            "post": {
+                "tags": [
+                    "Actions"
+                ],
+                "parameters": [
+                    {
+                        "name": "payload",
+                        "in": "body",
+                        "description": "The parameters for the action being invoked",
+                        "required": false,
                         "schema": {
-                            "$ref": "#/definitions/KeyValue"
+                            "type": "object"
                         }
                     }
                 ],
                 "responses": {
-                    "200": {
-                        "description": "Successful activation",
-                        "schema": {
-                            "$ref": "#/definitions/Activation"
-                        }
-                    },
-                    "202": {
-                        "$ref": "#/responses/AcceptedActivation"
-                    },
-                    "401": {
-                        "$ref": "#/responses/UnauthorizedRequest"
-                    },
-                    "404": {
-                        "$ref": "#/responses/ItemNotFound"
-                    },
-                    "408": {
-                        "$ref": "#/responses/Timeout"
-                    },
-                    "500": {
-                        "$ref": "#/responses/ServerError"
-                    },
-                    "502": {
-                        "description": "Activation produced an application error",
-                        "schema": {
-                            "$ref": "#/definitions/Activation"
-                        }
+                    "default": {
+                        "description": "any response",
+                        "schema": {}
                     }
                 }
             }
@@ -405,7 +715,7 @@
                         "schema": {
                             "type": "array",
                             "items": {
-                                "$ref": "#/definitions/EntityBrief"
+                                "$ref": "#/definitions/Rule"
                             }
                         }
                     },
@@ -514,7 +824,10 @@
                 ],
                 "responses": {
                     "200": {
-                        "$ref": "#/responses/UpdatedItem"
+                        "description": "Updated rule",
+                        "schema": {
+                            "$ref": "#/definitions/Rule"
+                        }
                     },
                     "400": {
                         "$ref": "#/responses/BadRequest"
@@ -522,6 +835,9 @@
                     "401": {
                         "$ref": "#/responses/UnauthorizedRequest"
                     },
+                    "404": {
+                        "$ref": "#/responses/ItemNotFound"
+                    },
                     "409": {
                         "$ref": "#/responses/Conflict"
                     },
@@ -594,23 +910,34 @@
                         "type": "string"
                     },
                     {
-                        "name": "state",
-                        "in": "query",
-                        "type": "string",
-                        "description": "Set state to enable or disable",
+                        "name": "status",
+                        "in": "body",
+                        "description": "Set status to active or inactive",
                         "required": true,
-                        "enum": [
-                            "disabled",
-                            "enabled"
-                        ]
+                        "schema": {
+                            "type": "object",
+                            "required": [
+                                "status"
+                            ],
+                            "properties": {
+                                "status": {
+                                    "type": "string",
+                                    "enum": [
+                                        "inactive",
+                                        "active"
+                                    ]
+                                }
+                            }
+                        }
                     }
                 ],
                 "produces": [
-                    "application/json"
+                    "application/json",
+                    "text/plain"
                 ],
                 "responses": {
                     "200": {
-                        "$ref": "#/responses/UpdatedItem"
+                        "$ref": "#/responses/AcceptedRuleStateChange"
                     },
                     "202": {
                         "$ref": "#/responses/AcceptedRuleStateChange"
@@ -621,6 +948,9 @@
                     "401": {
                         "$ref": "#/responses/UnauthorizedRequest"
                     },
+                    "404": {
+                        "$ref": "#/responses/ItemNotFound"
+                    },
                     "500": {
                         "$ref": "#/responses/ServerError"
                     }
@@ -667,7 +997,7 @@
                         "schema": {
                             "type": "array",
                             "items": {
-                                "$ref": "#/definitions/EntityBrief"
+                                "$ref": "#/definitions/Trigger"
                             }
                         }
                     },
@@ -776,7 +1106,10 @@
                 ],
                 "responses": {
                     "200": {
-                        "$ref": "#/responses/UpdatedItem"
+                        "description": "Updated trigger",
+                        "schema": {
+                            "$ref": "#/definitions/Trigger"
+                        }
                     },
                     "400": {
                         "$ref": "#/responses/BadRequest"
@@ -859,9 +1192,9 @@
                         "name": "payload",
                         "in": "body",
                         "description": "The trigger payload",
-                        "required": true,
+                        "required": false,
                         "schema": {
-                            "$ref": "#/definitions/KeyValue"
+                            "type": "object"
                         }
                     }
                 ],
@@ -869,7 +1202,7 @@
                     "202": {
                         "description": "Activation id",
                         "schema": {
-                            "$ref": "#/definitions/ItemId"
+                            "$ref": "#/definitions/ActivationId"
                         }
                     },
                     "204": {
@@ -884,6 +1217,9 @@
                     "408": {
                         "$ref": "#/responses/Timeout"
                     },
+                    "429": {
+                        "$ref": "#/responses/TooManyRequests"
+                    },
                     "500": {
                         "$ref": "#/responses/ServerError"
                     }
@@ -897,7 +1233,7 @@
                 ],
                 "description": "Get all packages",
                 "summary": "Get all packages",
-                "operationId": "getAlPackages",
+                "operationId": "getAllPackages",
                 "parameters": [
                     {
                         "name": "namespace",
@@ -937,7 +1273,7 @@
                         "schema": {
                             "type": "array",
                             "items": {
-                                "$ref": "#/definitions/EntityBrief"
+                                "$ref": "#/definitions/Package"
                             }
                         }
                     },
@@ -990,6 +1326,9 @@
                     "404": {
                         "$ref": "#/responses/ItemNotFound"
                     },
+                    "409": {
+                        "$ref": "#/responses/Conflict"
+                    },
                     "500": {
                         "$ref": "#/responses/ServerError"
                     }
@@ -1046,7 +1385,10 @@
                 ],
                 "responses": {
                     "200": {
-                        "$ref": "#/responses/UpdatedItem"
+                        "description": "Updated Package",
+                        "schema": {
+                            "$ref": "#/definitions/Package"
+                        }
                     },
                     "400": {
                         "$ref": "#/responses/BadRequest"
@@ -1054,6 +1396,9 @@
                     "401": {
                         "$ref": "#/responses/UnauthorizedRequest"
                     },
+                    "403": {
+                        "$ref": "#/responses/UnauthorizedRequest"
+                    },
                     "409": {
                         "$ref": "#/responses/Conflict"
                     },
@@ -1098,6 +1443,9 @@
                     "404": {
                         "$ref": "#/responses/ItemNotFound"
                     },
+                    "409": {
+                        "$ref": "#/responses/Conflict"
+                    },
                     "500": {
                         "$ref": "#/responses/ServerError"
                     }
@@ -1324,10 +1672,6 @@
     },
     "definitions": {
         "KeyValue": {
-            "required": [
-                "key",
-                "value"
-            ],
             "properties": {
                 "key": {
                     "type": "string"
@@ -1347,6 +1691,20 @@
                 }
             }
         },
+        "PathName": {
+            "required": [
+                "path",
+                "name"
+            ],
+            "properties": {
+                "path": {
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                }
+            }
+        },
         "ErrorMessage": {
             "required": [
                 "error"
@@ -1354,6 +1712,9 @@
             "properties": {
                 "error": {
                     "type": "string"
+                },
+                "code": {
+                    "type": "string"
                 }
             }
         },
@@ -1363,12 +1724,20 @@
                 "timeout": {
                     "type": "integer",
                     "format": "int32",
-                    "default": 30000
+                    "description": "timeout in milliseconds",
+                    "default": 60000
                 },
                 "memory": {
                     "type": "integer",
                     "format": "int32",
+                    "description": "memory in megabytes",
                     "default": 256
+                },
+                "logs": {
+                    "type": "integer",
+                    "format": "int32",
+                    "description": "log size in megabytes",
+                    "default": 10
                 }
             }
         },
@@ -1408,7 +1777,6 @@
                 "version",
                 "publish",
                 "exec",
-                "parameters",
                 "limits"
             ],
             "properties": {
@@ -1450,12 +1818,26 @@
                 },
                 "limits": {
                     "$ref": "#/definitions/ActionLimits"
+                },
+                "updated": {
+                    "type": "integer",
+                    "description": "Time when the action was updated"
                 }
             }
         },
         "ActionPut": {
-            "description": "A restricted Action view that elides properties that are auto-assigned or derived from the URI (i.e., the namespace and name).",
+            "description": "A restricted Action view used when updating an Action",
             "properties": {
+                "namespace": {
+                    "type": "string",
+                    "description": "Namespace of the item",
+                    "minLength": 1
+                },
+                "name": {
+                    "type": "string",
+                    "description": "Name of the item",
+                    "minLength": 1
+                },
                 "version": {
                     "type": "string",
                     "description": "Semantic version of the item",
@@ -1488,22 +1870,23 @@
             }
         },
         "ActionExec": {
-            "required": [
-                "kind"
-            ],
             "properties": {
                 "kind": {
                     "type": "string",
                     "enum": [
                         "blackbox",
                         "java",
+                        "java:default",
                         "nodejs:6",
                         "nodejs:8",
+                        "nodejs:default",
                         "php:7.1",
                         "php:7.2",
                         "python:2",
                         "python:3",
+                        "python:default",
                         "ruby:2.5",
+                        "sequence",
                         "swift:3.1.1",
                         "swift:4.1"
                     ],
@@ -1517,9 +1900,24 @@
                     "type": "string",
                     "description": "container image name when kind is 'blackbox'"
                 },
+                "main": {
+                    "type": "string",
+                    "description": "main entrypoint of the action code"
+                },
                 "init": {
                     "type": "string",
                     "description": "optional zipfile reference when code kind is 'nodejs'"
+                },
+                "binary": {
+                    "type": "boolean",
+                    "description": "Whether the action has a binary attachment or not"
+                },
+                "components": {
+                    "type": "array",
+                    "description": "For sequence actions, the individual action components",
+                    "items": {
+                        "type": "string"
+                    }
                 }
             },
             "description": "definition of the action, such as javascript code or the name of a container"
@@ -1541,7 +1939,6 @@
                 "name",
                 "version",
                 "publish",
-                "status",
                 "trigger",
                 "action"
             ],
@@ -1565,6 +1962,13 @@
                     "type": "boolean",
                     "description": "Whether to publish the item or not"
                 },
+                "annotations": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/KeyValue"
+                    },
+                    "description": "annotations on the item"
+                },
                 "status": {
                     "type": "string",
                     "description": "Status of a rule",
@@ -1576,20 +1980,21 @@
                     ]
                 },
                 "trigger": {
-                    "type": "string",
-                    "description": "Name of the trigger",
-                    "minLength": 1
+                    "$ref": "#/definitions/PathName"
                 },
                 "action": {
-                    "type": "string",
-                    "description": "Name of the action",
-                    "minLength": 1
+                    "$ref": "#/definitions/PathName"
                 }
             }
         },
         "RulePut": {
-            "description": "A restricted Rule view that elides properties that are auto-assigned or derived from the URI (i.e., the namespace and name).",
+            "description": "A restricted Rule view used when updating a Rule",
             "properties": {
+                "name": {
+                    "type": "string",
+                    "description": "Name of the item",
+                    "minLength": 1
+                },
                 "version": {
                     "type": "string",
                     "description": "Semantic version of the item",
@@ -1599,6 +2004,22 @@
                     "type": "boolean",
                     "description": "Whether to publish the item or not"
                 },
+                "annotations": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/KeyValue"
+                    },
+                    "description": "annotations on the item"
+                },
+                "status": {
+                    "type": "string",
+                    "description": "Status of a rule",
+                    "enum": [
+                        "active",
+                        "inactive",
+                        ""
+                    ]
+                },
                 "trigger": {
                     "type": "string",
                     "description": "Name of the trigger",
@@ -1616,9 +2037,7 @@
                 "namespace",
                 "name",
                 "version",
-                "publish",
-                "parameters",
-                "limits"
+                "publish"
             ],
             "properties": {
                 "namespace": {
@@ -1660,12 +2079,26 @@
                 "rules": {
                     "type": "object",
                     "description": "rules associated with the trigger"
+                },
+                "updated": {
+                    "type": "integer",
+                    "description": "Time when the trigger was updated"
                 }
             }
         },
         "TriggerPut": {
-            "description": "A restricted Trigger view that elides properties that are auto-assigned or derived from the URI (i.e., the namespace and name).",
+            "description": "A restricted Trigger view used when updating the Trigger",
             "properties": {
+                "namespace": {
+                    "type": "string",
+                    "description": "Namespace of the item",
+                    "minLength": 1
+                },
+                "name": {
+                    "type": "string",
+                    "description": "Name of the item",
+                    "minLength": 1
+                },
                 "version": {
                     "type": "string",
                     "description": "Semantic version of the item",
@@ -1714,8 +2147,7 @@
                 "namespace",
                 "name",
                 "version",
-                "publish",
-                "parameters"
+                "publish"
             ],
             "properties": {
                 "namespace": {
@@ -1753,12 +2185,40 @@
                 },
                 "binding": {
                     "$ref": "#/definitions/PackageBinding"
+                },
+                "actions": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/PackageAction"
+                    },
+                    "description": "Actions contained in this package"
+                },
+                "feeds": {
+                    "type": "array",
+                    "items": {
+                        "type": "object"
+                    },
+                    "description": "Feeds contained in this package"
+                },
+                "updated": {
+                    "type": "integer",
+                    "description": "Time when the package was updated"
                 }
             }
         },
         "PackagePut": {
-            "description": "A restricted Package view that elides properties that are auto-assigned or derived from the URI (i.e., the namespace and name).",
+            "description": "A restricted Package view used when updating a Package",
             "properties": {
+                "namespace": {
+                    "type": "string",
+                    "description": "Namespace of the item",
+                    "minLength": 1
+                },
+                "name": {
+                    "type": "string",
+                    "description": "Name of the item",
+                    "minLength": 1
+                },
                 "version": {
                     "type": "string",
                     "description": "Semantic version of the item",
@@ -1788,10 +2248,6 @@
             }
         },
         "PackageBinding": {
-            "required": [
-                "namespace",
-                "name"
-            ],
             "properties": {
                 "namespace": {
                     "type": "string",
@@ -1803,6 +2259,39 @@
                 }
             }
         },
+        "PackageAction": {
+            "description": "A restricted Action view used when listing actions in a package",
+            "required": [
+                "name",
+                "version"
+            ],
+            "properties": {
+                "name": {
+                    "type": "string",
+                    "description": "Name of the item",
+                    "minLength": 1
+                },
+                "version": {
+                    "type": "string",
+                    "description": "Semantic version of the item",
+                    "minLength": 1
+                },
+                "annotations": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/KeyValue"
+                    },
+                    "description": "annotations on the item"
+                },
+                "parameters": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/KeyValue"
+                    },
+                    "description": "parameter bindings included in the context passed to the action"
+                }
+            }
+        },
         "Activation": {
             "required": [
                 "namespace",
@@ -1812,8 +2301,7 @@
                 "subject",
                 "activationId",
                 "start",
-                "end",
-                "result",
+                "response",
                 "logs"
             ],
             "properties": {
@@ -1833,6 +2321,13 @@
                     "type": "boolean",
                     "description": "Whether to publish the item or not"
                 },
+                "annotations": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/KeyValue"
+                    },
+                    "description": "annotations on the item"
+                },
                 "subject": {
                     "type": "string",
                     "description": "The subject that activated the item"
@@ -1842,19 +2337,40 @@
                     "description": "Id of the activation"
                 },
                 "start": {
-                    "type": "string",
+                    "type": "integer",
                     "description": "Time when the activation began"
                 },
                 "end": {
-                    "type": "string",
+                    "type": "integer",
                     "description": "Time when the activation completed"
                 },
-                "result": {
+                "duration": {
+                    "type": "integer",
+                    "description": "How long the invocation took, in millisecnods"
+                },
+                "response": {
                     "$ref": "#/definitions/ActivationResult"
                 },
                 "logs": {
+                    "type": "array",
+                    "description": "Logs generated by the activation",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "cause": {
                     "type": "string",
-                    "description": "Logs generated by the activation"
+                    "description": "the activation id that caused this activation"
+                }
+            }
+        },
+        "ActivationId": {
+            "required": [
+                "activationId"
+            ],
+            "properties": {
+                "activationId": {
+                    "type": "string"
                 }
             }
         },
@@ -1864,7 +2380,7 @@
                     "type": "array",
                     "description": "Array of activation ids",
                     "items": {
-                        "type": "string"
+                        "$ref": "#/definitions/ActivationId"
                     }
                 }
             }
@@ -1901,8 +2417,11 @@
         "ActivationLogs": {
             "properties": {
                 "logs": {
-                    "type": "string",
-                    "description": "Interleaved standard output and error of an activation"
+                    "type": "array",
+                    "description": "Interleaved standard output and error of an activation",
+                    "items": {
+                        "type": "string"
+                    }
                 }
             }
         },
@@ -1920,8 +2439,12 @@
                     "type": "string",
                     "description": "Exit status of the activation"
                 },
-                "value": {
+                "result": {
                     "description": "The return value from the activation"
+                },
+                "success": {
+                    "type": "boolean",
+                    "description": "Whether the activation was successful or not"
                 }
             }
         },
@@ -2037,7 +2560,7 @@
         "AcceptedActivation": {
             "description": "Accepted activation request",
             "schema": {
-                "$ref": "#/definitions/ItemId"
+                "$ref": "#/definitions/ActivationId"
             }
         },
         "AcceptedRuleStateChange": {
@@ -2051,6 +2574,9 @@
         },
         "NoActiveRules": {
             "description": "Trigger has no active rules"
+        },
+        "TooManyRequests": {
+            "description": "Too many requests in a given time period"
         }
     }
 }
diff --git a/tests/build.gradle b/tests/build.gradle
index e82c59de99..51324fa928 100644
--- a/tests/build.gradle
+++ b/tests/build.gradle
@@ -18,6 +18,10 @@
 import org.scoverage.ScoverageReport
 import static groovy.json.JsonOutput.*
 
+plugins {
+    id 'org.hidetake.swagger.generator' version '2.12.0'
+}
+
 apply plugin: 'scala'
 apply plugin: 'eclipse'
 apply plugin: 'maven'
@@ -147,6 +151,7 @@ dependencies {
     compile "org.mockito:mockito-core:2.15.0"
     compile 'io.opentracing:opentracing-mock:0.31.0'
     compile "org.apache.curator:curator-test:${gradle.curator.version}"
+    compile 'com.atlassian.oai:swagger-request-validator-core:1.4.5'
 
     compile "com.amazonaws:aws-java-sdk-s3:1.11.295"
 
@@ -158,6 +163,8 @@ dependencies {
 
 
     scoverage gradle.scoverage.deps
+
+    swaggerCodegen 'io.swagger:swagger-codegen-cli:2.3.1'
 }
 
 tasks.withType(ScalaCompile) {
@@ -295,3 +302,20 @@ def getScoverageClasspath(Project project) {
 
     combinedClasspath + sourceSets.test.runtimeClasspath
 }
+
+swaggerSources {
+    java {
+        inputFile = file("$projectDir/../core/controller/src/main/resources/apiv1swagger.json")
+        code {
+            language = 'java'
+            configFile = file('src/test/resources/swagger-config.json')
+            dependsOn validation
+        }
+    }
+}
+
+task testSwaggerCodegen(type: GradleBuild) {
+    dependsOn swaggerSources.java.code
+    buildFile = "${buildDir}/swagger-code-java/build.gradle"
+    tasks = ['build']
+}
diff --git a/tests/src/test/resources/swagger-config.json b/tests/src/test/resources/swagger-config.json
new file mode 100644
index 0000000000..f8696d36bf
--- /dev/null
+++ b/tests/src/test/resources/swagger-config.json
@@ -0,0 +1,4 @@
+{
+    "library": "okhttp-gson",
+    "dateLibrary": "java8"
+}
diff --git a/tests/src/test/scala/common/rest/SwaggerValidator.scala b/tests/src/test/scala/common/rest/SwaggerValidator.scala
new file mode 100644
index 0000000000..b13c94e60c
--- /dev/null
+++ b/tests/src/test/scala/common/rest/SwaggerValidator.scala
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package common.rest
+
+import scala.collection.JavaConverters._
+
+import akka.http.scaladsl.model.HttpEntity
+import akka.http.scaladsl.model.HttpRequest
+import akka.http.scaladsl.model.HttpResponse
+import com.atlassian.oai.validator.SwaggerRequestResponseValidator
+import com.atlassian.oai.validator.model.SimpleRequest
+import com.atlassian.oai.validator.model.SimpleResponse
+import com.atlassian.oai.validator.report.ValidationReport
+import com.atlassian.oai.validator.whitelist.ValidationErrorsWhitelist
+import com.atlassian.oai.validator.whitelist.rule.WhitelistRules
+
+trait SwaggerValidator {
+  private val specWhitelist = ValidationErrorsWhitelist
+    .create()
+    .withRule(
+      "Ignore action and trigger payloads",
+      WhitelistRules.allOf(
+        WhitelistRules.messageContains("Object instance has properties which are not allowed by the schema"),
+        WhitelistRules.anyOf(
+          WhitelistRules.pathContains("/web/"),
+          WhitelistRules.pathContains("/actions/"),
+          WhitelistRules.pathContains("/triggers/")),
+        WhitelistRules.methodIs(io.swagger.models.HttpMethod.POST)))
+    .withRule(
+      "Ignore invalid action kinds",
+      WhitelistRules.allOf(
+        WhitelistRules.messageContains("kind"),
+        WhitelistRules.messageContains("Instance value"),
+        WhitelistRules.messageContains("not found"),
+        WhitelistRules.pathContains("/actions/"),
+        WhitelistRules.methodIs(io.swagger.models.HttpMethod.PUT)))
+    .withRule(
+      "Ignore tests that check for invalid DELETEs and PUTs on actions",
+      WhitelistRules.anyOf(
+        WhitelistRules.messageContains("DELETE operation not allowed on path '/api/v1/namespaces/_/actions/'"),
+        WhitelistRules.messageContains("PUT operation not allowed on path '/api/v1/namespaces/_/actions/'")))
+
+  private val specValidator = SwaggerRequestResponseValidator
+    .createFor("apiv1swagger.json")
+    .withWhitelist(specWhitelist)
+    .build()
+
+  /**
+   * Validate a HTTP request and response against the Swagger spec. Request
+   * and response bodies are passed separately so that this validation
+   * does not have to consume the body content directly from the request
+   * and response, which would prevent callers from later consuming it.
+   *
+   * @param request the HttpRequest
+   * @param response the HttpResponse
+   * @return The list of validation error messages, if any
+   */
+  def validateRequestAndResponse(request: HttpRequest, response: HttpResponse): Seq[String] = {
+    val specRequest = {
+      val builder = new SimpleRequest.Builder(request.method.value, request.uri.path.toString())
+      val body = strictEntityBodyAsString(request.entity)
+      val withBody =
+        if (body.isEmpty) builder
+        else
+          builder
+            .withBody(body)
+            .withHeader("content-type", request.entity.contentType.value)
+      val withHeaders = request.headers.foldLeft(builder)((b, header) => b.withHeader(header.name, header.value))
+      val andQuery =
+        request.uri.query().foldLeft(withHeaders) { case (b, (key, value)) => b.withQueryParam(key, value) }
+      andQuery.build()
+    }
+
+    val specResponse = {
+      val builder = SimpleResponse.Builder
+        .status(response.status.intValue())
+      val body = strictEntityBodyAsString(response.entity)
+      val withBody =
+        if (body.isEmpty) builder
+        else
+          builder
+            .withBody(body)
+            .withHeader("content-type", response.entity.contentType.value)
+      val withHeaders = response.headers.foldLeft(builder)((b, header) => b.withHeader(header.name, header.value))
+      withHeaders.build()
+    }
+
+    specValidator
+      .validate(specRequest, specResponse)
+      .getMessages
+      .asScala
+      .filter(m => m.getLevel == ValidationReport.Level.ERROR)
+      .map(_.toString)
+  }
+
+  def strictEntityBodyAsString(entity: HttpEntity): String = entity match {
+    case s: HttpEntity.Strict => s.data.utf8String
+    case _                    => ""
+  }
+}
diff --git a/tests/src/test/scala/common/rest/WskRestOperations.scala b/tests/src/test/scala/common/rest/WskRestOperations.scala
index eefa782d13..85742ccf3d 100644
--- a/tests/src/test/scala/common/rest/WskRestOperations.scala
+++ b/tests/src/test/scala/common/rest/WskRestOperations.scala
@@ -74,6 +74,7 @@ import java.nio.charset.StandardCharsets
 import java.security.KeyStore
 
 import akka.actor.ActorSystem
+import akka.util.ByteString
 import pureconfig.loadConfigOrThrow
 import whisk.common.Https.HttpsConfig
 
@@ -1132,10 +1133,11 @@ class RestGatewayOperations(implicit val actorSystem: ActorSystem) extends Gatew
   }
 }
 
-trait RunRestCmd extends Matchers with ScalaFutures {
+trait RunRestCmd extends Matchers with ScalaFutures with SwaggerValidator {
 
   val protocol = loadConfigOrThrow[String]("whisk.controller.protocol")
   val idleTimeout = 90 seconds
+  val toStrictTimeout = 5 seconds
   val queueSize = 10
   val maxOpenRequest = 1024
   val basePath = Path("/api/v1")
@@ -1187,8 +1189,17 @@ trait RunRestCmd extends Matchers with ScalaFutures {
       method,
       hostWithScheme.withPath(path).withQuery(Query(params)),
       List(Authorization(creds)),
-      entity = body.map(b => HttpEntity(ContentTypes.`application/json`, b)).getOrElse(HttpEntity.Empty))
-    Http().singleRequest(request, connectionContext).futureValue
+      entity =
+        body.map(b => HttpEntity.Strict(ContentTypes.`application/json`, ByteString(b))).getOrElse(HttpEntity.Empty))
+    val response = Http().singleRequest(request, connectionContext).flatMap { _.toStrict(toStrictTimeout) }.futureValue
+
+    val validationErrors = validateRequestAndResponse(request, response)
+    if (validationErrors.nonEmpty) {
+      fail(
+        s"HTTP request or response did not match the Swagger spec.\nRequest: $request\n" +
+          s"Response: $response\nValidation Error: $validationErrors")
+    }
+    response
   }
 
   private def getBasicHttpCredentials(wp: WskProps): BasicHttpCredentials = {
@@ -1280,7 +1291,7 @@ trait RunRestCmd extends Matchers with ScalaFutures {
   }
 
   def getRespData(resp: HttpResponse): String = {
-    val timeout = 5.seconds
+    val timeout = toStrictTimeout
     Try(resp.entity.toStrict(timeout).map { _.data }.map(_.utf8String).futureValue).getOrElse("")
   }
 
diff --git a/tools/travis/runTests.sh b/tools/travis/runTests.sh
index 9f53284bc7..5d5b6d7f35 100755
--- a/tools/travis/runTests.sh
+++ b/tools/travis/runTests.sh
@@ -26,7 +26,7 @@ ROOTDIR="$SCRIPTDIR/../.."
 
 cd $ROOTDIR
 cat whisk.properties
-TERM=dumb ./gradlew :tests:testCoverageLean :tests:reportCoverage
+TERM=dumb ./gradlew :tests:testCoverageLean :tests:reportCoverage :tests:testSwaggerCodegen
 
 bash <(curl -s https://codecov.io/bash)
 echo "Time taken for ${0##*/} is $SECONDS secs"


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services