Generate swagger files (#278)

* Generate swagger files

* Add basic Swagger definitions

* Add reposerver swagger file

* Consolidate swagger files

* Move swagger files to swagger-ui directory instead

* Put swagger files in swagger-ui

* Fix order of operations

* Move back to swagger directory

* Serve API server swagger files raw for now

* Serve reposerver swagger files from API server

* Move back to subdirectories, thanks @alexmt

* Fix comment on application Rollback

* Update two more comments

* Fix comment in session.proto

* Update generated code

* Update generated swagger docs

* Fix comment for delete actions in cluster and repository swagger

* Set expected collisions and invoke mixins

* Update generated code

* Create swagger mixins from codegen

* Move swagger.json location, thanks @jazminGonzalez-Rivero

* Add ref cleanup for swagger combined

* Make fewer temp files when generating swagger

* Delete intermediate swagger files

* Serve new file at /swagger.json

* Set up UI server

* Update package lock

* Commit generated swagger.json files

* Add install commands for swagger

* Use ReDoc server instead of Swagger UI server

* Update lockfile

* Make URL paths more consistent

* Update package lock

* Separate out handlers for Swagger UI, JSON

* Rm unnecessary CORS headers

...since we're serving from the app server

* Simplify serving

* Further simplify serving code

* Update package lock

* Factor out swagger serving into util

* Add test for Swagger server

* Use ServeSwaggerUI method to run tests

* Update package lock

* Don't generate swagger for reposerver

* Reset to master Gopkg.lock and server/server.go

* Merge in prev change to server/server.go

* Redo changes to Gopkg.lock

* Fix number of conflicts

* Update generated swagger.json for server

* Fix issue with project feature error
This commit is contained in:
Andrew Merenbach
2018-06-25 13:49:38 -07:00
committed by GitHub
parent 653f9d3913
commit ab00aef75e
16 changed files with 2595 additions and 23 deletions

View File

@@ -1,10 +1,14 @@
## Requirements
Make sure you have following tools installed [golang](https://golang.org/), [dep](https://github.com/golang/dep), [protobuf](https://developers.google.com/protocol-buffers/),
Make sure you have following tools installed [docker](https://docs.docker.com/install/#supported-platforms), [golang](https://golang.org/), [dep](https://github.com/golang/dep), [protobuf](https://developers.google.com/protocol-buffers/), [ksonnet](https://github.com/ksonnet/ksonnet#install), [go-swagger](https://github.com/go-swagger/go-swagger/blob/master/docs/install.md), and [jq](https://stedolan.github.io/jq/)
[kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/).
```
$ brew install go dep protobuf kubectl
$ brew tap go-swagger/go-swagger
$ brew install go dep protobuf kubectl ksonnet/tap/ks jq go-swagger
$ go get -u github.com/golang/protobuf/protoc-gen-go
$ go get -u github.com/go-swagger/go-swagger/cmd/swagger
$ go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
$ go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
```
Nice to have [gometalinter](https://github.com/alecthomas/gometalinter) and [goreman](https://github.com/mattn/goreman):
@@ -20,6 +24,11 @@ $ go get -u github.com/argoproj/argo-cd
$ dep ensure
$ make
```
NOTE: The make command can take a while, and we recommend building the specific component you are working on
* `make cli` - Make the argocd CLI tool
* `make server` - Make the API/repo/controller server
* `make codegen` - Builds protobuf and swagger files
* `make argocd-util` - Make the administrator's utility, used for certain tasks such as import/export
## Running locally
@@ -38,3 +47,10 @@ $ kubectl create -f install/manifests/01_application-crd.yaml
```
$ goreman start
```
## Troubleshooting
* Ensure argocd is installed: ./dist/argocd install
* Ensure you're logged in: ./dist/argocd login --username admin --password <whatever password you set at install> localhost:8080
* Ensure that roles are configured: kubectl create -f install/manifests/02c_argocd-rbac-cm.yaml
* Ensure minikube is running: minikube stop && minikube start
* Ensure Argo CD is aware of minikube: ./dist/argocd cluster add minikube

79
Gopkg.lock generated
View File

@@ -32,6 +32,12 @@
packages = ["."]
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
[[projects]]
name = "github.com/asaskevich/govalidator"
packages = ["."]
revision = "ccb8e960c48f04d6935e72476ae4a51028f9e22f"
version = "v9"
[[projects]]
name = "github.com/blang/semver"
packages = ["."]
@@ -89,6 +95,18 @@
packages = ["."]
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
[[projects]]
branch = "master"
name = "github.com/go-openapi/analysis"
packages = ["."]
revision = "5957818e100395077187fb7ef3b8a28227af06c6"
[[projects]]
branch = "master"
name = "github.com/go-openapi/errors"
packages = ["."]
revision = "b2b2befaf267d082d779bcef52d682a47c779517"
[[projects]]
branch = "master"
name = "github.com/go-openapi/jsonpointer"
@@ -101,18 +119,50 @@
packages = ["."]
revision = "36d33bfe519efae5632669801b180bf1a245da3b"
[[projects]]
branch = "master"
name = "github.com/go-openapi/loads"
packages = ["."]
revision = "2a2b323bab96e6b1fdee110e57d959322446e9c9"
[[projects]]
branch = "master"
name = "github.com/go-openapi/runtime"
packages = [
".",
"logger",
"middleware",
"middleware/denco",
"middleware/header",
"middleware/untyped",
"security"
]
revision = "cd9d8ed52e4b4665463cbc655500e4faa09c3c16"
[[projects]]
branch = "master"
name = "github.com/go-openapi/spec"
packages = ["."]
revision = "1de3e0542de65ad8d75452a595886fdd0befb363"
[[projects]]
branch = "master"
name = "github.com/go-openapi/strfmt"
packages = ["."]
revision = "481808443b00a14745fada967cb5eeff0f9b1df2"
[[projects]]
branch = "master"
name = "github.com/go-openapi/swag"
packages = ["."]
revision = "84f4bee7c0a6db40e3166044c7983c1c32125429"
[[projects]]
branch = "master"
name = "github.com/go-openapi/validate"
packages = ["."]
revision = "b0a3ed684d0fdd3e1eda00433382188ce8aa7169"
[[projects]]
name = "github.com/go-redis/cache"
packages = [
@@ -190,7 +240,11 @@
packages = [
"jsonpb",
"proto",
"protoc-gen-go",
"protoc-gen-go/descriptor",
"protoc-gen-go/generator",
"protoc-gen-go/grpc",
"protoc-gen-go/plugin",
"ptypes",
"ptypes/any",
"ptypes/duration",
@@ -243,6 +297,14 @@
[[projects]]
name = "github.com/grpc-ecosystem/grpc-gateway"
packages = [
"protoc-gen-grpc-gateway",
"protoc-gen-grpc-gateway/descriptor",
"protoc-gen-grpc-gateway/generator",
"protoc-gen-grpc-gateway/gengateway",
"protoc-gen-grpc-gateway/httprule",
"protoc-gen-swagger",
"protoc-gen-swagger/genswagger",
"protoc-gen-swagger/options",
"runtime",
"runtime/internal",
"utilities"
@@ -333,6 +395,12 @@
]
revision = "32fa128f234d041f196a9f3e0fea5ac9772c08e1"
[[projects]]
branch = "master"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b"
[[projects]]
name = "github.com/patrickmn/go-cache"
packages = ["."]
@@ -614,6 +682,15 @@
revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
version = "v0.9.0"
[[projects]]
branch = "v2"
name = "gopkg.in/mgo.v2"
packages = [
"bson",
"internal/json"
]
revision = "3f83fa5005286a7fe593b055f0d7771a7dce4655"
[[projects]]
name = "gopkg.in/square/go-jose.v2"
packages = [
@@ -933,6 +1010,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "f2d179e0bbae6ede81f78cf6b0b16cb09fbeb5e97add78bdd97e3051238b86da"
inputs-digest = "38ccdbf0eaabe461fdf17a5d12463b3db0b61aab4daf9937f2e813d2ae2d2eb5"
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -3,6 +3,9 @@ required = [
"github.com/gogo/protobuf/protoc-gen-gogofast",
"golang.org/x/sync/errgroup",
"k8s.io/code-generator/cmd/go-to-protobuf",
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway",
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger",
"github.com/golang/protobuf/protoc-gen-go",
]
[[constraint]]

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#! /usr/bin/env bash
# This script auto-generates protobuf related files. It is intended to be run manually when either
# API types are added/modified, or server gRPC calls are added. The generated files should then
@@ -77,5 +77,44 @@ for i in ${PROTO_FILES}; do
-I${GOGO_PROTOBUF_PATH} \
--${GOPROTOBINARY}_out=plugins=grpc:$GOPATH/src \
--grpc-gateway_out=logtostderr=true:$GOPATH/src \
--swagger_out=logtostderr=true:. \
$i
done
# collect_swagger gathers swagger files into a subdirectory
collect_swagger() {
SWAGGER_ROOT="$1"
EXPECTED_COLLISIONS="$2"
SWAGGER_OUT="${SWAGGER_ROOT}/swagger.json"
PRIMARY_SWAGGER=`mktemp`
COMBINED_SWAGGER=`mktemp`
cat <<EOF > "${PRIMARY_SWAGGER}"
{
"swagger": "2.0",
"info": {
"title": "Consolidate Services",
"description": "Description of all APIs",
"version": "version not set"
},
"paths": {}
}
EOF
/bin/rm -f "${SWAGGER_OUT}"
/usr/bin/find "${SWAGGER_ROOT}" -name '*.swagger.json' -exec /usr/local/bin/swagger mixin -c "${EXPECTED_COLLISIONS}" "${PRIMARY_SWAGGER}" '{}' \+ > "${COMBINED_SWAGGER}"
/usr/local/bin/jq -r 'del(.definitions[].properties[]? | select(."$ref"!=null and .description!=null).description) | del(.definitions[].properties[]? | select(."$ref"!=null and .title!=null).title)' "${COMBINED_SWAGGER}" > "${SWAGGER_OUT}"
/bin/rm "${PRIMARY_SWAGGER}" "${COMBINED_SWAGGER}"
}
# clean up generated swagger files (should come after collect_swagger)
clean_swagger() {
SWAGGER_ROOT="$1"
/usr/bin/find "${SWAGGER_ROOT}" -name '*.swagger.json' -delete
}
collect_swagger server 15
clean_swagger server
clean_swagger reposerver

136
reposerver/swagger.json Normal file
View File

@@ -0,0 +1,136 @@
{
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"schemes": [
"http",
"https"
],
"swagger": "2.0",
"info": {
"description": "Description of all APIs",
"title": "Consolidate Services",
"version": "version not set"
},
"paths": {},
"definitions": {
"repositoryFileList": {
"type": "object",
"title": "FileList returns the contents of the repo of a ListDir request",
"properties": {
"items": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"repositoryGetFileResponse": {
"type": "object",
"title": "GetFileResponse returns the contents of the file of a GetFile request",
"properties": {
"data": {
"type": "string",
"format": "byte"
}
}
},
"repositoryManifestResponse": {
"type": "object",
"properties": {
"manifests": {
"type": "array",
"items": {
"type": "string"
}
},
"namespace": {
"type": "string"
},
"params": {
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1ComponentParameter"
}
},
"revision": {
"type": "string"
},
"server": {
"type": "string"
}
}
},
"v1Time": {
"description": "Time is a wrapper around time.Time which supports correct\nmarshaling to YAML and JSON. Wrappers are provided for many\nof the factory methods that the time package offers.\n\n+protobuf.options.marshal=false\n+protobuf.as=Timestamp\n+protobuf.options.(gogoproto.goproto_stringer)=false",
"type": "object",
"properties": {
"nanos": {
"description": "Non-negative fractions of a second at nanosecond resolution. Negative\nsecond values with fractions must still have non-negative nanos values\nthat count forward in time. Must be from 0 to 999,999,999\ninclusive. This field may be limited in precision depending on context.",
"type": "integer",
"format": "int32"
},
"seconds": {
"description": "Represents seconds of UTC time since Unix epoch\n1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to\n9999-12-31T23:59:59Z inclusive.",
"type": "string",
"format": "int64"
}
}
},
"v1alpha1ComponentParameter": {
"type": "object",
"title": "ComponentParameter contains information about component parameter value",
"properties": {
"component": {
"type": "string"
},
"name": {
"type": "string"
},
"value": {
"type": "string"
}
}
},
"v1alpha1ConnectionState": {
"type": "object",
"title": "ConnectionState contains information about remote resource connection state",
"properties": {
"attemptedAt": {
"$ref": "#/definitions/v1Time"
},
"message": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"v1alpha1Repository": {
"type": "object",
"title": "Repository is a Git repository holding application configurations",
"properties": {
"connectionState": {
"$ref": "#/definitions/v1alpha1ConnectionState"
},
"password": {
"type": "string"
},
"repo": {
"type": "string"
},
"sshPrivateKey": {
"type": "string"
},
"username": {
"type": "string"
}
}
}
}
}

View File

@@ -509,15 +509,15 @@ type ApplicationServiceClient interface {
GetManifests(ctx context.Context, in *ApplicationManifestQuery, opts ...grpc.CallOption) (*repository.ManifestResponse, error)
// Update updates an application
Update(ctx context.Context, in *ApplicationUpdateRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Application, error)
// Update updates an application spec
// UpdateSpec updates an application spec
UpdateSpec(ctx context.Context, in *ApplicationUpdateSpecRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.ApplicationSpec, error)
// Delete deletes an application
Delete(ctx context.Context, in *ApplicationDeleteRequest, opts ...grpc.CallOption) (*ApplicationResponse, error)
// Sync syncs an application to its target state
Sync(ctx context.Context, in *ApplicationSyncRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Application, error)
// Sync syncs an application to its target state
// Rollback syncs an application to its target state
Rollback(ctx context.Context, in *ApplicationRollbackRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Application, error)
// PodLogs returns stream of log entries for the specified pod. Pod
// DeletePod returns stream of log entries for the specified pod. Pod
DeletePod(ctx context.Context, in *ApplicationDeletePodRequest, opts ...grpc.CallOption) (*ApplicationResponse, error)
// PodLogs returns stream of log entries for the specified pod. Pod
PodLogs(ctx context.Context, in *ApplicationPodLogsQuery, opts ...grpc.CallOption) (ApplicationService_PodLogsClient, error)
@@ -711,15 +711,15 @@ type ApplicationServiceServer interface {
GetManifests(context.Context, *ApplicationManifestQuery) (*repository.ManifestResponse, error)
// Update updates an application
Update(context.Context, *ApplicationUpdateRequest) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Application, error)
// Update updates an application spec
// UpdateSpec updates an application spec
UpdateSpec(context.Context, *ApplicationUpdateSpecRequest) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.ApplicationSpec, error)
// Delete deletes an application
Delete(context.Context, *ApplicationDeleteRequest) (*ApplicationResponse, error)
// Sync syncs an application to its target state
Sync(context.Context, *ApplicationSyncRequest) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Application, error)
// Sync syncs an application to its target state
// Rollback syncs an application to its target state
Rollback(context.Context, *ApplicationRollbackRequest) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Application, error)
// PodLogs returns stream of log entries for the specified pod. Pod
// DeletePod returns stream of log entries for the specified pod. Pod
DeletePod(context.Context, *ApplicationDeletePodRequest) (*ApplicationResponse, error)
// PodLogs returns stream of log entries for the specified pod. Pod
PodLogs(*ApplicationPodLogsQuery, ApplicationService_PodLogsServer) error

View File

@@ -135,7 +135,7 @@ service ApplicationService {
};
}
// Update updates an application spec
// UpdateSpec updates an application spec
rpc UpdateSpec(ApplicationUpdateSpecRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ApplicationSpec) {
option (google.api.http) = {
put: "/api/v1/applications/{name}/spec"
@@ -156,7 +156,7 @@ service ApplicationService {
};
}
// Sync syncs an application to its target state
// Rollback syncs an application to its target state
rpc Rollback(ApplicationRollbackRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Application) {
option (google.api.http) = {
post: "/api/v1/applications/{name}/rollback"
@@ -164,7 +164,7 @@ service ApplicationService {
};
}
// PodLogs returns stream of log entries for the specified pod. Pod
// DeletePod returns stream of log entries for the specified pod. Pod
rpc DeletePod(ApplicationDeletePodRequest) returns (ApplicationResponse) {
option (google.api.http).delete = "/api/v1/applications/{name}/pods/{podName}";
}

View File

@@ -126,7 +126,7 @@ type ClusterServiceClient interface {
Get(ctx context.Context, in *ClusterQuery, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
// Update updates a cluster
Update(ctx context.Context, in *ClusterUpdateRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
// Delete updates a cluster
// Delete deletes a cluster
Delete(ctx context.Context, in *ClusterQuery, opts ...grpc.CallOption) (*ClusterResponse, error)
}
@@ -194,7 +194,7 @@ type ClusterServiceServer interface {
Get(context.Context, *ClusterQuery) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
// Update updates a cluster
Update(context.Context, *ClusterUpdateRequest) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
// Delete updates a cluster
// Delete deletes a cluster
Delete(context.Context, *ClusterQuery) (*ClusterResponse, error)
}

View File

@@ -56,7 +56,7 @@ service ClusterService {
};
}
// Delete updates a cluster
// Delete deletes a cluster
rpc Delete(ClusterQuery) returns (ClusterResponse) {
option (google.api.http).delete = "/api/v1/clusters/{server}";
}

View File

@@ -37,7 +37,7 @@ func (s *Server) Create(ctx context.Context, q *ProjectCreateRequest) (*v1alpha1
return nil, grpc.ErrPermissionDenied
}
if q.Project.Name == common.DefaultAppProjectName {
return nil, status.Errorf(codes.InvalidArgument, "name '%s' is reserved and cannot be used as a project name")
return nil, status.Errorf(codes.InvalidArgument, "name '%s' is reserved and cannot be used as a project name", q.Project.Name)
}
return s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Create(q.Project)
}

View File

@@ -50,6 +50,7 @@ import (
"github.com/argoproj/argo-cd/util/rbac"
util_session "github.com/argoproj/argo-cd/util/session"
settings_util "github.com/argoproj/argo-cd/util/settings"
"github.com/argoproj/argo-cd/util/swagger"
tlsutil "github.com/argoproj/argo-cd/util/tls"
"github.com/argoproj/argo-cd/util/webhook"
)
@@ -377,6 +378,8 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int) *http.Server
mustRegisterGWHandler(settings.RegisterSettingsServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts)
mustRegisterGWHandler(project.RegisterProjectServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts)
swagger.ServeSwaggerUI(mux, "server", "/swagger-ui")
// Dex reverse proxy and client app and OAuth2 login/callback
a.registerDexHandlers(mux)

View File

@@ -118,9 +118,9 @@ const _ = grpc.SupportPackageIsVersion4
// Client API for SessionService service
type SessionServiceClient interface {
// Create a new JWT for authentication.
// Create a new JWT for authentication and set a cookie if using HTTP.
Create(ctx context.Context, in *SessionCreateRequest, opts ...grpc.CallOption) (*SessionResponse, error)
// Create a new JWT for authentication.
// Delete an existing JWT cookie if using HTTP.
Delete(ctx context.Context, in *SessionDeleteRequest, opts ...grpc.CallOption) (*SessionResponse, error)
}
@@ -153,9 +153,9 @@ func (c *sessionServiceClient) Delete(ctx context.Context, in *SessionDeleteRequ
// Server API for SessionService service
type SessionServiceServer interface {
// Create a new JWT for authentication.
// Create a new JWT for authentication and set a cookie if using HTTP.
Create(context.Context, *SessionCreateRequest) (*SessionResponse, error)
// Create a new JWT for authentication.
// Delete an existing JWT cookie if using HTTP.
Delete(context.Context, *SessionDeleteRequest) (*SessionResponse, error)
}

View File

@@ -30,7 +30,7 @@ message SessionResponse {
// SessionService
service SessionService {
// Create a new JWT for authentication.
// Create a new JWT for authentication and set a cookie if using HTTP.
rpc Create(SessionCreateRequest) returns (SessionResponse) {
option (google.api.http) = {
post: "/api/v1/session"
@@ -38,7 +38,7 @@ service SessionService {
};
}
// Create a new JWT for authentication.
// Delete an existing JWT cookie if using HTTP.
rpc Delete(SessionDeleteRequest) returns (SessionResponse) {
option (google.api.http) = {
delete: "/api/v1/session"

2207
server/swagger.json Normal file

File diff suppressed because it is too large Load Diff

25
util/swagger/swagger.go Normal file
View File

@@ -0,0 +1,25 @@
package swagger
import (
"net/http"
"path"
"path/filepath"
"github.com/go-openapi/runtime/middleware"
)
// ServeSwaggerUI serves the Swagger UI and JSON spec.
func ServeSwaggerUI(mux *http.ServeMux, component, uiPath string) {
prefix := path.Dir(uiPath)
specURL := path.Join(prefix, "swagger.json")
mux.HandleFunc(specURL, func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, filepath.Join(component, "swagger.json"))
})
mux.Handle(uiPath, middleware.Redoc(middleware.RedocOpts{
BasePath: prefix,
SpecURL: specURL,
Path: path.Base(uiPath),
}, http.NotFoundHandler()))
}

View File

@@ -0,0 +1,66 @@
package swagger
import (
"encoding/json"
"net"
"net/http"
"testing"
"github.com/go-openapi/loads"
)
func TestSwaggerUI(t *testing.T) {
const sentinel = `{
"swagger": "2.0",
"info": {
"title": "Consolidate Services",
"description": "Description of all APIs",
"version": "version not set"
},
"paths": {}
}`
serve := func(c chan<- string) {
// listen on first available dynamic (unprivileged) port
listener, err := net.Listen("tcp", ":0")
if err != nil {
panic(err)
}
// send back the address so that it can be used
c <- listener.Addr().String()
mux := http.NewServeMux()
ServeSwaggerUI(mux, "../../server", "/swagger-ui")
panic(http.Serve(listener, mux))
}
c := make(chan string, 1)
// run a local webserver to test data retrieval
go serve(c)
address := <-c
t.Logf("Listening at address: %s", address)
server := "http://" + address
specDoc, err := loads.Spec(server + "/swagger.json")
if err != nil {
t.Fatal(err)
}
_, err = json.MarshalIndent(specDoc.Spec(), "", " ")
if err != nil {
t.Fatal(err)
}
resp, err := http.Get(server + "/swagger-ui")
if err != nil {
t.Fatal(err)
}
if resp.StatusCode != 200 {
t.Fatalf("Was expecting status code 200 from swagger-ui, but got %d instead", resp.StatusCode)
}
}