Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fakeサーバの初期実装 #11

Merged
merged 1 commit into from
Feb 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions fake/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2022 The sacloud/object-storage-api-go authors
//
// 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 fake

import "fmt"

type ErrorType int

const (
ErrorTypeUnknown ErrorType = iota
ErrorTypeInvalidRequest
ErrorTypeNotFound
ErrorTypeConflict
)

func (e ErrorType) String() string {
switch e {
case ErrorTypeInvalidRequest:
return "invalid request"
case ErrorTypeNotFound:
return "not found"
case ErrorTypeConflict:
return "conflict"
default:
return "unknown error"
}
}

type Error struct {
Type ErrorType
Resource string
Id interface{}
msgFmtAndVars []interface{}
}

func NewError(errorType ErrorType, resource string, id interface{}, msgFmtAndVars ...interface{}) *Error {
return &Error{
Type: errorType,
Resource: resource,
Id: id,
msgFmtAndVars: msgFmtAndVars,
}
}

func (e *Error) Error() string {
return fmt.Errorf("%s: %s[%s]%s", e.Type, e.Resource, e.Id, e.message()).Error()
}

func (e *Error) message() string {
switch len(e.msgFmtAndVars) {
case 0:
return ""
case 1:
return " " + e.msgFmtAndVars[0].(string)
default:
return " " + fmt.Sprintf(e.msgFmtAndVars[0].(string), e.msgFmtAndVars[1:]...)
}
}
108 changes: 108 additions & 0 deletions fake/server/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2022 The sacloud/object-storage-api-go authors
//
// 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 server

import "github.com/gin-gonic/gin"

// DeleteBucket バケットの削除
// (DELETE /fed/v1/buckets/{name})
func (s *Server) DeleteBucket(c *gin.Context, name string) {

}

// CreateBucket バケットの作成
// (PUT /fed/v1/buckets/{name})
func (s *Server) CreateBucket(c *gin.Context, name string) {

}

// ListClusters サイト一覧の取得
// (GET /fed/v1/clusters)
func (s *Server) ListClusters(c *gin.Context) {

}

// ReadCluster サイトの取得
// (GET /fed/v1/clusters/{id})
func (s *Server) ReadCluster(c *gin.Context, id string) {}

// DeleteSiteAccount サイトアカウントの削除
// (DELETE /{site_name}/v2/account)
func (s *Server) DeleteSiteAccount(c *gin.Context, siteName string) {}

// ReadSiteAccount サイトアカウントの取得
// (GET /{site_name}/v2/account)
func (s *Server) ReadSiteAccount(c *gin.Context, siteName string) {}

// CreateSiteAccount サイトアカウントの作成
// (POST /{site_name}/v2/account)
func (s *Server) CreateSiteAccount(c *gin.Context, siteName string) {}

// ListAccountAccessKeys サイトアカウントのアクセスキーの取得
// (GET /{site_name}/v2/account/keys)
func (s *Server) ListAccountAccessKeys(c *gin.Context, siteName string) {}

// CreateAccountAccessKey サイトアカウントのアクセスキーの発行
// (POST /{site_name}/v2/account/keys)
func (s *Server) CreateAccountAccessKey(c *gin.Context, siteName string) {}

// DeleteAccountAccessKey サイトアカウントのアクセスキーの削除
// (DELETE /{site_name}/v2/account/keys/{id})
func (s *Server) DeleteAccountAccessKey(c *gin.Context, siteName string, id string) {}

// ReadAccountAccessKey サイトアカウントのアクセスキーの取得
// (GET /{site_name}/v2/account/keys/{id})
func (s *Server) ReadAccountAccessKey(c *gin.Context, siteName string, id string) {}

// ListPermissions パーミッション一覧の取得
// (GET /{site_name}/v2/permissions)
func (s *Server) ListPermissions(c *gin.Context, siteName string) {}

// CreatePermission パーミッションの作成
// (POST /{site_name}/v2/permissions)
func (s *Server) CreatePermission(c *gin.Context, siteName string) {}

// DeletePermission パーミッションの削除
// (DELETE /{site_name}/v2/permissions/{id})
func (s *Server) DeletePermission(c *gin.Context, siteName string, id string) {}

// ReadPermission パーミッションの取得
// (GET /{site_name}/v2/permissions/{id})
func (s *Server) ReadPermission(c *gin.Context, siteName string, id string) {}

