From a2a32973ff59836a2ffbcd975bddb0232f68cce4 Mon Sep 17 00:00:00 2001 From: daz-3ux Date: Wed, 11 Oct 2023 16:14:12 +0800 Subject: [PATCH] test: add test for User in Biz Signed-off-by: daz-3ux --- go.mod | 13 +- go.sum | 28 +- internal/dazBlog/biz/biz.go | 2 + internal/dazBlog/biz/mock_biz.go | 64 + internal/dazBlog/biz/post/mock_post.go | 123 ++ internal/dazBlog/biz/post/post.go | 2 + internal/dazBlog/biz/user/mock_user.go | 137 ++ internal/dazBlog/biz/user/user.go | 244 +-- internal/dazBlog/biz/user/user_test.go | 365 +++++ internal/dazBlog/store/helper_test.go | 27 + internal/dazBlog/store/mock_store.go | 271 ++++ internal/dazBlog/store/store.go | 2 + pkg/api/dazBlog/v1/user.go | 50 +- pkg/util/id/cpu.profile | Bin 0 -> 8042 bytes pkg/util/id/id_test.go | 38 + pkg/util/id/profile001.svg | 2071 ++++++++++++++++++++++++ 16 files changed, 3281 insertions(+), 156 deletions(-) create mode 100644 internal/dazBlog/biz/mock_biz.go create mode 100644 internal/dazBlog/biz/post/mock_post.go create mode 100644 internal/dazBlog/biz/user/mock_user.go create mode 100644 internal/dazBlog/biz/user/user_test.go create mode 100644 internal/dazBlog/store/helper_test.go create mode 100644 internal/dazBlog/store/mock_store.go create mode 100644 pkg/util/id/cpu.profile create mode 100644 pkg/util/id/id_test.go create mode 100644 pkg/util/id/profile001.svg diff --git a/go.mod b/go.mod index 63aba09..4b07cdc 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,13 @@ module github.com/Daz-3ux/dBlog go 1.21.0 require ( + github.com/AlekSi/pointer v1.2.0 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/casbin/casbin/v2 v2.77.2 github.com/casbin/gorm-adapter/v3 v3.20.0 github.com/gin-gonic/gin v1.9.1 github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/golang/mock v1.6.0 github.com/google/uuid v1.3.0 github.com/gosuri/uitable v0.0.4 github.com/jasonsoft/go-short-id v0.0.0-20180410073244-6ed30cc4305d @@ -15,9 +17,10 @@ require ( github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.16.0 + github.com/stretchr/testify v1.8.3 go.uber.org/automaxprocs v1.5.3 go.uber.org/zap v1.25.0 - golang.org/x/crypto v0.12.0 + golang.org/x/crypto v0.14.0 google.golang.org/grpc v1.55.0 google.golang.org/protobuf v1.30.0 gorm.io/driver/mysql v1.5.1 @@ -28,6 +31,7 @@ require ( github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fatih/color v1.13.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect @@ -70,6 +74,7 @@ require ( github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/gomega v1.28.0 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/spf13/afero v1.9.5 // indirect @@ -83,9 +88,9 @@ require ( github.com/ugorji/go/codec v1.2.11 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/net v0.14.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/net v0.16.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 6518694..1e9d6cf 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w= +github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= @@ -151,8 +153,9 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -414,6 +417,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -457,8 +461,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -492,6 +496,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -527,10 +532,11 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -550,6 +556,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -595,8 +602,10 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -606,8 +615,8 @@ golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -619,8 +628,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -677,6 +686,7 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/dazBlog/biz/biz.go b/internal/dazBlog/biz/biz.go index 9f29f70..295bc62 100644 --- a/internal/dazBlog/biz/biz.go +++ b/internal/dazBlog/biz/biz.go @@ -5,6 +5,8 @@ package biz +//go:generate mockgen -destination mock_biz.go -package biz github.com/Daz-3ux/dBlog/internal/dazBlog/biz IBiz + import ( "github.com/Daz-3ux/dBlog/internal/dazBlog/biz/post" "github.com/Daz-3ux/dBlog/internal/dazBlog/biz/user" diff --git a/internal/dazBlog/biz/mock_biz.go b/internal/dazBlog/biz/mock_biz.go new file mode 100644 index 0000000..b7d685c --- /dev/null +++ b/internal/dazBlog/biz/mock_biz.go @@ -0,0 +1,64 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/Daz-3ux/dBlog/internal/dazBlog/biz (interfaces: IBiz) + +// Package biz is a generated GoMock package. +package biz + +import ( + reflect "reflect" + + post "github.com/Daz-3ux/dBlog/internal/dazBlog/biz/post" + user "github.com/Daz-3ux/dBlog/internal/dazBlog/biz/user" + gomock "github.com/golang/mock/gomock" +) + +// MockIBiz is a mock of IBiz interface. +type MockIBiz struct { + ctrl *gomock.Controller + recorder *MockIBizMockRecorder +} + +// MockIBizMockRecorder is the mock recorder for MockIBiz. +type MockIBizMockRecorder struct { + mock *MockIBiz +} + +// NewMockIBiz creates a new mock instance. +func NewMockIBiz(ctrl *gomock.Controller) *MockIBiz { + mock := &MockIBiz{ctrl: ctrl} + mock.recorder = &MockIBizMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockIBiz) EXPECT() *MockIBizMockRecorder { + return m.recorder +} + +// Posts mocks base method. +func (m *MockIBiz) Posts() post.PostBiz { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Posts") + ret0, _ := ret[0].(post.PostBiz) + return ret0 +} + +// Posts indicates an expected call of Posts. +func (mr *MockIBizMockRecorder) Posts() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Posts", reflect.TypeOf((*MockIBiz)(nil).Posts)) +} + +// Users mocks base method. +func (m *MockIBiz) Users() user.UserBiz { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Users") + ret0, _ := ret[0].(user.UserBiz) + return ret0 +} + +// Users indicates an expected call of Users. +func (mr *MockIBizMockRecorder) Users() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Users", reflect.TypeOf((*MockIBiz)(nil).Users)) +} diff --git a/internal/dazBlog/biz/post/mock_post.go b/internal/dazBlog/biz/post/mock_post.go new file mode 100644 index 0000000..a65d375 --- /dev/null +++ b/internal/dazBlog/biz/post/mock_post.go @@ -0,0 +1,123 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/Daz-3ux/dBlog/internal/dazBlog/biz/post (interfaces: PostBiz) + +// Package post is a generated GoMock package. +package post + +import ( + context "context" + reflect "reflect" + + v1 "github.com/Daz-3ux/dBlog/pkg/api/dazBlog/v1" + gomock "github.com/golang/mock/gomock" +) + +// MockPostBiz is a mock of PostBiz interface. +type MockPostBiz struct { + ctrl *gomock.Controller + recorder *MockPostBizMockRecorder +} + +// MockPostBizMockRecorder is the mock recorder for MockPostBiz. +type MockPostBizMockRecorder struct { + mock *MockPostBiz +} + +// NewMockPostBiz creates a new mock instance. +func NewMockPostBiz(ctrl *gomock.Controller) *MockPostBiz { + mock := &MockPostBiz{ctrl: ctrl} + mock.recorder = &MockPostBizMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockPostBiz) EXPECT() *MockPostBizMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockPostBiz) Create(arg0 context.Context, arg1 string, arg2 *v1.CreatePostRequest) (*v1.CreatePostResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", arg0, arg1, arg2) + ret0, _ := ret[0].(*v1.CreatePostResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Create indicates an expected call of Create. +func (mr *MockPostBizMockRecorder) Create(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockPostBiz)(nil).Create), arg0, arg1, arg2) +} + +// Delete mocks base method. +func (m *MockPostBiz) Delete(arg0 context.Context, arg1, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockPostBizMockRecorder) Delete(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockPostBiz)(nil).Delete), arg0, arg1, arg2) +} + +// DeleteCollection mocks base method. +func (m *MockPostBiz) DeleteCollection(arg0 context.Context, arg1 string, arg2 []string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteCollection", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteCollection indicates an expected call of DeleteCollection. +func (mr *MockPostBizMockRecorder) DeleteCollection(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteCollection", reflect.TypeOf((*MockPostBiz)(nil).DeleteCollection), arg0, arg1, arg2) +} + +// Get mocks base method. +func (m *MockPostBiz) Get(arg0 context.Context, arg1, arg2 string) (*v1.GetPostResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0, arg1, arg2) + ret0, _ := ret[0].(*v1.GetPostResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockPostBizMockRecorder) Get(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockPostBiz)(nil).Get), arg0, arg1, arg2) +} + +// List mocks base method. +func (m *MockPostBiz) List(arg0 context.Context, arg1 string, arg2, arg3 int) (*v1.ListPostsResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "List", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*v1.ListPostsResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// List indicates an expected call of List. +func (mr *MockPostBizMockRecorder) List(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockPostBiz)(nil).List), arg0, arg1, arg2, arg3) +} + +// Update mocks base method. +func (m *MockPostBiz) Update(arg0 context.Context, arg1, arg2 string, arg3 *v1.UpdatePostRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(error) + return ret0 +} + +// Update indicates an expected call of Update. +func (mr *MockPostBizMockRecorder) Update(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockPostBiz)(nil).Update), arg0, arg1, arg2, arg3) +} diff --git a/internal/dazBlog/biz/post/post.go b/internal/dazBlog/biz/post/post.go index 988162d..f1461cc 100644 --- a/internal/dazBlog/biz/post/post.go +++ b/internal/dazBlog/biz/post/post.go @@ -5,6 +5,8 @@ package post +//go:generate mockgen -destination mock_post.go -package post github.com/Daz-3ux/dBlog/internal/dazBlog/biz/post PostBiz + import ( "context" "errors" diff --git a/internal/dazBlog/biz/user/mock_user.go b/internal/dazBlog/biz/user/mock_user.go new file mode 100644 index 0000000..f6299ba --- /dev/null +++ b/internal/dazBlog/biz/user/mock_user.go @@ -0,0 +1,137 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/Daz-3ux/dBlog/internal/dazBlog/biz/user (interfaces: UserBiz) + +// Package user is a generated GoMock package. +package user + +import ( + context "context" + reflect "reflect" + + v1 "github.com/Daz-3ux/dBlog/pkg/api/dazBlog/v1" + gomock "github.com/golang/mock/gomock" +) + +// MockUserBiz is a mock of UserBiz interface. +type MockUserBiz struct { + ctrl *gomock.Controller + recorder *MockUserBizMockRecorder +} + +// MockUserBizMockRecorder is the mock recorder for MockUserBiz. +type MockUserBizMockRecorder struct { + mock *MockUserBiz +} + +// NewMockUserBiz creates a new mock instance. +func NewMockUserBiz(ctrl *gomock.Controller) *MockUserBiz { + mock := &MockUserBiz{ctrl: ctrl} + mock.recorder = &MockUserBizMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockUserBiz) EXPECT() *MockUserBizMockRecorder { + return m.recorder +} + +// ChangePassword mocks base method. +func (m *MockUserBiz) ChangePassword(arg0 context.Context, arg1 string, arg2 *v1.ChangePasswordRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChangePassword", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// ChangePassword indicates an expected call of ChangePassword. +func (mr *MockUserBizMockRecorder) ChangePassword(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangePassword", reflect.TypeOf((*MockUserBiz)(nil).ChangePassword), arg0, arg1, arg2) +} + +// Create mocks base method. +func (m *MockUserBiz) Create(arg0 context.Context, arg1 *v1.CreateUserRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockUserBizMockRecorder) Create(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockUserBiz)(nil).Create), arg0, arg1) +} + +// Delete mocks base method. +func (m *MockUserBiz) Delete(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockUserBizMockRecorder) Delete(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockUserBiz)(nil).Delete), arg0, arg1) +} + +// Get mocks base method. +func (m *MockUserBiz) Get(arg0 context.Context, arg1 string) (*v1.GetUserResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0, arg1) + ret0, _ := ret[0].(*v1.GetUserResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockUserBizMockRecorder) Get(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockUserBiz)(nil).Get), arg0, arg1) +} + +// List mocks base method. +func (m *MockUserBiz) List(arg0 context.Context, arg1, arg2 int) (*v1.ListUserResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "List", arg0, arg1, arg2) + ret0, _ := ret[0].(*v1.ListUserResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// List indicates an expected call of List. +func (mr *MockUserBizMockRecorder) List(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockUserBiz)(nil).List), arg0, arg1, arg2) +} + +// Login mocks base method. +func (m *MockUserBiz) Login(arg0 context.Context, arg1 *v1.LoginRequest) (*v1.LoginResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Login", arg0, arg1) + ret0, _ := ret[0].(*v1.LoginResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Login indicates an expected call of Login. +func (mr *MockUserBizMockRecorder) Login(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Login", reflect.TypeOf((*MockUserBiz)(nil).Login), arg0, arg1) +} + +// Update mocks base method. +func (m *MockUserBiz) Update(arg0 context.Context, arg1 string, arg2 *v1.UpdateUserRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// Update indicates an expected call of Update. +func (mr *MockUserBizMockRecorder) Update(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockUserBiz)(nil).Update), arg0, arg1, arg2) +} diff --git a/internal/dazBlog/biz/user/user.go b/internal/dazBlog/biz/user/user.go index bdc6682..309a48f 100644 --- a/internal/dazBlog/biz/user/user.go +++ b/internal/dazBlog/biz/user/user.go @@ -5,36 +5,38 @@ package user +//go:generate mockgen -destination mock_user.go -package user github.com/Daz-3ux/dBlog/internal/dazBlog/biz/user UserBiz + import ( - "context" - "errors" - "github.com/Daz-3ux/dBlog/internal/dazBlog/store" - "github.com/Daz-3ux/dBlog/internal/pkg/errno" - "github.com/Daz-3ux/dBlog/internal/pkg/log" - "github.com/Daz-3ux/dBlog/internal/pkg/model" - v1 "github.com/Daz-3ux/dBlog/pkg/api/dazBlog/v1" - "github.com/Daz-3ux/dBlog/pkg/auth" - "github.com/Daz-3ux/dBlog/pkg/token" - "github.com/jinzhu/copier" - "gorm.io/gorm" - "regexp" + "context" + "errors" + "github.com/Daz-3ux/dBlog/internal/dazBlog/store" + "github.com/Daz-3ux/dBlog/internal/pkg/errno" + "github.com/Daz-3ux/dBlog/internal/pkg/log" + "github.com/Daz-3ux/dBlog/internal/pkg/model" + v1 "github.com/Daz-3ux/dBlog/pkg/api/dazBlog/v1" + "github.com/Daz-3ux/dBlog/pkg/auth" + "github.com/Daz-3ux/dBlog/pkg/token" + "github.com/jinzhu/copier" + "gorm.io/gorm" + "regexp" ) // UserBiz defines the methods implemented in the user module at the biz layer // implement the specific implementations of the REST resources for the user type UserBiz interface { - Create(ctx context.Context, r *v1.CreateUserRequest) error - Get(ctx context.Context, id string) (*v1.GetUserResponse, error) - List(ctx context.Context, offset, limit int) (*v1.ListUserResponse, error) - Update(ctx context.Context, username string, r *v1.UpdateUserRequest) error - Delete(ctx context.Context, username string) error - ChangePassword(ctx context.Context, username string, r *v1.ChangePasswordRequest) error - Login(ctx context.Context, r *v1.LoginRequest) (*v1.LoginResponse, error) + Create(ctx context.Context, r *v1.CreateUserRequest) error + Get(ctx context.Context, id string) (*v1.GetUserResponse, error) + List(ctx context.Context, offset, limit int) (*v1.ListUserResponse, error) + Update(ctx context.Context, username string, r *v1.UpdateUserRequest) error + Delete(ctx context.Context, username string) error + ChangePassword(ctx context.Context, username string, r *v1.ChangePasswordRequest) error + Login(ctx context.Context, r *v1.LoginRequest) (*v1.LoginResponse, error) } // userBiz implements the UserBiz interface type userBiz struct { - ds store.IStore + ds store.IStore } // ensure that userBiz implements the UserBiz interface @@ -42,140 +44,146 @@ var _ UserBiz = (*userBiz)(nil) // NewUserBiz create an instance of type UserBiz func NewUserBiz(ds store.IStore) UserBiz { - return &userBiz{ds: ds} + return &userBiz{ds: ds} } // Create is the implementation of the `Create` method of the UserBiz interface func (b *userBiz) Create(ctx context.Context, r *v1.CreateUserRequest) error { - var userM model.UserM - _ = copier.Copy(&userM, r) + var userM model.UserM + _ = copier.Copy(&userM, r) - if err := b.ds.Users().Create(ctx, &userM); err != nil { - if match, _ := regexp.MatchString("Duplicate entry '.*' for key 'username'", err.Error()); match { - return errno.ErrUserAlreadyExist - } + if err := b.ds.Users().Create(ctx, &userM); err != nil { + if match, _ := regexp.MatchString("Duplicate entry '.*' for key 'username'", err.Error()); match { + return errno.ErrUserAlreadyExist + } - return err - } + return err + } - return nil + return nil } // Get is the implementation of the `Get` method in the UserBiz interface func (b *userBiz) Get(ctx context.Context, id string) (*v1.GetUserResponse, error) { - user, err := b.ds.Users().Get(ctx, id) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, errno.ErrUserNotFound - } + user, err := b.ds.Users().Get(ctx, id) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, errno.ErrUserNotFound + } - return nil, err - } + return nil, err + } - var resp v1.GetUserResponse - _ = copier.Copy(&resp, user) + var resp v1.GetUserResponse + _ = copier.Copy(&resp, user) - resp.CreatedAt = user.CreatedAt.Format("2006-01-02 15:04:05") - resp.UpdatedAt = user.UpdatedAt.Format("2006-01-02 15:04:05") + resp.CreatedAt = user.CreatedAt.Format("2006-01-02 15:04:05") + resp.UpdatedAt = user.UpdatedAt.Format("2006-01-02 15:04:05") - return &resp, nil + return &resp, nil } // List is the implementation of the `List` method of the UserBiz interface func (b *userBiz) List(ctx context.Context, offset, limit int) (*v1.ListUserResponse, error) { - count, list, err := b.ds.Users().List(ctx, offset, limit) - if err != nil { - log.C(ctx).Errorw("failed to list users from storage", "err", err) - return nil, err - } - - users := make([]*v1.UserInfo, 0, len(list)) - for _, user := range list { - users = append(users, &v1.UserInfo{ - Username: user.Username, - Nickname: user.Nickname, - Email: user.Email, - Phone: user.Phone, - PostCount: user.PostCount, - CreatedAt: user.CreatedAt.Format("2006-01-02 15:04:05"), - UpdatedAt: user.UpdatedAt.Format("2006-01-02 15:04:05"), - }) - } - - log.C(ctx).Debugw("Get users from storage", "count", count) - - return &v1.ListUserResponse{TotalCount: count, Users: users}, nil + count, list, err := b.ds.Users().List(ctx, offset, limit) + if err != nil { + log.C(ctx).Errorw("failed to list users from storage", "err", err) + return nil, err + } + + users := make([]*v1.UserInfo, 0, len(list)) + for _, user := range list { + count, _, err := b.ds.Posts().List(ctx, user.Username, 0, 0) + if err != nil { + log.C(ctx).Errorw("Failed to list posts", "err", err) + return nil, err + } + + users = append(users, &v1.UserInfo{ + Username: user.Username, + Nickname: user.Nickname, + Email: user.Email, + Phone: user.Phone, + PostCount: count, + CreatedAt: user.CreatedAt.Format("2006-01-02 15:04:05"), + UpdatedAt: user.UpdatedAt.Format("2006-01-02 15:04:05"), + }) + } + + log.C(ctx).Debugw("Get users from storage", "count", count) + + return &v1.ListUserResponse{TotalCount: count, Users: users}, nil } // Update is the implementation of the `Update` method of the UserBiz interface func (b *userBiz) Update(ctx context.Context, username string, user *v1.UpdateUserRequest) error { - userM, err := b.ds.Users().Get(ctx, username) - if err != nil { - return err - } - - if user.Email != "" { - userM.Email = user.Email - } - if user.Nickname != "" { - userM.Nickname = user.Nickname - } - if user.Phone != "" { - userM.Phone = user.Phone - } - - if err := b.ds.Users().Update(ctx, userM); err != nil { - return err - } - - return nil + userM, err := b.ds.Users().Get(ctx, username) + if err != nil { + return err + } + + if *user.Email != "" { + userM.Email = *user.Email + } + if *user.Nickname != "" { + userM.Nickname = *user.Nickname + } + if *user.Phone != "" { + userM.Phone = *user.Phone + } + + if err := b.ds.Users().Update(ctx, userM); err != nil { + return err + } + + return nil } func (b *userBiz) Delete(ctx context.Context, username string) error { - if err := b.ds.Users().Delete(ctx, username); err != nil { - return err - } + if err := b.ds.Users().Delete(ctx, username); err != nil { + return err + } - return nil + return nil } // ChangePassword is the implementation of the `ChangePassword` method of the UserBiz interface func (b *userBiz) ChangePassword(ctx context.Context, username string, r *v1.ChangePasswordRequest) error { - userM, err := b.ds.Users().Get(ctx, username) - if err != nil { - return err - } + userM, err := b.ds.Users().Get(ctx, username) + if err != nil { + return err + } - if err := auth.Compare(userM.Password, r.OldPassword); err != nil { - return errno.ErrPasswordIncorrect - } + if err := auth.Compare(userM.Password, r.OldPassword); err != nil { + return errno.ErrPasswordIncorrect + } - userM.Password, _ = auth.Encrypt(r.NewPassword) - if err := b.ds.Users().Update(ctx, userM); err != nil { - return err - } + userM.Password, _ = auth.Encrypt(r.NewPassword) + if err := b.ds.Users().Update(ctx, userM); err != nil { + return err + } - return nil + return nil } // Login is the implementation of the `Login` method of the UserBiz interface func (b *userBiz) Login(ctx context.Context, r *v1.LoginRequest) (*v1.LoginResponse, error) { - // get all infos of the logged-in user - user, err := b.ds.Users().Get(ctx, r.Username) - if err != nil { - return nil, errno.ErrUserNotFound - } - - // compare the password - if err := auth.Compare(user.Password, r.Password); err != nil { - return nil, errno.ErrPasswordIncorrect - } - - // if the password is correct, generate a JWT token - t, err := token.Sign(r.Username) - if err != nil { - return nil, errno.ErrSignToken - } - - return &v1.LoginResponse{Token: t}, nil + // get all infos of the logged-in user + user, err := b.ds.Users().Get(ctx, r.Username) + if err != nil { + return nil, errno.ErrUserNotFound + } + + // compare the password + if err := auth.Compare(user.Password, r.Password); err != nil { + return nil, errno.ErrPasswordIncorrect + } + + // if the password is correct, generate a JWT token + t, err := token.Sign(r.Username) + if err != nil { + return nil, errno.ErrSignToken + } + + return &v1.LoginResponse{Token: t}, nil } diff --git a/internal/dazBlog/biz/user/user_test.go b/internal/dazBlog/biz/user/user_test.go new file mode 100644 index 0000000..c0f9d16 --- /dev/null +++ b/internal/dazBlog/biz/user/user_test.go @@ -0,0 +1,365 @@ +package user + +import ( + "context" + "fmt" + "github.com/AlekSi/pointer" + "github.com/Daz-3ux/dBlog/internal/dazBlog/store" + "github.com/Daz-3ux/dBlog/internal/pkg/errno" + "github.com/Daz-3ux/dBlog/internal/pkg/model" + v1 "github.com/Daz-3ux/dBlog/pkg/api/dazBlog/v1" + "github.com/golang/mock/gomock" + "github.com/jinzhu/copier" + "github.com/stretchr/testify/assert" + "testing" + "time" +) + +func fakeUser(id int64) *model.UserM { + return &model.UserM{ + ID: id, + PostCount: 10, + Username: fmt.Sprintf("daz%d", id), + Password: fmt.Sprintf("daz%d", id), + Nickname: fmt.Sprintf("daz%d", id), + Email: "daz@qq.com", + Phone: "18139238989", + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } +} + +// Test_NewUserBiz tests the NewUserBiz function +func Test_NewUserBiz(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // mock an interface -- IStore, which is required by NewUserBiz + mockStore := store.NewMockIStore(ctrl) + + type args struct { + ds store.IStore + } + tests := []struct { + name string + args args + want *userBiz + }{ + {name: "default", args: args{mockStore}, want: &userBiz{mockStore}}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := NewUserBiz(tt.args.ds) + assert.Equal(t, tt.want, got) + }) + } +} + +// TestUserBiz_Create tests the Create method of the UserBiz interface +func TestUserBiz_Create(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // create a mockUserStore and specify the expected behavior + // When the Create method is called, it returns nil + mockUserStore := store.NewMockUserStore(ctrl) + mockUserStore.EXPECT().Create(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + + // create a mockStore and specify the expected behavior + // When the Users method is called, it returns the mockUserStore + mockStore := store.NewMockIStore(ctrl) + mockStore.EXPECT().Users().Return(mockUserStore).AnyTimes() + + type fields struct { + ds store.IStore + } + type args struct { + ctx context.Context + r *v1.CreateUserRequest + } + tests := []struct { + name string + fields fields + args args + }{ + {name: "default", fields: fields{mockStore}, args: args{context.Background(), nil}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &userBiz{ + ds: tt.fields.ds, + } + /* + 当调用 b.Create 方法时, 它会间接地调用 mockStore.Users().Create 方法 + 因为我们已经设置了 mockStore.Users() 的预期行为并返回 mockUserStore + 所以实际上调用的是 mockUserStore.Create 方法,返回 nil (预期行为) + */ + assert.Nil(t, b.Create(tt.args.ctx, tt.args.r)) + }) + } +} + +// TestUserBiz_Get tests the Get method of the UserBiz interface +func TestUserBiz_Get(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + fakeUser := fakeUser(1) + mockUserStore := store.NewMockUserStore(ctrl) + mockUserStore.EXPECT().Get(gomock.Any(), gomock.Any()).Return(fakeUser, nil).AnyTimes() + + mockStore := store.NewMockIStore(ctrl) + mockStore.EXPECT().Users().Return(mockUserStore).AnyTimes() + + var want v1.GetUserResponse + _ = copier.Copy(&want, fakeUser) + want.CreatedAt = fakeUser.CreatedAt.Format("2006-01-02 15:04:05") + want.UpdatedAt = fakeUser.UpdatedAt.Format("2006-01-02 15:04:05") + + type fields struct { + ds store.IStore + } + type args struct { + ctx context.Context + username string + } + tests := []struct { + name string + fields fields + args args + want *v1.GetUserResponse + }{ + {name: "default", fields: fields{mockStore}, args: args{context.Background(), "daz1"}, want: &want}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &userBiz{ + ds: tt.fields.ds, + } + got, err := b.Get(tt.args.ctx, tt.args.username) + assert.Nil(t, err) + assert.Equal(t, tt.want, got) + }) + } +} + +// TestUserBiz_List tests the List method of the UserBiz interface +func TestUserBiz_List(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + fakeUsers := []*model.UserM{fakeUser(1), fakeUser(2), fakeUser(3)} + wantUsers := make([]*v1.UserInfo, 0, len(fakeUsers)) + for _, u := range fakeUsers { + wantUsers = append(wantUsers, &v1.UserInfo{ + Username: u.Username, + Nickname: u.Nickname, + Email: u.Email, + Phone: u.Phone, + PostCount: 10, + CreatedAt: u.CreatedAt.Format("2006-01-02 15:04:05"), + UpdatedAt: u.UpdatedAt.Format("2006-01-02 15:04:05"), + }) + } + + mockUserStore := store.NewMockUserStore(ctrl) + mockUserStore.EXPECT().List(gomock.Any(), gomock.Any(), gomock.Any()).Return(int64(5), fakeUsers, nil).Times(1) + + mockPostStore := store.NewMockPostStore(ctrl) + mockPostStore.EXPECT().List(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(int64(10), nil, nil).AnyTimes() + + mockStore := store.NewMockIStore(ctrl) + mockStore.EXPECT().Users().Return(mockUserStore).Times(1) + mockStore.EXPECT().Posts().Return(mockPostStore).AnyTimes() + + tests := []struct { + name string + want *v1.ListUserResponse + wantErr bool + }{ + {name: "default", want: &v1.ListUserResponse{TotalCount: 5, Users: wantUsers}, wantErr: false}, + } + + ub := NewUserBiz(mockStore) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ub.List(context.Background(), 0, 10) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.want, got) + }) + } +} + +// TestUserBiz_Update tests the Update method of the UserBiz interface +func TestUserBiz_Update(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + fakeUser := fakeUser(1) + r := &v1.UpdateUserRequest{ + Nickname: pointer.ToString("ddaazz"), + Email: pointer.ToString("qq@daz.com"), + Phone: pointer.ToString("12312312312"), + } + wantedUser := *fakeUser + wantedUser.Nickname = *r.Nickname + wantedUser.Email = *r.Email + wantedUser.Phone = *r.Phone + + mockUserStore := store.NewMockUserStore(ctrl) + mockUserStore.EXPECT().Get(gomock.Any(), gomock.Any()).Return(fakeUser, nil).AnyTimes() + // if update successfully, return nil + mockUserStore.EXPECT().Update(gomock.Any(), &wantedUser).Return(nil).AnyTimes() + + mockStore := store.NewMockIStore(ctrl) + mockStore.EXPECT().Users().Return(mockUserStore).AnyTimes() + + type fields struct { + ds store.IStore + } + type args struct { + ctx context.Context + username string + user *v1.UpdateUserRequest + } + tests := []struct { + name string + fields fields + args args + }{ + {name: "default", fields: fields{mockStore}, args: args{context.Background(), "daz1", r}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &userBiz{ + ds: tt.fields.ds, + } + err := b.Update(tt.args.ctx, tt.args.username, tt.args.user) + assert.Nil(t, err) + }) + } +} + +// TestUserBiz_ChangePassword tests the ChangePassword method of the UserBiz interface +func TestUserBiz_Delete(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockUserStore := store.NewMockUserStore(ctrl) + mockUserStore.EXPECT().Delete(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + + mockStore := store.NewMockIStore(ctrl) + mockStore.EXPECT().Users().Return(mockUserStore).AnyTimes() + + type fields struct { + ds store.IStore + } + type args struct { + ctx context.Context + username string + } + tests := []struct { + name string + fields fields + args args + }{ + {name: "default", fields: fields{mockStore}, args: args{context.Background(), "daz"}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &userBiz{ + ds: tt.fields.ds, + } + assert.Nil(t, b.Delete(tt.args.ctx, tt.args.username)) + }) + } +} + +// TestUserBiz_ChangePassword tests the ChangePassword method of the UserBiz interface +func TestUserBiz_ChangePassword(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + fakeUser := fakeUser(1) + mockUserStore := store.NewMockUserStore(ctrl) + mockUserStore.EXPECT().Get(gomock.Any(), gomock.Any()).Return(fakeUser, nil).AnyTimes() + mockUserStore.EXPECT().Update(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + + mockStore := store.NewMockIStore(ctrl) + mockStore.EXPECT().Users().Return(mockUserStore).AnyTimes() + + type fields struct { + ds store.IStore + } + type args struct { + ctx context.Context + username string + r *v1.ChangePasswordRequest + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "default", + fields: fields{mockStore}, + args: args{context.Background(), "daz", &v1.ChangePasswordRequest{"daz1", "daz123"}}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &userBiz{ + ds: tt.fields.ds, + } + err := b.ChangePassword(tt.args.ctx, tt.args.username, tt.args.r) + assert.Equal(t, errno.ErrPasswordIncorrect, err) + }) + } +} + +// TestUserBiz_Login tests the Login method of the UserBiz interface +func TestUserBiz_Login(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + fakeUser := fakeUser(1) + mockUserStore := store.NewMockUserStore(ctrl) + mockUserStore.EXPECT().Get(gomock.Any(), gomock.Any()).Return(fakeUser, nil).AnyTimes() + + mockStore := store.NewMockIStore(ctrl) + mockStore.EXPECT().Users().AnyTimes().Return(mockUserStore) + + type fields struct { + ds store.IStore + } + type args struct { + ctx context.Context + r *v1.LoginRequest + } + tests := []struct { + name string + fields fields + args args + want *errno.Errno + }{ + { + name: "default", + fields: fields{mockStore}, + args: args{context.Background(), &v1.LoginRequest{Username: "daz1", Password: "daz1"}}, + want: errno.ErrPasswordIncorrect, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &userBiz{ + ds: tt.fields.ds, + } + got, err := b.Login(tt.args.ctx, tt.args.r) + assert.Nil(t, got) + assert.Equal(t, tt.want, err) + }) + } +} diff --git a/internal/dazBlog/store/helper_test.go b/internal/dazBlog/store/helper_test.go new file mode 100644 index 0000000..014f2b9 --- /dev/null +++ b/internal/dazBlog/store/helper_test.go @@ -0,0 +1,27 @@ +// Copyright 2023 daz-3ux(杨鹏达) . All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. The original repo for +// this file is https://github.com/Daz-3ux/dBlog. + +package store + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func FuzzDefaultLimit(f *testing.F) { + testcases := []int{0, 1, 2} + for _, tc := range testcases { + f.Add(tc) + } + + f.Fuzz(func(t *testing.T, orig int) { + limit := defaultLimit(orig) + if orig == 0 { + assert.Equal(t, defaultLimitNumber, limit) + } else { + assert.Equal(t, orig, limit) + } + }) +} diff --git a/internal/dazBlog/store/mock_store.go b/internal/dazBlog/store/mock_store.go new file mode 100644 index 0000000..e967fc3 --- /dev/null +++ b/internal/dazBlog/store/mock_store.go @@ -0,0 +1,271 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/Daz-3ux/dBlog/internal/dazBlog/store (interfaces: IStore,UserStore,PostStore) + +// Package store is a generated GoMock package. +package store + +import ( + context "context" + reflect "reflect" + + model "github.com/Daz-3ux/dBlog/internal/pkg/model" + gomock "github.com/golang/mock/gomock" + gorm "gorm.io/gorm" +) + +// MockIStore is a mock of IStore interface. +type MockIStore struct { + ctrl *gomock.Controller + recorder *MockIStoreMockRecorder +} + +// MockIStoreMockRecorder is the mock recorder for MockIStore. +type MockIStoreMockRecorder struct { + mock *MockIStore +} + +// NewMockIStore creates a new mock instance. +func NewMockIStore(ctrl *gomock.Controller) *MockIStore { + mock := &MockIStore{ctrl: ctrl} + mock.recorder = &MockIStoreMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockIStore) EXPECT() *MockIStoreMockRecorder { + return m.recorder +} + +// DB mocks base method. +func (m *MockIStore) DB() *gorm.DB { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DB") + ret0, _ := ret[0].(*gorm.DB) + return ret0 +} + +// DB indicates an expected call of DB. +func (mr *MockIStoreMockRecorder) DB() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DB", reflect.TypeOf((*MockIStore)(nil).DB)) +} + +// Posts mocks base method. +func (m *MockIStore) Posts() PostStore { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Posts") + ret0, _ := ret[0].(PostStore) + return ret0 +} + +// Posts indicates an expected call of Posts. +func (mr *MockIStoreMockRecorder) Posts() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Posts", reflect.TypeOf((*MockIStore)(nil).Posts)) +} + +// Users mocks base method. +func (m *MockIStore) Users() UserStore { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Users") + ret0, _ := ret[0].(UserStore) + return ret0 +} + +// Users indicates an expected call of Users. +func (mr *MockIStoreMockRecorder) Users() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Users", reflect.TypeOf((*MockIStore)(nil).Users)) +} + +// MockUserStore is a mock of UserStore interface. +type MockUserStore struct { + ctrl *gomock.Controller + recorder *MockUserStoreMockRecorder +} + +// MockUserStoreMockRecorder is the mock recorder for MockUserStore. +type MockUserStoreMockRecorder struct { + mock *MockUserStore +} + +// NewMockUserStore creates a new mock instance. +func NewMockUserStore(ctrl *gomock.Controller) *MockUserStore { + mock := &MockUserStore{ctrl: ctrl} + mock.recorder = &MockUserStoreMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockUserStore) EXPECT() *MockUserStoreMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockUserStore) Create(arg0 context.Context, arg1 *model.UserM) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockUserStoreMockRecorder) Create(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockUserStore)(nil).Create), arg0, arg1) +} + +// Delete mocks base method. +func (m *MockUserStore) Delete(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockUserStoreMockRecorder) Delete(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockUserStore)(nil).Delete), arg0, arg1) +} + +// Get mocks base method. +func (m *MockUserStore) Get(arg0 context.Context, arg1 string) (*model.UserM, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0, arg1) + ret0, _ := ret[0].(*model.UserM) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockUserStoreMockRecorder) Get(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockUserStore)(nil).Get), arg0, arg1) +} + +// List mocks base method. +func (m *MockUserStore) List(arg0 context.Context, arg1, arg2 int) (int64, []*model.UserM, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "List", arg0, arg1, arg2) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].([]*model.UserM) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// List indicates an expected call of List. +func (mr *MockUserStoreMockRecorder) List(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockUserStore)(nil).List), arg0, arg1, arg2) +} + +// Update mocks base method. +func (m *MockUserStore) Update(arg0 context.Context, arg1 *model.UserM) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Update indicates an expected call of Update. +func (mr *MockUserStoreMockRecorder) Update(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockUserStore)(nil).Update), arg0, arg1) +} + +// MockPostStore is a mock of PostStore interface. +type MockPostStore struct { + ctrl *gomock.Controller + recorder *MockPostStoreMockRecorder +} + +// MockPostStoreMockRecorder is the mock recorder for MockPostStore. +type MockPostStoreMockRecorder struct { + mock *MockPostStore +} + +// NewMockPostStore creates a new mock instance. +func NewMockPostStore(ctrl *gomock.Controller) *MockPostStore { + mock := &MockPostStore{ctrl: ctrl} + mock.recorder = &MockPostStoreMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockPostStore) EXPECT() *MockPostStoreMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockPostStore) Create(arg0 context.Context, arg1 *model.PostM) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockPostStoreMockRecorder) Create(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockPostStore)(nil).Create), arg0, arg1) +} + +// Delete mocks base method. +func (m *MockPostStore) Delete(arg0 context.Context, arg1 string, arg2 []string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockPostStoreMockRecorder) Delete(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockPostStore)(nil).Delete), arg0, arg1, arg2) +} + +// Get mocks base method. +func (m *MockPostStore) Get(arg0 context.Context, arg1, arg2 string) (*model.PostM, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.PostM) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockPostStoreMockRecorder) Get(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockPostStore)(nil).Get), arg0, arg1, arg2) +} + +// List mocks base method. +func (m *MockPostStore) List(arg0 context.Context, arg1 string, arg2, arg3 int) (int64, []*model.PostM, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "List", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].([]*model.PostM) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// List indicates an expected call of List. +func (mr *MockPostStoreMockRecorder) List(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockPostStore)(nil).List), arg0, arg1, arg2, arg3) +} + +// Update mocks base method. +func (m *MockPostStore) Update(arg0 context.Context, arg1 *model.PostM) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Update indicates an expected call of Update. +func (mr *MockPostStoreMockRecorder) Update(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockPostStore)(nil).Update), arg0, arg1) +} diff --git a/internal/dazBlog/store/store.go b/internal/dazBlog/store/store.go index a6ffa7c..2731b3c 100644 --- a/internal/dazBlog/store/store.go +++ b/internal/dazBlog/store/store.go @@ -10,6 +10,8 @@ import ( "sync" ) +//go:generate mockgen -destination mock_store.go -package store github.com/Daz-3ux/dBlog/internal/dazBlog/store IStore,UserStore,PostStore + /* singleton factory pattern */ diff --git a/pkg/api/dazBlog/v1/user.go b/pkg/api/dazBlog/v1/user.go index 025c164..582fbbe 100644 --- a/pkg/api/dazBlog/v1/user.go +++ b/pkg/api/dazBlog/v1/user.go @@ -8,12 +8,12 @@ package v1 // CreateUserRequest specifies the request parameters for // `POST /v1/users` type CreateUserRequest struct { - Postcount int64 `json:"postcount" valid:"required,stringlength(1|255)"` - Username string `json:"username" valid:"alphanum,required,stringlength(1|255)"` - Password string `json:"password" valid:"required,stringlength(6|18)"` - Nickname string `json:"nickname" valid:"required,stringlength(1|255)"` - Email string `json:"email" valid:"required,email"` - Phone string `json:"phone" valid:"required,numeric,stringlength(11|11)"` + Postcount int64 `json:"postcount" valid:"required,stringlength(1|255)"` + Username string `json:"username" valid:"alphanum,required,stringlength(1|255)"` + Password string `json:"password" valid:"required,stringlength(6|18)"` + Nickname string `json:"nickname" valid:"required,stringlength(1|255)"` + Email string `json:"email" valid:"required,email"` + Phone string `json:"phone" valid:"required,numeric,stringlength(11|11)"` } // GetUserResponse specifies the response parameters for @@ -22,53 +22,53 @@ type GetUserResponse UserInfo // UserInfo is the user's all information type UserInfo struct { - Username string `json:"username"` - Nickname string `json:"nickname"` - Email string `json:"email"` - Phone string `json:"phone"` - PostCount int64 `json:"postcount"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` + Username string `json:"username"` + Nickname string `json:"nickname"` + Email string `json:"email"` + Phone string `json:"phone"` + PostCount int64 `json:"postcount"` + CreatedAt string `json:"createdAt"` + UpdatedAt string `json:"updatedAt"` } // ListUserRequest specifies the request parameters for // `GET /v1/users` type ListUserRequest struct { - Offset int `form:"offset" valid:"numeric"` - Limit int `form:"limit" valid:"numeric"` + Offset int `form:"offset" valid:"numeric"` + Limit int `form:"limit" valid:"numeric"` } // ListUserResponse specifies the response parameters for // `GET /v1/users` type ListUserResponse struct { - TotalCount int64 `json:"totalCount" valid:"numeric"` - Users []*UserInfo `json:"users"` + TotalCount int64 `json:"totalCount" valid:"numeric"` + Users []*UserInfo `json:"users"` } // UpdateUserRequest specifies the request parameters for // `PUT /v1/users/{username}` type UpdateUserRequest struct { - Nickname string `json:"nickname" valid:"required,stringlength(1|255)"` - Email string `json:"email" valid:"email"` - Phone string `json:"phone" valid:"numeric,stringlength(11|11)"` + Nickname *string `json:"nickname" valid:"required,stringlength(1|255)"` + Email *string `json:"email" valid:"email"` + Phone *string `json:"phone" valid:"numeric,stringlength(11|11)"` } // ChangePasswordRequest specifies the request parameters for // `POST /v1/users/{username}/change-password` type ChangePasswordRequest struct { - OldPassword string `json:"oldPassword" valid:"required,stringlength(6|18)"` - NewPassword string `json:"newPassword" valid:"required,stringlength(6|18)"` + OldPassword string `json:"oldPassword" valid:"required,stringlength(6|18)"` + NewPassword string `json:"newPassword" valid:"required,stringlength(6|18)"` } // LoginRequest specifies the request parameters for // `POST /login` type LoginRequest struct { - Username string `json:"username" valid:"alphanum,required,stringlength(1|255)"` - Password string `json:"password" valid:"required,stringlength(6|18)"` + Username string `json:"username" valid:"alphanum,required,stringlength(1|255)"` + Password string `json:"password" valid:"required,stringlength(6|18)"` } // LoginResponse specifies the response parameters for // `POST /login` type LoginResponse struct { - Token string `json:"token"` + Token string `json:"token"` } diff --git a/pkg/util/id/cpu.profile b/pkg/util/id/cpu.profile new file mode 100644 index 0000000000000000000000000000000000000000..7712069d0522bb34c62619346853869ac9a4413b GIT binary patch literal 8042 zcmV-wAC=%AiwFP!00004|CD-pd=y3c_ghUuD(5^MAUp(+rUmRonMpb!B;qQU-~q@X z-inh+CyXRBab_Z-D@N`c1OWv(L{P!o^;TR|RKWE_5fv2_UGQLaJwR9R{XErO(>;N> z`|}S&s-Al4Ilj+Topa{g`{bTC_B{A%$E-BYK*>tuZ6IyrPhUK<(RZ2n_tni0ex9cL zIKzh)-=gS5)dN^@7H5!-=~`Q(v+m;x&a*ca=p{B4$iNJZ8$ER&Z-cL_SxqO~z-Y1A z1~M^I%Q6P*KAwi_KV3(gY0yP%ra?AlYdJ;--N)1M*bCceGaU@EnGU&_tK}J|=sw;S z|Fv0cwsr1o3qJH|U}(CJXW+dri_HwE6elx4MODi;N_5~H7e2U7(bGAHw-jK-*_=Z= zY^Sw1wkvu8&&1`=ZBz7go(Z4R*44<0i|9q5m@WG2ri06Zo@FcC9@dVR>`|$fe#5Ta2 zwu%56YFamAgOc9~`a|=UWsfRZKBlxuOK+ROGqbXDa`Sw;j{|O;zMDkKA*kTJLC`pA1}ZUCBS+C%kKaRG=H=;Gb^VcRqu{?P^#4@g;Pf<3gUv9Ye|$2@BtSl z?*OOZDVkyI;<}G_!k?t0%LRkB(7fQyE?I4{lMn@XA?|p6DlsU4=WPZBP=rNVvGI6@ z-jR34qbrxvc1M^?KMy#D}MjbLSokm?zS)O1ii7h<~J5|9r#JOa{nUQE`t>t$%44J^Nt6ac!O)J;nPR!80)_q`{y?*gx;>FH#I zOmSfsD8*9EG+w4OqvL_)w-LI!LY)9mS17|Wt=zao2Yxc{e@lSjB$!R6$>JwLAMB&` zGA8T5d*G3sVz(Roop!T%H>ki0t(Wl}(|x=r9-QU`A~`r;%9`0-Ke~PRG-=D&zMw9e6Rm^`+Q88GcCh(;5m@XA zQ|z$o31{M&nr<9sdIuiB19sl>M6xINdiw)*@Ri^j5}>6bCY)r_wnW0S6qm1_MaJp{ zJ8d}hg0t`}t-tY7rViZ1ANS3q?NeZtEypP^00(IOjaiBgybQnEBeo5A)ONW61970% z-?*EyU^)K2Tre+!2W{*Z!5|!@^*81b_WR)ed&KEt*p($rT?~V9uy(ewJxd2(fg2C3 zpu10nqiw|YsW1eGXhV%p+vvdi;ty-Y>C<4lefl&w2hY*YHonQs2dQaBsaaOur=qX! zuP$)Hx?76Xs%)$E;HTqULP0w34ZE41&i(K%{RqH8 zuBY)Ff<|#R?+xeTxtd{oK)?9mJUmY`j5q0*0GyBKYld-vdlLNV0zE$757)fp)J_wa z2V(t_WdisaxMPC@ki!hTb>a-+d*FY;=KT(kzfDU~<1Z4YXX5-F4o;`=6r7$ZaoUxi zg@1gth;Uj0f7R1@Dcnb@7Q#D}kFt0P48vjCaO1|}Y+ec@aD+D8xR>Rlw65>07MaM$ z`{Tx!R}x3lsbD5tfEQ>ZjgxgBAAtYy)&bX%{Ri0A2R;x#d{$^y2D@z3mBA<+rBxYE z6Y2)xm*0u)?yx*P#ef3`$r$zV!T7xQ9=G%jme-t(Q)Ib#j04j<@*()OZFHwX^n{~i zd-v?wLxk~td?>yzxl@{ODTdnIef%8!bg=-LsMH=9oa0p9b8*RMBAu4QdOP&WVKk1` zdKs%I^v=WkWnq3u0p>B(x#x8dNb1PX$A9e*mgob^+vw@M0#?|8)Cb1k7_G`!-ljO4 zSHOjMp;l!qq^KH(A1zr!LDwA~O*P*6!(8JH$Jb?qbWMTQa9cg#BXGlZadibOY?I=I z5lKG4FTfw{l55vmj}jMju{rtpNIdANNV<=Y!u7J23Fd}Srs+k~YI2)-BNYwroacN3kZ$0iqD+*3Ff_$Bzp3XvKs;bTpt z#!9#tFV_6VX6n8##Sdks8v_)JjvBtMmt5K+*IkBB%LcA0C5>F>Ty;7A^WCW=U_r}T zcDbv?75L&$qKm15McsuwRd5MjqWO(Q-F4ts;;(iWQwiI&6oIa|vZX**;SA~B5h>8R z%66`gkHfcTt)=vFI$SCW=jm`MUaDPYT&x4X8bAG7;I|*_x3S(2F2~C?!`Mgg4&ugd z1T4G59D;W{X_~BYR|h4&fmh>)uQ^ITk?Oi?*S{e=YBy8`uqCz1hg{3l;JYcD+)Pko z=L+B!ekPr{m#ouK%9LldG)^rZdC@5iRL}DzWoE6XG}Pf*ng5oNj&568CpGl(@p$OO z>1Vu?e!}>N>|y?v2^4qN;FBvv#ySHUh2779EAR?UH%95eC*U60HXWvF<6auRW`e9Y z_4qd#Hg~1gn|ev);|;j`#F8}#$$UJ5M^8);5d^@axNU~hAI_s|Tr)+JO`4B4;(kwF z@q}5U6Tv=yEpC?+pbuDnjx=|hYx8`%kH>I|XV~(j@R%b=9OrwR`+SrPeDULoVgh&E z;aGPRP>t~35`7bb3G!+Ac(fzxEz*ESP%w++7@x2048*PGW%2zB6-aJn2PQI3=Oxw7u3O`;YQ_zl>+TZGb? zaM*4z&xEV+Dy`T!ObzCZI7=qUuPM^pdVj->GC=-{tG-=BDX1U(lv+#vnvB_w{3d+y zAL633U|NQlZ#LUK=UFfg$7#jJk+vR_-6WY$#(fViB<7u9F@eSP(c~7%68O#du1s^c zbx+A-H@C=RDsN`^ncDRK}QKv9mEW3(|l*%`S+0|0z zQyD&$0s%MSOl1NCDxb!1SBiV{rPDH}G3j5GPiMG5y6)FZVEOGOe6y#s8&Kk^92{J)IAL159AGKU|GhYeA!baW)?S)mW_sjjc>q`Amk#KA%oj9|&uRHk%KG z5Qemij3u-`i{aL-!kL3$6;Mu55ierTAc8(g*Vy?v#0s z<{nS@%xBlwv5I^F!>u;-`@$5rN%07`z!47kLWa-ETdCo46h{2>z2C0gbfQRT}S9? z_HaLCN0(?h>mV|y%5P`*dMhxvJqZJq-@$O3eAZb(7rFqvgSE&TDqq2HhJ3mb7Ibf3 z!R*&5m9JztLxvk=N)KvQvScp2li}X4#PBp2@Kv`JdW3T8F7zJYnd~qsQfO5-?d`% zyO`5&dGgqqc0NSDj^P@a@*N;i%JO00>B?<`1?`uY<~_tM-^xB zbKn}hM(b*{_ee64T=O^+Z}v|xoGFJodX)!R-ZP$Hf+oKZ%Aoo1@*i0icyoa`ukt4u z{wm{fM`|K}QUnyyd7RWw3?E|Ay=v@`fLL)`M*<=(=>_~LhKK&_0rM#)2vzfGr~m<-Lniom2|s_&TVO)wUI`I`2ac4eCM52SsB>L zUMZ9&R8wBo1+}Z;MFaAMZFJzzF?>~muU|@^@Eo&gRQ^1}f2Y{lmF9U@8eQd^89p)1 znP~QtLtMhmc4Z|&bl@*A+%QWF4cX#t#1-uYmMw_#J4sEz`xrpyJ!q<-tV?Tp0slM0 zpZ?5Of0w@6!f={wJ^!G0F&Ft;nDo?(3_sZ2-lw@!<@>J?fv1co*V;Swg#&D;^ z;7r1xF4In@7uie9EPI)4Wv{S`SJ`Xq#%r2vy8++E@O3-J8T1C`NmkoV5OdoZez@!%|}5KHfb?qCmHb#hCgf)`=eo}JvWVp>+m`)X1q!J zZ!+9CWgeX$1M6)gje&_cQM=w)NB6(Q@W>vK!!Lxl?FQmPn1qwGVq-^^uJX4TJ|WA> z(-e8G5x27)>~;1JR`CXVlfA{>PNo%i(V3d0!CZz&~X8gsj*!J-WH!LzYZiA2HlPFS2PIVRA~k{fKo* zQhm(uQ8|vJe)#;@WwnRl3$oV z`W5)645u7(>f}j4FA+|2llG}y7C&S7j{RVf3++-myU#=l^Dy2i+D^xCdl^nYG2^|& zSmpZ|zG;6K=xKk9aZ$Q2nfN|uxaoZnAO-MRX3BH$=giT}J$IA6qO1H1hCh41c6i|W z1ry&hNKB9H_Owciy2|%6oF(7FnyF=S!M@+E9GKUo%`Pi|Hq+#q?{}Bs%hM7_K|fc;Vvj8y9~n|CZs==}wVuVd`%^d{zD( z!>8mM^*(yfa((h06AxOBi4HNmU1lorHQc@Vkm~`J|BK<#O{*zUmBF)AcwL77av`Ft z{CkE6Wy2xfINW&q-oc=*@*f!fDz6o9axT>mk_!008Q!y545AkSib3=uxDjvE{%R19 z9~thK4>Wto8wD~NbN|hLO!3E04Cl!5D&}5S%b(nOs`8&1uBGXc=E_wxzPoMs&+NPo z!f2i~@ugiD68J9+w@8SlHeIE zn`}IlqpSQ6hWo#nP5YO?YJ2|@xEXKOCL0TKbmYwnezQmHUkVFy^mKk19Hu|o$mN$p zGs9-4O*ZD|6zB2F;1-6rFl`DmexZKk76rfBCJtT>v#DRnSmC1bn)JN2ZCM-~Nj+H~&so>|?HYrzNLE zmCsOc>BCOec%QUzoj*fK78V`(Oa-^wQm6J;uJALZ@Ggk&^TKhKf*b4)(G~DeYQ~$T z45JrkQjgws6@30}0hcS`u3TWnx%^6)&TzW$b1uE*DtPB+L2(rvpguE~Uj;K5&LD~} zsneXR;D^r$igB>TrWgk^8O|h%<@A^}Pr;8j3W}>?8$I0Q@~dGM!&yY}QiiVb`3gRJ zpP&fBOEyIiW;2{k6q|`+fr39A5pzs6{KAB!)i8(Q9Hs@0e^bZ4P{A*M78D`4hbVG* z2<9@JOBADYl`m58vHgNzAUsJ9I7Q~jlV&S(l)1`0rDDFaKv}3PQj#y)WGIiBzfYRk zv$!$2s3X5s!DF`fhJyEj$aU4NN)i>o7b`eZc4Q?fUCLr5*%~ZS@K)LRuAc?E|3izE0?vT^G`_;}T%ShWh6;jWWGSXyyv{)h@Vga!eU1Ak+MegYyOreMYmk&W^7RTndqAY78h97dqU*K+W>PoPZ)zEQ!wGVP>J zlp7s0>&Q1L_`NM$Eo^L~r}F}Mgq|w$cr7eoxPWO3nQ>nmkIb9g)TZ+L75qYevk{+q z3&EKX)%z9CHybi^p~@LFH#aNTymqf*EMk?cunSk9dGFrGkNnsTo7X<|#E~DnY0Xv+WN@!U=zgzdD!*jkjw2wM~&wsd@5$V@Sdjdf6Do zF)LVO#fto+tzgaZcJk2L5(#V6Ma{f$R2&(Q7-j|I2@_jh9gYUVQKHOtD2FuF*PGyB zD9)SZb>YPLrfPpE+7P%V7>`Ec(b`0yF4{XjJ{n8(4wJzmRxFsXYzGXSl(6FF_`vvR zgB6Hb!TOru4S~97pm9Q7pdnfl_;2j`UsvKU@t5>AOG+zC%1cX1`j(mH<-IGcnzE8m zsJyJCPfZ|BSC6Bsqh`^6W9T31$Y*-*9vr-(cUjZ*ftrE!(K;bqQzBd+2n+Ht#Q)sE zW*}9I8+td!qSsiV#PO%-U|rO#^a#`X4Fj!6XnaF3HeslhysG^Fa@Dwm6;IH8D*YoI zsq-7f1B?8zrpO4hM@vULB!OyqD;;d-tl9_bgH4gpc(a3(68xcPBos`<6R~ilE^c;j z${bMg2WcGBVaZ7D55p4*E z{6_KEa3oP#tdwq~-!!oYoUqbvV%wY$Tf| z1#^7`0*P2KWK{=4BGY<&>#`yrx|mDSj~o} z@u4JTYG{l_YsqlQ27ngA^_G1u*P-)I49BcSH_10x4Watji0C<1uyJHmq7RGbx{|3VkH`}T<28Ri8a@WMsY*DF&HTlW7P@dqG?N{fMjw? ziYy!>_L3zxbx$Z;>f%0i*9$zEjEd|=sHZWjgO<84CrCHv$s;oRvT~bm? zg9-KeW_}WF_2KG}KOXg0m_}uFtyNN1TTxwGRb3IRu*^PHrPaaenv&}3kXcbtS=P6v zvbLg6rPb{|>($bQ$YO~A= s)tc2MrKZ{T^6P5i(JRfY%dd-1iid*r^;iD?00030{|P6DQ(Qp+0HY({;Q#;t literal 0 HcmV?d00001 diff --git a/pkg/util/id/id_test.go b/pkg/util/id/id_test.go new file mode 100644 index 0000000..b79b3a1 --- /dev/null +++ b/pkg/util/id/id_test.go @@ -0,0 +1,38 @@ +// Copyright 2023 daz-3ux(杨鹏达) . All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. The original repo for +// this file is https://github.com/Daz-3ux/dBlog. + +package id + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestGenShortID(t *testing.T) { + shortID := GenShortID() + assert.NotEqual(t, "", shortID) + assert.Equal(t, 6, len(shortID)) +} + +func BenchmarkGenShortID(b *testing.B) { + for i := 0; i < b.N; i++ { + GenShortID() + } +} + +func BenchmarkGenShortIDTimeConsuming(b *testing.B) { + b.StopTimer() + + shortid := GenShortID() + if shortid == "" { + b.Error("Failed to generate short id") + } + + b.StartTimer() + + for i := 0; i < b.N; i++ { + GenShortID() + } +} diff --git a/pkg/util/id/profile001.svg b/pkg/util/id/profile001.svg new file mode 100644 index 0000000..452a466 --- /dev/null +++ b/pkg/util/id/profile001.svg @@ -0,0 +1,2071 @@ + + + + + + +id.test + + +cluster_L + + + + +File: id.test + + +File: id.test +Type: cpu +Time: Oct 10, 2023 at 6:04pm (CST) +Duration: 4.11s, Total samples = 3.96s (96.27%) +Showing nodes accounting for 3.82s, 96.46% of 3.96s total +Dropped 36 nodes (cum <= 0.02s) +See https://git.io/JfYMW for how to read the graph + + + + + +N1 + + +id +GenShortID +0.02s (0.51%) +of 3.85s (97.22%) + + + + + +N2 + + +go-short-id +Generate +0.10s (2.53%) +of 2.70s (68.18%) + + + + + +N1->N2 + + + + + + + 2.70s + + + + + +N8 + + +id +toLower +0.06s (1.52%) +of 1.13s (28.54%) + + + + + +N1->N8 + + + + + + + 1.13s + (inline) + + + + + +N11 + + +go-short-id +generateRandomBytes +0.02s (0.51%) +of 1.65s (41.67%) + + + + + +N2->N11 + + + + + + + 1.65s + + + + + +N13 + + +time +Time +Format +0.03s (0.76%) +of 0.39s (9.85%) + + + + + +N2->N13 + + + + + + + 0.39s + + + + + +N16 + + +time +Now +0.19s (4.80%) + + + + + +N2->N16 + + + + + + + 0.19s + + + + + +N29 + + +bytes +(*Buffer) +WriteString +0.02s (0.51%) +of 0.22s (5.56%) + + + + + +N2->N29 + + + + + + + 0.22s + + + + + +N39 + + +bytes +(*Buffer) +WriteRune +0.02s (0.51%) +of 0.06s (1.52%) + + + + + +N2->N39 + + + + + + + 0.06s + + + + + +N43 + + +bytes +(*Buffer) +String +0.01s (0.25%) +of 0.08s (2.02%) + + + + + +N2->N43 + + + + + + + 0.08s + (inline) + + + + + +N3 + + +testing +(*B) +launch +0 of 3.89s (98.23%) + + + + + +N4 + + +testing +(*B) +runN +0 of 3.89s (98.23%) + + + + + +N3->N4 + + + + + + + 3.89s + + + + + +N20 + + +id +BenchmarkGenShortIDTimeConsuming +0.03s (0.76%) +of 1.97s (49.75%) + + + + + +N4->N20 + + + + + + + 1.97s + + + + + +N36 + + +id +BenchmarkGenShortID +0.01s (0.25%) +of 1.92s (48.48%) + + + + + +N4->N36 + + + + + + + 1.92s + + + + + +N5 + + +runtime +mallocgc +0.61s (15.40%) +of 1s (25.25%) + + + + + +N24 + + +runtime +nextFreeFast +0.12s (3.03%) + + + + + +N5->N24 + + + + + + + 0.12s + (inline) + + + + + +N33 + + +runtime +acquirem +0.06s (1.52%) + + + + + +N5->N33 + + + + + + + 0.06s + (inline) + + + + + +N34 + + +runtime +getMCache +0.06s (1.52%) + + + + + +N5->N34 + + + + + + + 0.06s + (inline) + + + + + +N35 + + +runtime +deductAssistCredit +0.07s (1.77%) +of 0.08s (2.02%) + + + + + +N5->N35 + + + + + + + 0.08s + + + + + +N48 + + +runtime +releasem +0.02s (0.51%) + + + + + +N5->N48 + + + + + + + 0.02s + (inline) + + + + + +N58 + + +runtime +(*mcache) +nextFree +0 of 0.02s (0.51%) + + + + + +N5->N58 + + + + + + + 0.02s + + + + + +N6 + + +syscall +Syscall6 +1.17s (29.55%) + + + + + +N7 + + +syscall +Syscall +0.03s (0.76%) +of 1.47s (37.12%) + + + + + +N21 + + +runtime +exitsyscall +0.02s (0.51%) +of 0.16s (4.04%) + + + + + +N7->N21 + + + + + + + 0.16s + + + + + +N37 + + +syscall +RawSyscall6 +0.01s (0.25%) +of 1.18s (29.80%) + + + + + +N7->N37 + + + + + + + 1.18s + + + + + +N61 + + +runtime +entersyscall +0 of 0.10s (2.53%) + + + + + +N7->N61 + + + + + + + 0.10s + + + + + +N14 + + +runtime +concatstring2 +0.09s (2.27%) +of 0.66s (16.67%) + + + + + +N8->N14 + + + + + + + 0.66s + + + + + +N17 + + +runtime +intstring +0.06s (1.52%) +of 0.41s (10.35%) + + + + + +N8->N17 + + + + + + + 0.41s + + + + + +N9 + + +runtime +concatstrings +0.23s (5.81%) +of 0.57s (14.39%) + + + + + +N30 + + +runtime +rawstringtmp +0.03s (0.76%) +of 0.30s (7.58%) + + + + + +N9->N30 + + + + + + + 0.30s + + + + + +N32 + + +runtime +memmove +0.05s (1.26%) + + + + + +N9->N32 + + + + + + + 0.04s + + + + + +N10 + + +runtime +rawstring +0.01s (0.25%) +of 0.61s (15.40%) + + + + + +N10->N5 + + + + + + + 0.60s + + + + + +N15 + + +runtime +makeslice +0.03s (0.76%) +of 0.27s (6.82%) + + + + + +N11->N15 + + + + + + + 0.08s + + + + + +N54 + + +rand +Read +0 of 1.55s (39.14%) + + + + + +N11->N54 + + + + + + + 1.55s + + + + + +N12 + + +Time +appendFormat +0.06s (1.52%) +of 0.25s (6.31%) + + + + + +N27 + + +time +absDate +0.09s (2.27%) + + + + + +N12->N27 + + + + + + + 0.09s + + + + + +N38 + + +time +nextStdChunk +0.04s (1.01%) + + + + + +N12->N38 + + + + + + + 0.04s + + + + + +N44 + + +Time +locabs +0.02s (0.51%) +of 0.03s (0.76%) + + + + + +N12->N44 + + + + + + + 0.03s + + + + + +N45 + + +time +appendInt +0.02s (0.51%) +of 0.03s (0.76%) + + + + + +N12->N45 + + + + + + + 0.03s + + + + + +N19 + + +runtime +slicebytetostring +0.02s (0.51%) +of 0.18s (4.55%) + + + + + +N13->N19 + + + + + + + 0.11s + + + + + +N66 + + +time +Time +AppendFormat +0 of 0.25s (6.31%) + + + + + +N13->N66 + + + + + + + 0.25s + + + + + +N14->N9 + + + + + + + 0.57s + + + + + +N15->N5 + + + + + + + 0.24s + + + + + +N17->N10 + + + + + + + 0.34s + (inline) + + + + + +N18 + + +runtime +casgstatus +0.10s (2.53%) + + + + + +N19->N5 + + + + + + + 0.16s + + + + + +N20->N1 + + + + + + + 1.94s + + + + + +N21->N18 + + + + + + + 0.06s + + + + + +N31 + + +runtime +exitsyscallfast +0.07s (1.77%) +of 0.08s (2.02%) + + + + + +N21->N31 + + + + + + + 0.08s + + + + + +N22 + + +rand +(*reader) +Read +0.03s (0.76%) +of 1.53s (38.64%) + + + + + +N56 + + +rand +init +0 +batched +func1 +0 of 1.50s (37.88%) + + + + + +N22->N56 + + + + + + + 1.50s + + + + + +N23 + + +unix +GetRandom +0.03s (0.76%) +of 1.50s (37.88%) + + + + + +N23->N7 + + + + + + + 1.47s + + + + + +N25 + + +runtime +systemstack +0 of 0.08s (2.02%) + + + + + +N62 + + +runtime +gcBgMarkWorker +func2 +0 of 0.04s (1.01%) + + + + + +N25->N62 + + + + + + + 0.04s + + + + + +N26 + + +runtime +reentersyscall +0.03s (0.76%) +of 0.10s (2.53%) + + + + + +N26->N18 + + + + + + + 0.04s + + + + + +N65 + + +atomic +(*Bool) +Load +0 of 0.03s (0.76%) + + + + + +N26->N65 + + + + + + + 0.03s + (inline) + + + + + +N28 + + +io +ReadAtLeast +0.02s (0.51%) +of 1.55s (39.14%) + + + + + +N28->N22 + + + + + + + 1.53s + + + + + +N29->N32 + + + + + + + 0.01s + + + + + +N53 + + +bytes +(*Buffer) +grow +0 of 0.19s (4.80%) + + + + + +N29->N53 + + + + + + + 0.19s + + + + + +N30->N10 + + + + + + + 0.27s + (inline) + + + + + +N35->N25 + + + + + + + 0.01s + + + + + +N36->N1 + + + + + + + 1.91s + + + + + +N37->N6 + + + + + + + 1.17s + + + + + +N40 + + +bytes +(*Buffer) +WriteByte +0.02s (0.51%) +of 0.04s (1.01%) + + + + + +N39->N40 + + + + + + + 0.04s + + + + + +N46 + + +bytes +(*Buffer) +tryGrowByReslice +0.02s (0.51%) + + + + + +N40->N46 + + + + + + + 0.02s + (inline) + + + + + +N41 + + +runtime +scanobject +0.03s (0.76%) + + + + + +N42 + + +atomic +(*Uint8) +Load +0.03s (0.76%) + + + + + +N43->N19 + + + + + + + 0.07s + + + + + +N47 + + +runtime +gcBgMarkWorker +0 of 0.04s (1.01%) + + + + + +N47->N25 + + + + + + + 0.04s + + + + + +N49 + + +runtime +gcDrain +0 of 0.04s (1.01%) + + + + + +N49->N41 + + + + + + + 0.03s + + + + + +N52 + + +runtime +markroot +0 of 0.02s (0.51%) + + + + + +N49->N52 + + + + + + + 0.01s + + + + + +N50 + + +runtime +scanblock +0.01s (0.25%) +of 0.02s (0.51%) + + + + + +N51 + + +runtime +bgsweep +0 of 0.02s (0.51%) + + + + + +N64 + + +runtime +sweepone +0 of 0.02s (0.51%) + + + + + +N51->N64 + + + + + + + 0.02s + + + + + +N63 + + +runtime +markrootBlock +0 of 0.02s (0.51%) + + + + + +N52->N63 + + + + + + + 0.02s + + + + + +N53->N15 + + + + + + + 0.19s + + + + + +N57 + + +io +ReadFull +0 of 1.55s (39.14%) + + + + + +N54->N57 + + + + + + + 1.55s + (inline) + + + + + +N55 + + +rand +getRandom +0 of 1.50s (37.88%) + + + + + +N55->N23 + + + + + + + 1.50s + + + + + +N56->N55 + + + + + + + 1.50s + + + + + +N57->N28 + + + + + + + 1.55s + + + + + +N59 + + +runtime +(*mcache) +refill +0 of 0.02s (0.51%) + + + + + +N58->N59 + + + + + + + 0.02s + + + + + +N59->N25 + + + + + + + 0.01s + + + + + +N60 + + +runtime +(*sweepLocked) +sweep +0 of 0.02s (0.51%) + + + + + +N60->N25 + + + + + + + 0.01s + + + + + +N61->N26 + + + + + + + 0.10s + + + + + +N62->N49 + + + + + + + 0.04s + + + + + +N63->N50 + + + + + + + 0.02s + + + + + +N64->N60 + + + + + + + 0.02s + + + + + +N65->N42 + + + + + + + 0.03s + (inline) + + + + + +N66->N12 + + + + + + + 0.25s + + + + +