Skip to content

Commit

Permalink
Add CSV Support
Browse files Browse the repository at this point in the history
Signed-off-by: Hiroki Sakamoto <[email protected]>
  • Loading branch information
taisho6339 authored and casualjim committed Mar 3, 2019
1 parent cdfa0fc commit 5e1ff77
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 1 deletion.
2 changes: 2 additions & 0 deletions client/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,15 @@ func New(host, basePath string, schemes []string) *Runtime {
runtime.XMLMime: runtime.XMLConsumer(),
runtime.TextMime: runtime.TextConsumer(),
runtime.HTMLMime: runtime.TextConsumer(),
runtime.CSVMime: runtime.CSVConsumer(),
runtime.DefaultMime: runtime.ByteStreamConsumer(),
}
rt.Producers = map[string]runtime.Producer{
runtime.JSONMime: runtime.JSONProducer(),
runtime.XMLMime: runtime.XMLProducer(),
runtime.TextMime: runtime.TextProducer(),
runtime.HTMLMime: runtime.TextProducer(),
runtime.CSVMime: runtime.CSVProducer(),
runtime.DefaultMime: runtime.ByteStreamProducer(),
}
rt.Transport = http.DefaultTransport
Expand Down
45 changes: 44 additions & 1 deletion client/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import (

// task This describes a task. Tasks require a content property to be set.
type task struct {

// Completed
Completed bool `json:"completed" xml:"completed"`

Expand Down Expand Up @@ -366,6 +365,50 @@ func TestRuntime_TextCanary(t *testing.T) {
}
}

func TestRuntime_CSVCanary(t *testing.T) {
// test that it can make a simple csv request
// and get the response for it.
result := `task,content,result
1,task1,ok
2,task2,fail
`
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Add(runtime.HeaderContentType, runtime.CSVMime)
rw.WriteHeader(http.StatusOK)
_, _ = rw.Write([]byte(result))
}))
defer server.Close()

rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
return nil
})

hu, _ := url.Parse(server.URL)
rt := New(hu.Host, "/", []string{"http"})
res, err := rt.Submit(&runtime.ClientOperation{
ID: "getTasks",
Method: "GET",
PathPattern: "/",
Params: rwrtr,
Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
if response.Code() == 200 {
var result bytes.Buffer
if err := consumer.Consume(response.Body(), &result); err != nil {
return nil, err
}
return result, nil
}
return nil, errors.New("Generic error")
}),
})

if assert.NoError(t, err) {
assert.IsType(t, bytes.Buffer{}, res)
actual := res.(bytes.Buffer)
assert.EqualValues(t, result, actual.String())
}
}

type roundTripperFunc func(*http.Request) (*http.Response, error)

func (fn roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
Expand Down
2 changes: 2 additions & 0 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const (
TextMime = "text/plain"
// HTMLMime the html mime type
HTMLMime = "text/html"
// CSVMime the csv mime type
CSVMime = "text/csv"
// MultipartFormMime the multipart form mime type
MultipartFormMime = "multipart/form-data"
// URLencodedFormMime the url encoded form mime type
Expand Down
77 changes: 77 additions & 0 deletions csv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed 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 runtime

import (
"bytes"
"encoding/csv"
"errors"
"io"
)

// CSVConsumer creates a new CSV consumer
func CSVConsumer() Consumer {
return ConsumerFunc(func(reader io.Reader, data interface{}) error {
if reader == nil {
return errors.New("CSVConsumer requires a reader")
}

csvReader := csv.NewReader(reader)
writer, ok := data.(io.Writer)
if !ok {
return errors.New("data type must be io.Writer")
}
csvWriter := csv.NewWriter(writer)
records, err := csvReader.ReadAll()
if err != nil {
return err
}
for _, r := range records {
if err := csvWriter.Write(r); err != nil {
return err
}
}
csvWriter.Flush()
return nil
})
}

// CSVProducer creates a new CSV producer
func CSVProducer() Producer {
return ProducerFunc(func(writer io.Writer, data interface{}) error {
if writer == nil {
return errors.New("CSVProducer requires a writer")
}

dataBytes, ok := data.([]byte)
if !ok {
return errors.New("data type must be byte array")
}

csvReader := csv.NewReader(bytes.NewBuffer(dataBytes))
records, err := csvReader.ReadAll()
if err != nil {
return err
}
csvWriter := csv.NewWriter(writer)
for _, r := range records {
if err := csvWriter.Write(r); err != nil {
return err
}
}
csvWriter.Flush()
return nil
})
}
73 changes: 73 additions & 0 deletions csv_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed 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 runtime

import (
"bytes"
"github.com/stretchr/testify/assert"
"io"
"net/http/httptest"
"testing"
)

const consProdCSV = `name,country,age
John,US,19
Mike,US,20
`

type csvEmptyReader struct{}

func (r *csvEmptyReader) Read(d []byte) (int, error) {
return 0, io.EOF
}

func TestCSVConsumer(t *testing.T) {
cons := CSVConsumer()
reader := bytes.NewBuffer([]byte(consProdCSV))

outBuf := new(bytes.Buffer)
err := cons.Consume(reader, outBuf)
assert.NoError(t, err)
assert.Equal(t, consProdCSV, outBuf.String())

outBuf2 := new(bytes.Buffer)
err = cons.Consume(nil, outBuf2)
assert.Error(t, err)

err = cons.Consume(reader, struct{}{})
assert.Error(t, err)

emptyOutBuf := new(bytes.Buffer)
err = cons.Consume(&csvEmptyReader{}, emptyOutBuf)
assert.NoError(t, err)
assert.Equal(t, "", emptyOutBuf.String())
}

func TestCSVProducer(t *testing.T) {
prod := CSVProducer()
data := []byte(consProdCSV)

rw := httptest.NewRecorder()
err := prod.Produce(rw, data)
assert.NoError(t, err)
assert.Equal(t, consProdCSV, rw.Body.String())

rw2 := httptest.NewRecorder()
err = prod.Produce(rw2, struct{}{})
assert.Error(t, err)

err = prod.Produce(nil, data)
assert.Error(t, err)
}

0 comments on commit 5e1ff77

Please sign in to comment.