// UpdatePermission パーミッションの更新
// (PUT /{site_name}/v2/permissions/{id})
func (s *Server) UpdatePermission(c *gin.Context, siteName string, id string) {}

// ListPermissionAccessKeys パーミッションが保有するアクセスキー一覧の取得
// (GET /{site_name}/v2/permissions/{id}/keys)
func (s *Server) ListPermissionAccessKeys(c *gin.Context, siteName string, id string) {}

// CreatePermissionAccessKey パーミッションのアクセスキーの発行
// (POST /{site_name}/v2/permissions/{id}/keys)
func (s *Server) CreatePermissionAccessKey(c *gin.Context, siteName string, id string) {}

// DeletePermissionAccessKey パーミッションが保有するアクセスキーの削除
// (DELETE /{site_name}/v2/permissions/{id}/keys/{key_id})
func (s *Server) DeletePermissionAccessKey(c *gin.Context, siteName string, id string, keyId string) {
}

// ReadPermissionAccessKey パーミッションが保有するアクセスキーの取得
// (GET /{site_name}/v2/permissions/{id}/keys/{key_id})
func (s *Server) ReadPermissionAccessKey(c *gin.Context, siteName string, id string, keyId string) {}

// ReadSiteStatus サイトのステータスの取得
// (GET /{site_name}/v2/status)
func (s *Server) ReadSiteStatus(c *gin.Context, siteName string) {}
82 changes: 82 additions & 0 deletions fake/server/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright 2022 The sacloud/object-storage-api-go authors
//
// 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 server

import (
"fmt"
"net/http"
"os"

"github.com/gin-gonic/gin"
v1 "github.com/sacloud/object-storage-api-go/apis/v1"
"github.com/sacloud/object-storage-api-go/fake"
)

var _ v1.ServerInterface = (*Server)(nil)

type Server struct {
}

func (s *Server) Handler() http.Handler {
gin.SetMode(gin.ReleaseMode)
if os.Getenv("OJS_SERVER_DEBUG") != "" {
gin.SetMode(gin.DebugMode)
}
engine := gin.New()
engine.Use(gin.Recovery())
if os.Getenv("OJS_SERVER_LOGGING") != "" {
engine.Use(gin.Logger())
}

engine.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
return v1.RegisterHandlers(engine, s)
}

func (s *Server) handleError(c *gin.Context, err error) { // nolint TODO fake実装を進めた後でnolintを消す
if c == nil || err == nil {
panic("invalid arguments")
}

if engineErr, ok := err.(*fake.Error); ok {
switch engineErr.Type {
case fake.ErrorTypeInvalidRequest:
c.JSON(http.StatusBadRequest, &v1.Error400{
Error: v1.ErrorDetail{
Code: http.StatusBadRequest,
Message: v1.ErrorMessage(engineErr.Error()),
},
})
case fake.ErrorTypeNotFound:
c.JSON(http.StatusNotFound, &v1.Error404{
Error: v1.ErrorDetail{
Code: http.StatusNotFound,
Message: v1.ErrorMessage(engineErr.Error()),
},
})
case fake.ErrorTypeConflict:
c.JSON(http.StatusConflict, &v1.Error409{
Error: v1.ErrorDetail{
Code: http.StatusConflict,
Message: v1.ErrorMessage(engineErr.Error()),
},
})
}
}

// Note: この実装ではfake.Errorで未知のステータスコードについて全てInternalServerErrorとして扱う
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Errorf("unknown error: %s", err)})
}
51 changes: 51 additions & 0 deletions fake/server/server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2022 The sacloud/object-storage-api-go authors
//
// 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 server

import (
"io"
"net/http"
"net/http/httptest"
"os"
"testing"

"github.com/stretchr/testify/require"
)

var (
server = &Server{}
testServer *httptest.Server
)

func TestMain(m *testing.M) {
testServer = httptest.NewServer(server.Handler())
defer testServer.Close()

os.Exit(m.Run())
}

func TestServer_ping(t *testing.T) {
resp, err := http.Get(testServer.URL + "/ping")
if err != nil {
t.Fatal(err)
}

body, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}

require.Equal(t, "pong", string(body))
}
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ go 1.17
require (
github.com/deepmap/oapi-codegen v1.9.1
github.com/gin-gonic/gin v1.7.4
github.com/stretchr/testify v1.7.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
Expand All @@ -18,10 +20,12 @@ require (
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/ugorji/go/codec v1.2.6 // indirect
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)