Relationships are always nil when doing dynamoattribute.UnmarshalMap - amazon-web-services

I have two structs. Sample and Test. 'Sample' has a relationship of type 'Test'. When I try to do 'dynamoattribute.UnmarshalMap', the relationship is always nil. Could you advise how to populate relationships ('Test' in this case) please?
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)
type Sample struct {
SampleId string `jsonapi:"attr,sampleId,omitempty" dynamodbav:"sample_id"`
Test *Test `jsonapi:"relation,test"`
}
type Test struct {
TestId string `jsonapi:"attr,testId,omitempty" dynamodbav:"test_id"`
}
func main() {
var m map[string]*dynamodb.AttributeValue
m = make(map[string]*dynamodb.AttributeValue)
m["sample_id"] = &dynamodb.AttributeValue{
S: aws.String("sample1"),
}
m["test_id"] = &dynamodb.AttributeValue{
S: aws.String("test"),
}
sam := Sample{}
err := dynamodbattribute.UnmarshalMap(m, &sam)
if err != nil {
fmt.Println(err)
}
fmt.Println(sam)
}

package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)
type Sample struct {
SampleId string `jsonapi:"attr,sampleId,omitempty" dynamodbav:"sample_id"`
Test *Test `jsonapi:"relation,test"`
}
type Test struct {
TestId string `jsonapi:"primary,testId" dynamodbav:"test_id"`
}
func main() {
var m map[string]*dynamodb.AttributeValue
m = make(map[string]*dynamodb.AttributeValue)
m["sample_id"] = &dynamodb.AttributeValue{
S: aws.String("sample1"),
}
var mTest map[string]*dynamodb.AttributeValue
mTest = make(map[string]*dynamodb.AttributeValue)
mTest["test_id"] = &dynamodb.AttributeValue{
S: aws.String("test1"),
}
m["test"] = &dynamodb.AttributeValue{
M: mTest,
}
sam := Sample{}
err := dynamodbattribute.UnmarshalMap(m, &sam)
if err != nil {
fmt.Println(err)
}
fmt.Println(sam)
}

Related

Can you mock the page values in an AWS API Paginator/paginated/Pages call?

