From 08ec9e3a602cb352d16cc29b6c917a044a1c6cf5 Mon Sep 17 00:00:00 2001 From: jobala Date: Sun, 16 Jan 2022 13:03:18 +0300 Subject: [PATCH 01/31] adds page iterator --- .gitignore | 3 + page_iterator.go | 71 +++++++++++++++++++ page_iterator_test.go | 154 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 228 insertions(+) create mode 100644 page_iterator.go create mode 100644 page_iterator_test.go diff --git a/.gitignore b/.gitignore index 66fd13c..0dcba2d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ # Dependency directories (remove the comment below to include it) # vendor/ + +# Jetbrains files +.idea/ diff --git a/page_iterator.go b/page_iterator.go new file mode 100644 index 0000000..5bf628f --- /dev/null +++ b/page_iterator.go @@ -0,0 +1,71 @@ +package msgraphgocore + +import "net/http" + +type Item interface { + GetDisplayName() string +} +type Page interface { + GetValue() []Item + GetNextLink() string + GetNextPage() Page +} + +type PageIterator struct { + page Page + client http.Client + keepIterating bool + pauseIndex int +} + +func NewPageIterator(page Page, client http.Client) *PageIterator { + return &PageIterator{ + page, + client, + true, + 0, + } +} + +func (pI *PageIterator) HasNext() bool { + if pI.page.GetNextLink() == "" { + return false + } + return true +} + +func (pI *PageIterator) Next() Page { + nextPage := pI.page.GetNextPage() + pI.page = nextPage + + return nextPage +} + +func (pI *PageIterator) Iterate(callback func(pageItem Item) bool) { + for pI.page != nil { + keepIterating := pI.enumerate(callback) + + if !keepIterating { + return + } + + pI.Next() + pI.pauseIndex = 0 + } +} + +func (pI *PageIterator) enumerate(callback func(item Item) bool) bool { + keepIterating := true + pageItems := pI.page.GetValue() + + for i := pI.pauseIndex; i < len(pageItems); i++ { + keepIterating = callback(pageItems[i]) + + if !keepIterating { + pI.pauseIndex = i + break + } + } + + return keepIterating +} diff --git a/page_iterator_test.go b/page_iterator_test.go new file mode 100644 index 0000000..23b0d4e --- /dev/null +++ b/page_iterator_test.go @@ -0,0 +1,154 @@ +package msgraphgocore + +import ( + "github.com/stretchr/testify/assert" + "net/http" + testing "testing" +) + +type PageItem struct { + DisplayName string +} + +type UserPage struct { + Value []Item + NextLink string +} + +var page1 = &UserPage{ + Value: []Item{ + PageItem{DisplayName: "User A"}, + PageItem{DisplayName: "User B"}, + PageItem{DisplayName: "User C"}, + PageItem{DisplayName: "User D"}, + }, + NextLink: "page_2", +} + +var page2 = &UserPage{ + Value: []Item{ + PageItem{DisplayName: "User E"}, + PageItem{DisplayName: "User F"}, + PageItem{DisplayName: "User G"}, + PageItem{DisplayName: "User H"}, + }, + NextLink: "page_3", +} + +var page3 = &UserPage{ + Value: []Item{ + PageItem{DisplayName: "User I"}, + PageItem{DisplayName: "User J"}, + PageItem{DisplayName: "User K"}, + PageItem{DisplayName: "User L"}, + }, + NextLink: "", +} + +func (p *UserPage) GetValue() []Item { + return p.Value +} + +func (p *UserPage) GetNextLink() string { + return p.NextLink +} + +func (p *UserPage) GetNextPage() Page { + switch nextLink := p.GetNextLink(); nextLink { + case "page_2": + return page2 + case "page_3": + return page3 + } + return nil +} + +func (i PageItem) GetDisplayName() string { + return i.DisplayName +} + +func TestHasNextReturnsTrueIfNextPageIsAvailable(t *testing.T) { + client := http.Client{} + pageIterator := NewPageIterator(page1, client) + hasNext := pageIterator.HasNext() + + assert.True(t, hasNext) +} + +func TestNextReturnsNextPage(t *testing.T) { + client := http.Client{} + pageIterator := NewPageIterator(page1, client) + nextPage := pageIterator.Next() + + assert.Equal(t, nextPage, page2) +} + +func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { + res := make([]string, 0) + + client := http.Client{} + pageIterator := NewPageIterator(page1, client) + pageIterator.Iterate(func(pageItem Item) bool { + res = append(res, pageItem.GetDisplayName()) + if pageItem.GetDisplayName() == "User D" { + return false + } + return true + }) + + assert.Equal(t, 4, len(res)) +} + +func TestNextAndHasNext(t *testing.T) { + pageCount := 1 + client := http.Client{} + pageIterator := NewPageIterator(page1, client) + + for pageIterator.HasNext() { + pageCount += 1 + _ = pageIterator.Next() + } + + assert.Equal(t, pageCount, 3) +} +func TestIterateEnumeratesAllPages(t *testing.T) { + res := make([]string, 0) + client := http.Client{} + pageIterator := NewPageIterator(page1, client) + + pageIterator.Iterate(func(pageItem Item) bool { + res = append(res, pageItem.GetDisplayName()) + return true + }) + + assert.Equal(t, 12, len(res)) +} + +func TestIterateCanBePausedAndResumed(t *testing.T) { + res := make([]string, 0) + res2 := make([]string, 0) + client := http.Client{} + pageIterator := NewPageIterator(page1, client) + + pageIterator.Iterate(func(pageItem Item) bool { + res = append(res, pageItem.GetDisplayName()) + + if pageItem.GetDisplayName() == "User D" { + return false + } + + return true + }) + assert.Equal(t, res, []string{"User A", "User B", "User C", "User D"}) + + pageIterator.Iterate(func(pageItem Item) bool { + res2 = append(res2, pageItem.GetDisplayName()) + + if pageItem.GetDisplayName() == "User G" { + return false + } + + return true + }) + assert.Equal(t, res2, []string{"User D", "User E", "User F", "User G"}) +} From 5481491742d8b9b0fd8458e59ad47b060512c385 Mon Sep 17 00:00:00 2001 From: jobala Date: Sun, 16 Jan 2022 22:32:12 +0300 Subject: [PATCH 02/31] adds comments --- page_iterator.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/page_iterator.go b/page_iterator.go index 5bf628f..d8ecdd2 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -5,6 +5,7 @@ import "net/http" type Item interface { GetDisplayName() string } + type Page interface { GetValue() []Item GetNextLink() string @@ -12,18 +13,18 @@ type Page interface { } type PageIterator struct { - page Page - client http.Client - keepIterating bool - pauseIndex int + page Page + client http.Client + pauseIndex int } func NewPageIterator(page Page, client http.Client) *PageIterator { + //TODO: Pass client to page + return &PageIterator{ page, client, - true, - 0, + 0, // pauseIndex helps us remember where we paused enumeration in the page. } } @@ -46,11 +47,12 @@ func (pI *PageIterator) Iterate(callback func(pageItem Item) bool) { keepIterating := pI.enumerate(callback) if !keepIterating { + // Callback returned false, stop iterating through pages. return } pI.Next() - pI.pauseIndex = 0 + pI.pauseIndex = 0 // when moving to the next page reset pauseIndex } } @@ -58,10 +60,14 @@ func (pI *PageIterator) enumerate(callback func(item Item) bool) bool { keepIterating := true pageItems := pI.page.GetValue() + // start/continue enumerating page items from pauseIndex. + // this makes it possible to resume iteration from where we paused iteration. for i := pI.pauseIndex; i < len(pageItems); i++ { keepIterating = callback(pageItems[i]) if !keepIterating { + // Callback returned false, pause! stop enumerating page items. Set pauseIndex so that we know + // where to resume from. pI.pauseIndex = i break } From c659bb1dae53af2e263468e1e6e0526750e928de Mon Sep 17 00:00:00 2001 From: jobala Date: Wed, 19 Jan 2022 12:19:14 +0300 Subject: [PATCH 03/31] updates page iterator --- go.mod | 12 +--------- go.sum | 40 ++------------------------------ page_iterator.go | 60 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 48 insertions(+), 64 deletions(-) diff --git a/go.mod b/go.mod index 55a6e3d..265a23b 100644 --- a/go.mod +++ b/go.mod @@ -9,14 +9,4 @@ require ( github.com/stretchr/testify v1.7.0 ) -require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v0.20.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.2 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/microsoft/kiota/authentication/go/azure v0.0.0-20211201125630-3501743a5dc5 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/yosida95/uritemplate/v3 v3.0.1 // indirect - golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 // indirect - golang.org/x/text v0.3.7 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect -) +require github.com/microsoft/kiota/serialization/go/json v0.0.0-20220118084409-ae624d0bd384 diff --git a/go.sum b/go.sum index b19c9fc..8ef0d43 100644 --- a/go.sum +++ b/go.sum @@ -1,30 +1,15 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v0.20.0 h1:KQgdWmEOmaJKxaUUZwHAYh12t+b+ZJf8q3friycK1kA= -github.com/Azure/azure-sdk-for-go/sdk/azcore v0.20.0/go.mod h1:ZPW/Z0kLCTdDZaDbYTetxc9Cxl/2lNqxYHYNOF2bti0= -github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.1/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= -github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.2 h1:rImM7Yjz9yUgpdxp3A4cZLm1JZuo4XbtIp2LrUZnwYw= -github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.2/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/microsoft/kiota/abstractions/go v0.0.0-20211129093841-858bd540489b/go.mod h1:pIT6aBVb0aHisY52bSbYvb0nyxe+TqdZ8lkpKB7pLIo= -github.com/microsoft/kiota/abstractions/go v0.0.0-20211130101617-a4871ba0f35f h1:nmvVToTSNolrvh7OBJjmVJSyZ+VB9Ql2I5chDAqhPWc= -github.com/microsoft/kiota/abstractions/go v0.0.0-20211130101617-a4871ba0f35f/go.mod h1:m37MbLdeSZ7DBzKtGI+GmlDSIybJBkKhsvLMqkYosb8= -github.com/microsoft/kiota/abstractions/go v0.0.0-20211201125630-3501743a5dc5 h1:IL8rUlP+UMFRvL/bu26HkVMnhU7I5IWKciDIWOAQfEQ= -github.com/microsoft/kiota/abstractions/go v0.0.0-20211201125630-3501743a5dc5/go.mod h1:m37MbLdeSZ7DBzKtGI+GmlDSIybJBkKhsvLMqkYosb8= github.com/microsoft/kiota/abstractions/go v0.0.0-20211202082735-099f3c37853a h1:c2vBeXjRwGJUL7aG1gHFwB+LpdDL20XKIOKQWKUoNQk= github.com/microsoft/kiota/abstractions/go v0.0.0-20211202082735-099f3c37853a/go.mod h1:m37MbLdeSZ7DBzKtGI+GmlDSIybJBkKhsvLMqkYosb8= -github.com/microsoft/kiota/authentication/go/azure v0.0.0-20211201125630-3501743a5dc5 h1:d1ilFuzPOvADm4xiFHJ1SZ00SufAgyqfVXd3TCtS8c0= -github.com/microsoft/kiota/authentication/go/azure v0.0.0-20211201125630-3501743a5dc5/go.mod h1:bmdumwBCIHlVdafcpHNNGzySN/v2mImqWTPgV1adBmA= -github.com/microsoft/kiota/http/go/nethttp v0.0.0-20211130101617-a4871ba0f35f h1:1VRJ6bj+YljEUqXRf+MgPWdfJZf85/juVCwkS7GviZ8= -github.com/microsoft/kiota/http/go/nethttp v0.0.0-20211130101617-a4871ba0f35f/go.mod h1:GHdBYJaaiuZKz78KcLSrjcin5FGXUK3e0wlX69NJMwE= -github.com/microsoft/kiota/http/go/nethttp v0.0.0-20211202082735-099f3c37853a h1:w93KbR22weJ4CKHepKHkirx18j0XMShPWjSRn5ziMwA= -github.com/microsoft/kiota/http/go/nethttp v0.0.0-20211202082735-099f3c37853a/go.mod h1:GHdBYJaaiuZKz78KcLSrjcin5FGXUK3e0wlX69NJMwE= github.com/microsoft/kiota/http/go/nethttp v0.0.0-20211203130928-8449c9e67101 h1:kTG9Tg52O2gNm8LzwyiPyjFendknhU4iqnylDjKQgNU= github.com/microsoft/kiota/http/go/nethttp v0.0.0-20211203130928-8449c9e67101/go.mod h1:GHdBYJaaiuZKz78KcLSrjcin5FGXUK3e0wlX69NJMwE= -github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/microsoft/kiota/serialization/go/json v0.0.0-20220118084409-ae624d0bd384 h1:Ry9Nxq2JKda89pd3E9v3y5N8xN8dDnj4MDyP9SM5Nik= +github.com/microsoft/kiota/serialization/go/json v0.0.0-20220118084409-ae624d0bd384/go.mod h1:IpPcnMiN1topbt3+Tk2NAZiwvMI2Sa+xpSapGHC3wyw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -32,29 +17,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yosida95/uritemplate/v3 v3.0.1 h1:+Fs//CsT+x231WmUQhMHWMxZizMvpnkOVWop02mVCfs= github.com/yosida95/uritemplate/v3 v3.0.1/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 h1:0qxwC5n+ttVOINCBeRHO0nq9X7uy8SDsPoi5OaCdIEI= -golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/page_iterator.go b/page_iterator.go index d8ecdd2..b9eeb84 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -1,47 +1,77 @@ package msgraphgocore -import "net/http" +import ( + abstractions "github.com/microsoft/kiota/abstractions/go" + serialization "github.com/microsoft/kiota/abstractions/go/serialization" + jsonserialization "github.com/microsoft/kiota/serialization/go/json" + "log" + url "net/url" +) -type Item interface { - GetDisplayName() string -} +type Item interface{} type Page interface { GetValue() []Item - GetNextLink() string - GetNextPage() Page + GetNextLink() *string } type PageIterator struct { - page Page - client http.Client - pauseIndex int + page Page + reqAdapter GraphRequestAdapterBase + pauseIndex int + constructorFunc ParsableConstructor } -func NewPageIterator(page Page, client http.Client) *PageIterator { - //TODO: Pass client to page +type ParsableConstructor func() serialization.Parsable + +func NewPageIterator(page Page, reqAdapter GraphRequestAdapterBase, constructorFunc ParsableConstructor) *PageIterator { + abstractions.RegisterDefaultSerializer(func() serialization.SerializationWriterFactory { + return jsonserialization.NewJsonSerializationWriterFactory() + }) + abstractions.RegisterDefaultDeserializer(func() serialization.ParseNodeFactory { + return jsonserialization.NewJsonParseNodeFactory() + }) return &PageIterator{ page, - client, + reqAdapter, 0, // pauseIndex helps us remember where we paused enumeration in the page. + constructorFunc, } } func (pI *PageIterator) HasNext() bool { - if pI.page.GetNextLink() == "" { + if pI.page.GetNextLink() == nil { return false } return true } func (pI *PageIterator) Next() Page { - nextPage := pI.page.GetNextPage() - pI.page = nextPage + nextPage := pI.getNextPage().(Page) + pI.page = nextPage return nextPage } +func (pI *PageIterator) getNextPage() interface{} { + nextLink, err := url.Parse(*pI.page.GetNextLink()) + if err != nil { + log.Fatal(err) + } + + requestInfo := abstractions.NewRequestInformation() + requestInfo.Method = abstractions.GET + requestInfo.SetUri(*nextLink) + + res, err := pI.reqAdapter.SendAsync(*requestInfo, pI.constructorFunc, nil) + if err != nil { + log.Fatal(err) + } + + return res +} + func (pI *PageIterator) Iterate(callback func(pageItem Item) bool) { for pI.page != nil { keepIterating := pI.enumerate(callback) From 10820b929c7b77dcfc2b92336180877e1a635f91 Mon Sep 17 00:00:00 2001 From: jobala Date: Wed, 19 Jan 2022 12:30:18 +0300 Subject: [PATCH 04/31] accepts empty interface for page --- page_iterator.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/page_iterator.go b/page_iterator.go index b9eeb84..354f5d8 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -24,7 +24,7 @@ type PageIterator struct { type ParsableConstructor func() serialization.Parsable -func NewPageIterator(page Page, reqAdapter GraphRequestAdapterBase, constructorFunc ParsableConstructor) *PageIterator { +func NewPageIterator(page interface{}, reqAdapter GraphRequestAdapterBase, constructorFunc ParsableConstructor) *PageIterator { abstractions.RegisterDefaultSerializer(func() serialization.SerializationWriterFactory { return jsonserialization.NewJsonSerializationWriterFactory() }) @@ -33,7 +33,7 @@ func NewPageIterator(page Page, reqAdapter GraphRequestAdapterBase, constructorF }) return &PageIterator{ - page, + page.(Page), reqAdapter, 0, // pauseIndex helps us remember where we paused enumeration in the page. constructorFunc, From 94b6b571ddbeac82dc851b84561779f127844ce9 Mon Sep 17 00:00:00 2001 From: jobala Date: Wed, 19 Jan 2022 12:34:14 +0300 Subject: [PATCH 05/31] values have an empty interface --- page_iterator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/page_iterator.go b/page_iterator.go index 354f5d8..0bbaccb 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -11,7 +11,7 @@ import ( type Item interface{} type Page interface { - GetValue() []Item + GetValue() []interface{} GetNextLink() *string } From 0347e585925c1998fe1f91da57ac2279992f93c7 Mon Sep 17 00:00:00 2001 From: jobala Date: Wed, 19 Jan 2022 12:56:40 +0300 Subject: [PATCH 06/31] updates page iterator --- page_iterator_test.go | 322 ++++++++++++++++++++++-------------------- 1 file changed, 170 insertions(+), 152 deletions(-) diff --git a/page_iterator_test.go b/page_iterator_test.go index 23b0d4e..cfa7db3 100644 --- a/page_iterator_test.go +++ b/page_iterator_test.go @@ -1,154 +1,172 @@ package msgraphgocore -import ( - "github.com/stretchr/testify/assert" - "net/http" - testing "testing" -) - -type PageItem struct { - DisplayName string -} - -type UserPage struct { - Value []Item - NextLink string -} - -var page1 = &UserPage{ - Value: []Item{ - PageItem{DisplayName: "User A"}, - PageItem{DisplayName: "User B"}, - PageItem{DisplayName: "User C"}, - PageItem{DisplayName: "User D"}, - }, - NextLink: "page_2", -} - -var page2 = &UserPage{ - Value: []Item{ - PageItem{DisplayName: "User E"}, - PageItem{DisplayName: "User F"}, - PageItem{DisplayName: "User G"}, - PageItem{DisplayName: "User H"}, - }, - NextLink: "page_3", -} - -var page3 = &UserPage{ - Value: []Item{ - PageItem{DisplayName: "User I"}, - PageItem{DisplayName: "User J"}, - PageItem{DisplayName: "User K"}, - PageItem{DisplayName: "User L"}, - }, - NextLink: "", -} - -func (p *UserPage) GetValue() []Item { - return p.Value -} - -func (p *UserPage) GetNextLink() string { - return p.NextLink -} - -func (p *UserPage) GetNextPage() Page { - switch nextLink := p.GetNextLink(); nextLink { - case "page_2": - return page2 - case "page_3": - return page3 - } - return nil -} - -func (i PageItem) GetDisplayName() string { - return i.DisplayName -} - -func TestHasNextReturnsTrueIfNextPageIsAvailable(t *testing.T) { - client := http.Client{} - pageIterator := NewPageIterator(page1, client) - hasNext := pageIterator.HasNext() - - assert.True(t, hasNext) -} - -func TestNextReturnsNextPage(t *testing.T) { - client := http.Client{} - pageIterator := NewPageIterator(page1, client) - nextPage := pageIterator.Next() - - assert.Equal(t, nextPage, page2) -} - -func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { - res := make([]string, 0) - - client := http.Client{} - pageIterator := NewPageIterator(page1, client) - pageIterator.Iterate(func(pageItem Item) bool { - res = append(res, pageItem.GetDisplayName()) - if pageItem.GetDisplayName() == "User D" { - return false - } - return true - }) - - assert.Equal(t, 4, len(res)) -} - -func TestNextAndHasNext(t *testing.T) { - pageCount := 1 - client := http.Client{} - pageIterator := NewPageIterator(page1, client) - - for pageIterator.HasNext() { - pageCount += 1 - _ = pageIterator.Next() - } - - assert.Equal(t, pageCount, 3) -} -func TestIterateEnumeratesAllPages(t *testing.T) { - res := make([]string, 0) - client := http.Client{} - pageIterator := NewPageIterator(page1, client) - - pageIterator.Iterate(func(pageItem Item) bool { - res = append(res, pageItem.GetDisplayName()) - return true - }) - - assert.Equal(t, 12, len(res)) -} - -func TestIterateCanBePausedAndResumed(t *testing.T) { - res := make([]string, 0) - res2 := make([]string, 0) - client := http.Client{} - pageIterator := NewPageIterator(page1, client) - - pageIterator.Iterate(func(pageItem Item) bool { - res = append(res, pageItem.GetDisplayName()) - - if pageItem.GetDisplayName() == "User D" { - return false - } - - return true - }) - assert.Equal(t, res, []string{"User A", "User B", "User C", "User D"}) - - pageIterator.Iterate(func(pageItem Item) bool { - res2 = append(res2, pageItem.GetDisplayName()) - - if pageItem.GetDisplayName() == "User G" { - return false - } - - return true - }) - assert.Equal(t, res2, []string{"User D", "User E", "User F", "User G"}) -} +// +//import ( +// abstractions "github.com/microsoft/kiota/abstractions/go" +// absauth "github.com/microsoft/kiota/abstractions/go/authentication" +// "github.com/microsoft/kiota/abstractions/go/serialization" +// "github.com/stretchr/testify/assert" +// "net/http" +// u "net/url" +// testing "testing" +//) +// +//type PageItem struct { +// DisplayName string +//} +// +//type UserPage struct { +// Value []Item +// NextLink *string +//} +// +//var page2Link = "page2" +//var page3Link = "page3" +// +//var page1 = &UserPage{ +// Value: []Item{ +// PageItem{DisplayName: "User A"}, +// PageItem{DisplayName: "User B"}, +// PageItem{DisplayName: "User C"}, +// PageItem{DisplayName: "User D"}, +// }, +// NextLink: &page2Link, +//} +// +//var page2 = &UserPage{ +// Value: []Item{ +// PageItem{DisplayName: "User E"}, +// PageItem{DisplayName: "User F"}, +// PageItem{DisplayName: "User G"}, +// PageItem{DisplayName: "User H"}, +// }, +// NextLink: &page3Link, +//} +// +//var page3 = &UserPage{ +// Value: []Item{ +// PageItem{DisplayName: "User I"}, +// PageItem{DisplayName: "User J"}, +// PageItem{DisplayName: "User K"}, +// PageItem{DisplayName: "User L"}, +// }, +// NextLink: nil, +//} +// +//func (p *UserPage) GetValue() []Item { +// return p.Value +//} +// +//func (p *UserPage) GetNextLink() *string { +// return p.NextLink +//} +// +//func (p *UserPage) GetNextPage() Page { +// switch nextLink := p.GetNextLink(); *nextLink { +// case "page_2": +// return page2 +// case "page_3": +// return page3 +// } +// return nil +//} +// +//func (i PageItem) GetDisplayName() string { +// return i.DisplayName +//} +// +//func TestHasNextReturnsTrueIfNextPageIsAvailable(t *testing.T) { +// client := http.Client{} +// pageIterator := NewPageIterator(page1, client) +// hasNext := pageIterator.HasNext() +// +// assert.True(t, hasNext) +//} +// +//func TestNextReturnsNextPage(t *testing.T) { +// client := http.Client{} +// pageIterator := NewPageIterator(page1, client) +// nextPage := pageIterator.Next() +// +// assert.Equal(t, nextPage, page2) +//} +// +//func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { +// res := make([]string, 0) +// +// requestInformation := abstractions.NewRequestInformation() +// requestInformation.SetUri(u.URL{}) +// +// client, _ := NewGraphRequestAdapterBase(absauth.AuthenticationProvider(abstractions.RequestInformation{ +// Method: abstractions.HttpMethod(0), +// }), GraphClientOptions{ +// GraphServiceVersion: "", +// GraphServiceLibraryVersion: "", +// }) +// +// pageIterator := NewPageIterator(page1, client) +// pageIterator.Iterate(func(pageItem Item) bool { +// res = append(res, pageItem.GetDisplayName()) +// if pageItem.GetDisplayName() == "User D" { +// return false +// } +// return true +// }) +// +// assert.Equal(t, 4, len(res)) +//} +// +//func TestNextAndHasNext(t *testing.T) { +// pageCount := 1 +// client := http.Client{} +// pageIterator := NewPageIterator(page1, client) +// +// for pageIterator.HasNext() { +// pageCount += 1 +// _ = pageIterator.Next() +// } +// +// assert.Equal(t, pageCount, 3) +//} +//func TestIterateEnumeratesAllPages(t *testing.T) { +// res := make([]string, 0) +// client := http.Client{} +// pageIterator := NewPageIterator(page1, client) +// +// pageIterator.Iterate(func(pageItem Item) bool { +// res = append(res, pageItem.GetDisplayName()) +// return true +// }) +// +// assert.Equal(t, 12, len(res)) +//} +// +//func TestIterateCanBePausedAndResumed(t *testing.T) { +// res := make([]string, 0) +// res2 := make([]string, 0) +// client := http.Client{} +// pageIterator := NewPageIterator(page1, client) +// +// pageIterator.Iterate(func(pageItem Item) bool { +// res = append(res, pageItem.GetDisplayName()) +// +// if pageItem.GetDisplayName() == "User D" { +// return false +// } +// +// return true +// }) +// assert.Equal(t, res, []string{"User A", "User B", "User C", "User D"}) +// +// pageIterator.Iterate(func(pageItem Item) bool { +// pageItem = pageItem +// res2 = append(res2, pageItem.GetDisplayName()) +// +// if pageItem.GetDisplayName() == "User G" { +// return false +// } +// +// return true +// }) +// assert.Equal(t, res2, []string{"User D", "User E", "User F", "User G"}) +//} From aa323018f871318a403c7d152d79dc14c2a7dcca Mon Sep 17 00:00:00 2001 From: jobala Date: Fri, 21 Jan 2022 11:09:12 +0300 Subject: [PATCH 07/31] adds working iterator --- go.mod | 7 ++++ page_iterator.go | 91 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 80 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 265a23b..51d13fe 100644 --- a/go.mod +++ b/go.mod @@ -10,3 +10,10 @@ require ( ) require github.com/microsoft/kiota/serialization/go/json v0.0.0-20220118084409-ae624d0bd384 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/yosida95/uritemplate/v3 v3.0.1 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect +) diff --git a/page_iterator.go b/page_iterator.go index 0bbaccb..14457e6 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -1,22 +1,23 @@ package msgraphgocore import ( + "log" + "net/url" + "reflect" + "unsafe" + abstractions "github.com/microsoft/kiota/abstractions/go" - serialization "github.com/microsoft/kiota/abstractions/go/serialization" + "github.com/microsoft/kiota/abstractions/go/serialization" jsonserialization "github.com/microsoft/kiota/serialization/go/json" - "log" - url "net/url" ) -type Item interface{} - type Page interface { GetValue() []interface{} GetNextLink() *string } type PageIterator struct { - page Page + currentPage Page reqAdapter GraphRequestAdapterBase pauseIndex int constructorFunc ParsableConstructor @@ -24,7 +25,28 @@ type PageIterator struct { type ParsableConstructor func() serialization.Parsable -func NewPageIterator(page interface{}, reqAdapter GraphRequestAdapterBase, constructorFunc ParsableConstructor) *PageIterator { +type PageResult struct { + nextLink *string + value []interface{} +} + +func (p *PageResult) GetValue() []interface{} { + if p == nil { + return nil + } + + return p.value +} + +func (p *PageResult) GetNextLink() *string { + if p == nil { + return nil + } + + return p.nextLink +} + +func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constructorFunc ParsableConstructor) *PageIterator { abstractions.RegisterDefaultSerializer(func() serialization.SerializationWriterFactory { return jsonserialization.NewJsonSerializationWriterFactory() }) @@ -33,7 +55,7 @@ func NewPageIterator(page interface{}, reqAdapter GraphRequestAdapterBase, const }) return &PageIterator{ - page.(Page), + convertToPage(res), reqAdapter, 0, // pauseIndex helps us remember where we paused enumeration in the page. constructorFunc, @@ -41,21 +63,25 @@ func NewPageIterator(page interface{}, reqAdapter GraphRequestAdapterBase, const } func (pI *PageIterator) HasNext() bool { - if pI.page.GetNextLink() == nil { + if pI.currentPage == nil || pI.currentPage.GetNextLink() == nil { return false } return true } func (pI *PageIterator) Next() Page { - nextPage := pI.getNextPage().(Page) + nextPage := pI.getNextPage() - pI.page = nextPage + pI.currentPage = nextPage return nextPage } -func (pI *PageIterator) getNextPage() interface{} { - nextLink, err := url.Parse(*pI.page.GetNextLink()) +func (pI *PageIterator) getNextPage() *PageResult { + if pI.currentPage.GetNextLink() == nil { + return nil + } + + nextLink, err := url.Parse(*pI.currentPage.GetNextLink()) if err != nil { log.Fatal(err) } @@ -69,11 +95,11 @@ func (pI *PageIterator) getNextPage() interface{} { log.Fatal(err) } - return res + return convertToPage(res) } -func (pI *PageIterator) Iterate(callback func(pageItem Item) bool) { - for pI.page != nil { +func (pI *PageIterator) Iterate(callback func(pageItem interface{}) bool) { + for pI.currentPage != nil { keepIterating := pI.enumerate(callback) if !keepIterating { @@ -86,9 +112,17 @@ func (pI *PageIterator) Iterate(callback func(pageItem Item) bool) { } } -func (pI *PageIterator) enumerate(callback func(item Item) bool) bool { +func (pI *PageIterator) enumerate(callback func(item interface{}) bool) bool { keepIterating := true - pageItems := pI.page.GetValue() + + if pI.currentPage == nil { + return false + } + + pageItems := pI.currentPage.GetValue() + if pageItems == nil { + return false + } // start/continue enumerating page items from pauseIndex. // this makes it possible to resume iteration from where we paused iteration. @@ -105,3 +139,24 @@ func (pI *PageIterator) enumerate(callback func(item Item) bool) bool { return keepIterating } + +func convertToPage(response interface{}) *PageResult { + ref := reflect.ValueOf(response).Elem() + value := ref.FieldByName("value") + value = reflect.NewAt(value.Type(), unsafe.Pointer(value.UnsafeAddr())).Elem() + + nextLink := ref.FieldByName("nextLink") + nextLink = reflect.NewAt(nextLink.Type(), unsafe.Pointer(nextLink.UnsafeAddr())).Elem() + + // Collect all entities in the value slice. + // This converts a graph slice ie []graph.User to a dynamic slice []interface{} + collected := make([]interface{}, 0) + for i := 0; i < value.Len(); i++ { + collected = append(collected, value.Index(i).Interface()) + } + + return &PageResult{ + nextLink: nextLink.Interface().(*string), + value: collected, + } +} From 8a7f8f784b65679be4823e539f3553b9a6f01b5c Mon Sep 17 00:00:00 2001 From: jobala Date: Fri, 21 Jan 2022 13:37:23 +0300 Subject: [PATCH 08/31] adds mocked types --- msgraphgocore_test/user.go | 171 ++++++++++++++++ msgraphgocore_test/user_response.go | 133 ++++++++++++ page_iterator_test.go | 301 ++++++++++++---------------- 3 files changed, 435 insertions(+), 170 deletions(-) create mode 100644 msgraphgocore_test/user.go create mode 100644 msgraphgocore_test/user_response.go diff --git a/msgraphgocore_test/user.go b/msgraphgocore_test/user.go new file mode 100644 index 0000000..254f85a --- /dev/null +++ b/msgraphgocore_test/user.go @@ -0,0 +1,171 @@ +package msgraphgocore_test + +import ( + i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e "time" + + i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55 "github.com/microsoft/kiota/abstractions/go/serialization" +) + +type User struct { + DisplayName *string + DirectoryObject +} + +func (u *User) GetDisplayName() *string { + return u.DisplayName +} + +var displayName = "A User" + +func NewUser() *User { + return &User{ + DisplayName: &displayName, + } +} + +type DirectoryObject struct { + Entity + // + deletedDateTime *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time +} + +// NewDirectoryObject instantiates a new directoryObject and sets the default values. +func NewDirectoryObject() *DirectoryObject { + m := &DirectoryObject{ + Entity: *NewEntity(), + } + return m +} + +// GetDeletedDateTime gets the deletedDateTime property value. +func (m *DirectoryObject) GetDeletedDateTime() *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time { + if m == nil { + return nil + } else { + return m.deletedDateTime + } +} + +// GetFieldDeserializers the deserialization information for the current model +func (m *DirectoryObject) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + res := m.Entity.GetFieldDeserializers() + res["deletedDateTime"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + val, err := n.GetTimeValue() + if err != nil { + return err + } + if val != nil { + m.SetDeletedDateTime(val) + } + return nil + } + return res +} +func (m *DirectoryObject) IsNil() bool { + return m == nil +} + +// Serialize serializes information the current object +func (m *DirectoryObject) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { + err := m.Entity.Serialize(writer) + if err != nil { + return err + } + { + err = writer.WriteTimeValue("deletedDateTime", m.GetDeletedDateTime()) + if err != nil { + return err + } + } + return nil +} + +// SetDeletedDateTime sets the deletedDateTime property value. +func (m *DirectoryObject) SetDeletedDateTime(value *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time) { + if m != nil { + m.deletedDateTime = value + } +} + +// Entity +type Entity struct { + // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + additionalData map[string]interface{} + // Read-only. + id *string +} + +// NewEntity instantiates a new entity and sets the default values. +func NewEntity() *Entity { + m := &Entity{} + m.SetAdditionalData(make(map[string]interface{})) + return m +} + +// GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. +func (m *Entity) GetAdditionalData() map[string]interface{} { + if m == nil { + return nil + } else { + return m.additionalData + } +} + +// GetId gets the id property value. Read-only. +func (m *Entity) GetId() *string { + if m == nil { + return nil + } else { + return m.id + } +} + +// GetFieldDeserializers the deserialization information for the current model +func (m *Entity) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + res := make(map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error) + res["id"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetId(val) + } + return nil + } + return res +} +func (m *Entity) IsNil() bool { + return m == nil +} + +// Serialize serializes information the current object +func (m *Entity) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { + { + err := writer.WriteStringValue("id", m.GetId()) + if err != nil { + return err + } + } + { + err := writer.WriteAdditionalData(m.GetAdditionalData()) + if err != nil { + return err + } + } + return nil +} + +// SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. +func (m *Entity) SetAdditionalData(value map[string]interface{}) { + if m != nil { + m.additionalData = value + } +} + +// SetId sets the id property value. Read-only. +func (m *Entity) SetId(value *string) { + if m != nil { + m.id = value + } +} diff --git a/msgraphgocore_test/user_response.go b/msgraphgocore_test/user_response.go new file mode 100644 index 0000000..78276b1 --- /dev/null +++ b/msgraphgocore_test/user_response.go @@ -0,0 +1,133 @@ +package msgraphgocore_test + +import ( + i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55 "github.com/microsoft/kiota/abstractions/go/serialization" +) + +// UsersResponse +type UsersResponse struct { + // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + additionalData map[string]interface{} + // + nextLink *string + // + value []User +} + +// NewUsersResponse instantiates a new usersResponse and sets the default values. +func NewUsersResponse() *UsersResponse { + m := &UsersResponse{} + m.SetAdditionalData(make(map[string]interface{})) + return m +} + +// GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. +func (m *UsersResponse) GetAdditionalData() map[string]interface{} { + if m == nil { + return nil + } else { + return m.additionalData + } +} + +// GetNextLink gets the @odata.nextLink property value. +func (m *UsersResponse) GetNextLink() *string { + if m == nil { + return nil + } else { + return m.nextLink + } +} + +// GetValue gets the value property value. +func (m *UsersResponse) GetValue() []User { + if m == nil { + return nil + } else { + return m.value + } +} + +// GetFieldDeserializers the deserialization information for the current model +func (m *UsersResponse) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + res := make(map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error) + res["@odata.nextLink"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetNextLink(val) + } + return nil + } + res["value"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + val, err := n.GetCollectionOfObjectValues(func() i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable { + return NewUser() + }) + if err != nil { + return err + } + if val != nil { + res := make([]User, len(val)) + for i, v := range val { + res[i] = *(v.(*User)) + } + m.SetValue(res) + } + return nil + } + return res +} +func (m *UsersResponse) IsNil() bool { + return m == nil +} + +// Serialize serializes information the current object +func (m *UsersResponse) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { + { + err := writer.WriteStringValue("@odata.nextLink", m.GetNextLink()) + if err != nil { + return err + } + } + { + cast := make([]i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable, len(m.GetValue())) + for i, v := range m.GetValue() { + temp := v + cast[i] = i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable(&temp) + } + err := writer.WriteCollectionOfObjectValues("value", cast) + if err != nil { + return err + } + } + { + err := writer.WriteAdditionalData(m.GetAdditionalData()) + if err != nil { + return err + } + } + return nil +} + +// SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. +func (m *UsersResponse) SetAdditionalData(value map[string]interface{}) { + if m != nil { + m.additionalData = value + } +} + +// SetNextLink sets the @odata.nextLink property value. +func (m *UsersResponse) SetNextLink(value *string) { + if m != nil { + m.nextLink = value + } +} + +// SetValue sets the value property value. +func (m *UsersResponse) SetValue(value []User) { + if m != nil { + m.value = value + } +} diff --git a/page_iterator_test.go b/page_iterator_test.go index cfa7db3..6ebf40c 100644 --- a/page_iterator_test.go +++ b/page_iterator_test.go @@ -1,172 +1,133 @@ package msgraphgocore -// -//import ( -// abstractions "github.com/microsoft/kiota/abstractions/go" -// absauth "github.com/microsoft/kiota/abstractions/go/authentication" -// "github.com/microsoft/kiota/abstractions/go/serialization" -// "github.com/stretchr/testify/assert" -// "net/http" -// u "net/url" -// testing "testing" -//) -// -//type PageItem struct { -// DisplayName string -//} -// -//type UserPage struct { -// Value []Item -// NextLink *string -//} -// -//var page2Link = "page2" -//var page3Link = "page3" -// -//var page1 = &UserPage{ -// Value: []Item{ -// PageItem{DisplayName: "User A"}, -// PageItem{DisplayName: "User B"}, -// PageItem{DisplayName: "User C"}, -// PageItem{DisplayName: "User D"}, -// }, -// NextLink: &page2Link, -//} -// -//var page2 = &UserPage{ -// Value: []Item{ -// PageItem{DisplayName: "User E"}, -// PageItem{DisplayName: "User F"}, -// PageItem{DisplayName: "User G"}, -// PageItem{DisplayName: "User H"}, -// }, -// NextLink: &page3Link, -//} -// -//var page3 = &UserPage{ -// Value: []Item{ -// PageItem{DisplayName: "User I"}, -// PageItem{DisplayName: "User J"}, -// PageItem{DisplayName: "User K"}, -// PageItem{DisplayName: "User L"}, -// }, -// NextLink: nil, -//} -// -//func (p *UserPage) GetValue() []Item { -// return p.Value -//} -// -//func (p *UserPage) GetNextLink() *string { -// return p.NextLink -//} -// -//func (p *UserPage) GetNextPage() Page { -// switch nextLink := p.GetNextLink(); *nextLink { -// case "page_2": -// return page2 -// case "page_3": -// return page3 -// } -// return nil -//} -// -//func (i PageItem) GetDisplayName() string { -// return i.DisplayName -//} -// -//func TestHasNextReturnsTrueIfNextPageIsAvailable(t *testing.T) { -// client := http.Client{} -// pageIterator := NewPageIterator(page1, client) -// hasNext := pageIterator.HasNext() -// -// assert.True(t, hasNext) -//} -// -//func TestNextReturnsNextPage(t *testing.T) { -// client := http.Client{} -// pageIterator := NewPageIterator(page1, client) -// nextPage := pageIterator.Next() -// -// assert.Equal(t, nextPage, page2) -//} -// -//func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { -// res := make([]string, 0) -// -// requestInformation := abstractions.NewRequestInformation() -// requestInformation.SetUri(u.URL{}) -// -// client, _ := NewGraphRequestAdapterBase(absauth.AuthenticationProvider(abstractions.RequestInformation{ -// Method: abstractions.HttpMethod(0), -// }), GraphClientOptions{ -// GraphServiceVersion: "", -// GraphServiceLibraryVersion: "", -// }) -// -// pageIterator := NewPageIterator(page1, client) -// pageIterator.Iterate(func(pageItem Item) bool { -// res = append(res, pageItem.GetDisplayName()) -// if pageItem.GetDisplayName() == "User D" { -// return false -// } -// return true -// }) -// -// assert.Equal(t, 4, len(res)) -//} -// -//func TestNextAndHasNext(t *testing.T) { -// pageCount := 1 -// client := http.Client{} -// pageIterator := NewPageIterator(page1, client) -// -// for pageIterator.HasNext() { -// pageCount += 1 -// _ = pageIterator.Next() -// } -// -// assert.Equal(t, pageCount, 3) -//} -//func TestIterateEnumeratesAllPages(t *testing.T) { -// res := make([]string, 0) -// client := http.Client{} -// pageIterator := NewPageIterator(page1, client) -// -// pageIterator.Iterate(func(pageItem Item) bool { -// res = append(res, pageItem.GetDisplayName()) -// return true -// }) -// -// assert.Equal(t, 12, len(res)) -//} -// -//func TestIterateCanBePausedAndResumed(t *testing.T) { -// res := make([]string, 0) -// res2 := make([]string, 0) -// client := http.Client{} -// pageIterator := NewPageIterator(page1, client) -// -// pageIterator.Iterate(func(pageItem Item) bool { -// res = append(res, pageItem.GetDisplayName()) -// -// if pageItem.GetDisplayName() == "User D" { -// return false -// } -// -// return true -// }) -// assert.Equal(t, res, []string{"User A", "User B", "User C", "User D"}) -// -// pageIterator.Iterate(func(pageItem Item) bool { -// pageItem = pageItem -// res2 = append(res2, pageItem.GetDisplayName()) -// -// if pageItem.GetDisplayName() == "User G" { -// return false -// } -// -// return true -// }) -// assert.Equal(t, res2, []string{"User D", "User E", "User F", "User G"}) -//} +import ( + testing "testing" + + "github.com/microsoft/kiota/abstractions/go/serialization" + "github.com/microsoftgraph/msgraph-sdk-go-core/msgraphgocore_test" + "github.com/stretchr/testify/assert" +) + +type PageItem struct { + DisplayName string +} + +type UserPage struct { + Value []interface{} + NextLink *string +} + +var page2Link = "page2" +var page3Link = "page3" + +var page1 = &UserPage{ + Value: []interface{}{ + PageItem{DisplayName: "User A"}, + PageItem{DisplayName: "User B"}, + PageItem{DisplayName: "User C"}, + PageItem{DisplayName: "User D"}, + }, + NextLink: &page2Link, +} + +var page2 = &UserPage{ + Value: []interface{}{ + PageItem{DisplayName: "User E"}, + PageItem{DisplayName: "User F"}, + PageItem{DisplayName: "User G"}, + PageItem{DisplayName: "User H"}, + }, + NextLink: &page3Link, +} + +var page3 = &UserPage{ + Value: []interface{}{ + PageItem{DisplayName: "User I"}, + PageItem{DisplayName: "User J"}, + PageItem{DisplayName: "User K"}, + PageItem{DisplayName: "User L"}, + }, + NextLink: nil, +} + +var reqAdapter = &GraphRequestAdapterBase{} + +func ParsableCons() serialization.Parsable { + return msgraphgocore_test.NewUsersResponse() +} + +var res = msgraphgocore_test.NewUsersResponse() + +func TestHasNextReturnsTrueIfNextPageIsAvailable(t *testing.T) { + pageIterator := NewPageIterator(res, *reqAdapter, ParsableCons) + hasNext := pageIterator.HasNext() + assert.True(t, hasNext) +} + +func TestNextReturnsNextPage(t *testing.T) { + pageIterator := NewPageIterator(res, *reqAdapter, ParsableCons) + nextPage := pageIterator.Next() + + assert.Equal(t, nextPage, page2) +} + +func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { + res := make([]string, 0) + + pageIterator := NewPageIterator(res, *reqAdapter, ParsableCons) + pageIterator.Iterate(func(pageItem interface{}) bool { + item := pageItem.(msgraphgocore_test.User) + + res = append(res, *item.GetDisplayName()) + return *item.GetDisplayName() == "User D" + }) + + assert.Equal(t, 4, len(res)) +} + +func TestNextAndHasNext(t *testing.T) { + pageCount := 1 + pageIterator := NewPageIterator(res, *reqAdapter, ParsableCons) + + for pageIterator.HasNext() { + pageCount += 1 + _ = pageIterator.Next() + } + + assert.Equal(t, pageCount, 3) +} +func TestIterateEnumeratesAllPages(t *testing.T) { + pageIterator := NewPageIterator(res, *reqAdapter, ParsableCons) + res := make([]string, 0) + + pageIterator.Iterate(func(pageItem interface{}) bool { + item := pageItem.(msgraphgocore_test.User) + res = append(res, *item.GetDisplayName()) + return true + }) + + assert.Equal(t, 12, len(res)) +} + +func TestIterateCanBePausedAndResumed(t *testing.T) { + res := make([]string, 0) + res2 := make([]string, 0) + pageIterator := NewPageIterator(res, *reqAdapter, ParsableCons) + + pageIterator.Iterate(func(pageItem interface{}) bool { + item := pageItem.(msgraphgocore_test.User) + + res = append(res, *item.GetDisplayName()) + + return *item.GetDisplayName() == "User D" + }) + assert.Equal(t, res, []string{"User A", "User B", "User C", "User D"}) + + pageIterator.Iterate(func(pageItem interface{}) bool { + item := pageItem.(msgraphgocore_test.User) + res2 = append(res2, *item.GetDisplayName()) + + return *item.GetDisplayName() == "User G" + }) + assert.Equal(t, res2, []string{"User D", "User E", "User F", "User G"}) +} From 526a5e00303f7d7d8ec07037ad5ab9aad8842dc7 Mon Sep 17 00:00:00 2001 From: jobala Date: Sat, 22 Jan 2022 16:15:09 +0300 Subject: [PATCH 09/31] updates tests --- page_iterator_test.go | 175 ++++++++++++++++++++++++------------------ 1 file changed, 101 insertions(+), 74 deletions(-) diff --git a/page_iterator_test.go b/page_iterator_test.go index 6ebf40c..f54ca3d 100644 --- a/page_iterator_test.go +++ b/page_iterator_test.go @@ -1,8 +1,12 @@ package msgraphgocore import ( + "fmt" + nethttp "net/http" + httptest "net/http/httptest" testing "testing" + "github.com/microsoft/kiota/abstractions/go/authentication" "github.com/microsoft/kiota/abstractions/go/serialization" "github.com/microsoftgraph/msgraph-sdk-go-core/msgraphgocore_test" "github.com/stretchr/testify/assert" @@ -17,117 +21,140 @@ type UserPage struct { NextLink *string } -var page2Link = "page2" -var page3Link = "page3" - -var page1 = &UserPage{ - Value: []interface{}{ - PageItem{DisplayName: "User A"}, - PageItem{DisplayName: "User B"}, - PageItem{DisplayName: "User C"}, - PageItem{DisplayName: "User D"}, - }, - NextLink: &page2Link, -} - -var page2 = &UserPage{ - Value: []interface{}{ - PageItem{DisplayName: "User E"}, - PageItem{DisplayName: "User F"}, - PageItem{DisplayName: "User G"}, - PageItem{DisplayName: "User H"}, - }, - NextLink: &page3Link, -} - -var page3 = &UserPage{ - Value: []interface{}{ - PageItem{DisplayName: "User I"}, - PageItem{DisplayName: "User J"}, - PageItem{DisplayName: "User K"}, - PageItem{DisplayName: "User L"}, - }, - NextLink: nil, -} - -var reqAdapter = &GraphRequestAdapterBase{} +var reqAdapter, _ = NewGraphRequestAdapterBase(&authentication.AnonymousAuthenticationProvider{}, GraphClientOptions{ + GraphServiceVersion: "", + GraphServiceLibraryVersion: "", +}) func ParsableCons() serialization.Parsable { return msgraphgocore_test.NewUsersResponse() } -var res = msgraphgocore_test.NewUsersResponse() - -func TestHasNextReturnsTrueIfNextPageIsAvailable(t *testing.T) { - pageIterator := NewPageIterator(res, *reqAdapter, ParsableCons) - hasNext := pageIterator.HasNext() - assert.True(t, hasNext) -} - -func TestNextReturnsNextPage(t *testing.T) { - pageIterator := NewPageIterator(res, *reqAdapter, ParsableCons) - nextPage := pageIterator.Next() - - assert.Equal(t, nextPage, page2) -} - func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { res := make([]string, 0) + graphResponse := buildGraphResponse() + testServer := httptest.NewServer(nethttp.HandlerFunc(func(w nethttp.ResponseWriter, req *nethttp.Request) { + w.Header().Set("Content-Type", "application/json") + fmt.Fprint(w, ` + { + "nextLink": "", + "value": [ + { + "id": "10" + } + ] + } + `) + + })) + defer testServer.Close() + pageIterator := NewPageIterator(graphResponse, *reqAdapter, ParsableCons) - pageIterator := NewPageIterator(res, *reqAdapter, ParsableCons) pageIterator.Iterate(func(pageItem interface{}) bool { item := pageItem.(msgraphgocore_test.User) res = append(res, *item.GetDisplayName()) - return *item.GetDisplayName() == "User D" + return !(*item.GetId() == "2") }) - assert.Equal(t, 4, len(res)) + assert.Equal(t, len(res), 3) } -func TestNextAndHasNext(t *testing.T) { - pageCount := 1 - pageIterator := NewPageIterator(res, *reqAdapter, ParsableCons) - - for pageIterator.HasNext() { - pageCount += 1 - _ = pageIterator.Next() - } - - assert.Equal(t, pageCount, 3) -} func TestIterateEnumeratesAllPages(t *testing.T) { - pageIterator := NewPageIterator(res, *reqAdapter, ParsableCons) + testServer := httptest.NewServer(nethttp.HandlerFunc(func(w nethttp.ResponseWriter, req *nethttp.Request) { + w.Header().Set("Content-Type", "application/json") + fmt.Fprint(w, ` + { + "nextLink": "", + "value": [ + { + "id": "10" + } + ] + } + `) + + })) + defer testServer.Close() + + graphResponse := buildGraphResponse() + mockPath := testServer.URL + "/next-page" + graphResponse.SetNextLink(&mockPath) + + pageIterator := NewPageIterator(graphResponse, *reqAdapter, ParsableCons) res := make([]string, 0) pageIterator.Iterate(func(pageItem interface{}) bool { item := pageItem.(msgraphgocore_test.User) - res = append(res, *item.GetDisplayName()) + res = append(res, *item.GetId()) return true }) - assert.Equal(t, 12, len(res)) + // Initial page has 5 items and the next page has 1 item. + assert.Equal(t, len(res), 6) } func TestIterateCanBePausedAndResumed(t *testing.T) { res := make([]string, 0) res2 := make([]string, 0) - pageIterator := NewPageIterator(res, *reqAdapter, ParsableCons) + testServer := httptest.NewServer(nethttp.HandlerFunc(func(w nethttp.ResponseWriter, req *nethttp.Request) { + w.Header().Set("Content-Type", "application/json") + fmt.Fprint(w, ` + { + "nextLink": "", + "value": [ + { + "id": "10" + } + ] + } + `) + + })) + defer testServer.Close() + + response := buildGraphResponse() + mockPath := testServer.URL + "/next-page" + response.SetNextLink(&mockPath) + + pageIterator := NewPageIterator(response, *reqAdapter, ParsableCons) pageIterator.Iterate(func(pageItem interface{}) bool { item := pageItem.(msgraphgocore_test.User) + res = append(res, *item.GetId()) - res = append(res, *item.GetDisplayName()) - - return *item.GetDisplayName() == "User D" + if *item.GetId() == "2" { + return false + } + return true }) - assert.Equal(t, res, []string{"User A", "User B", "User C", "User D"}) + assert.Equal(t, res, []string{"0", "1", "2"}) pageIterator.Iterate(func(pageItem interface{}) bool { item := pageItem.(msgraphgocore_test.User) - res2 = append(res2, *item.GetDisplayName()) + res2 = append(res2, *item.GetId()) - return *item.GetDisplayName() == "User G" + return true }) - assert.Equal(t, res2, []string{"User D", "User E", "User F", "User G"}) + assert.Equal(t, res2, []string{"2", "3", "4", "10"}) +} + +func buildGraphResponse() *msgraphgocore_test.UsersResponse { + var res = msgraphgocore_test.NewUsersResponse() + + nextLink := "next-page" + users := make([]msgraphgocore_test.User, 0) + + for i := 0; i < 5; i++ { + u := msgraphgocore_test.NewUser() + id := fmt.Sprint(i) + u.SetId(&id) + + users = append(users, *u) + } + + res.SetNextLink(&nextLink) + res.SetValue(users) + + return res } From 815588ea498ef94e211ec9ba9794fa3c69c2a94f Mon Sep 17 00:00:00 2001 From: jobala Date: Sat, 22 Jan 2022 16:18:33 +0300 Subject: [PATCH 10/31] makes next & hasNext private --- page_iterator.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/page_iterator.go b/page_iterator.go index 14457e6..f597a2f 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -12,8 +12,8 @@ import ( ) type Page interface { - GetValue() []interface{} - GetNextLink() *string + getValue() []interface{} + getNextLink() *string } type PageIterator struct { @@ -30,7 +30,7 @@ type PageResult struct { value []interface{} } -func (p *PageResult) GetValue() []interface{} { +func (p *PageResult) getValue() []interface{} { if p == nil { return nil } @@ -38,7 +38,7 @@ func (p *PageResult) GetValue() []interface{} { return p.value } -func (p *PageResult) GetNextLink() *string { +func (p *PageResult) getNextLink() *string { if p == nil { return nil } @@ -62,14 +62,14 @@ func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constr } } -func (pI *PageIterator) HasNext() bool { - if pI.currentPage == nil || pI.currentPage.GetNextLink() == nil { +func (pI *PageIterator) hasNext() bool { + if pI.currentPage == nil || pI.currentPage.getNextLink() == nil { return false } return true } -func (pI *PageIterator) Next() Page { +func (pI *PageIterator) next() Page { nextPage := pI.getNextPage() pI.currentPage = nextPage @@ -77,11 +77,11 @@ func (pI *PageIterator) Next() Page { } func (pI *PageIterator) getNextPage() *PageResult { - if pI.currentPage.GetNextLink() == nil { + if pI.currentPage.getNextLink() == nil { return nil } - nextLink, err := url.Parse(*pI.currentPage.GetNextLink()) + nextLink, err := url.Parse(*pI.currentPage.getNextLink()) if err != nil { log.Fatal(err) } @@ -107,7 +107,7 @@ func (pI *PageIterator) Iterate(callback func(pageItem interface{}) bool) { return } - pI.Next() + pI.next() pI.pauseIndex = 0 // when moving to the next page reset pauseIndex } } @@ -119,7 +119,7 @@ func (pI *PageIterator) enumerate(callback func(item interface{}) bool) bool { return false } - pageItems := pI.currentPage.GetValue() + pageItems := pI.currentPage.getValue() if pageItems == nil { return false } From 9d0d7f01f23d65049e344961b41c099052a87aaa Mon Sep 17 00:00:00 2001 From: jobala Date: Sat, 22 Jan 2022 16:52:36 +0300 Subject: [PATCH 11/31] supports passing headers for subsequent requests --- page_iterator.go | 33 ++++++++++++++++++--------------- page_iterator_test.go | 6 +++--- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/page_iterator.go b/page_iterator.go index f597a2f..fbf2f4d 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -21,6 +21,7 @@ type PageIterator struct { reqAdapter GraphRequestAdapterBase pauseIndex int constructorFunc ParsableConstructor + headers map[string]string } type ParsableConstructor func() serialization.Parsable @@ -46,7 +47,7 @@ func (p *PageResult) getNextLink() *string { return p.nextLink } -func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constructorFunc ParsableConstructor) *PageIterator { +func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constructorFunc ParsableConstructor, headers map[string]string) *PageIterator { abstractions.RegisterDefaultSerializer(func() serialization.SerializationWriterFactory { return jsonserialization.NewJsonSerializationWriterFactory() }) @@ -59,6 +60,21 @@ func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constr reqAdapter, 0, // pauseIndex helps us remember where we paused enumeration in the page. constructorFunc, + headers, + } +} + +func (pI *PageIterator) Iterate(callback func(pageItem interface{}) bool) { + for pI.currentPage != nil { + keepIterating := pI.enumerate(callback) + + if !keepIterating { + // Callback returned false, stop iterating through pages. + return + } + + pI.next() + pI.pauseIndex = 0 // when moving to the next page reset pauseIndex } } @@ -89,6 +105,7 @@ func (pI *PageIterator) getNextPage() *PageResult { requestInfo := abstractions.NewRequestInformation() requestInfo.Method = abstractions.GET requestInfo.SetUri(*nextLink) + requestInfo.Headers = pI.headers res, err := pI.reqAdapter.SendAsync(*requestInfo, pI.constructorFunc, nil) if err != nil { @@ -98,20 +115,6 @@ func (pI *PageIterator) getNextPage() *PageResult { return convertToPage(res) } -func (pI *PageIterator) Iterate(callback func(pageItem interface{}) bool) { - for pI.currentPage != nil { - keepIterating := pI.enumerate(callback) - - if !keepIterating { - // Callback returned false, stop iterating through pages. - return - } - - pI.next() - pI.pauseIndex = 0 // when moving to the next page reset pauseIndex - } -} - func (pI *PageIterator) enumerate(callback func(item interface{}) bool) bool { keepIterating := true diff --git a/page_iterator_test.go b/page_iterator_test.go index f54ca3d..5b076b4 100644 --- a/page_iterator_test.go +++ b/page_iterator_test.go @@ -48,7 +48,7 @@ func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { })) defer testServer.Close() - pageIterator := NewPageIterator(graphResponse, *reqAdapter, ParsableCons) + pageIterator := NewPageIterator(graphResponse, *reqAdapter, ParsableCons, nil) pageIterator.Iterate(func(pageItem interface{}) bool { item := pageItem.(msgraphgocore_test.User) @@ -81,7 +81,7 @@ func TestIterateEnumeratesAllPages(t *testing.T) { mockPath := testServer.URL + "/next-page" graphResponse.SetNextLink(&mockPath) - pageIterator := NewPageIterator(graphResponse, *reqAdapter, ParsableCons) + pageIterator := NewPageIterator(graphResponse, *reqAdapter, ParsableCons, nil) res := make([]string, 0) pageIterator.Iterate(func(pageItem interface{}) bool { @@ -118,7 +118,7 @@ func TestIterateCanBePausedAndResumed(t *testing.T) { mockPath := testServer.URL + "/next-page" response.SetNextLink(&mockPath) - pageIterator := NewPageIterator(response, *reqAdapter, ParsableCons) + pageIterator := NewPageIterator(response, *reqAdapter, ParsableCons, nil) pageIterator.Iterate(func(pageItem interface{}) bool { item := pageItem.(msgraphgocore_test.User) res = append(res, *item.GetId()) From c5f572e7da29481c264cc44c6fbc3be06fdc7853 Mon Sep 17 00:00:00 2001 From: jobala Date: Sun, 23 Jan 2022 01:32:58 +0300 Subject: [PATCH 12/31] moves tests to msgraphcore_test directory and package --- .../graph_odata_query_handler_test.go | 10 +- .../graph_telemetry_handler_test.go | 12 +- .../page_iterator_test.go | 32 ++-- msgraphgocore_test/user.go | 171 ------------------ msgraphgocore_test/user_response.go | 133 -------------- 5 files changed, 30 insertions(+), 328 deletions(-) rename graph_odata_query_handler_test.go => msgraphgocore_test/graph_odata_query_handler_test.go (85%) rename graph_telemetry_handler_test.go => msgraphgocore_test/graph_telemetry_handler_test.go (86%) rename page_iterator_test.go => msgraphgocore_test/page_iterator_test.go (77%) delete mode 100644 msgraphgocore_test/user.go delete mode 100644 msgraphgocore_test/user_response.go diff --git a/graph_odata_query_handler_test.go b/msgraphgocore_test/graph_odata_query_handler_test.go similarity index 85% rename from graph_odata_query_handler_test.go rename to msgraphgocore_test/graph_odata_query_handler_test.go index 1c4e2b1..294fbb3 100644 --- a/graph_odata_query_handler_test.go +++ b/msgraphgocore_test/graph_odata_query_handler_test.go @@ -1,4 +1,4 @@ -package msgraphgocore +package msgraphgocore_test import ( nethttp "net/http" @@ -7,6 +7,8 @@ import ( "strings" testing "testing" + msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core" + abs "github.com/microsoft/kiota/abstractions/go" absauth "github.com/microsoft/kiota/abstractions/go/authentication" assert "github.com/stretchr/testify/assert" @@ -18,7 +20,7 @@ func TestItReplacesQueryParameters(t *testing.T) { res.Write([]byte("body")) })) defer func() { testServer.Close() }() - handler := NewGraphODataQueryHandler() + handler := msgraphgocore.NewGraphODataQueryHandler() req, err := nethttp.NewRequest(nethttp.MethodGet, testServer.URL+"/?Select=something&exPand=somethingElse(select=nested)&$top=10", nil) if err != nil { t.Error(err) @@ -44,7 +46,7 @@ func TestItDoesNotReplaceWithLocalQueryOptions(t *testing.T) { })) defer func() { testServer.Close() }() auth := &absauth.AnonymousAuthenticationProvider{} - requestAdapter, err := NewGraphRequestAdapterBase(auth, GraphClientOptions{ + requestAdapter, err := msgraphgocore.NewGraphRequestAdapterBase(auth, msgraphgocore.GraphClientOptions{ GraphServiceVersion: "na", GraphServiceLibraryVersion: "na", }) @@ -58,7 +60,7 @@ func TestItDoesNotReplaceWithLocalQueryOptions(t *testing.T) { } absRequest.SetUri(*targetUrl) absRequest.Method = abs.GET - absRequest.AddRequestOptions(&GraphODataQueryHandlerOptions{ + absRequest.AddRequestOptions(&msgraphgocore.GraphODataQueryHandlerOptions{ ShouldReplace: func(*nethttp.Request) bool { return false }, }) requestAdapter.SendNoContentAsync(*absRequest, nil) diff --git a/graph_telemetry_handler_test.go b/msgraphgocore_test/graph_telemetry_handler_test.go similarity index 86% rename from graph_telemetry_handler_test.go rename to msgraphgocore_test/graph_telemetry_handler_test.go index f9d1a84..d6f0caf 100644 --- a/graph_telemetry_handler_test.go +++ b/msgraphgocore_test/graph_telemetry_handler_test.go @@ -1,10 +1,12 @@ -package msgraphgocore +package msgraphgocore_test import ( nethttp "net/http" httptest "net/http/httptest" testing "testing" + msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core" + assert "github.com/stretchr/testify/assert" ) @@ -22,7 +24,7 @@ func newNoopPipeline() *NoopPipeline { } func TestItCreatesANewHandler(t *testing.T) { - handler := NewGraphTelemetryHandler(&GraphClientOptions{}) + handler := msgraphgocore.NewGraphTelemetryHandler(&msgraphgocore.GraphClientOptions{}) if handler == nil { t.Error("handler is nil") } @@ -34,7 +36,7 @@ func TestItAddsHeaders(t *testing.T) { res.Write([]byte("body")) })) defer func() { testServer.Close() }() - handler := NewGraphTelemetryHandler(&GraphClientOptions{}) + handler := msgraphgocore.NewGraphTelemetryHandler(&msgraphgocore.GraphClientOptions{}) req, err := nethttp.NewRequest(nethttp.MethodGet, testServer.URL, nil) if err != nil { t.Error(err) @@ -59,7 +61,7 @@ func TestItAddsServiceLibInfo(t *testing.T) { res.Write([]byte("body")) })) defer func() { testServer.Close() }() - handler := NewGraphTelemetryHandler(&GraphClientOptions{ + handler := msgraphgocore.NewGraphTelemetryHandler(&msgraphgocore.GraphClientOptions{ GraphServiceLibraryVersion: "1.0.0", }) req, err := nethttp.NewRequest(nethttp.MethodGet, testServer.URL, nil) @@ -82,7 +84,7 @@ func TestItAddsServiceInfo(t *testing.T) { res.Write([]byte("body")) })) defer func() { testServer.Close() }() - handler := NewGraphTelemetryHandler(&GraphClientOptions{ + handler := msgraphgocore.NewGraphTelemetryHandler(&msgraphgocore.GraphClientOptions{ GraphServiceLibraryVersion: "1.0.0", GraphServiceVersion: "v1", }) diff --git a/page_iterator_test.go b/msgraphgocore_test/page_iterator_test.go similarity index 77% rename from page_iterator_test.go rename to msgraphgocore_test/page_iterator_test.go index 5b076b4..ce8ec85 100644 --- a/page_iterator_test.go +++ b/msgraphgocore_test/page_iterator_test.go @@ -1,4 +1,4 @@ -package msgraphgocore +package msgraphgocore_test import ( "fmt" @@ -6,9 +6,11 @@ import ( httptest "net/http/httptest" testing "testing" + msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core" + "github.com/microsoftgraph/msgraph-sdk-go-core/mocks" + "github.com/microsoft/kiota/abstractions/go/authentication" "github.com/microsoft/kiota/abstractions/go/serialization" - "github.com/microsoftgraph/msgraph-sdk-go-core/msgraphgocore_test" "github.com/stretchr/testify/assert" ) @@ -21,13 +23,13 @@ type UserPage struct { NextLink *string } -var reqAdapter, _ = NewGraphRequestAdapterBase(&authentication.AnonymousAuthenticationProvider{}, GraphClientOptions{ +var reqAdapter, _ = msgraphgocore.NewGraphRequestAdapterBase(&authentication.AnonymousAuthenticationProvider{}, msgraphgocore.GraphClientOptions{ GraphServiceVersion: "", GraphServiceLibraryVersion: "", }) func ParsableCons() serialization.Parsable { - return msgraphgocore_test.NewUsersResponse() + return mocks.NewUsersResponse() } func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { @@ -48,10 +50,10 @@ func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { })) defer testServer.Close() - pageIterator := NewPageIterator(graphResponse, *reqAdapter, ParsableCons, nil) + pageIterator := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons, nil) pageIterator.Iterate(func(pageItem interface{}) bool { - item := pageItem.(msgraphgocore_test.User) + item := pageItem.(mocks.User) res = append(res, *item.GetDisplayName()) return !(*item.GetId() == "2") @@ -81,11 +83,11 @@ func TestIterateEnumeratesAllPages(t *testing.T) { mockPath := testServer.URL + "/next-page" graphResponse.SetNextLink(&mockPath) - pageIterator := NewPageIterator(graphResponse, *reqAdapter, ParsableCons, nil) + pageIterator := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons, nil) res := make([]string, 0) pageIterator.Iterate(func(pageItem interface{}) bool { - item := pageItem.(msgraphgocore_test.User) + item := pageItem.(mocks.User) res = append(res, *item.GetId()) return true }) @@ -118,9 +120,9 @@ func TestIterateCanBePausedAndResumed(t *testing.T) { mockPath := testServer.URL + "/next-page" response.SetNextLink(&mockPath) - pageIterator := NewPageIterator(response, *reqAdapter, ParsableCons, nil) + pageIterator := msgraphgocore.NewPageIterator(response, *reqAdapter, ParsableCons, nil) pageIterator.Iterate(func(pageItem interface{}) bool { - item := pageItem.(msgraphgocore_test.User) + item := pageItem.(mocks.User) res = append(res, *item.GetId()) if *item.GetId() == "2" { @@ -131,7 +133,7 @@ func TestIterateCanBePausedAndResumed(t *testing.T) { assert.Equal(t, res, []string{"0", "1", "2"}) pageIterator.Iterate(func(pageItem interface{}) bool { - item := pageItem.(msgraphgocore_test.User) + item := pageItem.(mocks.User) res2 = append(res2, *item.GetId()) return true @@ -139,14 +141,14 @@ func TestIterateCanBePausedAndResumed(t *testing.T) { assert.Equal(t, res2, []string{"2", "3", "4", "10"}) } -func buildGraphResponse() *msgraphgocore_test.UsersResponse { - var res = msgraphgocore_test.NewUsersResponse() +func buildGraphResponse() *mocks.UsersResponse { + var res = mocks.NewUsersResponse() nextLink := "next-page" - users := make([]msgraphgocore_test.User, 0) + users := make([]mocks.User, 0) for i := 0; i < 5; i++ { - u := msgraphgocore_test.NewUser() + u := mocks.NewUser() id := fmt.Sprint(i) u.SetId(&id) diff --git a/msgraphgocore_test/user.go b/msgraphgocore_test/user.go deleted file mode 100644 index 254f85a..0000000 --- a/msgraphgocore_test/user.go +++ /dev/null @@ -1,171 +0,0 @@ -package msgraphgocore_test - -import ( - i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e "time" - - i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55 "github.com/microsoft/kiota/abstractions/go/serialization" -) - -type User struct { - DisplayName *string - DirectoryObject -} - -func (u *User) GetDisplayName() *string { - return u.DisplayName -} - -var displayName = "A User" - -func NewUser() *User { - return &User{ - DisplayName: &displayName, - } -} - -type DirectoryObject struct { - Entity - // - deletedDateTime *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time -} - -// NewDirectoryObject instantiates a new directoryObject and sets the default values. -func NewDirectoryObject() *DirectoryObject { - m := &DirectoryObject{ - Entity: *NewEntity(), - } - return m -} - -// GetDeletedDateTime gets the deletedDateTime property value. -func (m *DirectoryObject) GetDeletedDateTime() *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time { - if m == nil { - return nil - } else { - return m.deletedDateTime - } -} - -// GetFieldDeserializers the deserialization information for the current model -func (m *DirectoryObject) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - res := m.Entity.GetFieldDeserializers() - res["deletedDateTime"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - val, err := n.GetTimeValue() - if err != nil { - return err - } - if val != nil { - m.SetDeletedDateTime(val) - } - return nil - } - return res -} -func (m *DirectoryObject) IsNil() bool { - return m == nil -} - -// Serialize serializes information the current object -func (m *DirectoryObject) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { - err := m.Entity.Serialize(writer) - if err != nil { - return err - } - { - err = writer.WriteTimeValue("deletedDateTime", m.GetDeletedDateTime()) - if err != nil { - return err - } - } - return nil -} - -// SetDeletedDateTime sets the deletedDateTime property value. -func (m *DirectoryObject) SetDeletedDateTime(value *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time) { - if m != nil { - m.deletedDateTime = value - } -} - -// Entity -type Entity struct { - // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. - additionalData map[string]interface{} - // Read-only. - id *string -} - -// NewEntity instantiates a new entity and sets the default values. -func NewEntity() *Entity { - m := &Entity{} - m.SetAdditionalData(make(map[string]interface{})) - return m -} - -// GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *Entity) GetAdditionalData() map[string]interface{} { - if m == nil { - return nil - } else { - return m.additionalData - } -} - -// GetId gets the id property value. Read-only. -func (m *Entity) GetId() *string { - if m == nil { - return nil - } else { - return m.id - } -} - -// GetFieldDeserializers the deserialization information for the current model -func (m *Entity) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - res := make(map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error) - res["id"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetId(val) - } - return nil - } - return res -} -func (m *Entity) IsNil() bool { - return m == nil -} - -// Serialize serializes information the current object -func (m *Entity) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { - { - err := writer.WriteStringValue("id", m.GetId()) - if err != nil { - return err - } - } - { - err := writer.WriteAdditionalData(m.GetAdditionalData()) - if err != nil { - return err - } - } - return nil -} - -// SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *Entity) SetAdditionalData(value map[string]interface{}) { - if m != nil { - m.additionalData = value - } -} - -// SetId sets the id property value. Read-only. -func (m *Entity) SetId(value *string) { - if m != nil { - m.id = value - } -} diff --git a/msgraphgocore_test/user_response.go b/msgraphgocore_test/user_response.go deleted file mode 100644 index 78276b1..0000000 --- a/msgraphgocore_test/user_response.go +++ /dev/null @@ -1,133 +0,0 @@ -package msgraphgocore_test - -import ( - i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55 "github.com/microsoft/kiota/abstractions/go/serialization" -) - -// UsersResponse -type UsersResponse struct { - // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. - additionalData map[string]interface{} - // - nextLink *string - // - value []User -} - -// NewUsersResponse instantiates a new usersResponse and sets the default values. -func NewUsersResponse() *UsersResponse { - m := &UsersResponse{} - m.SetAdditionalData(make(map[string]interface{})) - return m -} - -// GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *UsersResponse) GetAdditionalData() map[string]interface{} { - if m == nil { - return nil - } else { - return m.additionalData - } -} - -// GetNextLink gets the @odata.nextLink property value. -func (m *UsersResponse) GetNextLink() *string { - if m == nil { - return nil - } else { - return m.nextLink - } -} - -// GetValue gets the value property value. -func (m *UsersResponse) GetValue() []User { - if m == nil { - return nil - } else { - return m.value - } -} - -// GetFieldDeserializers the deserialization information for the current model -func (m *UsersResponse) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - res := make(map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error) - res["@odata.nextLink"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetNextLink(val) - } - return nil - } - res["value"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - val, err := n.GetCollectionOfObjectValues(func() i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable { - return NewUser() - }) - if err != nil { - return err - } - if val != nil { - res := make([]User, len(val)) - for i, v := range val { - res[i] = *(v.(*User)) - } - m.SetValue(res) - } - return nil - } - return res -} -func (m *UsersResponse) IsNil() bool { - return m == nil -} - -// Serialize serializes information the current object -func (m *UsersResponse) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { - { - err := writer.WriteStringValue("@odata.nextLink", m.GetNextLink()) - if err != nil { - return err - } - } - { - cast := make([]i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable, len(m.GetValue())) - for i, v := range m.GetValue() { - temp := v - cast[i] = i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable(&temp) - } - err := writer.WriteCollectionOfObjectValues("value", cast) - if err != nil { - return err - } - } - { - err := writer.WriteAdditionalData(m.GetAdditionalData()) - if err != nil { - return err - } - } - return nil -} - -// SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *UsersResponse) SetAdditionalData(value map[string]interface{}) { - if m != nil { - m.additionalData = value - } -} - -// SetNextLink sets the @odata.nextLink property value. -func (m *UsersResponse) SetNextLink(value *string) { - if m != nil { - m.nextLink = value - } -} - -// SetValue sets the value property value. -func (m *UsersResponse) SetValue(value []User) { - if m != nil { - m.value = value - } -} From 519f588487cd5f00f596f646031808aecf3ad377 Mon Sep 17 00:00:00 2001 From: jobala Date: Sun, 23 Jan 2022 09:47:18 +0300 Subject: [PATCH 13/31] creates mocks package --- mocks/user.go | 171 +++++++++++++++++++++++++++++++++++++++++ mocks/user_response.go | 133 ++++++++++++++++++++++++++++++++ 2 files changed, 304 insertions(+) create mode 100644 mocks/user.go create mode 100644 mocks/user_response.go diff --git a/mocks/user.go b/mocks/user.go new file mode 100644 index 0000000..b606722 --- /dev/null +++ b/mocks/user.go @@ -0,0 +1,171 @@ +package mocks + +import ( + i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e "time" + + i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55 "github.com/microsoft/kiota/abstractions/go/serialization" +) + +type User struct { + DisplayName *string + DirectoryObject +} + +func (u *User) GetDisplayName() *string { + return u.DisplayName +} + +var displayName = "A User" + +func NewUser() *User { + return &User{ + DisplayName: &displayName, + } +} + +type DirectoryObject struct { + Entity + // + deletedDateTime *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time +} + +// NewDirectoryObject instantiates a new directoryObject and sets the default values. +func NewDirectoryObject() *DirectoryObject { + m := &DirectoryObject{ + Entity: *NewEntity(), + } + return m +} + +// GetDeletedDateTime gets the deletedDateTime property value. +func (m *DirectoryObject) GetDeletedDateTime() *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time { + if m == nil { + return nil + } else { + return m.deletedDateTime + } +} + +// GetFieldDeserializers the deserialization information for the current model +func (m *DirectoryObject) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + res := m.Entity.GetFieldDeserializers() + res["deletedDateTime"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + val, err := n.GetTimeValue() + if err != nil { + return err + } + if val != nil { + m.SetDeletedDateTime(val) + } + return nil + } + return res +} +func (m *DirectoryObject) IsNil() bool { + return m == nil +} + +// Serialize serializes information the current object +func (m *DirectoryObject) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { + err := m.Entity.Serialize(writer) + if err != nil { + return err + } + { + err = writer.WriteTimeValue("deletedDateTime", m.GetDeletedDateTime()) + if err != nil { + return err + } + } + return nil +} + +// SetDeletedDateTime sets the deletedDateTime property value. +func (m *DirectoryObject) SetDeletedDateTime(value *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time) { + if m != nil { + m.deletedDateTime = value + } +} + +// Entity +type Entity struct { + // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + additionalData map[string]interface{} + // Read-only. + id *string +} + +// NewEntity instantiates a new entity and sets the default values. +func NewEntity() *Entity { + m := &Entity{} + m.SetAdditionalData(make(map[string]interface{})) + return m +} + +// GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. +func (m *Entity) GetAdditionalData() map[string]interface{} { + if m == nil { + return nil + } else { + return m.additionalData + } +} + +// GetId gets the id property value. Read-only. +func (m *Entity) GetId() *string { + if m == nil { + return nil + } else { + return m.id + } +} + +// GetFieldDeserializers the deserialization information for the current model +func (m *Entity) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + res := make(map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error) + res["id"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetId(val) + } + return nil + } + return res +} +func (m *Entity) IsNil() bool { + return m == nil +} + +// Serialize serializes information the current object +func (m *Entity) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { + { + err := writer.WriteStringValue("id", m.GetId()) + if err != nil { + return err + } + } + { + err := writer.WriteAdditionalData(m.GetAdditionalData()) + if err != nil { + return err + } + } + return nil +} + +// SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. +func (m *Entity) SetAdditionalData(value map[string]interface{}) { + if m != nil { + m.additionalData = value + } +} + +// SetId sets the id property value. Read-only. +func (m *Entity) SetId(value *string) { + if m != nil { + m.id = value + } +} diff --git a/mocks/user_response.go b/mocks/user_response.go new file mode 100644 index 0000000..5283cd5 --- /dev/null +++ b/mocks/user_response.go @@ -0,0 +1,133 @@ +package mocks + +import ( + i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55 "github.com/microsoft/kiota/abstractions/go/serialization" +) + +// UsersResponse +type UsersResponse struct { + // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + additionalData map[string]interface{} + // + nextLink *string + // + value []User +} + +// NewUsersResponse instantiates a new usersResponse and sets the default values. +func NewUsersResponse() *UsersResponse { + m := &UsersResponse{} + m.SetAdditionalData(make(map[string]interface{})) + return m +} + +// GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. +func (m *UsersResponse) GetAdditionalData() map[string]interface{} { + if m == nil { + return nil + } else { + return m.additionalData + } +} + +// GetNextLink gets the @odata.nextLink property value. +func (m *UsersResponse) GetNextLink() *string { + if m == nil { + return nil + } else { + return m.nextLink + } +} + +// GetValue gets the value property value. +func (m *UsersResponse) GetValue() []User { + if m == nil { + return nil + } else { + return m.value + } +} + +// GetFieldDeserializers the deserialization information for the current model +func (m *UsersResponse) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + res := make(map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error) + res["@odata.nextLink"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetNextLink(val) + } + return nil + } + res["value"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + val, err := n.GetCollectionOfObjectValues(func() i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable { + return NewUser() + }) + if err != nil { + return err + } + if val != nil { + res := make([]User, len(val)) + for i, v := range val { + res[i] = *(v.(*User)) + } + m.SetValue(res) + } + return nil + } + return res +} +func (m *UsersResponse) IsNil() bool { + return m == nil +} + +// Serialize serializes information the current object +func (m *UsersResponse) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { + { + err := writer.WriteStringValue("@odata.nextLink", m.GetNextLink()) + if err != nil { + return err + } + } + { + cast := make([]i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable, len(m.GetValue())) + for i, v := range m.GetValue() { + temp := v + cast[i] = i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable(&temp) + } + err := writer.WriteCollectionOfObjectValues("value", cast) + if err != nil { + return err + } + } + { + err := writer.WriteAdditionalData(m.GetAdditionalData()) + if err != nil { + return err + } + } + return nil +} + +// SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. +func (m *UsersResponse) SetAdditionalData(value map[string]interface{}) { + if m != nil { + m.additionalData = value + } +} + +// SetNextLink sets the @odata.nextLink property value. +func (m *UsersResponse) SetNextLink(value *string) { + if m != nil { + m.nextLink = value + } +} + +// SetValue sets the value property value. +func (m *UsersResponse) SetValue(value []User) { + if m != nil { + m.value = value + } +} From 3feac760bdd3a81e121267efb8cd4254a1c791f5 Mon Sep 17 00:00:00 2001 From: jobala Date: Sun, 23 Jan 2022 12:02:29 +0300 Subject: [PATCH 14/31] hides mocks from public api --- mocks/user.go | 171 ----------------------- mocks/user_response.go | 133 ------------------ msgraphgocore_test/page_iterator_test.go | 20 +-- 3 files changed, 10 insertions(+), 314 deletions(-) delete mode 100644 mocks/user.go delete mode 100644 mocks/user_response.go diff --git a/mocks/user.go b/mocks/user.go deleted file mode 100644 index b606722..0000000 --- a/mocks/user.go +++ /dev/null @@ -1,171 +0,0 @@ -package mocks - -import ( - i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e "time" - - i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55 "github.com/microsoft/kiota/abstractions/go/serialization" -) - -type User struct { - DisplayName *string - DirectoryObject -} - -func (u *User) GetDisplayName() *string { - return u.DisplayName -} - -var displayName = "A User" - -func NewUser() *User { - return &User{ - DisplayName: &displayName, - } -} - -type DirectoryObject struct { - Entity - // - deletedDateTime *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time -} - -// NewDirectoryObject instantiates a new directoryObject and sets the default values. -func NewDirectoryObject() *DirectoryObject { - m := &DirectoryObject{ - Entity: *NewEntity(), - } - return m -} - -// GetDeletedDateTime gets the deletedDateTime property value. -func (m *DirectoryObject) GetDeletedDateTime() *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time { - if m == nil { - return nil - } else { - return m.deletedDateTime - } -} - -// GetFieldDeserializers the deserialization information for the current model -func (m *DirectoryObject) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - res := m.Entity.GetFieldDeserializers() - res["deletedDateTime"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - val, err := n.GetTimeValue() - if err != nil { - return err - } - if val != nil { - m.SetDeletedDateTime(val) - } - return nil - } - return res -} -func (m *DirectoryObject) IsNil() bool { - return m == nil -} - -// Serialize serializes information the current object -func (m *DirectoryObject) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { - err := m.Entity.Serialize(writer) - if err != nil { - return err - } - { - err = writer.WriteTimeValue("deletedDateTime", m.GetDeletedDateTime()) - if err != nil { - return err - } - } - return nil -} - -// SetDeletedDateTime sets the deletedDateTime property value. -func (m *DirectoryObject) SetDeletedDateTime(value *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time) { - if m != nil { - m.deletedDateTime = value - } -} - -// Entity -type Entity struct { - // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. - additionalData map[string]interface{} - // Read-only. - id *string -} - -// NewEntity instantiates a new entity and sets the default values. -func NewEntity() *Entity { - m := &Entity{} - m.SetAdditionalData(make(map[string]interface{})) - return m -} - -// GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *Entity) GetAdditionalData() map[string]interface{} { - if m == nil { - return nil - } else { - return m.additionalData - } -} - -// GetId gets the id property value. Read-only. -func (m *Entity) GetId() *string { - if m == nil { - return nil - } else { - return m.id - } -} - -// GetFieldDeserializers the deserialization information for the current model -func (m *Entity) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - res := make(map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error) - res["id"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetId(val) - } - return nil - } - return res -} -func (m *Entity) IsNil() bool { - return m == nil -} - -// Serialize serializes information the current object -func (m *Entity) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { - { - err := writer.WriteStringValue("id", m.GetId()) - if err != nil { - return err - } - } - { - err := writer.WriteAdditionalData(m.GetAdditionalData()) - if err != nil { - return err - } - } - return nil -} - -// SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *Entity) SetAdditionalData(value map[string]interface{}) { - if m != nil { - m.additionalData = value - } -} - -// SetId sets the id property value. Read-only. -func (m *Entity) SetId(value *string) { - if m != nil { - m.id = value - } -} diff --git a/mocks/user_response.go b/mocks/user_response.go deleted file mode 100644 index 5283cd5..0000000 --- a/mocks/user_response.go +++ /dev/null @@ -1,133 +0,0 @@ -package mocks - -import ( - i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55 "github.com/microsoft/kiota/abstractions/go/serialization" -) - -// UsersResponse -type UsersResponse struct { - // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. - additionalData map[string]interface{} - // - nextLink *string - // - value []User -} - -// NewUsersResponse instantiates a new usersResponse and sets the default values. -func NewUsersResponse() *UsersResponse { - m := &UsersResponse{} - m.SetAdditionalData(make(map[string]interface{})) - return m -} - -// GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *UsersResponse) GetAdditionalData() map[string]interface{} { - if m == nil { - return nil - } else { - return m.additionalData - } -} - -// GetNextLink gets the @odata.nextLink property value. -func (m *UsersResponse) GetNextLink() *string { - if m == nil { - return nil - } else { - return m.nextLink - } -} - -// GetValue gets the value property value. -func (m *UsersResponse) GetValue() []User { - if m == nil { - return nil - } else { - return m.value - } -} - -// GetFieldDeserializers the deserialization information for the current model -func (m *UsersResponse) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - res := make(map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error) - res["@odata.nextLink"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetNextLink(val) - } - return nil - } - res["value"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { - val, err := n.GetCollectionOfObjectValues(func() i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable { - return NewUser() - }) - if err != nil { - return err - } - if val != nil { - res := make([]User, len(val)) - for i, v := range val { - res[i] = *(v.(*User)) - } - m.SetValue(res) - } - return nil - } - return res -} -func (m *UsersResponse) IsNil() bool { - return m == nil -} - -// Serialize serializes information the current object -func (m *UsersResponse) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { - { - err := writer.WriteStringValue("@odata.nextLink", m.GetNextLink()) - if err != nil { - return err - } - } - { - cast := make([]i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable, len(m.GetValue())) - for i, v := range m.GetValue() { - temp := v - cast[i] = i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable(&temp) - } - err := writer.WriteCollectionOfObjectValues("value", cast) - if err != nil { - return err - } - } - { - err := writer.WriteAdditionalData(m.GetAdditionalData()) - if err != nil { - return err - } - } - return nil -} - -// SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *UsersResponse) SetAdditionalData(value map[string]interface{}) { - if m != nil { - m.additionalData = value - } -} - -// SetNextLink sets the @odata.nextLink property value. -func (m *UsersResponse) SetNextLink(value *string) { - if m != nil { - m.nextLink = value - } -} - -// SetValue sets the value property value. -func (m *UsersResponse) SetValue(value []User) { - if m != nil { - m.value = value - } -} diff --git a/msgraphgocore_test/page_iterator_test.go b/msgraphgocore_test/page_iterator_test.go index ce8ec85..360e0d1 100644 --- a/msgraphgocore_test/page_iterator_test.go +++ b/msgraphgocore_test/page_iterator_test.go @@ -7,7 +7,7 @@ import ( testing "testing" msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core" - "github.com/microsoftgraph/msgraph-sdk-go-core/mocks" + "github.com/microsoftgraph/msgraph-sdk-go-core/internal" "github.com/microsoft/kiota/abstractions/go/authentication" "github.com/microsoft/kiota/abstractions/go/serialization" @@ -29,7 +29,7 @@ var reqAdapter, _ = msgraphgocore.NewGraphRequestAdapterBase(&authentication.Ano }) func ParsableCons() serialization.Parsable { - return mocks.NewUsersResponse() + return internal.NewUsersResponse() } func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { @@ -53,7 +53,7 @@ func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { pageIterator := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons, nil) pageIterator.Iterate(func(pageItem interface{}) bool { - item := pageItem.(mocks.User) + item := pageItem.(internal.User) res = append(res, *item.GetDisplayName()) return !(*item.GetId() == "2") @@ -87,7 +87,7 @@ func TestIterateEnumeratesAllPages(t *testing.T) { res := make([]string, 0) pageIterator.Iterate(func(pageItem interface{}) bool { - item := pageItem.(mocks.User) + item := pageItem.(internal.User) res = append(res, *item.GetId()) return true }) @@ -122,7 +122,7 @@ func TestIterateCanBePausedAndResumed(t *testing.T) { pageIterator := msgraphgocore.NewPageIterator(response, *reqAdapter, ParsableCons, nil) pageIterator.Iterate(func(pageItem interface{}) bool { - item := pageItem.(mocks.User) + item := pageItem.(internal.User) res = append(res, *item.GetId()) if *item.GetId() == "2" { @@ -133,7 +133,7 @@ func TestIterateCanBePausedAndResumed(t *testing.T) { assert.Equal(t, res, []string{"0", "1", "2"}) pageIterator.Iterate(func(pageItem interface{}) bool { - item := pageItem.(mocks.User) + item := pageItem.(internal.User) res2 = append(res2, *item.GetId()) return true @@ -141,14 +141,14 @@ func TestIterateCanBePausedAndResumed(t *testing.T) { assert.Equal(t, res2, []string{"2", "3", "4", "10"}) } -func buildGraphResponse() *mocks.UsersResponse { - var res = mocks.NewUsersResponse() +func buildGraphResponse() *internal.UsersResponse { + var res = internal.NewUsersResponse() nextLink := "next-page" - users := make([]mocks.User, 0) + users := make([]internal.User, 0) for i := 0; i < 5; i++ { - u := mocks.NewUser() + u := internal.NewUser() id := fmt.Sprint(i) u.SetId(&id) From 4d7daa548a2cb8197b8a1e2514d34dcf1d193ef6 Mon Sep 17 00:00:00 2001 From: jobala Date: Sun, 23 Jan 2022 12:03:25 +0300 Subject: [PATCH 15/31] moves mocks to internal package --- internal/user.go | 171 ++++++++++++++++++++++++++++++++++++++ internal/user_response.go | 133 +++++++++++++++++++++++++++++ 2 files changed, 304 insertions(+) create mode 100644 internal/user.go create mode 100644 internal/user_response.go diff --git a/internal/user.go b/internal/user.go new file mode 100644 index 0000000..28d402f --- /dev/null +++ b/internal/user.go @@ -0,0 +1,171 @@ +package internal + +import ( + i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e "time" + + i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55 "github.com/microsoft/kiota/abstractions/go/serialization" +) + +type User struct { + DisplayName *string + DirectoryObject +} + +func (u *User) GetDisplayName() *string { + return u.DisplayName +} + +var displayName = "A User" + +func NewUser() *User { + return &User{ + DisplayName: &displayName, + } +} + +type DirectoryObject struct { + Entity + // + deletedDateTime *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time +} + +// NewDirectoryObject instantiates a new directoryObject and sets the default values. +func NewDirectoryObject() *DirectoryObject { + m := &DirectoryObject{ + Entity: *NewEntity(), + } + return m +} + +// GetDeletedDateTime gets the deletedDateTime property value. +func (m *DirectoryObject) GetDeletedDateTime() *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time { + if m == nil { + return nil + } else { + return m.deletedDateTime + } +} + +// GetFieldDeserializers the deserialization information for the current model +func (m *DirectoryObject) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + res := m.Entity.GetFieldDeserializers() + res["deletedDateTime"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + val, err := n.GetTimeValue() + if err != nil { + return err + } + if val != nil { + m.SetDeletedDateTime(val) + } + return nil + } + return res +} +func (m *DirectoryObject) IsNil() bool { + return m == nil +} + +// Serialize serializes information the current object +func (m *DirectoryObject) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { + err := m.Entity.Serialize(writer) + if err != nil { + return err + } + { + err = writer.WriteTimeValue("deletedDateTime", m.GetDeletedDateTime()) + if err != nil { + return err + } + } + return nil +} + +// SetDeletedDateTime sets the deletedDateTime property value. +func (m *DirectoryObject) SetDeletedDateTime(value *i336074805fc853987abe6f7fe3ad97a6a6f3077a16391fec744f671a015fbd7e.Time) { + if m != nil { + m.deletedDateTime = value + } +} + +// Entity +type Entity struct { + // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + additionalData map[string]interface{} + // Read-only. + id *string +} + +// NewEntity instantiates a new entity and sets the default values. +func NewEntity() *Entity { + m := &Entity{} + m.SetAdditionalData(make(map[string]interface{})) + return m +} + +// GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. +func (m *Entity) GetAdditionalData() map[string]interface{} { + if m == nil { + return nil + } else { + return m.additionalData + } +} + +// GetId gets the id property value. Read-only. +func (m *Entity) GetId() *string { + if m == nil { + return nil + } else { + return m.id + } +} + +// GetFieldDeserializers the deserialization information for the current model +func (m *Entity) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + res := make(map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error) + res["id"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetId(val) + } + return nil + } + return res +} +func (m *Entity) IsNil() bool { + return m == nil +} + +// Serialize serializes information the current object +func (m *Entity) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { + { + err := writer.WriteStringValue("id", m.GetId()) + if err != nil { + return err + } + } + { + err := writer.WriteAdditionalData(m.GetAdditionalData()) + if err != nil { + return err + } + } + return nil +} + +// SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. +func (m *Entity) SetAdditionalData(value map[string]interface{}) { + if m != nil { + m.additionalData = value + } +} + +// SetId sets the id property value. Read-only. +func (m *Entity) SetId(value *string) { + if m != nil { + m.id = value + } +} diff --git a/internal/user_response.go b/internal/user_response.go new file mode 100644 index 0000000..314fc45 --- /dev/null +++ b/internal/user_response.go @@ -0,0 +1,133 @@ +package internal + +import ( + i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55 "github.com/microsoft/kiota/abstractions/go/serialization" +) + +// UsersResponse +type UsersResponse struct { + // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + additionalData map[string]interface{} + // + nextLink *string + // + value []User +} + +// NewUsersResponse instantiates a new usersResponse and sets the default values. +func NewUsersResponse() *UsersResponse { + m := &UsersResponse{} + m.SetAdditionalData(make(map[string]interface{})) + return m +} + +// GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. +func (m *UsersResponse) GetAdditionalData() map[string]interface{} { + if m == nil { + return nil + } else { + return m.additionalData + } +} + +// GetNextLink gets the @odata.nextLink property value. +func (m *UsersResponse) GetNextLink() *string { + if m == nil { + return nil + } else { + return m.nextLink + } +} + +// GetValue gets the value property value. +func (m *UsersResponse) GetValue() []User { + if m == nil { + return nil + } else { + return m.value + } +} + +// GetFieldDeserializers the deserialization information for the current model +func (m *UsersResponse) GetFieldDeserializers() map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + res := make(map[string]func(interface{}, i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error) + res["@odata.nextLink"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetNextLink(val) + } + return nil + } + res["value"] = func(o interface{}, n i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.ParseNode) error { + val, err := n.GetCollectionOfObjectValues(func() i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable { + return NewUser() + }) + if err != nil { + return err + } + if val != nil { + res := make([]User, len(val)) + for i, v := range val { + res[i] = *(v.(*User)) + } + m.SetValue(res) + } + return nil + } + return res +} +func (m *UsersResponse) IsNil() bool { + return m == nil +} + +// Serialize serializes information the current object +func (m *UsersResponse) Serialize(writer i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.SerializationWriter) error { + { + err := writer.WriteStringValue("@odata.nextLink", m.GetNextLink()) + if err != nil { + return err + } + } + { + cast := make([]i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable, len(m.GetValue())) + for i, v := range m.GetValue() { + temp := v + cast[i] = i04eb5309aeaafadd28374d79c8471df9b267510b4dc2e3144c378c50f6fd7b55.Parsable(&temp) + } + err := writer.WriteCollectionOfObjectValues("value", cast) + if err != nil { + return err + } + } + { + err := writer.WriteAdditionalData(m.GetAdditionalData()) + if err != nil { + return err + } + } + return nil +} + +// SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. +func (m *UsersResponse) SetAdditionalData(value map[string]interface{}) { + if m != nil { + m.additionalData = value + } +} + +// SetNextLink sets the @odata.nextLink property value. +func (m *UsersResponse) SetNextLink(value *string) { + if m != nil { + m.nextLink = value + } +} + +// SetValue sets the value property value. +func (m *UsersResponse) SetValue(value []User) { + if m != nil { + m.value = value + } +} From f976c9ddfecbb04a9bf3ba6714cf98cc1a553915 Mon Sep 17 00:00:00 2001 From: jobala Date: Mon, 24 Jan 2022 09:40:35 +0300 Subject: [PATCH 16/31] resumes from the next item --- msgraphgocore_test/page_iterator_test.go | 2 +- page_iterator.go | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/msgraphgocore_test/page_iterator_test.go b/msgraphgocore_test/page_iterator_test.go index 360e0d1..6568f97 100644 --- a/msgraphgocore_test/page_iterator_test.go +++ b/msgraphgocore_test/page_iterator_test.go @@ -138,7 +138,7 @@ func TestIterateCanBePausedAndResumed(t *testing.T) { return true }) - assert.Equal(t, res2, []string{"2", "3", "4", "10"}) + assert.Equal(t, res2, []string{"3", "4", "10"}) } func buildGraphResponse() *internal.UsersResponse { diff --git a/page_iterator.go b/page_iterator.go index fbf2f4d..08397db 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -127,6 +127,10 @@ func (pI *PageIterator) enumerate(callback func(item interface{}) bool) bool { return false } + if pI.pauseIndex >= len(pageItems) { + return false + } + // start/continue enumerating page items from pauseIndex. // this makes it possible to resume iteration from where we paused iteration. for i := pI.pauseIndex; i < len(pageItems); i++ { @@ -135,7 +139,8 @@ func (pI *PageIterator) enumerate(callback func(item interface{}) bool) bool { if !keepIterating { // Callback returned false, pause! stop enumerating page items. Set pauseIndex so that we know // where to resume from. - pI.pauseIndex = i + // Resumes from the next item + pI.pauseIndex = i + 1 break } } From 7e6cb717220339138a6ef7277d85fd2b52baf0df Mon Sep 17 00:00:00 2001 From: jobala Date: Mon, 24 Jan 2022 09:56:41 +0300 Subject: [PATCH 17/31] provides API for setting headers --- msgraphgocore_test/page_iterator_test.go | 6 +++--- page_iterator.go | 16 ++++++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/msgraphgocore_test/page_iterator_test.go b/msgraphgocore_test/page_iterator_test.go index 6568f97..b989b54 100644 --- a/msgraphgocore_test/page_iterator_test.go +++ b/msgraphgocore_test/page_iterator_test.go @@ -50,7 +50,7 @@ func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { })) defer testServer.Close() - pageIterator := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons, nil) + pageIterator := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons) pageIterator.Iterate(func(pageItem interface{}) bool { item := pageItem.(internal.User) @@ -83,7 +83,7 @@ func TestIterateEnumeratesAllPages(t *testing.T) { mockPath := testServer.URL + "/next-page" graphResponse.SetNextLink(&mockPath) - pageIterator := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons, nil) + pageIterator := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons) res := make([]string, 0) pageIterator.Iterate(func(pageItem interface{}) bool { @@ -120,7 +120,7 @@ func TestIterateCanBePausedAndResumed(t *testing.T) { mockPath := testServer.URL + "/next-page" response.SetNextLink(&mockPath) - pageIterator := msgraphgocore.NewPageIterator(response, *reqAdapter, ParsableCons, nil) + pageIterator := msgraphgocore.NewPageIterator(response, *reqAdapter, ParsableCons) pageIterator.Iterate(func(pageItem interface{}) bool { item := pageItem.(internal.User) res = append(res, *item.GetId()) diff --git a/page_iterator.go b/page_iterator.go index 08397db..65e76c3 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -47,7 +47,7 @@ func (p *PageResult) getNextLink() *string { return p.nextLink } -func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constructorFunc ParsableConstructor, headers map[string]string) *PageIterator { +func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constructorFunc ParsableConstructor) *PageIterator { abstractions.RegisterDefaultSerializer(func() serialization.SerializationWriterFactory { return jsonserialization.NewJsonSerializationWriterFactory() }) @@ -56,11 +56,11 @@ func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constr }) return &PageIterator{ - convertToPage(res), - reqAdapter, - 0, // pauseIndex helps us remember where we paused enumeration in the page. - constructorFunc, - headers, + currentPage: convertToPage(res), + reqAdapter: reqAdapter, + pauseIndex: 0, + constructorFunc: constructorFunc, + headers: map[string]string{}, } } @@ -78,6 +78,10 @@ func (pI *PageIterator) Iterate(callback func(pageItem interface{}) bool) { } } +func (pI *PageIterator) SetHeaders(headers map[string]string) { + pI.headers = headers +} + func (pI *PageIterator) hasNext() bool { if pI.currentPage == nil || pI.currentPage.getNextLink() == nil { return false From 9264ba4f88025d5956abe1082add38a06d72a8e8 Mon Sep 17 00:00:00 2001 From: jobala Date: Mon, 24 Jan 2022 10:14:54 +0300 Subject: [PATCH 18/31] updates condition in test --- msgraphgocore_test/page_iterator_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/msgraphgocore_test/page_iterator_test.go b/msgraphgocore_test/page_iterator_test.go index b989b54..cc41fac 100644 --- a/msgraphgocore_test/page_iterator_test.go +++ b/msgraphgocore_test/page_iterator_test.go @@ -125,11 +125,9 @@ func TestIterateCanBePausedAndResumed(t *testing.T) { item := pageItem.(internal.User) res = append(res, *item.GetId()) - if *item.GetId() == "2" { - return false - } - return true + return *item.GetId() != "2" }) + assert.Equal(t, res, []string{"0", "1", "2"}) pageIterator.Iterate(func(pageItem interface{}) bool { From 682d1daa33c3137c5350f6cb80344ac78400d8ae Mon Sep 17 00:00:00 2001 From: jobala Date: Mon, 24 Jan 2022 11:04:12 +0300 Subject: [PATCH 19/31] adds documentation --- page_iterator.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/page_iterator.go b/page_iterator.go index 65e76c3..761a808 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -16,6 +16,7 @@ type Page interface { getNextLink() *string } +// PageIterator represents an iterator object that can be used to get subsequent pages of a collection. type PageIterator struct { currentPage Page reqAdapter GraphRequestAdapterBase @@ -47,6 +48,10 @@ func (p *PageResult) getNextLink() *string { return p.nextLink } +// NewpageIterator creates an iterator instance +// +// It has three parameters. res is the graph response from the initial request and represents the first page. +// reqAdapter is used for getting the next page and constructorFunc is used for serializing next page's response to the specified type. func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constructorFunc ParsableConstructor) *PageIterator { abstractions.RegisterDefaultSerializer(func() serialization.SerializationWriterFactory { return jsonserialization.NewJsonSerializationWriterFactory() @@ -64,6 +69,19 @@ func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constr } } +// Iterate traverses all pages and enumerates all items in a page. +// +// Iterate receives a callback function which is called with each item in the current page as an argument. The callback function +// returns a boolean. To traverse and enumerate all pages always return true and to pause traversal and enumeration +// return false from the callback. +// +// Example +// pageIterator := NewPageIterator(resp, reqAdapter, parsableCons) +// callbackFunc := func (pageItem interface{}) bool { +// fmt.Println(pageitem.GetDisplayName()) +// return true +// } +// pageIterator.Iterate(callbackFunc) func (pI *PageIterator) Iterate(callback func(pageItem interface{}) bool) { for pI.currentPage != nil { keepIterating := pI.enumerate(callback) @@ -78,6 +96,9 @@ func (pI *PageIterator) Iterate(callback func(pageItem interface{}) bool) { } } +// SetHeaders provides headers for requests made to get subsequent pages +// +// Headers in the initial request -- request to get the first page -- are not included in subsequent page requests. func (pI *PageIterator) SetHeaders(headers map[string]string) { pI.headers = headers } From cabb0152141515f1ab539176f1b8cb399ce044ed Mon Sep 17 00:00:00 2001 From: jobala Date: Mon, 24 Jan 2022 11:34:02 +0300 Subject: [PATCH 20/31] updates documentation --- page_iterator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/page_iterator.go b/page_iterator.go index 761a808..cc3c4fb 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -69,7 +69,7 @@ func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constr } } -// Iterate traverses all pages and enumerates all items in a page. +// Iterate traverses all pages and enumerates all items in the current page. // // Iterate receives a callback function which is called with each item in the current page as an argument. The callback function // returns a boolean. To traverse and enumerate all pages always return true and to pause traversal and enumeration From 49e46bc70a0c62fc8e1c5bee723c3d5abbcf57f9 Mon Sep 17 00:00:00 2001 From: jobala Date: Mon, 24 Jan 2022 18:08:30 +0300 Subject: [PATCH 21/31] pr review feedback --- .github/workflows/go.yml | 2 +- msgraphgocore_test/page_iterator_test.go | 11 +++++++++++ page_iterator.go | 7 ------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 13a5c96..7549820 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -25,5 +25,5 @@ jobs: run: go build working-directory: ${{ env.relativePath }} - name: Run unit tests - run: go test + run: go test ./msgraphgocore_test working-directory: ${{ env.relativePath }} diff --git a/msgraphgocore_test/page_iterator_test.go b/msgraphgocore_test/page_iterator_test.go index cc41fac..e0656d5 100644 --- a/msgraphgocore_test/page_iterator_test.go +++ b/msgraphgocore_test/page_iterator_test.go @@ -9,11 +9,22 @@ import ( msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core" "github.com/microsoftgraph/msgraph-sdk-go-core/internal" + abstractions "github.com/microsoft/kiota/abstractions/go" "github.com/microsoft/kiota/abstractions/go/authentication" "github.com/microsoft/kiota/abstractions/go/serialization" + jsonserialization "github.com/microsoft/kiota/serialization/go/json" "github.com/stretchr/testify/assert" ) +func init() { + abstractions.RegisterDefaultSerializer(func() serialization.SerializationWriterFactory { + return jsonserialization.NewJsonSerializationWriterFactory() + }) + abstractions.RegisterDefaultDeserializer(func() serialization.ParseNodeFactory { + return jsonserialization.NewJsonParseNodeFactory() + }) +} + type PageItem struct { DisplayName string } diff --git a/page_iterator.go b/page_iterator.go index cc3c4fb..83ddd86 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -8,7 +8,6 @@ import ( abstractions "github.com/microsoft/kiota/abstractions/go" "github.com/microsoft/kiota/abstractions/go/serialization" - jsonserialization "github.com/microsoft/kiota/serialization/go/json" ) type Page interface { @@ -53,12 +52,6 @@ func (p *PageResult) getNextLink() *string { // It has three parameters. res is the graph response from the initial request and represents the first page. // reqAdapter is used for getting the next page and constructorFunc is used for serializing next page's response to the specified type. func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constructorFunc ParsableConstructor) *PageIterator { - abstractions.RegisterDefaultSerializer(func() serialization.SerializationWriterFactory { - return jsonserialization.NewJsonSerializationWriterFactory() - }) - abstractions.RegisterDefaultDeserializer(func() serialization.ParseNodeFactory { - return jsonserialization.NewJsonParseNodeFactory() - }) return &PageIterator{ currentPage: convertToPage(res), From 6059fb080c68a3dc0e093880aee2efb00c6967d5 Mon Sep 17 00:00:00 2001 From: jobala Date: Mon, 24 Jan 2022 18:10:52 +0300 Subject: [PATCH 22/31] specify test package for sonar --- .github/workflows/sonarcloud.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 49c5f96..00f55a9 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -24,7 +24,7 @@ jobs: run: go build working-directory: ${{ env.relativePath }} - name: Run unit tests - run: go test -o result.out -coverprofile cover.out + run: go test ./msgraphgocore_test -o result.out -coverprofile cover.out working-directory: ${{ env.relativePath }} - name: SonarCloud Scan uses: SonarSource/sonarcloud-github-action@master From c040abdf95ec9ccc27015efe5605bfd0a4f9819e Mon Sep 17 00:00:00 2001 From: jobala Date: Wed, 26 Jan 2022 00:49:43 +0300 Subject: [PATCH 23/31] Iterate() returns err --- msgraphgocore_test/page_iterator_test.go | 14 +++++-- page_iterator.go | 53 +++++++++++++++--------- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/msgraphgocore_test/page_iterator_test.go b/msgraphgocore_test/page_iterator_test.go index e0656d5..20acff9 100644 --- a/msgraphgocore_test/page_iterator_test.go +++ b/msgraphgocore_test/page_iterator_test.go @@ -43,6 +43,14 @@ func ParsableCons() serialization.Parsable { return internal.NewUsersResponse() } +func TestConstructorWithInvalidGraphResponse(t *testing.T) { + graphResponse := internal.NewUsersResponse() + + _, err := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons) + + assert.NotNil(t, err) +} + func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { res := make([]string, 0) graphResponse := buildGraphResponse() @@ -61,7 +69,7 @@ func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { })) defer testServer.Close() - pageIterator := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons) + pageIterator, _ := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons) pageIterator.Iterate(func(pageItem interface{}) bool { item := pageItem.(internal.User) @@ -94,7 +102,7 @@ func TestIterateEnumeratesAllPages(t *testing.T) { mockPath := testServer.URL + "/next-page" graphResponse.SetNextLink(&mockPath) - pageIterator := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons) + pageIterator, _ := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons) res := make([]string, 0) pageIterator.Iterate(func(pageItem interface{}) bool { @@ -131,7 +139,7 @@ func TestIterateCanBePausedAndResumed(t *testing.T) { mockPath := testServer.URL + "/next-page" response.SetNextLink(&mockPath) - pageIterator := msgraphgocore.NewPageIterator(response, *reqAdapter, ParsableCons) + pageIterator, _ := msgraphgocore.NewPageIterator(response, *reqAdapter, ParsableCons) pageIterator.Iterate(func(pageItem interface{}) bool { item := pageItem.(internal.User) res = append(res, *item.GetId()) diff --git a/page_iterator.go b/page_iterator.go index 83ddd86..445e183 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -1,7 +1,7 @@ package msgraphgocore import ( - "log" + "errors" "net/url" "reflect" "unsafe" @@ -51,42 +51,51 @@ func (p *PageResult) getNextLink() *string { // // It has three parameters. res is the graph response from the initial request and represents the first page. // reqAdapter is used for getting the next page and constructorFunc is used for serializing next page's response to the specified type. -func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constructorFunc ParsableConstructor) *PageIterator { +func NewPageIterator(res interface{}, reqAdapter GraphRequestAdapterBase, constructorFunc ParsableConstructor) (*PageIterator, error) { + page, err := convertToPage(res) + if err != nil { + return nil, err + } return &PageIterator{ - currentPage: convertToPage(res), + currentPage: page, reqAdapter: reqAdapter, pauseIndex: 0, constructorFunc: constructorFunc, headers: map[string]string{}, - } + }, nil } -// Iterate traverses all pages and enumerates all items in the current page. +// Iterate traverses all pages and enumerates all items in the current page and returns an error if something goes wrong. // // Iterate receives a callback function which is called with each item in the current page as an argument. The callback function // returns a boolean. To traverse and enumerate all pages always return true and to pause traversal and enumeration // return false from the callback. // // Example -// pageIterator := NewPageIterator(resp, reqAdapter, parsableCons) +// pageIterator, err := NewPageIterator(resp, reqAdapter, parsableCons) // callbackFunc := func (pageItem interface{}) bool { // fmt.Println(pageitem.GetDisplayName()) // return true // } -// pageIterator.Iterate(callbackFunc) -func (pI *PageIterator) Iterate(callback func(pageItem interface{}) bool) { +// err := pageIterator.Iterate(callbackFunc) +func (pI *PageIterator) Iterate(callback func(pageItem interface{}) bool) error { for pI.currentPage != nil { keepIterating := pI.enumerate(callback) if !keepIterating { // Callback returned false, stop iterating through pages. - return + return nil } - pI.next() + err := pI.next() + if err != nil { + return err + } pI.pauseIndex = 0 // when moving to the next page reset pauseIndex } + + return nil } // SetHeaders provides headers for requests made to get subsequent pages @@ -103,21 +112,24 @@ func (pI *PageIterator) hasNext() bool { return true } -func (pI *PageIterator) next() Page { - nextPage := pI.getNextPage() +func (pI *PageIterator) next() error { + nextPage, err := pI.getNextPage() + if err != nil { + return err + } pI.currentPage = nextPage - return nextPage + return nil } -func (pI *PageIterator) getNextPage() *PageResult { +func (pI *PageIterator) getNextPage() (*PageResult, error) { if pI.currentPage.getNextLink() == nil { - return nil + return nil, nil } nextLink, err := url.Parse(*pI.currentPage.getNextLink()) if err != nil { - log.Fatal(err) + return nil, errors.New("Parsing nextLink url failed") } requestInfo := abstractions.NewRequestInformation() @@ -127,7 +139,7 @@ func (pI *PageIterator) getNextPage() *PageResult { res, err := pI.reqAdapter.SendAsync(*requestInfo, pI.constructorFunc, nil) if err != nil { - log.Fatal(err) + return nil, errors.New("Fetching next page failed") } return convertToPage(res) @@ -166,10 +178,13 @@ func (pI *PageIterator) enumerate(callback func(item interface{}) bool) bool { return keepIterating } -func convertToPage(response interface{}) *PageResult { +func convertToPage(response interface{}) (*PageResult, error) { ref := reflect.ValueOf(response).Elem() value := ref.FieldByName("value") value = reflect.NewAt(value.Type(), unsafe.Pointer(value.UnsafeAddr())).Elem() + if value.IsNil() { + return nil, errors.New("value property missing in response object") + } nextLink := ref.FieldByName("nextLink") nextLink = reflect.NewAt(nextLink.Type(), unsafe.Pointer(nextLink.UnsafeAddr())).Elem() @@ -184,5 +199,5 @@ func convertToPage(response interface{}) *PageResult { return &PageResult{ nextLink: nextLink.Interface().(*string), value: collected, - } + }, nil } From f6b6898984115d71de82d5c7b7cf25701a01d131 Mon Sep 17 00:00:00 2001 From: jobala Date: Wed, 26 Jan 2022 18:27:06 +0300 Subject: [PATCH 24/31] move nil check up --- page_iterator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/page_iterator.go b/page_iterator.go index 445e183..6a69092 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -181,10 +181,10 @@ func (pI *PageIterator) enumerate(callback func(item interface{}) bool) bool { func convertToPage(response interface{}) (*PageResult, error) { ref := reflect.ValueOf(response).Elem() value := ref.FieldByName("value") - value = reflect.NewAt(value.Type(), unsafe.Pointer(value.UnsafeAddr())).Elem() if value.IsNil() { return nil, errors.New("value property missing in response object") } + value = reflect.NewAt(value.Type(), unsafe.Pointer(value.UnsafeAddr())).Elem() nextLink := ref.FieldByName("nextLink") nextLink = reflect.NewAt(nextLink.Type(), unsafe.Pointer(nextLink.UnsafeAddr())).Elem() From 4e5760131d71ee7f739d32896f3be3e73952c5ad Mon Sep 17 00:00:00 2001 From: jobala Date: Wed, 26 Jan 2022 19:23:09 +0300 Subject: [PATCH 25/31] adds more nil checks --- page_iterator.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/page_iterator.go b/page_iterator.go index 6a69092..492ed4b 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -179,7 +179,11 @@ func (pI *PageIterator) enumerate(callback func(item interface{}) bool) bool { } func convertToPage(response interface{}) (*PageResult, error) { + if response == nil { + return nil, errors.New("response cannot be nil") + } ref := reflect.ValueOf(response).Elem() + value := ref.FieldByName("value") if value.IsNil() { return nil, errors.New("value property missing in response object") @@ -187,7 +191,11 @@ func convertToPage(response interface{}) (*PageResult, error) { value = reflect.NewAt(value.Type(), unsafe.Pointer(value.UnsafeAddr())).Elem() nextLink := ref.FieldByName("nextLink") - nextLink = reflect.NewAt(nextLink.Type(), unsafe.Pointer(nextLink.UnsafeAddr())).Elem() + var link *string + if !nextLink.IsNil() { + nextLink = reflect.NewAt(nextLink.Type(), unsafe.Pointer(nextLink.UnsafeAddr())).Elem() + link = nextLink.Interface().(*string) + } // Collect all entities in the value slice. // This converts a graph slice ie []graph.User to a dynamic slice []interface{} @@ -197,7 +205,7 @@ func convertToPage(response interface{}) (*PageResult, error) { } return &PageResult{ - nextLink: nextLink.Interface().(*string), + nextLink: link, value: collected, }, nil } From ecc4dfd6ac5f430a55ed18a713b26e7ba2dcc5b4 Mon Sep 17 00:00:00 2001 From: jobala Date: Thu, 27 Jan 2022 10:44:22 +0300 Subject: [PATCH 26/31] adds SetReqOptions --- page_iterator.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/page_iterator.go b/page_iterator.go index 492ed4b..62b5ddc 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -22,6 +22,7 @@ type PageIterator struct { pauseIndex int constructorFunc ParsableConstructor headers map[string]string + reqOptions []abstractions.RequestOption } type ParsableConstructor func() serialization.Parsable @@ -105,6 +106,10 @@ func (pI *PageIterator) SetHeaders(headers map[string]string) { pI.headers = headers } +func (pI *PageIterator) SetReqOptions(reqOptions []abstractions.RequestOption) { + pI.reqOptions = reqOptions +} + func (pI *PageIterator) hasNext() bool { if pI.currentPage == nil || pI.currentPage.getNextLink() == nil { return false @@ -136,6 +141,7 @@ func (pI *PageIterator) getNextPage() (*PageResult, error) { requestInfo.Method = abstractions.GET requestInfo.SetUri(*nextLink) requestInfo.Headers = pI.headers + requestInfo.AddRequestOptions(pI.reqOptions...) res, err := pI.reqAdapter.SendAsync(*requestInfo, pI.constructorFunc, nil) if err != nil { From 0d4ce2004432753d49a01c57bec1c701712a026b Mon Sep 17 00:00:00 2001 From: jobala Date: Thu, 27 Jan 2022 11:19:10 +0300 Subject: [PATCH 27/31] moves test file to fix failing sonarcloud build --- .github/workflows/go.yml | 2 +- .github/workflows/sonarcloud.yml | 2 +- .../graph_odata_query_handler_test.go | 67 ------- .../graph_telemetry_handler_test.go | 103 ---------- msgraphgocore_test/page_iterator_test.go | 179 ------------------ 5 files changed, 2 insertions(+), 351 deletions(-) delete mode 100644 msgraphgocore_test/graph_odata_query_handler_test.go delete mode 100644 msgraphgocore_test/graph_telemetry_handler_test.go delete mode 100644 msgraphgocore_test/page_iterator_test.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 7549820..13a5c96 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -25,5 +25,5 @@ jobs: run: go build working-directory: ${{ env.relativePath }} - name: Run unit tests - run: go test ./msgraphgocore_test + run: go test working-directory: ${{ env.relativePath }} diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 00f55a9..49c5f96 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -24,7 +24,7 @@ jobs: run: go build working-directory: ${{ env.relativePath }} - name: Run unit tests - run: go test ./msgraphgocore_test -o result.out -coverprofile cover.out + run: go test -o result.out -coverprofile cover.out working-directory: ${{ env.relativePath }} - name: SonarCloud Scan uses: SonarSource/sonarcloud-github-action@master diff --git a/msgraphgocore_test/graph_odata_query_handler_test.go b/msgraphgocore_test/graph_odata_query_handler_test.go deleted file mode 100644 index 294fbb3..0000000 --- a/msgraphgocore_test/graph_odata_query_handler_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package msgraphgocore_test - -import ( - nethttp "net/http" - httptest "net/http/httptest" - "net/url" - "strings" - testing "testing" - - msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core" - - abs "github.com/microsoft/kiota/abstractions/go" - absauth "github.com/microsoft/kiota/abstractions/go/authentication" - assert "github.com/stretchr/testify/assert" -) - -func TestItReplacesQueryParameters(t *testing.T) { - testServer := httptest.NewServer(nethttp.HandlerFunc(func(res nethttp.ResponseWriter, req *nethttp.Request) { - res.WriteHeader(200) - res.Write([]byte("body")) - })) - defer func() { testServer.Close() }() - handler := msgraphgocore.NewGraphODataQueryHandler() - req, err := nethttp.NewRequest(nethttp.MethodGet, testServer.URL+"/?Select=something&exPand=somethingElse(select=nested)&$top=10", nil) - if err != nil { - t.Error(err) - } - resp, err := handler.Intercept(newNoopPipeline(), 0, req) - if err != nil { - t.Error(err) - } - assert.NotNil(t, resp) - query := req.URL.Query() - assert.Equal(t, "something", query.Get("$Select")) - assert.Equal(t, "somethingElse($select=nested)", query.Get("$exPand")) - assert.Equal(t, "10", query.Get("$top")) -} - -func TestItDoesNotReplaceWithLocalQueryOptions(t *testing.T) { - testServer := httptest.NewServer(nethttp.HandlerFunc(func(res nethttp.ResponseWriter, req *nethttp.Request) { - if strings.Contains(req.URL.RawQuery, "$") { - t.Error("Query parameter $ was added") - } - res.WriteHeader(200) - res.Write([]byte("body")) - })) - defer func() { testServer.Close() }() - auth := &absauth.AnonymousAuthenticationProvider{} - requestAdapter, err := msgraphgocore.NewGraphRequestAdapterBase(auth, msgraphgocore.GraphClientOptions{ - GraphServiceVersion: "na", - GraphServiceLibraryVersion: "na", - }) - if err != nil { - t.Error(err) - } - absRequest := abs.NewRequestInformation() - targetUrl, err := url.Parse(testServer.URL + "/?Select=something") - if err != nil { - t.Error(err) - } - absRequest.SetUri(*targetUrl) - absRequest.Method = abs.GET - absRequest.AddRequestOptions(&msgraphgocore.GraphODataQueryHandlerOptions{ - ShouldReplace: func(*nethttp.Request) bool { return false }, - }) - requestAdapter.SendNoContentAsync(*absRequest, nil) -} diff --git a/msgraphgocore_test/graph_telemetry_handler_test.go b/msgraphgocore_test/graph_telemetry_handler_test.go deleted file mode 100644 index d6f0caf..0000000 --- a/msgraphgocore_test/graph_telemetry_handler_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package msgraphgocore_test - -import ( - nethttp "net/http" - httptest "net/http/httptest" - testing "testing" - - msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core" - - assert "github.com/stretchr/testify/assert" -) - -type NoopPipeline struct { - client *nethttp.Client -} - -func (pipeline *NoopPipeline) Next(req *nethttp.Request, middlewareIndex int) (*nethttp.Response, error) { - return pipeline.client.Do(req) -} -func newNoopPipeline() *NoopPipeline { - return &NoopPipeline{ - client: nethttp.DefaultClient, - } -} - -func TestItCreatesANewHandler(t *testing.T) { - handler := msgraphgocore.NewGraphTelemetryHandler(&msgraphgocore.GraphClientOptions{}) - if handler == nil { - t.Error("handler is nil") - } -} - -func TestItAddsHeaders(t *testing.T) { - testServer := httptest.NewServer(nethttp.HandlerFunc(func(res nethttp.ResponseWriter, req *nethttp.Request) { - res.WriteHeader(200) - res.Write([]byte("body")) - })) - defer func() { testServer.Close() }() - handler := msgraphgocore.NewGraphTelemetryHandler(&msgraphgocore.GraphClientOptions{}) - req, err := nethttp.NewRequest(nethttp.MethodGet, testServer.URL, nil) - if err != nil { - t.Error(err) - } - resp, err := handler.Intercept(newNoopPipeline(), 0, req) - if err != nil { - t.Error(err) - } - assert.NotNil(t, resp) - sdkVersionHeaderValue := req.Header[nethttp.CanonicalHeaderKey("SdkVersion")] - assert.NotEmpty(t, sdkVersionHeaderValue) - assert.Contains(t, sdkVersionHeaderValue[0], "graph-go-core") - assert.Contains(t, sdkVersionHeaderValue[0], "hostOS") - assert.Contains(t, sdkVersionHeaderValue[0], "hostArch") - assert.Contains(t, sdkVersionHeaderValue[0], "runtimeEnvironment") - assert.NotEmpty(t, req.Header[nethttp.CanonicalHeaderKey("client-request-id")]) -} - -func TestItAddsServiceLibInfo(t *testing.T) { - testServer := httptest.NewServer(nethttp.HandlerFunc(func(res nethttp.ResponseWriter, req *nethttp.Request) { - res.WriteHeader(200) - res.Write([]byte("body")) - })) - defer func() { testServer.Close() }() - handler := msgraphgocore.NewGraphTelemetryHandler(&msgraphgocore.GraphClientOptions{ - GraphServiceLibraryVersion: "1.0.0", - }) - req, err := nethttp.NewRequest(nethttp.MethodGet, testServer.URL, nil) - if err != nil { - t.Error(err) - } - resp, err := handler.Intercept(newNoopPipeline(), 0, req) - if err != nil { - t.Error(err) - } - assert.NotNil(t, resp) - sdkVersionHeaderValue := req.Header[nethttp.CanonicalHeaderKey("SdkVersion")] - assert.NotEmpty(t, sdkVersionHeaderValue) - assert.Contains(t, sdkVersionHeaderValue[0], "graph-go/") -} - -func TestItAddsServiceInfo(t *testing.T) { - testServer := httptest.NewServer(nethttp.HandlerFunc(func(res nethttp.ResponseWriter, req *nethttp.Request) { - res.WriteHeader(200) - res.Write([]byte("body")) - })) - defer func() { testServer.Close() }() - handler := msgraphgocore.NewGraphTelemetryHandler(&msgraphgocore.GraphClientOptions{ - GraphServiceLibraryVersion: "1.0.0", - GraphServiceVersion: "v1", - }) - req, err := nethttp.NewRequest(nethttp.MethodGet, testServer.URL, nil) - if err != nil { - t.Error(err) - } - resp, err := handler.Intercept(newNoopPipeline(), 0, req) - if err != nil { - t.Error(err) - } - assert.NotNil(t, resp) - sdkVersionHeaderValue := req.Header[nethttp.CanonicalHeaderKey("SdkVersion")] - assert.NotEmpty(t, sdkVersionHeaderValue) - assert.Contains(t, sdkVersionHeaderValue[0], "graph-go-v1/") -} diff --git a/msgraphgocore_test/page_iterator_test.go b/msgraphgocore_test/page_iterator_test.go deleted file mode 100644 index 20acff9..0000000 --- a/msgraphgocore_test/page_iterator_test.go +++ /dev/null @@ -1,179 +0,0 @@ -package msgraphgocore_test - -import ( - "fmt" - nethttp "net/http" - httptest "net/http/httptest" - testing "testing" - - msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core" - "github.com/microsoftgraph/msgraph-sdk-go-core/internal" - - abstractions "github.com/microsoft/kiota/abstractions/go" - "github.com/microsoft/kiota/abstractions/go/authentication" - "github.com/microsoft/kiota/abstractions/go/serialization" - jsonserialization "github.com/microsoft/kiota/serialization/go/json" - "github.com/stretchr/testify/assert" -) - -func init() { - abstractions.RegisterDefaultSerializer(func() serialization.SerializationWriterFactory { - return jsonserialization.NewJsonSerializationWriterFactory() - }) - abstractions.RegisterDefaultDeserializer(func() serialization.ParseNodeFactory { - return jsonserialization.NewJsonParseNodeFactory() - }) -} - -type PageItem struct { - DisplayName string -} - -type UserPage struct { - Value []interface{} - NextLink *string -} - -var reqAdapter, _ = msgraphgocore.NewGraphRequestAdapterBase(&authentication.AnonymousAuthenticationProvider{}, msgraphgocore.GraphClientOptions{ - GraphServiceVersion: "", - GraphServiceLibraryVersion: "", -}) - -func ParsableCons() serialization.Parsable { - return internal.NewUsersResponse() -} - -func TestConstructorWithInvalidGraphResponse(t *testing.T) { - graphResponse := internal.NewUsersResponse() - - _, err := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons) - - assert.NotNil(t, err) -} - -func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { - res := make([]string, 0) - graphResponse := buildGraphResponse() - testServer := httptest.NewServer(nethttp.HandlerFunc(func(w nethttp.ResponseWriter, req *nethttp.Request) { - w.Header().Set("Content-Type", "application/json") - fmt.Fprint(w, ` - { - "nextLink": "", - "value": [ - { - "id": "10" - } - ] - } - `) - - })) - defer testServer.Close() - pageIterator, _ := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons) - - pageIterator.Iterate(func(pageItem interface{}) bool { - item := pageItem.(internal.User) - - res = append(res, *item.GetDisplayName()) - return !(*item.GetId() == "2") - }) - - assert.Equal(t, len(res), 3) -} - -func TestIterateEnumeratesAllPages(t *testing.T) { - testServer := httptest.NewServer(nethttp.HandlerFunc(func(w nethttp.ResponseWriter, req *nethttp.Request) { - w.Header().Set("Content-Type", "application/json") - fmt.Fprint(w, ` - { - "nextLink": "", - "value": [ - { - "id": "10" - } - ] - } - `) - - })) - defer testServer.Close() - - graphResponse := buildGraphResponse() - mockPath := testServer.URL + "/next-page" - graphResponse.SetNextLink(&mockPath) - - pageIterator, _ := msgraphgocore.NewPageIterator(graphResponse, *reqAdapter, ParsableCons) - res := make([]string, 0) - - pageIterator.Iterate(func(pageItem interface{}) bool { - item := pageItem.(internal.User) - res = append(res, *item.GetId()) - return true - }) - - // Initial page has 5 items and the next page has 1 item. - assert.Equal(t, len(res), 6) -} - -func TestIterateCanBePausedAndResumed(t *testing.T) { - res := make([]string, 0) - res2 := make([]string, 0) - - testServer := httptest.NewServer(nethttp.HandlerFunc(func(w nethttp.ResponseWriter, req *nethttp.Request) { - w.Header().Set("Content-Type", "application/json") - fmt.Fprint(w, ` - { - "nextLink": "", - "value": [ - { - "id": "10" - } - ] - } - `) - - })) - defer testServer.Close() - - response := buildGraphResponse() - mockPath := testServer.URL + "/next-page" - response.SetNextLink(&mockPath) - - pageIterator, _ := msgraphgocore.NewPageIterator(response, *reqAdapter, ParsableCons) - pageIterator.Iterate(func(pageItem interface{}) bool { - item := pageItem.(internal.User) - res = append(res, *item.GetId()) - - return *item.GetId() != "2" - }) - - assert.Equal(t, res, []string{"0", "1", "2"}) - - pageIterator.Iterate(func(pageItem interface{}) bool { - item := pageItem.(internal.User) - res2 = append(res2, *item.GetId()) - - return true - }) - assert.Equal(t, res2, []string{"3", "4", "10"}) -} - -func buildGraphResponse() *internal.UsersResponse { - var res = internal.NewUsersResponse() - - nextLink := "next-page" - users := make([]internal.User, 0) - - for i := 0; i < 5; i++ { - u := internal.NewUser() - id := fmt.Sprint(i) - u.SetId(&id) - - users = append(users, *u) - } - - res.SetNextLink(&nextLink) - res.SetValue(users) - - return res -} From f67237884bc9455f91bd5b8d41ff355d61447c36 Mon Sep 17 00:00:00 2001 From: jobala Date: Thu, 27 Jan 2022 11:20:03 +0300 Subject: [PATCH 28/31] adds moved files --- graph_odata_query_handler_test.go | 65 +++++++++++ graph_telemetry_handler_test.go | 101 +++++++++++++++++ page_iterator_test.go | 177 ++++++++++++++++++++++++++++++ 3 files changed, 343 insertions(+) create mode 100644 graph_odata_query_handler_test.go create mode 100644 graph_telemetry_handler_test.go create mode 100644 page_iterator_test.go diff --git a/graph_odata_query_handler_test.go b/graph_odata_query_handler_test.go new file mode 100644 index 0000000..1c4e2b1 --- /dev/null +++ b/graph_odata_query_handler_test.go @@ -0,0 +1,65 @@ +package msgraphgocore + +import ( + nethttp "net/http" + httptest "net/http/httptest" + "net/url" + "strings" + testing "testing" + + abs "github.com/microsoft/kiota/abstractions/go" + absauth "github.com/microsoft/kiota/abstractions/go/authentication" + assert "github.com/stretchr/testify/assert" +) + +func TestItReplacesQueryParameters(t *testing.T) { + testServer := httptest.NewServer(nethttp.HandlerFunc(func(res nethttp.ResponseWriter, req *nethttp.Request) { + res.WriteHeader(200) + res.Write([]byte("body")) + })) + defer func() { testServer.Close() }() + handler := NewGraphODataQueryHandler() + req, err := nethttp.NewRequest(nethttp.MethodGet, testServer.URL+"/?Select=something&exPand=somethingElse(select=nested)&$top=10", nil) + if err != nil { + t.Error(err) + } + resp, err := handler.Intercept(newNoopPipeline(), 0, req) + if err != nil { + t.Error(err) + } + assert.NotNil(t, resp) + query := req.URL.Query() + assert.Equal(t, "something", query.Get("$Select")) + assert.Equal(t, "somethingElse($select=nested)", query.Get("$exPand")) + assert.Equal(t, "10", query.Get("$top")) +} + +func TestItDoesNotReplaceWithLocalQueryOptions(t *testing.T) { + testServer := httptest.NewServer(nethttp.HandlerFunc(func(res nethttp.ResponseWriter, req *nethttp.Request) { + if strings.Contains(req.URL.RawQuery, "$") { + t.Error("Query parameter $ was added") + } + res.WriteHeader(200) + res.Write([]byte("body")) + })) + defer func() { testServer.Close() }() + auth := &absauth.AnonymousAuthenticationProvider{} + requestAdapter, err := NewGraphRequestAdapterBase(auth, GraphClientOptions{ + GraphServiceVersion: "na", + GraphServiceLibraryVersion: "na", + }) + if err != nil { + t.Error(err) + } + absRequest := abs.NewRequestInformation() + targetUrl, err := url.Parse(testServer.URL + "/?Select=something") + if err != nil { + t.Error(err) + } + absRequest.SetUri(*targetUrl) + absRequest.Method = abs.GET + absRequest.AddRequestOptions(&GraphODataQueryHandlerOptions{ + ShouldReplace: func(*nethttp.Request) bool { return false }, + }) + requestAdapter.SendNoContentAsync(*absRequest, nil) +} diff --git a/graph_telemetry_handler_test.go b/graph_telemetry_handler_test.go new file mode 100644 index 0000000..f9d1a84 --- /dev/null +++ b/graph_telemetry_handler_test.go @@ -0,0 +1,101 @@ +package msgraphgocore + +import ( + nethttp "net/http" + httptest "net/http/httptest" + testing "testing" + + assert "github.com/stretchr/testify/assert" +) + +type NoopPipeline struct { + client *nethttp.Client +} + +func (pipeline *NoopPipeline) Next(req *nethttp.Request, middlewareIndex int) (*nethttp.Response, error) { + return pipeline.client.Do(req) +} +func newNoopPipeline() *NoopPipeline { + return &NoopPipeline{ + client: nethttp.DefaultClient, + } +} + +func TestItCreatesANewHandler(t *testing.T) { + handler := NewGraphTelemetryHandler(&GraphClientOptions{}) + if handler == nil { + t.Error("handler is nil") + } +} + +func TestItAddsHeaders(t *testing.T) { + testServer := httptest.NewServer(nethttp.HandlerFunc(func(res nethttp.ResponseWriter, req *nethttp.Request) { + res.WriteHeader(200) + res.Write([]byte("body")) + })) + defer func() { testServer.Close() }() + handler := NewGraphTelemetryHandler(&GraphClientOptions{}) + req, err := nethttp.NewRequest(nethttp.MethodGet, testServer.URL, nil) + if err != nil { + t.Error(err) + } + resp, err := handler.Intercept(newNoopPipeline(), 0, req) + if err != nil { + t.Error(err) + } + assert.NotNil(t, resp) + sdkVersionHeaderValue := req.Header[nethttp.CanonicalHeaderKey("SdkVersion")] + assert.NotEmpty(t, sdkVersionHeaderValue) + assert.Contains(t, sdkVersionHeaderValue[0], "graph-go-core") + assert.Contains(t, sdkVersionHeaderValue[0], "hostOS") + assert.Contains(t, sdkVersionHeaderValue[0], "hostArch") + assert.Contains(t, sdkVersionHeaderValue[0], "runtimeEnvironment") + assert.NotEmpty(t, req.Header[nethttp.CanonicalHeaderKey("client-request-id")]) +} + +func TestItAddsServiceLibInfo(t *testing.T) { + testServer := httptest.NewServer(nethttp.HandlerFunc(func(res nethttp.ResponseWriter, req *nethttp.Request) { + res.WriteHeader(200) + res.Write([]byte("body")) + })) + defer func() { testServer.Close() }() + handler := NewGraphTelemetryHandler(&GraphClientOptions{ + GraphServiceLibraryVersion: "1.0.0", + }) + req, err := nethttp.NewRequest(nethttp.MethodGet, testServer.URL, nil) + if err != nil { + t.Error(err) + } + resp, err := handler.Intercept(newNoopPipeline(), 0, req) + if err != nil { + t.Error(err) + } + assert.NotNil(t, resp) + sdkVersionHeaderValue := req.Header[nethttp.CanonicalHeaderKey("SdkVersion")] + assert.NotEmpty(t, sdkVersionHeaderValue) + assert.Contains(t, sdkVersionHeaderValue[0], "graph-go/") +} + +func TestItAddsServiceInfo(t *testing.T) { + testServer := httptest.NewServer(nethttp.HandlerFunc(func(res nethttp.ResponseWriter, req *nethttp.Request) { + res.WriteHeader(200) + res.Write([]byte("body")) + })) + defer func() { testServer.Close() }() + handler := NewGraphTelemetryHandler(&GraphClientOptions{ + GraphServiceLibraryVersion: "1.0.0", + GraphServiceVersion: "v1", + }) + req, err := nethttp.NewRequest(nethttp.MethodGet, testServer.URL, nil) + if err != nil { + t.Error(err) + } + resp, err := handler.Intercept(newNoopPipeline(), 0, req) + if err != nil { + t.Error(err) + } + assert.NotNil(t, resp) + sdkVersionHeaderValue := req.Header[nethttp.CanonicalHeaderKey("SdkVersion")] + assert.NotEmpty(t, sdkVersionHeaderValue) + assert.Contains(t, sdkVersionHeaderValue[0], "graph-go-v1/") +} diff --git a/page_iterator_test.go b/page_iterator_test.go new file mode 100644 index 0000000..a9ca442 --- /dev/null +++ b/page_iterator_test.go @@ -0,0 +1,177 @@ +package msgraphgocore + +import ( + "fmt" + nethttp "net/http" + httptest "net/http/httptest" + testing "testing" + + abstractions "github.com/microsoft/kiota/abstractions/go" + "github.com/microsoft/kiota/abstractions/go/authentication" + "github.com/microsoft/kiota/abstractions/go/serialization" + jsonserialization "github.com/microsoft/kiota/serialization/go/json" + "github.com/microsoftgraph/msgraph-sdk-go-core/internal" + "github.com/stretchr/testify/assert" +) + +func init() { + abstractions.RegisterDefaultSerializer(func() serialization.SerializationWriterFactory { + return jsonserialization.NewJsonSerializationWriterFactory() + }) + abstractions.RegisterDefaultDeserializer(func() serialization.ParseNodeFactory { + return jsonserialization.NewJsonParseNodeFactory() + }) +} + +type PageItem struct { + DisplayName string +} + +type UserPage struct { + Value []interface{} + NextLink *string +} + +var reqAdapter, _ = NewGraphRequestAdapterBase(&authentication.AnonymousAuthenticationProvider{}, GraphClientOptions{ + GraphServiceVersion: "", + GraphServiceLibraryVersion: "", +}) + +func ParsableCons() serialization.Parsable { + return internal.NewUsersResponse() +} + +func TestConstructorWithInvalidGraphResponse(t *testing.T) { + graphResponse := internal.NewUsersResponse() + + _, err := NewPageIterator(graphResponse, *reqAdapter, ParsableCons) + + assert.NotNil(t, err) +} + +func TestIterateStopsWhenCallbackReturnsFalse(t *testing.T) { + res := make([]string, 0) + graphResponse := buildGraphResponse() + testServer := httptest.NewServer(nethttp.HandlerFunc(func(w nethttp.ResponseWriter, req *nethttp.Request) { + w.Header().Set("Content-Type", "application/json") + fmt.Fprint(w, ` + { + "nextLink": "", + "value": [ + { + "id": "10" + } + ] + } + `) + + })) + defer testServer.Close() + pageIterator, _ := NewPageIterator(graphResponse, *reqAdapter, ParsableCons) + + pageIterator.Iterate(func(pageItem interface{}) bool { + item := pageItem.(internal.User) + + res = append(res, *item.GetDisplayName()) + return !(*item.GetId() == "2") + }) + + assert.Equal(t, len(res), 3) +} + +func TestIterateEnumeratesAllPages(t *testing.T) { + testServer := httptest.NewServer(nethttp.HandlerFunc(func(w nethttp.ResponseWriter, req *nethttp.Request) { + w.Header().Set("Content-Type", "application/json") + fmt.Fprint(w, ` + { + "nextLink": "", + "value": [ + { + "id": "10" + } + ] + } + `) + + })) + defer testServer.Close() + + graphResponse := buildGraphResponse() + mockPath := testServer.URL + "/next-page" + graphResponse.SetNextLink(&mockPath) + + pageIterator, _ := NewPageIterator(graphResponse, *reqAdapter, ParsableCons) + res := make([]string, 0) + + pageIterator.Iterate(func(pageItem interface{}) bool { + item := pageItem.(internal.User) + res = append(res, *item.GetId()) + return true + }) + + // Initial page has 5 items and the next page has 1 item. + assert.Equal(t, len(res), 6) +} + +func TestIterateCanBePausedAndResumed(t *testing.T) { + res := make([]string, 0) + res2 := make([]string, 0) + + testServer := httptest.NewServer(nethttp.HandlerFunc(func(w nethttp.ResponseWriter, req *nethttp.Request) { + w.Header().Set("Content-Type", "application/json") + fmt.Fprint(w, ` + { + "nextLink": "", + "value": [ + { + "id": "10" + } + ] + } + `) + + })) + defer testServer.Close() + + response := buildGraphResponse() + mockPath := testServer.URL + "/next-page" + response.SetNextLink(&mockPath) + + pageIterator, _ := NewPageIterator(response, *reqAdapter, ParsableCons) + pageIterator.Iterate(func(pageItem interface{}) bool { + item := pageItem.(internal.User) + res = append(res, *item.GetId()) + + return *item.GetId() != "2" + }) + + assert.Equal(t, res, []string{"0", "1", "2"}) + + pageIterator.Iterate(func(pageItem interface{}) bool { + item := pageItem.(internal.User) + res2 = append(res2, *item.GetId()) + + return true + }) + assert.Equal(t, res2, []string{"3", "4", "10"}) +} + +func buildGraphResponse() *internal.UsersResponse { + var res = internal.NewUsersResponse() + + nextLink := "next-page" + users := make([]internal.User, 0) + + for i := 0; i < 5; i++ { + u := internal.NewUser() + id := fmt.Sprint(i) + u.SetId(&id) + + users = append(users, *u) + } + + res.SetNextLink(&nextLink) + res.SetValue(users) + + return res +} From 87fca591a9aef5919321e349364520c67f1d9817 Mon Sep 17 00:00:00 2001 From: jobala Date: Thu, 27 Jan 2022 14:46:10 +0300 Subject: [PATCH 29/31] adds documentation --- page_iterator.go | 1 + 1 file changed, 1 insertion(+) diff --git a/page_iterator.go b/page_iterator.go index 62b5ddc..6650f23 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -106,6 +106,7 @@ func (pI *PageIterator) SetHeaders(headers map[string]string) { pI.headers = headers } +// SetReqOptions provides configuration for handlers during requests for subsequent pages func (pI *PageIterator) SetReqOptions(reqOptions []abstractions.RequestOption) { pI.reqOptions = reqOptions } From b3d8b8c492655a263a2341e00077a0d60b7b2fec Mon Sep 17 00:00:00 2001 From: jobala Date: Thu, 27 Jan 2022 16:28:13 +0300 Subject: [PATCH 30/31] add doc comment and remove Page interface --- page_iterator.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/page_iterator.go b/page_iterator.go index 6650f23..15cdca7 100644 --- a/page_iterator.go +++ b/page_iterator.go @@ -10,14 +10,9 @@ import ( "github.com/microsoft/kiota/abstractions/go/serialization" ) -type Page interface { - getValue() []interface{} - getNextLink() *string -} - // PageIterator represents an iterator object that can be used to get subsequent pages of a collection. type PageIterator struct { - currentPage Page + currentPage *PageResult reqAdapter GraphRequestAdapterBase pauseIndex int constructorFunc ParsableConstructor @@ -27,6 +22,7 @@ type PageIterator struct { type ParsableConstructor func() serialization.Parsable +// PageResult represents a page object built from a graph response object type PageResult struct { nextLink *string value []interface{} From 5269fc63425d6d8a9e71abb366ada25adb96273c Mon Sep 17 00:00:00 2001 From: jobala Date: Thu, 27 Jan 2022 17:00:17 +0300 Subject: [PATCH 31/31] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 667268c..6c0e9e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Adds missing delta token for OData query parameters dollar sign injection. +- Adds PageIterator task ### Changed