storagenode/heldamount: added api for heldamount history separated by periods
Change-Id: I170010364269822848bc6cd051e0e0fb3df95d91
This commit is contained in:
parent
0ae0cea93b
commit
16cd9b06ec
@ -152,6 +152,39 @@ func (heldAmount *HeldAmount) PayStubPeriod(w http.ResponseWriter, r *http.Reque
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HeldbackHistory returns heldback for each % period for specific satellite.
|
||||||
|
func (heldAmount *HeldAmount) HeldbackHistory(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
var err error
|
||||||
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
|
||||||
|
w.Header().Set(contentType, applicationJSON)
|
||||||
|
|
||||||
|
segmentParams := mux.Vars(r)
|
||||||
|
id, ok := segmentParams["id"]
|
||||||
|
if !ok {
|
||||||
|
heldAmount.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
satelliteID, err := storj.NodeIDFromString(id)
|
||||||
|
if err != nil {
|
||||||
|
heldAmount.serveJSONError(w, http.StatusBadRequest, ErrHeldAmountAPI.Wrap(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
heldbackHistory, err := heldAmount.service.AllHeldbackHistory(ctx, satelliteID)
|
||||||
|
if err != nil {
|
||||||
|
heldAmount.serveJSONError(w, http.StatusInternalServerError, ErrHeldAmountAPI.Wrap(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewEncoder(w).Encode(heldbackHistory); err != nil {
|
||||||
|
heldAmount.log.Error("failed to encode json response", zap.Error(ErrHeldAmountAPI.Wrap(err)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// serveJSONError writes JSON error to response output stream.
|
// serveJSONError writes JSON error to response output stream.
|
||||||
func (heldAmount *HeldAmount) serveJSONError(w http.ResponseWriter, status int, err error) {
|
func (heldAmount *HeldAmount) serveJSONError(w http.ResponseWriter, status int, err error) {
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
|
@ -340,6 +340,52 @@ func TestHeldAmountApi(t *testing.T) {
|
|||||||
|
|
||||||
require.Equal(t, "{\"error\":\"heldAmount console web error: wrong period format: period has wrong format\"}\n", string(body5))
|
require.Equal(t, "{\"error\":\"heldAmount console web error: wrong period format: period has wrong format\"}\n", string(body5))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("test HeldbackHistory", func(t *testing.T) {
|
||||||
|
// should return all heldback history inserted earlier
|
||||||
|
url := fmt.Sprintf("%s/heldback/%s", baseURL, satellite.ID().String())
|
||||||
|
res, err := http.Get(url)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, res)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode)
|
||||||
|
|
||||||
|
period75 := heldamount.HeldbackPeriod{
|
||||||
|
PercentageRate: 75,
|
||||||
|
Held: paystub2.Held + paystub3.Held,
|
||||||
|
}
|
||||||
|
|
||||||
|
var periods []heldamount.HeldbackPeriod
|
||||||
|
periods = append(periods, period75)
|
||||||
|
|
||||||
|
expected, err := json.Marshal(periods)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
err = res.Body.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, string(expected)+"\n", string(body))
|
||||||
|
|
||||||
|
// should return 400 because of bad period.
|
||||||
|
url = fmt.Sprintf("%s/heldback/%s", baseURL, satellite.ID().String()+"11")
|
||||||
|
res2, err := http.Get(url)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, res2)
|
||||||
|
require.Equal(t, http.StatusBadRequest, res2.StatusCode)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
err = res2.Body.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
body2, err := ioutil.ReadAll(res2.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, "{\"error\":\"heldAmount console web error: node ID error: checksum error\"}\n", string(body2))
|
||||||
|
})
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,7 @@ func NewServer(logger *zap.Logger, assets http.FileSystem, notifications *notifi
|
|||||||
heldAmountRouter.StrictSlash(true)
|
heldAmountRouter.StrictSlash(true)
|
||||||
heldAmountRouter.HandleFunc("/paystubs/{period}", heldAmountController.PayStubMonthly).Methods(http.MethodGet)
|
heldAmountRouter.HandleFunc("/paystubs/{period}", heldAmountController.PayStubMonthly).Methods(http.MethodGet)
|
||||||
heldAmountRouter.HandleFunc("/paystubs/{start}/{end}", heldAmountController.PayStubPeriod).Methods(http.MethodGet)
|
heldAmountRouter.HandleFunc("/paystubs/{start}/{end}", heldAmountController.PayStubPeriod).Methods(http.MethodGet)
|
||||||
|
heldAmountRouter.HandleFunc("/heldback/{id}", heldAmountController.HeldbackHistory).Methods(http.MethodGet)
|
||||||
|
|
||||||
if assets != nil {
|
if assets != nil {
|
||||||
fs := http.FileServer(assets)
|
fs := http.FileServer(assets)
|
||||||
|
@ -120,6 +120,13 @@ func TestHeldAmountDB(t *testing.T) {
|
|||||||
assert.Equal(t, len(stubs), 0)
|
assert.Equal(t, len(stubs), 0)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Test SatellitesHeldbackHistory", func(t *testing.T) {
|
||||||
|
heldback, err := heldAmount.SatellitesHeldbackHistory(ctx, satelliteID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, heldback[0].Held, paystub.Held)
|
||||||
|
assert.Equal(t, heldback[0].Period, paystub.Period)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,3 +232,58 @@ func TestAllPayStubPeriodCached(t *testing.T) {
|
|||||||
require.Equal(t, 0, len(payStubs))
|
require.Equal(t, 0, len(payStubs))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAllHeldbackHistory(t *testing.T) {
|
||||||
|
storagenodedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db storagenode.DB) {
|
||||||
|
heldAmountDB := db.HeldAmount()
|
||||||
|
service := heldamount.NewService(nil, heldAmountDB, rpc.Dialer{}, nil)
|
||||||
|
|
||||||
|
id := storj.NodeID{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
|
||||||
|
|
||||||
|
payStub := heldamount.PayStub{
|
||||||
|
SatelliteID: id,
|
||||||
|
Created: time.Now().UTC(),
|
||||||
|
Codes: "code",
|
||||||
|
UsageAtRest: 1,
|
||||||
|
UsageGet: 2,
|
||||||
|
UsagePut: 3,
|
||||||
|
UsageGetRepair: 4,
|
||||||
|
UsagePutRepair: 5,
|
||||||
|
UsageGetAudit: 6,
|
||||||
|
CompAtRest: 7,
|
||||||
|
CompGet: 8,
|
||||||
|
CompPut: 9,
|
||||||
|
CompGetRepair: 10,
|
||||||
|
CompPutRepair: 11,
|
||||||
|
CompGetAudit: 12,
|
||||||
|
SurgePercent: 13,
|
||||||
|
Held: 14,
|
||||||
|
Owed: 15,
|
||||||
|
Disposed: 16,
|
||||||
|
Paid: 17,
|
||||||
|
}
|
||||||
|
|
||||||
|
for j := 1; j < 5; j++ {
|
||||||
|
payStub.Period = fmt.Sprintf("2020-0%d", j)
|
||||||
|
err := heldAmountDB.StorePayStub(ctx, payStub)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
heldback, err := service.AllHeldbackHistory(ctx, id)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var expectedResult []heldamount.HeldbackPeriod
|
||||||
|
|
||||||
|
period75 := heldamount.HeldbackPeriod{
|
||||||
|
PercentageRate: 75,
|
||||||
|
Held: payStub.Held * 3,
|
||||||
|
}
|
||||||
|
period50 := heldamount.HeldbackPeriod{
|
||||||
|
PercentageRate: 50,
|
||||||
|
Held: payStub.Held,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedResult = append(expectedResult, period75, period50)
|
||||||
|
require.Equal(t, expectedResult, heldback)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -22,6 +22,8 @@ type DB interface {
|
|||||||
GetPayStub(ctx context.Context, satelliteID storj.NodeID, period string) (*PayStub, error)
|
GetPayStub(ctx context.Context, satelliteID storj.NodeID, period string) (*PayStub, error)
|
||||||
// AllPayStubs retrieves paystub data from all satellites in specific period from DB.
|
// AllPayStubs retrieves paystub data from all satellites in specific period from DB.
|
||||||
AllPayStubs(ctx context.Context, period string) ([]PayStub, error)
|
AllPayStubs(ctx context.Context, period string) ([]PayStub, error)
|
||||||
|
// SatellitesHeldbackHistory retrieves heldback history for specific satellite from DB.
|
||||||
|
SatellitesHeldbackHistory(ctx context.Context, satelliteID storj.NodeID) ([]Heldback, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrNoPayStubForPeriod represents errors from the heldamount database.
|
// ErrNoPayStubForPeriod represents errors from the heldamount database.
|
||||||
@ -51,3 +53,9 @@ type PayStub struct {
|
|||||||
Disposed int64 `json:"disposed"`
|
Disposed int64 `json:"disposed"`
|
||||||
Paid int64 `json:"paid"`
|
Paid int64 `json:"paid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Heldback is node's heldback amount for period.
|
||||||
|
type Heldback struct {
|
||||||
|
Period string `json:"period"`
|
||||||
|
Held int64 `json:"held"`
|
||||||
|
}
|
||||||
|
@ -239,6 +239,67 @@ func (service *Service) AllPayStubsPeriodCached(ctx context.Context, periodStart
|
|||||||
return payStubs, nil
|
return payStubs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HeldbackPeriod amount of held for specific percent rate period.
|
||||||
|
type HeldbackPeriod struct {
|
||||||
|
PercentageRate int
|
||||||
|
Held int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllHeldbackHistory retrieves heldback history for all specific satellite from storagenode database.
|
||||||
|
func (service *Service) AllHeldbackHistory(ctx context.Context, id storj.NodeID) (result []HeldbackPeriod, err error) {
|
||||||
|
defer mon.Task()(&ctx, &id)(&err)
|
||||||
|
|
||||||
|
heldback, err := service.db.SatellitesHeldbackHistory(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrHeldAmountService.Wrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var total75, total50, total25, total0 int64
|
||||||
|
|
||||||
|
for i, t := range heldback {
|
||||||
|
switch i {
|
||||||
|
case 0, 1, 2:
|
||||||
|
total75 += t.Held
|
||||||
|
case 3, 4, 5:
|
||||||
|
total50 += t.Held
|
||||||
|
case 6, 7, 8:
|
||||||
|
total25 += t.Held
|
||||||
|
default:
|
||||||
|
total0 += t.Held
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
period75percent := HeldbackPeriod{
|
||||||
|
PercentageRate: 75,
|
||||||
|
Held: total75,
|
||||||
|
}
|
||||||
|
period50percent := HeldbackPeriod{
|
||||||
|
PercentageRate: 50,
|
||||||
|
Held: total50,
|
||||||
|
}
|
||||||
|
period25percent := HeldbackPeriod{
|
||||||
|
PercentageRate: 25,
|
||||||
|
Held: total25,
|
||||||
|
}
|
||||||
|
period0percent := HeldbackPeriod{
|
||||||
|
PercentageRate: 0,
|
||||||
|
Held: total0,
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, period75percent)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case len(heldback) > 3:
|
||||||
|
result = append(result, period50percent)
|
||||||
|
case len(heldback) > 6:
|
||||||
|
result = append(result, period25percent)
|
||||||
|
case len(heldback) > 9:
|
||||||
|
result = append(result, period0percent)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// dial dials the HeldAmount client for the satellite by id
|
// dial dials the HeldAmount client for the satellite by id
|
||||||
func (service *Service) dial(ctx context.Context, satelliteID storj.NodeID) (_ *Client, err error) {
|
func (service *Service) dial(ctx context.Context, satelliteID storj.NodeID) (_ *Client, err error) {
|
||||||
defer mon.Task()(&ctx)(&err)
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
@ -218,3 +218,37 @@ func (db *heldamountDB) AllPayStubs(ctx context.Context, period string) (_ []hel
|
|||||||
|
|
||||||
return paystubList, nil
|
return paystubList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SatellitesHeldbackHistory retrieves heldback history for specific satellite.
|
||||||
|
func (db *heldamountDB) SatellitesHeldbackHistory(ctx context.Context, id storj.NodeID) (_ []heldamount.Heldback, err error) {
|
||||||
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
|
||||||
|
query := `SELECT
|
||||||
|
period,
|
||||||
|
held
|
||||||
|
FROM paystubs WHERE satellite_id = ? ORDER BY period ASC`
|
||||||
|
|
||||||
|
rows, err := db.QueryContext(ctx, query, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() { err = errs.Combine(err, rows.Close()) }()
|
||||||
|
|
||||||
|
var heldback []heldamount.Heldback
|
||||||
|
for rows.Next() {
|
||||||
|
var held heldamount.Heldback
|
||||||
|
|
||||||
|
err := rows.Scan(&held.Period, &held.Held)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrHeldAmount.Wrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
heldback = append(heldback, held)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return nil, ErrHeldAmount.Wrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return heldback, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user