Is there a way to return test page values returned from the AWS API paginators to test the code below? If not, I suppose it's better to split the tag checking into a function that can be tested in isolation?
Note: This is just an example, I realize there are input Filters on the I can apply to the API call to achieve the same thing demonstrated here.
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
)
type handler struct {
EC2 ec2iface.EC2API
}
func main() {
sess := session.New()
client := ec2.New(sess)
h := &handler{EC2: client}
tagged, err := h.findTagged()
if err != nil {
panic(err)
}
fmt.Println(tagged)
}
func (h *handler) findTagged() ([]string, error) {
defaults := []string{}
input := &ec2.DescribeVpcsInput{}
err := h.EC2.DescribeVpcsPages(input, func(page *ec2.DescribeVpcsOutput, lastPage bool) bool {
for _, p := range page.Vpcs {
for _, t := range p.Tags {
if aws.StringValue(t.Key) == "test" {
defaults = append(defaults, aws.StringValue(p.VpcId))
}
}
}
return false
})
return defaults, err
}
This is described on the official documentation (Unit Testing with the AWS SDK for Go V2 - How to mock the AWS SDK for Go V2 when unit testing your application
Extract from the page:
import "context"
import "fmt"
import "testing"
import "github.com/aws/aws-sdk-go-v2/service/s3"
// ...
type mockListObjectsV2Pager struct {
PageNum int
Pages []*s3.ListObjectsV2Output
}
func (m *mockListObjectsV2Pager) HasMorePages() bool {
return m.PageNum < len(m.Pages)
}
func (m *mockListObjectsV2Pager) NextPage(ctx context.Context, f ...func(*s3.Options)) (output *s3.ListObjectsV2Output, err error) {
if m.PageNum >= len(m.Pages) {
return nil, fmt.Errorf("no more pages")
}
output = m.Pages[m.PageNum]
m.PageNum++
return output, nil
}
func TestCountObjects(t *testing.T) {
pager := &mockListObjectsV2Pager{
Pages: []*s3.ListObjectsV2Output{
{
KeyCount: 5,
},
{
KeyCount: 10,
},
{
KeyCount: 15,
},
},
}
objects, err := CountObjects(context.TODO(), pager)
if err != nil {
t.Fatalf("expect no error, got %v", err)
}
if expect, actual := 30, objects; expect != actual {
t.Errorf("expect %v, got %v", expect, actual)
}
}

unit testing GraphQL in Golang

in this case I am using
Echo
mongo-driver (MongoDB)
gqlgen graphql type safe
is there any simple example for testing my Mutation and Query ? I do love to get advices for this. I have tried to find but can't found any so far,
thank you :)
Here is an test example using testify package and the gqlgen/client package which is used internally for testing.
GraphQL schema:
type Query {
user(loginname: String!): UserDetail
}
type Mutation {
validateAccessToken(accesstoken: String!): UserEntity
}
type User {
loginname: String
avatarUrl: String
}
type UserEntity {
id: ID!
loginname: String
avatarUrl: String
}
type UserDetail {
loginname: String
avatarUrl: String
githubUsername: String
createAt: String
score: Int
}
graph/resolver/resolver.go:
package resolver
import "github.com/mrdulin/gqlgen-cnode/services"
// This file will not be regenerated automatically.
//
// It serves as dependency injection for your app, add any dependencies you require here.
type Resolver struct {
UserService services.UserService
}
services/user.go:
package services
type UserService interface {
GetUserByLoginname(loginname string) *model.UserDetail
ValidateAccessToken(accesstoken string) *model.UserEntity
}
graph/resolver/root.resolver.go:
package resolver
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
import (
"context"
"github.com/mrdulin/gqlgen-cnode/graph/generated"
"github.com/mrdulin/gqlgen-cnode/graph/model"
)
func (r *mutationResolver) ValidateAccessToken(ctx context.Context, accesstoken string) (*model.UserEntity, error) {
return r.UserService.ValidateAccessToken(accesstoken), nil
}
func (r *queryResolver) User(ctx context.Context, loginname string) (*model.UserDetail, error) {
return r.UserService.GetUserByLoginname(loginname), nil
}
// Mutation returns generated.MutationResolver implementation.
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }
// Query returns generated.QueryResolver implementation.
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
type mutationResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }
Created mock object for UserService:
mocks/userService.go:
package mocks
import (
"github.com/mrdulin/gqlgen-cnode/graph/model"
"github.com/stretchr/testify/mock"
)
type MockedUserService struct {
mock.Mock
}
func (s *MockedUserService) GetUserByLoginname(loginname string) *model.UserDetail {
args := s.Called(loginname)
return args.Get(0).(*model.UserDetail)
}
func (s *MockedUserService) ValidateAccessToken(accesstoken string) *model.UserEntity {
args := s.Called(accesstoken)
return args.Get(0).(*model.UserEntity)
}
graph/resolver/root.resolver_test.go:
package resolver_test
import (
"testing"
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/mrdulin/gqlgen-cnode/graph/generated"
"github.com/mrdulin/gqlgen-cnode/graph/model"
"github.com/mrdulin/gqlgen-cnode/graph/resolver"
"github.com/mrdulin/gqlgen-cnode/mocks"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
var (
loginname = "mrdulin"
avatarURL = "avatar.jpg"
score = 50
createAt = "1900-01-01"
)
func TestMutationResolver_ValidateAccessToken(t *testing.T) {
t.Run("should validate accesstoken correctly", func(t *testing.T) {
testUserService := new(mocks.MockedUserService)
resolvers := resolver.Resolver{UserService: testUserService}
c := client.New(handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &resolvers})))
ue := model.UserEntity{ID: "123", User: model.User{Loginname: &loginname, AvatarURL: &avatarURL}}
testUserService.On("ValidateAccessToken", mock.AnythingOfType("string")).Return(&ue)
var resp struct {
ValidateAccessToken struct{ ID, Loginname, AvatarUrl string }
}
q := `
mutation {
validateAccessToken(accesstoken: "abc") {
id,
loginname,
avatarUrl
}
}
`
c.MustPost(q, &resp)
testUserService.AssertExpectations(t)
require.Equal(t, "123", resp.ValidateAccessToken.ID)
require.Equal(t, "mrdulin", resp.ValidateAccessToken.Loginname)
require.Equal(t, "avatar.jpg", resp.ValidateAccessToken.AvatarUrl)
})
}
func TestQueryResolver_User(t *testing.T) {
t.Run("should query user correctly", func(t *testing.T) {
testUserService := new(mocks.MockedUserService)
resolvers := resolver.Resolver{UserService: testUserService}
c := client.New(handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &resolvers})))
u := model.UserDetail{User: model.User{Loginname: &loginname, AvatarURL: &avatarURL}, Score: &score, CreateAt: &createAt}
testUserService.On("GetUserByLoginname", mock.AnythingOfType("string")).Return(&u)
var resp struct {
User struct {
Loginname, AvatarURL, CreateAt string
Score int
}
}
q := `
query GetUser($loginname: String!) {
user(loginname: $loginname) {
loginname
avatarUrl
createAt
score
}
}
`
c.MustPost(q, &resp, client.Var("loginname", "mrdulin"))
testUserService.AssertCalled(t, "GetUserByLoginname", "mrdulin")
require.Equal(t, "mrdulin", resp.User.Loginname)
require.Equal(t, "avatar.jpg", resp.User.AvatarURL)
require.Equal(t, 50, resp.User.Score)
require.Equal(t, "1900-01-01", resp.User.CreateAt)
})
}
test result:
=== RUN TestMutationResolver_ValidateAccessToken
=== RUN TestMutationResolver_ValidateAccessToken/should_validate_accesstoken_correctly
TestMutationResolver_ValidateAccessToken/should_validate_accesstoken_correctly: root.resolvers_test.go:44: PASS: ValidateAccessToken(mock.AnythingOfTypeArgument)
--- PASS: TestMutationResolver_ValidateAccessToken (0.00s)
--- PASS: TestMutationResolver_ValidateAccessToken/should_validate_accesstoken_correctly (0.00s)
=== RUN TestQueryResolver_User
=== RUN TestQueryResolver_User/should_query_user_correctly
--- PASS: TestQueryResolver_User (0.00s)
--- PASS: TestQueryResolver_User/should_query_user_correctly (0.00s)
PASS
ok github.com/mrdulin/gqlgen-cnode/graph/resolver 0.141s
test coverage report:
source code: https://github.com/mrdulin/gqlgen-cnode

