-// Package docs GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Package api GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag
-package docs
+package api
import (
"bytes"
"description": ""
},
"400": {
- "description": "Bad Request",
+ "description": "Problem as defined in https://tools.ietf.org/html/rfc7807",
"schema": {
- "type": "string"
+ "$ref": "#/definitions/ErrorInfo"
+ },
+ "headers": {
+ "Content-Type": {
+ "type": "string",
+ "description": "application/problem+json"
+ }
}
}
}
"/health_check": {
"get": {
"description": "Get the status of the producer. Will show if the producer has registered in ICS.",
+ "produces": [
+ "application/json"
+ ],
"tags": [
"Data producer (callbacks)"
],
"summary": "Get status",
"responses": {
"200": {
- "description": ""
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/"
+ }
}
}
}
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/jobs.JobInfo"
+ "$ref": "#/definitions/JobInfo"
}
}
],
"description": ""
},
"400": {
- "description": "Bad Request",
+ "description": "Problem as defined in https://tools.ietf.org/html/rfc7807",
"schema": {
- "type": "string"
+ "$ref": "#/definitions/ErrorInfo"
+ },
+ "headers": {
+ "Content-Type": {
+ "type": "string",
+ "description": "application/problem+json"
+ }
}
}
}
}
},
"definitions": {
- "jobs.BufferTimeout": {
+ "": {
+ "type": "object",
+ "properties": {
+ "registeredStatus": {
+ "description": "The registration status of the producer in Information Coordinator Service. Either ` + "`" + `registered` + "`" + ` or ` + "`" + `not registered` + "`" + `",
+ "type": "string",
+ "example": "registered"
+ }
+ }
+ },
+ "BufferTimeout": {
"type": "object",
"properties": {
"maxSize": {
}
}
},
- "jobs.JobInfo": {
+ "ErrorInfo": {
+ "type": "object",
+ "properties": {
+ "detail": {
+ "description": "A human-readable explanation specific to this occurrence of the problem.",
+ "type": "string",
+ "example": "Info job type not found"
+ },
+ "instance": {
+ "description": "A URI reference that identifies the specific occurrence of the problem.",
+ "type": "string"
+ },
+ "status": {
+ "description": "The HTTP status code generated by the origin server for this occurrence of the problem.",
+ "type": "integer",
+ "example": 400
+ },
+ "title": {
+ "description": "A short, human-readable summary of the problem type.",
+ "type": "string"
+ },
+ "type": {
+ "description": "A URI reference that identifies the problem type.",
+ "type": "string"
+ }
+ }
+ },
+ "JobInfo": {
"type": "object",
"properties": {
"info_job_data": {
- "$ref": "#/definitions/jobs.Parameters"
+ "$ref": "#/definitions/Parameters"
},
"info_job_identity": {
"type": "string"
}
}
},
- "jobs.Parameters": {
+ "Parameters": {
"type": "object",
"properties": {
"bufferTimeout": {
- "$ref": "#/definitions/jobs.BufferTimeout"
+ "$ref": "#/definitions/BufferTimeout"
}
}
}
"description": ""
},
"400": {
- "description": "Bad Request",
+ "description": "Problem as defined in https://tools.ietf.org/html/rfc7807",
"schema": {
- "type": "string"
+ "$ref": "#/definitions/ErrorInfo"
+ },
+ "headers": {
+ "Content-Type": {
+ "type": "string",
+ "description": "application/problem+json"
+ }
}
}
}
"/health_check": {
"get": {
"description": "Get the status of the producer. Will show if the producer has registered in ICS.",
+ "produces": [
+ "application/json"
+ ],
"tags": [
"Data producer (callbacks)"
],
"summary": "Get status",
"responses": {
"200": {
- "description": ""
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/"
+ }
}
}
}
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/jobs.JobInfo"
+ "$ref": "#/definitions/JobInfo"
}
}
],
"description": ""
},
"400": {
- "description": "Bad Request",
+ "description": "Problem as defined in https://tools.ietf.org/html/rfc7807",
"schema": {
- "type": "string"
+ "$ref": "#/definitions/ErrorInfo"
+ },
+ "headers": {
+ "Content-Type": {
+ "type": "string",
+ "description": "application/problem+json"
+ }
}
}
}
}
},
"definitions": {
- "jobs.BufferTimeout": {
+ "": {
+ "type": "object",
+ "properties": {
+ "registeredStatus": {
+ "description": "The registration status of the producer in Information Coordinator Service. Either `registered` or `not registered`",
+ "type": "string",
+ "example": "registered"
+ }
+ }
+ },
+ "BufferTimeout": {
"type": "object",
"properties": {
"maxSize": {
}
}
},
- "jobs.JobInfo": {
+ "ErrorInfo": {
+ "type": "object",
+ "properties": {
+ "detail": {
+ "description": "A human-readable explanation specific to this occurrence of the problem.",
+ "type": "string",
+ "example": "Info job type not found"
+ },
+ "instance": {
+ "description": "A URI reference that identifies the specific occurrence of the problem.",
+ "type": "string"
+ },
+ "status": {
+ "description": "The HTTP status code generated by the origin server for this occurrence of the problem.",
+ "type": "integer",
+ "example": 400
+ },
+ "title": {
+ "description": "A short, human-readable summary of the problem type.",
+ "type": "string"
+ },
+ "type": {
+ "description": "A URI reference that identifies the problem type.",
+ "type": "string"
+ }
+ }
+ },
+ "JobInfo": {
"type": "object",
"properties": {
"info_job_data": {
- "$ref": "#/definitions/jobs.Parameters"
+ "$ref": "#/definitions/Parameters"
},
"info_job_identity": {
"type": "string"
}
}
},
- "jobs.Parameters": {
+ "Parameters": {
"type": "object",
"properties": {
"bufferTimeout": {
- "$ref": "#/definitions/jobs.BufferTimeout"
+ "$ref": "#/definitions/BufferTimeout"
}
}
}
definitions:
- jobs.BufferTimeout:
+ "":
+ properties:
+ registeredStatus:
+ description: The registration status of the producer in Information Coordinator
+ Service. Either `registered` or `not registered`
+ example: registered
+ type: string
+ type: object
+ BufferTimeout:
properties:
maxSize:
type: integer
maxTimeMiliseconds:
type: integer
type: object
- jobs.JobInfo:
+ ErrorInfo:
+ properties:
+ detail:
+ description: A human-readable explanation specific to this occurrence of the
+ problem.
+ example: Info job type not found
+ type: string
+ instance:
+ description: A URI reference that identifies the specific occurrence of the
+ problem.
+ type: string
+ status:
+ description: The HTTP status code generated by the origin server for this
+ occurrence of the problem.
+ example: 400
+ type: integer
+ title:
+ description: A short, human-readable summary of the problem type.
+ type: string
+ type:
+ description: A URI reference that identifies the problem type.
+ type: string
+ type: object
+ JobInfo:
properties:
info_job_data:
- $ref: '#/definitions/jobs.Parameters'
+ $ref: '#/definitions/Parameters'
info_job_identity:
type: string
info_type_identity:
target_uri:
type: string
type: object
- jobs.Parameters:
+ Parameters:
properties:
bufferTimeout:
- $ref: '#/definitions/jobs.BufferTimeout'
+ $ref: '#/definitions/BufferTimeout'
type: object
info:
contact: {}
"200":
description: ""
"400":
- description: Bad Request
+ description: Problem as defined in https://tools.ietf.org/html/rfc7807
+ headers:
+ Content-Type:
+ description: application/problem+json
+ type: string
schema:
- type: string
+ $ref: '#/definitions/ErrorInfo'
summary: Set log level
tags:
- Admin
get:
description: Get the status of the producer. Will show if the producer has registered
in ICS.
+ produces:
+ - application/json
responses:
"200":
- description: ""
+ description: OK
+ schema:
+ $ref: '#/definitions/'
summary: Get status
tags:
- Data producer (callbacks)
name: user
required: true
schema:
- $ref: '#/definitions/jobs.JobInfo'
+ $ref: '#/definitions/JobInfo'
responses:
"200":
description: ""
"400":
- description: Bad Request
+ description: Problem as defined in https://tools.ietf.org/html/rfc7807
+ headers:
+ Content-Type:
+ description: application/problem+json
+ type: string
schema:
- type: string
+ $ref: '#/definitions/ErrorInfo'
summary: Add info job
tags:
- Data producer (callbacks)
#
##############################################################################
-swag init
\ No newline at end of file
+go get -u github.com/swaggo/swag/cmd/swag
+swag init --output api
+swag fmt
\ No newline at end of file
go 1.17
require (
+ github.com/confluentinc/confluent-kafka-go v1.8.2
github.com/gorilla/mux v1.8.0
github.com/hashicorp/go-retryablehttp v0.7.0
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
+ github.com/swaggo/http-swagger v1.1.2
+ github.com/swaggo/swag v1.7.8
)
require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
- github.com/confluentinc/confluent-kafka-go v1.8.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/stretchr/objx v0.1.0 // indirect
github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 // indirect
- github.com/swaggo/http-swagger v1.1.2 // indirect
- github.com/swaggo/swag v1.7.8 // indirect
github.com/urfave/cli/v2 v2.3.0 // indirect
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect
InfoJobData Parameters `json:"info_job_data"`
InfoTypeIdentity string `json:"info_type_identity"`
sourceType sourceType
-}
+} // @name JobInfo
type JobTypesManager interface {
LoadTypesFromConfiguration(types []config.TypeDefinition) []config.TypeDefinition
type Parameters struct {
BufferTimeout BufferTimeout `json:"bufferTimeout"`
-}
+} // @name Parameters
type BufferTimeout struct {
MaxSize int `json:"maxSize"`
MaxTimeMiliseconds int64 `json:"maxTimeMiliseconds"`
-}
+} // @name BufferTimeout
func (j *job) start() {
if j.isJobBuffered() {
const logLevelToken = "level"
const logAdminPath = "/admin/log"
+type ErrorInfo struct {
+ // A URI reference that identifies the problem type.
+ Type string `json:"type" swaggertype:"string"`
+ // A short, human-readable summary of the problem type.
+ Title string `json:"title" swaggertype:"string"`
+ // The HTTP status code generated by the origin server for this occurrence of the problem.
+ Status int `json:"status" swaggertype:"integer" example:"400"`
+ // A human-readable explanation specific to this occurrence of the problem.
+ Detail string `json:"detail" swaggertype:"string" example:"Info job type not found"`
+ // A URI reference that identifies the specific occurrence of the problem.
+ Instance string `json:"instance" swaggertype:"string"`
+} // @name ErrorInfo
+
type ProducerCallbackHandler struct {
jobsManager jobs.JobsManager
}
// @Accept json
// @Param user body jobs.JobInfo true "Info job data"
// @Success 200
-// @Failure 400 {string} Cause of error
+// @Failure 400 {object} ErrorInfo "Problem as defined in https://tools.ietf.org/html/rfc7807"
+// @Header 400 {string} Content-Type "application/problem+json"
// @Router /info_job [post]
func (h *ProducerCallbackHandler) addInfoJobHandler(w http.ResponseWriter, r *http.Request) {
b, readErr := ioutil.ReadAll(r.Body)
if readErr != nil {
- http.Error(w, fmt.Sprintf("Unable to read body due to: %v", readErr), http.StatusBadRequest)
+ returnError(fmt.Sprintf("Unable to read body due to: %v", readErr), w)
return
}
jobInfo := jobs.JobInfo{}
if unmarshalErr := json.Unmarshal(b, &jobInfo); unmarshalErr != nil {
- http.Error(w, fmt.Sprintf("Invalid json body. Cause: %v", unmarshalErr), http.StatusBadRequest)
+ returnError(fmt.Sprintf("Invalid json body. Cause: %v", unmarshalErr), w)
return
}
if err := h.jobsManager.AddJobFromRESTCall(jobInfo); err != nil {
- http.Error(w, fmt.Sprintf("Invalid job info. Cause: %v", err), http.StatusBadRequest)
+ returnError(fmt.Sprintf("Invalid job info. Cause: %v", err), w)
+ return
}
}
// @Tags Admin
// @Param level query string false "string enums" Enums(Error, Warn, Info, Debug)
// @Success 200
-// @Failure 400 {string} Cause of error
+// @Failure 400 {object} ErrorInfo "Problem as defined in https://tools.ietf.org/html/rfc7807"
+// @Header 400 {string} Content-Type "application/problem+json"
// @Router /admin/log [put]
func (h *ProducerCallbackHandler) setLogLevel(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
if loglevel, err := log.ParseLevel(logLevelStr); err == nil {
log.SetLevel(loglevel)
} else {
- http.Error(w, fmt.Sprintf("Invalid log level: %v. Log level will not be changed!", logLevelStr), http.StatusBadRequest)
+ returnError(fmt.Sprintf("Invalid log level: %v. Log level will not be changed!", logLevelStr), w)
return
}
}
func (h *methodNotAllowedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Method is not supported.", http.StatusMethodNotAllowed)
}
+
+func returnError(msg string, w http.ResponseWriter) {
+ errInfo := ErrorInfo{
+ Status: http.StatusBadRequest,
+ Detail: msg,
+ }
+ w.Header().Add("Content-Type", "application/problem+json")
+ w.WriteHeader(http.StatusBadRequest)
+ json.NewEncoder(w).Encode(errInfo)
+}
mockReturn error
}
tests := []struct {
- name string
- args args
- wantedStatus int
- wantedBody string
+ name string
+ args args
+ wantedStatus int
+ wantedErrorInfo *ErrorInfo
}{
{
name: "AddInfoJobToJobsHandler with correct job, should return OK",
mockReturn: errors.New("error"),
},
wantedStatus: http.StatusBadRequest,
- wantedBody: "Invalid job info. Cause: error",
+ wantedErrorInfo: &ErrorInfo{
+ Status: http.StatusBadRequest,
+ Detail: "Invalid job info. Cause: error",
+ },
},
}
for _, tt := range tests {
handler.ServeHTTP(responseRecorder, r)
assertions.Equal(tt.wantedStatus, responseRecorder.Code, tt.name)
- assertions.Contains(responseRecorder.Body.String(), tt.wantedBody, tt.name)
+ if tt.wantedErrorInfo != nil {
+ var actualErrInfo ErrorInfo
+ err := json.Unmarshal(getBody(responseRecorder, t), &actualErrInfo)
+ if err != nil {
+ t.Error("Unable to unmarshal error body", err)
+ t.Fail()
+ }
+ assertions.Equal(*tt.wantedErrorInfo, actualErrInfo, tt.name)
+ assertions.Equal("application/problem+json", responseRecorder.Result().Header.Get("Content-Type"))
+ }
jobsHandlerMock.AssertCalled(t, "AddJobFromRESTCall", tt.args.job)
})
}
logLevel string
}
tests := []struct {
- name string
- args args
- wantedStatus int
- wantedBody string
+ name string
+ args args
+ wantedStatus int
+ wantedErrorInfo *ErrorInfo
}{
{
name: "Set to valid log level, should return OK",
logLevel: "bad",
},
wantedStatus: http.StatusBadRequest,
- wantedBody: "Invalid log level: bad",
+ wantedErrorInfo: &ErrorInfo{
+ Detail: "Invalid log level: bad. Log level will not be changed!",
+ Status: http.StatusBadRequest,
+ },
},
}
for _, tt := range tests {
handler.ServeHTTP(responseRecorder, r)
assertions.Equal(tt.wantedStatus, responseRecorder.Code, tt.name)
- assertions.Contains(responseRecorder.Body.String(), tt.wantedBody, tt.name)
+ if tt.wantedErrorInfo != nil {
+ var actualErrInfo ErrorInfo
+ err := json.Unmarshal(getBody(responseRecorder, t), &actualErrInfo)
+ if err != nil {
+ t.Error("Unable to unmarshal error body", err)
+ t.Fail()
+ }
+ assertions.Equal(*tt.wantedErrorInfo, actualErrInfo, tt.name)
+ assertions.Equal("application/problem+json", responseRecorder.Result().Header.Get("Content-Type"))
+ }
})
}
}
return nil
}
}
+
+func getBody(responseRecorder *httptest.ResponseRecorder, t *testing.T) []byte {
+ buf := new(bytes.Buffer)
+ if _, err := buf.ReadFrom(responseRecorder.Body); err != nil {
+ t.Error("Unable to read error body", err)
+ t.Fail()
+ }
+ return buf.Bytes()
+}
import (
"crypto/tls"
+ "encoding/json"
"fmt"
"net/http"
"time"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
- _ "oransc.org/nonrtric/dmaapmediatorproducer/docs"
+ _ "oransc.org/nonrtric/dmaapmediatorproducer/api"
"oransc.org/nonrtric/dmaapmediatorproducer/internal/config"
"oransc.org/nonrtric/dmaapmediatorproducer/internal/jobs"
"oransc.org/nonrtric/dmaapmediatorproducer/internal/kafkaclient"
configuration = config.New()
}
-// @title DMaaP Mediator Producer
-// @version 1.1.0
+// @title DMaaP Mediator Producer
+// @version 1.1.0
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
}
}
-// @Summary Get status
-// @Description Get the status of the producer. Will show if the producer has registered in ICS.
-// @Tags Data producer (callbacks)
-// @Success 200
-// @Router /health_check [get]
+type ProducerStatus struct {
+ // The registration status of the producer in Information Coordinator Service. Either `registered` or `not registered`
+ RegisteredStatus string `json:"registeredStatus" swaggertype:"string" example:"registered"`
+} // @name ProducerStatus
+
+// @Summary Get status
+// @Description Get the status of the producer. Will show if the producer has registered in ICS.
+// @Tags Data producer (callbacks)
+// @Produce json
+// @Success 200 {object} ProducerStatus
+// @Router /health_check [get]
func statusHandler(w http.ResponseWriter, r *http.Request) {
- registeredStatus := "not registered"
+ status := ProducerStatus{
+ RegisteredStatus: "not registered",
+ }
if registered {
- registeredStatus = "registered"
+ status.RegisteredStatus = "registered"
}
- fmt.Fprintf(w, `{"status": "%v"}`, registeredStatus)
+ json.NewEncoder(w).Encode(status)
}
-// @Summary Get Swagger Documentation
-// @Description Get the Swagger API documentation for the producer.
-// @Tags Admin
-// @Success 200
-// @Router /swagger [get]
+// @Summary Get Swagger Documentation
+// @Description Get the Swagger API documentation for the producer.
+// @Tags Admin
+// @Success 200
+// @Router /swagger [get]
func addSwaggerHandler(r *mux.Router) {
r.PathPrefix("/swagger").Handler(httpSwagger.WrapHandler)
}
import (
"bytes"
+ "fmt"
"io/ioutil"
"net/http"
"os/exec"
func TestGenerateSwaggerDocs(t *testing.T) {
cmd := exec.Command("./generate_swagger_docs.sh")
- cmd.Run()
+ err := cmd.Run()
+ if err != nil {
+ fmt.Println("Error generating Swagger:", err)
+ }
}
func TestValidateConfiguration(t *testing.T) {
:header: "API name", "|swagger-icon|", "|yaml-icon|"
:widths: 10,5, 5
- "DMaaP Mediator Producer API", ":download:`link <../dmaap-mediator-producer/docs/swagger.json>`", ":download:`link <../dmaap-mediator-producer/docs/swagger.yaml>`"
+ "DMaaP Mediator Producer API", ":download:`link <../dmaap-mediator-producer/api/swagger.json>`", ":download:`link <../dmaap-mediator-producer/api/swagger.yaml>`"
Non-RT-RIC App Catalogue (Initial)
==================================
{
'name': 'DMaaP Mediator Producer API',
'page': 'dmaap-mediator-producer-api',
- 'spec': '../dmaap-mediator-producer/docs/swagger.json',
+ 'spec': '../dmaap-mediator-producer/api/swagger.json',
'embed': True,
}
]