Skip to content

Commit

Permalink
add support for NAS-specific errors; add more tests
Browse files Browse the repository at this point in the history
Signed-off-by: Rumen Vasilev <git@rumenvasilev.com>
  • Loading branch information
rumenvasilev committed Nov 17, 2023
1 parent 7ce73a0 commit 6241dfb
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 89 deletions.
7 changes: 0 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,5 @@ go 1.21.4

require (
github.com/matryer/is v1.4.1
github.com/stretchr/testify v1.8.4
golang.org/x/crypto v0.15.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
10 changes: 0 additions & 10 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,14 +1,4 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
32 changes: 32 additions & 0 deletions nas/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package nas

import (
"encoding/json"
"fmt"
)

type SystemError struct {
Message string
Data *json.RawMessage
Code int // http response code
}

type FileSystemControllerError struct {
Message string
Path string
Code int // internal NAS response code
}

func (e *SystemError) Error() string {
return e.Message
}

func (e *SystemError) Unwrap() error {
var fse *FileSystemControllerError
_ = json.Unmarshal(*e.Data, &fse)
return fse
}

func (e *FileSystemControllerError) Error() string {
return fmt.Sprintf("Code: %d, Path: %s, Msg: %s", e.Code, e.Path, e.Message)
}
37 changes: 37 additions & 0 deletions nas/errors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package nas

import (
"encoding/json"
"testing"

"github.com/matryer/is"
)

var sampleError = `{
"error": {
"message": "[file_system_controller] The folder with the name \"blabla\" already exists and therefore cannot be created.",
"data": {
"message": "The folder with the name \"blabla\" already exists and therefore cannot be created.",
"path": "/Dokumente",
"code": 5
},
"code": 400
}
}`

var sampleErrorStruct = SystemError{
Message: "[file_system_controller] The folder with the name \"blabla\" already exists and therefore cannot be created.",
Data: nil,
Code: 400,
}

func TestSystemError(t *testing.T) {
var e struct {
Err *SystemError `json:"error"`
}
err := json.Unmarshal([]byte(sampleError), &e)
is := is.New(t)
is.NoErr(err)
is.True(e.Err != nil)
is.Equal(e.Err.Error(), (&sampleErrorStruct).Error())
}
85 changes: 48 additions & 37 deletions nas/nas.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ type NAS struct {
address string
}

func New(s *auth.Session) *NAS {
return &NAS{
session: s,
address: auth.Address,
}
}

func (n *NAS) WithAddress(addr string) *NAS {
n.address = addr
return n
}

type BrowseResponse struct {
DiskInfo DiskInfo
Files []File
Expand Down Expand Up @@ -90,18 +102,6 @@ func (p *Timestamp) UnmarshalJSON(bytes []byte) error {
return nil
}

func New(s *auth.Session) *NAS {
return &NAS{
session: s,
address: auth.Address,
}
}

func (n *NAS) WithAddress(addr string) *NAS {
n.address = addr
return n
}

// ListDirectory would call FRITZ API and return the response structure with results
// or error.
func (n *NAS) ListDirectory(path string) (*BrowseResponse, error) {
Expand Down Expand Up @@ -131,11 +131,7 @@ func (n *NAS) ListDirectory(path string) (*BrowseResponse, error) {
// parse json
var result *BrowseResponse
err = json.Unmarshal(d, &result)
if err != nil {
return nil, err
}

return result, nil
return result, err
}

type CreateDirResponse struct {
Expand Down Expand Up @@ -164,11 +160,7 @@ func (n *NAS) CreateDir(name, path string) (*CreateDirResponse, error) {
// parse json
var result *CreateDirResponse
err = json.Unmarshal(d, &result)
if err != nil {
return nil, err
}

return result, nil
return result, err
}

// GetFile downloads an object from FRITZ NAS storage
Expand Down Expand Up @@ -197,7 +189,16 @@ func (n *NAS) GetFile(path string) (io.ReadCloser, error) {
resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("return status code %d, response: %q", resp.StatusCode, string(d))
// extract the error from the body
var e struct {
Err SystemError `json:"error"`
}
errU := json.Unmarshal(d, &e)
if errU != nil {
return nil, fmt.Errorf("couldn't unmarshal error response, %w", err)
}

return nil, &e.Err
}

return io.NopCloser(bytes.NewReader(d)), nil
Expand Down Expand Up @@ -294,7 +295,16 @@ func (n *NAS) PutFile(path string, data io.Reader) (*PutFileResponse, error) {
resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("return status code %d, response: %q", resp.StatusCode, string(d))
// extract the error from the body
var e struct {
Err SystemError `json:"error"`
}
errU := json.Unmarshal(d, &e)
if errU != nil {
return nil, fmt.Errorf("couldn't unmarshal error response, %w", err)
}

return nil, &e.Err
}

// parse JSON response
Expand Down Expand Up @@ -349,13 +359,9 @@ func (n *NAS) RenameObject(params []*RenameInput) (int, error) {
}

// parse json
var result *RenameResponse
var result RenameResponse
err = json.Unmarshal(d, &result)
if err != nil {
return 0, err
}

return result.RenameCount, nil
return result.RenameCount, err
}

type DeleteResponse struct {
Expand Down Expand Up @@ -387,13 +393,9 @@ func (n *NAS) DeleteObject(paths ...string) (int, error) {
}

// parse json
var result *DeleteResponse
var result DeleteResponse
err = json.Unmarshal(d, &result)
if err != nil {
return 0, err
}

return result.DeleteCount, nil
return result.DeleteCount, err
}

type MoveResponse struct {
Expand Down Expand Up @@ -452,7 +454,16 @@ func execute(ctx context.Context, addr string, p *url.Values) ([]byte, error) {
res.Body.Close()

if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("return status code %d, response: %q", res.StatusCode, string(d))
// extract the error from the body
var e struct {
Err SystemError `json:"error"`
}
errU := json.Unmarshal(d, &e)
if errU != nil {
return nil, fmt.Errorf("couldn't unmarshal error response, %w", err)
}

return nil, &e.Err
}

return d, nil
Expand Down
61 changes: 52 additions & 9 deletions nas/nas_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,73 @@ import (
"encoding/json"
"os"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/matryer/is"
)

func TestUnmarshal(t *testing.T) {
tests := []struct {
name string
path string
name string
path string
want interface{}
wantElement int
}{
{"int", "./testfixtures/nas-browse.json"},
{"float", "./testfixtures/nas-browse-float.json"},
{"int-n-dir", "../testfixtures/nas-browse.json", dirMockResponse, 0},
{"float-n-file", "../testfixtures/nas-browse-float.json", fileMockResponse, 0},
{"jpg", "../testfixtures/nas-browse-float.json", fileImageMockResponse, 1},
}

is := is.New(t)
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
var resp *BrowseResponse
f, err := os.ReadFile(tt.path)
require.NoError(t, err)
is.NoErr(err)
err = json.Unmarshal(f, &resp)
assert.NoError(t, err)
assert.NotNil(t, resp)
is.NoErr(err)
is.True(resp != nil)
if wantFile, ok := tt.want.(File); ok {
is.Equal(resp.Files[tt.wantElement], wantFile)
} else if wantDir, ok := tt.want.(Directory); ok {
is.Equal(resp.Directories[tt.wantElement], wantDir)
}
})
}
}

var dirMockResponse = Directory{
Path: "/Bilder",
Shared: false,
StorageType: "internal_storage",
Type: "directory",
Timestamp: getMockTimestamp(1700007000),
Filename: "Bilder",
}

var fileMockResponse = File{
Path: "/Dokumente/FRITZ-NAS.txt",
Shared: false,
StorageType: "internal_storage",
Type: "document",
Timestamp: getMockTimestamp(1322694000),
Filename: "FRITZ-NAS.txt",
Size: 6640,
}

var fileImageMockResponse = File{
Path: "/Dokumente/FRITZ-Picture.jpg",
Shared: false,
Width: 640,
StorageType: "internal_storage",
Type: "picture",
Height: 400,
Timestamp: getMockTimestamp(1700084400),
Filename: "FRITZ-Picture.jpg",
Size: 30192,
}

func getMockTimestamp(ts int) Timestamp {
return Timestamp{time.Unix(int64(ts), 0)}
}
Loading

0 comments on commit 6241dfb

Please sign in to comment.