How to parse dynamodb result to an integer?

I'm unable to unmarshall a fairly simple data structure:
"video_lite": { "id": 1573, "name": "Blade Runner (Movie)" }
Here's my code that doesn't work:
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)
type Video struct {
video_lite struct {
name string
id int
}
}
func check(err error) {
if err != nil {
panic(err.Error())
}
}
func main() {
svc := dynamodb.New(session.New())
input := &dynamodb.GetItemInput{
Key: map[string]*dynamodb.AttributeValue{"uuid": {S: aws.String("d610e853-5222-462c-9bb3-26ff5aa86e9d")}},
ProjectionExpression: aws.String("video_lite"),
TableName: aws.String("staging_video_ingestion"),
}
result, err := svc.GetItem(input)
check(err)
fmt.Printf("%+v\n", result.Item)
var t Video
err = dynamodbattribute.UnmarshalMap(result.Item, &t)
check(err)
fmt.Printf("%+v\n", t)
}
The output looks like:
map[video_lite:{
M: {
id: {
N: "1573"
},
name: {
S: "Bladerunner (Movie)"
}
}
}]
{video_lite:{name: id:0}}
Why doesn't the UnmarshalMap work?
Unmarshal instead of UnmarshalMap appears to be easier to work with.
type Video struct {
Name string `dynamodbav:"name"`
ID int `dynamodbav:"id"`
}
I threw in the dynamodbav struct tags in an act of desperation. It appears they are not needed when unmarshalling. And now I return the map value, instead of the whole map result.Item which I never figured out how to get to work with UnmarshalMap. :/
err = dynamodbattribute.Unmarshal(result.Item["video_lite"], &t)
Probably you can modify your struct to this :
type Video struct {
video_lite struct {
name struct {
N *string
S *string
}
id struct {
N *string
S *string
}
}
}

Gorilla Mux Regex for number between range and predefined options

My route looks like this
max := viper.GetInt("channels")
lights_router.Path("/{channel}/{action}").
Methods("OPTIONS","GET").
Handler( util.Adapt(SerialHandler(router), util.EnableCORS()))
Channels have to be between 1 and max and action has to be either false or true.
func ValidetaChannel() Adapter {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
channel, err := strconv.Atoi(mux.Vars(r)["channel"])
if err != nil {
http.Error(w, http.StatusText(400), 400)
return
}
if channel >= 1 && channel <= viper.GetInt("channels") {
h.ServeHTTP(w, r)
return
}
http.Error(w, http.StatusText(400), 400)
})
}
}
func ValidetaAction() Adapter {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if mux.Vars(r)["action"] == "true" || mux.Vars(r)["action"] == "false" {
h.ServeHTTP(w, r)
return
}
http.Error(w, http.StatusText(400), 400)
})
}
}
filter by Route
"/{channel:(?:[0-9]{1,3})}/{action:(?:true|false)}/"
Example
package main
import (
"github.com/gorilla/mux"
"log"
"net/http"
"regexp"
"strconv"
)
var myRegex *regexp.Regexp
func main() {
mux := mux.NewRouter()
myRegex = regexp.MustCompile(`/(?P<channel>[0-9]{1,3})/(?P<action>(true|false))/`)
maxChannel := 100
mux.Path("/{channel:(?:[0-9]{1,3})}/{action:(?:true|false)}/").
HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
matchs := myRegex.FindStringSubmatch(r.URL.Path) // [all, channel, action]
/* https://stackoverflow.com/a/20751656/9935654
dict := make(map[string]string)
for i, name := range myRegex.SubexpNames() {
if i != 0 && name != "" {
dict[name] = matchs[i]
}
}
channelStr := dict["channel"]
*/
channelStr := matchs[1]
curChannel, _ := strconv.Atoi(channelStr)
if channelStr[:1] == "0" || curChannel > maxChannel {
log.Println("error")
return
}
log.Println("ok")
})
server := http.Server{Addr:":1234", Handler: mux}
server.ListenAndServe()
}

Golang regex get value inside parentheses

Code:
package main
import (
"fmt"
"regexp"
)
func main() {
r := regexp.MustCompile(`((.*))`)
s := `(tag)SomeText`
res := r.FindStringSubmatch(s)
fmt.Println(res[1])
}
How to Get Value inside parentheses?
1- While it is simple using regex (try it on The Go Playground):
package main
import (
"fmt"
"regexp"
)
var rgx = regexp.MustCompile(`\((.*?)\)`)
func main() {
s := `(tag)SomeText`
rs := rgx.FindStringSubmatch(s)
fmt.Println(rs[1])
}
output:
tag
2- but sometimes using strings.Index is fast enough (try it on The Go Playground):
package main
import (
"fmt"
"strings"
)
func match(s string) string {
i := strings.Index(s, "(")
if i >= 0 {
j := strings.Index(s, ")")
if j >= 0 {
return s[i+1 : j]
}
}
return ""
}
func main() {
s := `Some(tag)Text`
r := match(s)
fmt.Println(r)
}
output:
tag
3- This simple benchmark shows using regex takes 931ms and using strings.Index takes 43ms for 1000000 iterations.
package main
import (
"fmt"
"regexp"
"strings"
"time"
)
var rgx = regexp.MustCompile(`\((.*?)\)`)
const n = 1000000
func main() {
var rs []string
var r string
s := `(tag)SomeText`
t := time.Now()
for i := 0; i < n; i++ {
rs = rgx.FindStringSubmatch(s)
}
fmt.Println(time.Since(t))
fmt.Println(rs[1]) // [(tag) tag]
t = time.Now()
for i := 0; i < n; i++ {
r = match(s)
}
fmt.Println(time.Since(t))
fmt.Println(r)
}
func match(s string) string {
i := strings.Index(s, "(")
if i >= 0 {
j := strings.Index(s, ")")
if j >= 0 {
return s[i+1 : j]
}
}
return ""
}
I got My problem solved by this regex
r := regexp.MustCompile(`\((.*?)\)`)
Refer to answers, I made my version of the code.
link: https://play.golang.org/p/b82iPZGU1gw
package main
import (
"fmt"
"strings"
)
func match(start, end, s string) string {
i := strings.Index(s, start)
if i >= 0 {
j := strings.Index(s[i:], end)
if j >= 0 {
return s[i+len(start) : i+j]
}
}
return ""
}
func main() {
errText := `facebook: Error validating access token: Session has expired on Tuesday, 28-Jul-20 22:00:00 PDT. The current time is Wednesday, 29-Jul-20 17:55:22 PDT. (code: 190; error_subcode: 463, error_user_title: , error_user_msg: )`
start := "code: "
end := ";"
r := match(start, end, errText)
fmt.Println(r)
}