From 95e9265fb3c9ae1086a8a73b42c3860933b34d6d Mon Sep 17 00:00:00 2001 From: antoniodiazplaza Date: Mon, 23 Oct 2023 09:42:06 +0200 Subject: [PATCH 01/27] 4727[GOLIUM][MongoDB] Create_generic_code_working_MongoDB --- go.mod | 9 + go.sum | 35 +++ steps/mongo/client.go | 38 +++ steps/mongo/context.go | 36 +++ steps/mongo/session.go | 521 +++++++++++++++++++++++++++++++++++++++++ steps/mongo/steps.go | 70 ++++++ 6 files changed, 709 insertions(+) create mode 100644 steps/mongo/client.go create mode 100755 steps/mongo/context.go create mode 100644 steps/mongo/session.go create mode 100755 steps/mongo/steps.go diff --git a/go.mod b/go.mod index 8890fe30..151a15f4 100644 --- a/go.mod +++ b/go.mod @@ -57,17 +57,20 @@ require ( github.com/goccy/go-json v0.4.7 // indirect github.com/gofrs/uuid v4.0.0+incompatible // indirect github.com/golang/mock v1.6.0 // indirect + github.com/golang/snappy v0.0.1 // indirect github.com/google/pprof v0.0.0-20230111200839-76d1ae5aea2b // indirect github.com/hashicorp/go-immutable-radix v1.3.0 // indirect github.com/hashicorp/go-memdb v1.3.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/klauspost/compress v1.13.6 // indirect github.com/lestrrat-go/backoff/v2 v2.0.7 // indirect github.com/lestrrat-go/httpcc v1.0.0 // indirect github.com/lestrrat-go/iter v1.0.0 // indirect github.com/lestrrat-go/option v1.0.0 // indirect github.com/lestrrat-go/pdebug/v3 v3.0.1 // indirect github.com/magefile/mage v1.10.0 // indirect + github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/onsi/ginkgo/v2 v2.7.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect @@ -76,12 +79,18 @@ require ( github.com/quic-go/quic-go v0.33.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + go.mongodb.org/mongo-driver v1.12.1 // indirect golang.org/x/crypto v0.5.0 // indirect golang.org/x/exp v0.0.0-20230306221820-f0f767cdffd6 // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/net v0.8.0 // indirect + golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.6.0 // indirect golang.org/x/text v0.8.0 // indirect golang.org/x/tools v0.6.0 // indirect diff --git a/go.sum b/go.sum index 0396e2e6..207e3320 100644 --- a/go.sum +++ b/go.sum @@ -133,10 +133,13 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -198,6 +201,8 @@ github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dv github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -239,6 +244,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow= @@ -321,6 +328,12 @@ github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhso github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc= github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= @@ -328,9 +341,14 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE= +go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -344,6 +362,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -369,6 +389,7 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -387,8 +408,11 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -402,7 +426,9 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -423,16 +449,23 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 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/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -459,10 +492,12 @@ golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4X golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= diff --git a/steps/mongo/client.go b/steps/mongo/client.go new file mode 100644 index 00000000..868025c3 --- /dev/null +++ b/steps/mongo/client.go @@ -0,0 +1,38 @@ +// Copyright (c) Telefónica Cybersecurity & Cloud Tech S.L. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mongo + + import ( + "context" + + + "go.mongodb.org/mongo-driver/mongo" +) + +type ClientFunctions interface { + + Ping(ctx context.Context, client *mongo.Client) error + +} +type ClientService struct{} + +func NewMongoClientService() *ClientService { + return &ClientService{} +} + +//Ping check that there is a connection to MongoDB +func (c ClientService) Ping(ctx context.Context, client *mongo.Client) error { + return client.Ping(context.Background(), nil) +} diff --git a/steps/mongo/context.go b/steps/mongo/context.go new file mode 100755 index 00000000..164c4f28 --- /dev/null +++ b/steps/mongo/context.go @@ -0,0 +1,36 @@ +// Copyright 2021 Telefonica Cybersecurity & Cloud Tech SL +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mongo + +import ( + "context" +) + +// ContextKey defines a type to store the mongo session in context.Context. +type ContextKey string + +const contextKey ContextKey = "mongoSession" + +// InitializeContext adds the mongo session to the context. +// The new context is returned because context is immutable. +func InitializeContext(ctx context.Context) context.Context { + return context.WithValue(ctx, contextKey, &Session{MongoClientService: *NewMongoClientService()}) +} + +// GetSession returns the mongo session stored in context. +// Note that the context should be previously initialized with InitializeContext function. +func GetSession(ctx context.Context) *Session { + return ctx.Value(contextKey).(*Session) +} diff --git a/steps/mongo/session.go b/steps/mongo/session.go new file mode 100644 index 00000000..ee3b230f --- /dev/null +++ b/steps/mongo/session.go @@ -0,0 +1,521 @@ +// Copyright (c) Telefónica Cybersecurity & Cloud Tech S.L. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + package mongo + + import ( + "context" + "errors" + "fmt" + "reflect" + "strings" + "strconv" + + "github.com/TelefonicaTC2Tech/golium" + "github.com/cucumber/godog" + "github.com/google/uuid" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + ) + + // Session contains the information of a MongoDB session. + type Session struct { + + // Save MongoDB login credentials: username, password, and AuthSource + credentials options.Credential + + // Saves the host from accessing MongoDB + host string + + // Save the MongoDB database + database string + + // Set the host and credentials for the connection + clientOptions *options.ClientOptions + + // Create the mongo client with the MongoDB connection + client *mongo.Client + + // Points to a record in a collection + singleResult *mongo.SingleResult + + // Saves the collection to be used + collection *mongo.Collection + + // Save the name of the collectionName fields + fieldsCollectionName []string + + // Save collection items as JSON + dataCollectionJSONBytes []byte + + // Access MongoDB features + MongoClientService ClientFunctions + } + + // FUNCTIONS CALLED BY STEPS + + // CheckMongoFieldExistOrEmptyStep check that a field does not exist or that it does exist and is empty + func (s *Session) CheckMongoFieldExistOrEmptyStep(ctx context.Context, fieldSearched string, collectionName string, idCollection string) error { + + // 1-Setting the Collection Name in the Session + s.SetCollection(ctx, collectionName) + + // 2-Set fields collection name in Session: s.fieldsCollectionName + err := s.SetFieldsCollectionName(ctx, idCollection, s.collection) + if err != nil { + return err + } + + // 3-If fieldSearched exists, check that the value of the fieldSearched is null + if s.ExistFieldCollection(ctx, fieldSearched) { + err = s.SetSingleResult(ctx, fieldSearched, nil) + } + + return err + } + + // CheckMongoFieldNameStep check if the name of the field searched of the mongo user collection is correct + func (s *Session) CheckMongoFieldNameStep(ctx context.Context, collectionName string, fieldSearched string, exist string, idCollection string) error { + + // 1-Set collection name and fields collection name in Session + s.SetCollection(ctx, collectionName) + s.SetFieldsCollectionName(ctx, idCollection, s.collection) + + // 2-Get boolean if field exist and must exist in collection + existField := s.ExistFieldCollection(ctx, fieldSearched) + mustExistField := VerifyMustExist(exist) + + // 3-Verify exist and must exist + return s.VerifyExistAndMustExistValue(existField, mustExistField, nil) + } + + // CheckMongoValueIDStep checks if the past idCollection exists in the collection + func (s *Session) CheckMongoValueIDStep(ctx context.Context, collectionName string, idCollection string, exist string) error { + + // 1-Set collection name and fields collection name in Session + s.SetCollection(ctx, collectionName) + + // 2-Get boolean if _id exist and must exist in collection + exist_id, err := s.VerifyExist_id(ctx, idCollection) + mustExist_id := VerifyMustExist(exist) + + // 3-Verify exist and must exist + return s.VerifyExistAndMustExistValue(exist_id, mustExist_id, err) + } + + // CheckMongoValuesStep checks the value of the MongoDB fields in the specified collection + func (s *Session) CheckMongoValuesStep(ctx context.Context, collectionName string, idCollection string, exist string, t *godog.Table) error { + + // 1-Set collection name and fields collection name in Session + s.SetCollection(ctx, collectionName) + + // 2-Get value of specified table + props, err := golium.ConvertTableToMap(ctx, t) + if err != nil { + return fmt.Errorf("ERROR: failed processing the table for validating the response body: %w", err) + } + + // 3-Get boolean if data exist and must exist in collection + existValue, err := s.ValidateDataMongo(ctx, idCollection, props) + mustExistValue := VerifyMustExist(exist) + + // 4-Verify exist and must exist + return s.VerifyExistAndMustExistValue(existValue, mustExistValue, err) + } + + // MongoConnectionStep establishes a connection in MongoDB. The connection data is saved in s.clientOptions, the client in s.client, and the database in s.database + func (s *Session) MongoConnectionStep(ctx context.Context) error { + + // 1-Set credentials and host in session + s.SetCredentials(ctx) + s.SetHost(ctx) + + // 2-Set clientOptions in session + s.clientOptions = options.Client().SetHosts(strings.Split(s.host, ",")).SetAuth(s.credentials) + + // 3-Connect to the MongoDB server and set client in session + var err error + s.client, err = mongo.Connect(context.Background(), s.clientOptions) + if err != nil { + return fmt.Errorf("Error with the client options or with the context. %s", err) + } + + // 4-Check the connection to the MongoDB server + err = s.MongoClientService.Ping(ctx, s.client) + if err != nil { + return fmt.Errorf("Error connecting to MongoDB. %s", err) + } + + // 5-Set the database in session + s.SetDatabase(ctx) + + return nil + } + + // CreateDocumentcollectionNameStep creates a number of documents in the specified collection + func (s *Session) CreateDocumentscollectionNameStep(ctx context.Context, num int, collectionName string) error { + + // 1-The collection to which the insertion is to be made is set. If it doesn't exist, it's created. + s.SetCollection(ctx, collectionName) + + // 2-The documents to be inserted are created + allDocuments := s.CreateDocumentsCollection(ctx, num, collectionName) + + // 3-Insert the documents into the "collectionName" collection of the database + _, err := s.collection.InsertMany(context.TODO(), allDocuments) + if err != nil { + return err + } + + return nil + } + + // DeleteDocumentscollectionNameStep delete a document from the MongoDB collection + func (s *Session) DeleteDocumentscollectionNameStep(ctx context.Context, collectionName string, field string, value string) error { + + // 1-The collection in which the deletion is to be made is established. + s.SetCollection(ctx, collectionName) + + //2-Performs the deletion of documents that match the filter after the data type is converted. You can only filter by string, int, float, or boolean values, also in slices and maps. + _, err := s.collection.DeleteMany(ctx, GetFilterConverted(field, value) ) + if err != nil { + return err + } + + return nil + } + + // CheckNumberDocumentscollectionNameStep verify the number of documents in collection + func (s *Session) CheckNumberDocumentscollectionNameStep(ctx context.Context, collectionName string, num int) error { + + //TODO. Investigate why the appropriate method for this function (CountDouments) is not working properly + + // 1-The collection from which the documents are to be counted is established + s.SetCollection(ctx, collectionName) + + // 2-Make a query to get all the documents in the collection + cursor, err := s.collection.Find(context.Background(), bson.D{}) + if err != nil { + return errors.New(fmt.Sprintf("Query error: %s", err)) + } + + // 3-Iterate through the documents and count the ones that are there + count := 0 + for cursor.Next(context.Background()) { + count++ + } + + // 4-Check the result + if count != num { + return errors.New(fmt.Sprintf("ERROR: The number of documents is '%d' and should be '%d'", count, num)) + } + return nil + } + + + // GENERIC FUNCTIONS + + // ContainsElement check if an item exists in a slice + func ContainsElement(expectedElement interface{}, sliceElements interface{}) bool { + + // 1-Create a reflection object from the slice + sliceValue := reflect.ValueOf(sliceElements) + + // 2-It is verified that the object of reflection is of the "slice" type + if sliceValue.Kind() != reflect.Slice { + return false + } + + for i := 0; i < sliceValue.Len(); i++ { + // 3-The slice element converted into an interface is compared with the searched element. The comparison is made in value and type + if reflect.DeepEqual(sliceValue.Index(i).Interface(), expectedElement) { + return true + } + } + + return false + } + + // GetFilter returns a filter to search for a record from a field + func GetFilter(key string, value interface{}) primitive.M { + if value == nil { + return bson.M{key: nil} + } else { + return bson.M{key: value} + } + } + + // GetFilterConverted returns a filter with the field and data type required for the deletion of a record + func GetFilterConverted(field string, value string) primitive.M { + // In golang, the values "1", "true", "t", "T", "TRUE", "True" and "0", "false", "f", "F", "FALSE", "False" are interpreted as Boolean. To force only a few values in a cell to be considered Boolean, this slice is created. + boolSlice := []string{"true", "[TRUE]", "TRUE", "True", "false", "[FALSE]", "FALSE", "False"} + + var filter bson.M + + // Try to convert to bool + if ContainsElement(value, boolSlice) { + convertedValue, err := strconv.ParseBool(value) + if err == nil { + filter = bson.M{field: convertedValue} + } + } else { + // Try to convert to int + if convertedValue, err := strconv.Atoi(value); err == nil { + filter = bson.M{field: convertedValue} + } else { + // Try converting to float64 + if convertedValue, err := strconv.ParseFloat(value, 64); err == nil { + filter = bson.M{field: convertedValue} + } else { + // If the passed value is [EMPTY] or [NULL] it evaluates to nil + if value == "[EMPTY]" || value == "[NULL]"{ + filter = bson.M{field: nil} + } else{ + // If none of the above is true, the value remains as the original type (string) + filter = bson.M{field: value} + } + } + } + } + return filter + } + + // GetOptionsSearchAllFields create an "Options" that states that the search will be done in all fields of the collection + func GetOptionsSearchAllFields() *options.FindOneOptions { + return options.FindOne().SetProjection(bson.M{}) + } + + // VerifyMustExist returns a boolean indicating whether the element should exist + func VerifyMustExist(exist string) bool { + if strings.Contains(strings.ToLower(exist), "not") { + return false + } else { + return true + } + } + + + // SESSION FUNCTIONS + + // CreateDocumentsCollection creates num documents in a slice and inserts them into a MongoDB collection + func (s *Session) CreateDocumentsCollection(ctx context.Context, num int, collectionName string) []interface{}{ + // 1-Initialize the document slice + allDocuments := []interface{}{} + + // 2-Obtaining the _id of the context, if it does not exist it is created + id := golium.GetContext(ctx).Get("_ID") + if id == nil { + var err error + id , err = uuid.NewRandom() + if err != nil { + return nil + } + // Transforming id into an interface + id = id.(uuid.UUID).String() + } + // 3-Creating Documents and Inserting Into the Slice + for i:=1; i<=num; i++ { + // Defines the document to be inserted. The _id will be the same across all + _ + iteration number + document := map[string]interface{}{ + "_id" : id.(string) + "_"+ strconv.Itoa(i), + "fieldString": "Example field string " +strconv.Itoa(i), + "fieldInt": i, + "fieldFloat": 3.14, + "fieldBool": true, + "fieldSlice": []string{"itemSlice_"+ strconv.Itoa(i), "itemSlice20", "itemSlice30"}, + "fieldEmpty": nil, + "fieldMap": map[string]interface{}{ + "fieldString": "Example field in map string " +strconv.Itoa(i), + "fieldInt": i*10, + "fieldFloat": 1974.1976, + "fieldBool": false, + "fieldSliceEmpty": []string{}, + "fieldMap2": map[string]interface{}{ + "fieldString": "Example field in map map string " +strconv.Itoa(i), + "fieldInt": i*100, + "fieldFloat": 1974.1976, + "fieldBool": false, + "fieldEmpty": nil, + "fieldEmptyText": "", + }, + }, + } + allDocuments = append(allDocuments, document) + } + return allDocuments + } + + // SetCredentials set an Options element. Credential with MongoDB access credentials + func (s *Session) SetCredentials(ctx context.Context) { + credentials := options.Credential{ + Username: golium.ValueAsString(ctx, fmt.Sprintf("[CONF:mongoUsername]")), + Password: golium.ValueAsString(ctx, fmt.Sprintf("[CONF:mongoPassword]")), + AuthSource: golium.ValueAsString(ctx, fmt.Sprintf("[CONF:mongoAuthSource]")), + } + s.credentials = credentials + } + + // SetHost set a string with the host + func (s *Session) SetHost(ctx context.Context) { + s.host = golium.ValueAsString(ctx, fmt.Sprintf("[CONF:mongoHost]")) + } + + // SetDatabase set a string with the database + func (s *Session) SetDatabase(ctx context.Context) { + s.database = golium.ValueAsString(ctx, fmt.Sprintf("[CONF:mongoDatabase]")) + } + + // SetSingleResult set a Single Result from a Filter Search (GetFilter(...) function) + func (s *Session) SetSingleResult(ctx context.Context, fieldSearched string, value interface{}) error { + + s.singleResult = s.collection.FindOne(ctx, GetFilter(fieldSearched, value), GetOptionsSearchAllFields()) + if s.singleResult.Err() != nil { + return errors.New(fmt.Sprintf("ERROR. The searched field (%s) does not have the value (%s) in the collection (%s)", fieldSearched, value, s.collection)) + } + return nil + } + + // SetCollection sets the collection. If the collection does not exist, no error is returned. Collections are created dynamically when you insert a document + func (s *Session) SetCollection(ctx context.Context, collectionName string) { + s.collection = s.client.Database(s.database).Collection(collectionName) + } + + // ExistFieldCollection evaluate whether or not the searched field exists + func (s *Session) ExistFieldCollection(ctx context.Context, fieldSearched string) bool { + existField := false + for _, element := range s.fieldsCollectionName { + if element == fieldSearched { + existField = true + } + } + return existField + } + + // GetDecodeDocument decodes the BSON document in the bsonDoc variable + func (s *Session) GetDecodeDocument(singleResult mongo.SingleResult) (bson.D, error) { + var bsonDoc bson.D + if err := s.singleResult.Decode(&bsonDoc); err != nil { + err = fmt.Errorf(fmt.Sprintf("ERROR. The decoding of the BSON has been erroneous: %s", err)) + return nil, err + } + return bsonDoc, nil + } + + // SetDataCollectionJSONBytes convert BSON object to JSON + func (s *Session) SetDataCollectionJSONBytes(bsonDoc bson.D) error { + var err error + s.dataCollectionJSONBytes, err = bson.MarshalExtJSON(bsonDoc, false, false) + if err != nil { + return errors.New(fmt.Sprintf("ERROR. The conversion from BSON to JSON has been erroneous: %s", err)) + } + return nil + } + + // SetFieldsCollectionName save a string slice with the names of the fields in the collection in s.fieldsCollectionName + func (s *Session) SetFieldsCollectionName(ctx context.Context, idCollection string, collectionName *mongo.Collection) error { + // Make a query to find past _id's document + var document bson.M + err := s.collection.FindOne(ctx, GetFilter("_id", idCollection)).Decode(&document) + if err == mongo.ErrNoDocuments { + return errors.New(fmt.Sprintf("ERROR: No documents matching the filter were found.")) + } else if err != nil { + return errors.New(fmt.Sprintf("ERROR: %s", err)) + } else { + // The s.fieldsCollectionName collection is flushed, and then the names of the fields in the document are added + s.fieldsCollectionName = s.fieldsCollectionName[:0] + for fieldName := range document { + s.fieldsCollectionName = append(s.fieldsCollectionName, fieldName) + } + } + return nil + } + + // VerifyExist_id returns a boolean indicating whether the _id searched exists in the collection + func (s *Session) VerifyExist_id(ctx context.Context, idCollection string) (bool, error) { + //Perform the search and get the result as singleResult + err := s.SetSingleResult(ctx, "_id", idCollection) + if err != nil { + return false, errors.New(fmt.Sprintf("ERROR. The searched _id (%s) does not exist in the '%s' collection", idCollection, s.collection.Name())) + } + return true, nil + } + + // VerifyExistAndMustExistValue check if the values exist and should exist + func (s *Session) VerifyExistAndMustExistValue(exist bool, mustExist bool, err error) error { + // If Exist and should NOT exist or NOT exist and should exist return error + // If Exist and shoud exist OR not exist and should not exist return nil + if exist && mustExist || !exist && !mustExist { + return nil + } else { + if err != nil { + return err + } else { + return errors.New(fmt.Sprintf("ERROR. The value DOES NOT EXIST and SHOULD, or EXIST and SHOULD NOT, in '%s' collection", s.collection.Name())) + } + } + } + + // ValidateDataMongo verifies that the feature table data exists in the MongoDB collection + func (s *Session) ValidateDataMongo(ctx context.Context, idCollection string, props map[string]interface{}) (bool, error) { + // 1-Sets a document to s.singleResult from a filter search + s.SetSingleResult(ctx, "_id", idCollection) + + // 2-Decodes the singleResult document into a BSON (bsonDoc) + bsonDoc, err := s.GetDecodeDocument(*s.singleResult) + if err != nil { + return false, err + } + + // 3-Convert the bsonDoc object to JSON + err = s.SetDataCollectionJSONBytes(bsonDoc) + if err != nil { + return false, err + } + + // 4-Set the list of fields in the document to fieldsCollectionName + s.SetFieldsCollectionName(ctx, idCollection, s.collection) + if err != nil { + return false, err + } + + // 5-Navigate through the feature table and check the data + m := golium.NewMapFromJSONBytes(s.dataCollectionJSONBytes) + for key, expectedValue := range props { + value := m.Get(key) + // Verify that the name of the clean field (fieldTableFeature) exists in the list of fields in the collection (s.fieldsCollectionName) + fieldTableFeature := strings.Split(key, ".")[0] + if ContainsElement(fieldTableFeature, s.fieldsCollectionName) { + if value == nil && expectedValue == "" { + //The value of the field in MongoDB is null and expectedValue is [EMPTY] + continue + } else if value != expectedValue { + return false, errors.New(fmt.Sprintf("ERROR. Mismatch of mongo field '%s': expected '%s', actual '%s'", key, expectedValue, value)) + } + } else { + return false, errors.New(fmt.Sprintf("ERROR. The mongo field '%s': does not exist in '%s' collection", key, s.collection)) + } + } + return true, nil + } + + // MongoDisconnection closes the connection to MongoDB if it exists + func (s *Session) MongoDisconnection(ctx context.Context) { + if s.client != nil{ + s.client.Disconnect(context.Background()) + } + } + \ No newline at end of file diff --git a/steps/mongo/steps.go b/steps/mongo/steps.go new file mode 100755 index 00000000..b665fd32 --- /dev/null +++ b/steps/mongo/steps.go @@ -0,0 +1,70 @@ +// Copyright (c) Telefónica Cybersecurity & Cloud Tech S.L. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mongo + +import ( + "context" + + "github.com/TelefonicaTC2Tech/golium" + "github.com/cucumber/godog" + "github.com/cucumber/messages-go/v16" + + "go.mongodb.org/mongo-driver/mongo" + +) + +var client *mongo.Client +var collection *mongo.Collection + +type MongoSteps struct { +} + +// InitializeSteps initializes all the steps +func (us MongoSteps) InitializeSteps(ctx context.Context, scenCtx *godog.ScenarioContext) context.Context { + // Initialize the HTTP session in the context + ctx = InitializeContext(ctx) + session := GetSession(ctx) + + scenCtx.Step(`^I connect to MongoDB$`, func() error { + return session.MongoConnectionStep(ctx) + }) + scenCtx.Step(`^I check that these values of the MongoDB "([^"]*)" collection with "([^"]*)" _id "([^"]*)" exist$`, func(collectionName string, idCollection string, exist string, t *godog.Table) error { + return session.CheckMongoValuesStep(ctx, golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, idCollection), golium.ValueAsString(ctx, exist), t) + }) + scenCtx.Step(`^I check that the MongoDB "([^"]*)" collection with "([^"]*)" _id "([^"]*)" exist$`, func(collectionName string, idCollection string, exist string) error { + return session.CheckMongoValueIDStep(ctx, golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, idCollection), golium.ValueAsString(ctx, exist)) + }) + scenCtx.Step(`^I check that in the MongoDB "([^"]*)" collection, "([^"]*)" field "([^"]*)" exist for the "([^"]*)" _id$`, func(collectionName string, fieldSearched string, exist string, idCollection string) error { + return session.CheckMongoFieldNameStep(ctx, golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, fieldSearched), golium.ValueAsString(ctx, exist), golium.ValueAsString(ctx, idCollection)) + }) + scenCtx.Step(`^I check that the "([^"]*)" field in the MongoDB "([^"]*)" collection does not exist or is empty for the "([^"]*)" _id$`, func(fieldSearched string, collectionName string, idCollection string) error { + return session.CheckMongoFieldExistOrEmptyStep(ctx, golium.ValueAsString(ctx, fieldSearched), golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, idCollection)) + }) + scenCtx.Step(`^I create "(\d+)" documents in the MongoDB "([^"]*)" collection$`, func(num int, collectionName string) error { + return session.CreateDocumentscollectionNameStep(ctx, num, golium.ValueAsString(ctx, collectionName)) + }) + scenCtx.Step(`^I delete documents from the MongoDB "([^"]*)" collection whose "([^"]*)" field is "([^"]*)" value$`, func(collectionName string, field string, value string) error { + return session.DeleteDocumentscollectionNameStep(ctx, golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, field), value) + }) + scenCtx.Step(`^I check that the number of documents in collection "([^"]*)" is "(\d+)"$`, func(collectionName string, num int) error { + return session.CheckNumberDocumentscollectionNameStep(ctx, golium.ValueAsString(ctx, collectionName), num) + }) + + scenCtx.AfterScenario(func(sc *messages.Pickle, err error) { + session.MongoDisconnection(ctx) + }) + + return ctx +} From 45b8460005fec0945051dd83a8298b8fadd94ab3 Mon Sep 17 00:00:00 2001 From: antoniodiazplaza Date: Mon, 23 Oct 2023 11:34:38 +0200 Subject: [PATCH 02/27] 4727_Golium_MongoDB_Repairs_1 --- steps/mongo/session.go | 58 ++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/steps/mongo/session.go b/steps/mongo/session.go index ee3b230f..4c73bd40 100644 --- a/steps/mongo/session.go +++ b/steps/mongo/session.go @@ -174,7 +174,7 @@ // 2-The documents to be inserted are created allDocuments := s.CreateDocumentsCollection(ctx, num, collectionName) - + // 3-Insert the documents into the "collectionName" collection of the database _, err := s.collection.InsertMany(context.TODO(), allDocuments) if err != nil { @@ -261,39 +261,41 @@ // GetFilterConverted returns a filter with the field and data type required for the deletion of a record func GetFilterConverted(field string, value string) primitive.M { - // In golang, the values "1", "true", "t", "T", "TRUE", "True" and "0", "false", "f", "F", "FALSE", "False" are interpreted as Boolean. To force only a few values in a cell to be considered Boolean, this slice is created. - boolSlice := []string{"true", "[TRUE]", "TRUE", "True", "false", "[FALSE]", "FALSE", "False"} - - var filter bson.M - + // In Golang, the values "1", "true", "t", "T", "TRUE", "True" and "0", "false", "f", "F", "FALSE", "False" are interpreted as Booleans. + // To force only a few values in a cell to be considered Boolean, this slice is created. + boolSlice := []string{"true", "TRUE", "True", "false", "FALSE", "False"} + + // var filter bson.M + // Try to convert to bool if ContainsElement(value, boolSlice) { convertedValue, err := strconv.ParseBool(value) if err == nil { - filter = bson.M{field: convertedValue} - } - } else { - // Try to convert to int - if convertedValue, err := strconv.Atoi(value); err == nil { - filter = bson.M{field: convertedValue} - } else { - // Try converting to float64 - if convertedValue, err := strconv.ParseFloat(value, 64); err == nil { - filter = bson.M{field: convertedValue} - } else { - // If the passed value is [EMPTY] or [NULL] it evaluates to nil - if value == "[EMPTY]" || value == "[NULL]"{ - filter = bson.M{field: nil} - } else{ - // If none of the above is true, the value remains as the original type (string) - filter = bson.M{field: value} - } - } + fmt.Println("bool: ", bson.M{field: convertedValue}) + return bson.M{field: convertedValue} } } - return filter + + // Try to convert to int + if convertedValue, err := strconv.Atoi(value); err == nil { + return bson.M{field: convertedValue} + } + + // Try converting to float64 + if convertedValue, err := strconv.ParseFloat(value, 64); err == nil { + return bson.M{field: convertedValue} + } + + // If the passed value is "[EMPTY]" or "[NULL]", it evaluates to nil + if value == "[EMPTY]" || value == "[NULL]" { + return bson.M{field: nil} + } + + // If none of the above is true, the value remains as the original type (string) + return bson.M{field: value} } + // GetOptionsSearchAllFields create an "Options" that states that the search will be done in all fields of the collection func GetOptionsSearchAllFields() *options.FindOneOptions { return options.FindOne().SetProjection(bson.M{}) @@ -384,7 +386,7 @@ s.singleResult = s.collection.FindOne(ctx, GetFilter(fieldSearched, value), GetOptionsSearchAllFields()) if s.singleResult.Err() != nil { - return errors.New(fmt.Sprintf("ERROR. The searched field (%s) does not have the value (%s) in the collection (%s)", fieldSearched, value, s.collection)) + return errors.New(fmt.Sprintf("ERROR. The searched field (%s) does not have the value (%s) in the collection (%s)", fieldSearched, value, s.collection.Name())) } return nil } @@ -506,7 +508,7 @@ return false, errors.New(fmt.Sprintf("ERROR. Mismatch of mongo field '%s': expected '%s', actual '%s'", key, expectedValue, value)) } } else { - return false, errors.New(fmt.Sprintf("ERROR. The mongo field '%s': does not exist in '%s' collection", key, s.collection)) + return false, errors.New(fmt.Sprintf("ERROR. The mongo field '%s': does not exist in '%s' collection", key, s.collection.Name())) } } return true, nil From 7c4e9740dbbfdc4d378b07c31740ec82090ce957 Mon Sep 17 00:00:00 2001 From: antoniodiazplaza Date: Mon, 23 Oct 2023 12:00:29 +0200 Subject: [PATCH 03/27] 4727_Golium_MongoDB_Repairs_2 --- steps/mongo/session.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/steps/mongo/session.go b/steps/mongo/session.go index 4c73bd40..361c55d3 100644 --- a/steps/mongo/session.go +++ b/steps/mongo/session.go @@ -110,11 +110,11 @@ s.SetCollection(ctx, collectionName) // 2-Get boolean if _id exist and must exist in collection - exist_id, err := s.VerifyExist_id(ctx, idCollection) - mustExist_id := VerifyMustExist(exist) + existId, err := s.VerifyExistId(ctx, idCollection) + mustExistId := VerifyMustExist(exist) // 3-Verify exist and must exist - return s.VerifyExistAndMustExistValue(exist_id, mustExist_id, err) + return s.VerifyExistAndMustExistValue(existId, mustExistId, err) } // CheckMongoValuesStep checks the value of the MongoDB fields in the specified collection @@ -202,8 +202,6 @@ // CheckNumberDocumentscollectionNameStep verify the number of documents in collection func (s *Session) CheckNumberDocumentscollectionNameStep(ctx context.Context, collectionName string, num int) error { - //TODO. Investigate why the appropriate method for this function (CountDouments) is not working properly - // 1-The collection from which the documents are to be counted is established s.SetCollection(ctx, collectionName) @@ -446,8 +444,8 @@ return nil } - // VerifyExist_id returns a boolean indicating whether the _id searched exists in the collection - func (s *Session) VerifyExist_id(ctx context.Context, idCollection string) (bool, error) { + // VerifyExistId returns a boolean indicating whether the _id searched exists in the collection + func (s *Session) VerifyExistId(ctx context.Context, idCollection string) (bool, error) { //Perform the search and get the result as singleResult err := s.SetSingleResult(ctx, "_id", idCollection) if err != nil { From 6d7a23aebe4c0d793b656108a983d295a4bba293 Mon Sep 17 00:00:00 2001 From: antoniodiazplaza Date: Mon, 23 Oct 2023 14:39:12 +0200 Subject: [PATCH 04/27] 4727_Golium_MongoDB_Repairs_3 --- steps/mongo/client.go | 15 +- steps/mongo/context.go | 2 +- steps/mongo/session.go | 958 +++++++++++++++++++++-------------------- steps/mongo/steps.go | 17 +- 4 files changed, 501 insertions(+), 491 deletions(-) diff --git a/steps/mongo/client.go b/steps/mongo/client.go index 868025c3..513658e1 100644 --- a/steps/mongo/client.go +++ b/steps/mongo/client.go @@ -14,17 +14,14 @@ package mongo - import ( - "context" +import ( + "context" - - "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo" ) type ClientFunctions interface { - - Ping(ctx context.Context, client *mongo.Client) error - + Ping(client *mongo.Client) error } type ClientService struct{} @@ -32,7 +29,7 @@ func NewMongoClientService() *ClientService { return &ClientService{} } -//Ping check that there is a connection to MongoDB -func (c ClientService) Ping(ctx context.Context, client *mongo.Client) error { +// Ping check that there is a connection to MongoDB +func (c ClientService) Ping(client *mongo.Client) error { return client.Ping(context.Background(), nil) } diff --git a/steps/mongo/context.go b/steps/mongo/context.go index 164c4f28..6d480b55 100755 --- a/steps/mongo/context.go +++ b/steps/mongo/context.go @@ -29,7 +29,7 @@ func InitializeContext(ctx context.Context) context.Context { return context.WithValue(ctx, contextKey, &Session{MongoClientService: *NewMongoClientService()}) } -// GetSession returns the mongo session stored in context. +// GetSession returns the mongo session stored in context. // Note that the context should be previously initialized with InitializeContext function. func GetSession(ctx context.Context) *Session { return ctx.Value(contextKey).(*Session) diff --git a/steps/mongo/session.go b/steps/mongo/session.go index 361c55d3..d507a505 100644 --- a/steps/mongo/session.go +++ b/steps/mongo/session.go @@ -12,510 +12,530 @@ // See the License for the specific language governing permissions and // limitations under the License. - package mongo - - import ( - "context" - "errors" - "fmt" - "reflect" - "strings" - "strconv" - - "github.com/TelefonicaTC2Tech/golium" - "github.com/cucumber/godog" - "github.com/google/uuid" - - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - ) - - // Session contains the information of a MongoDB session. - type Session struct { - - // Save MongoDB login credentials: username, password, and AuthSource - credentials options.Credential - - // Saves the host from accessing MongoDB - host string - - // Save the MongoDB database - database string - - // Set the host and credentials for the connection - clientOptions *options.ClientOptions - - // Create the mongo client with the MongoDB connection - client *mongo.Client - - // Points to a record in a collection - singleResult *mongo.SingleResult - - // Saves the collection to be used - collection *mongo.Collection - - // Save the name of the collectionName fields - fieldsCollectionName []string - - // Save collection items as JSON - dataCollectionJSONBytes []byte - - // Access MongoDB features - MongoClientService ClientFunctions - } - - // FUNCTIONS CALLED BY STEPS - - // CheckMongoFieldExistOrEmptyStep check that a field does not exist or that it does exist and is empty - func (s *Session) CheckMongoFieldExistOrEmptyStep(ctx context.Context, fieldSearched string, collectionName string, idCollection string) error { - - // 1-Setting the Collection Name in the Session - s.SetCollection(ctx, collectionName) - - // 2-Set fields collection name in Session: s.fieldsCollectionName - err := s.SetFieldsCollectionName(ctx, idCollection, s.collection) - if err != nil { - return err - } - - // 3-If fieldSearched exists, check that the value of the fieldSearched is null - if s.ExistFieldCollection(ctx, fieldSearched) { - err = s.SetSingleResult(ctx, fieldSearched, nil) - } +package mongo + +import ( + "context" + "fmt" + "reflect" + "strconv" + "strings" + + "github.com/TelefonicaTC2Tech/golium" + "github.com/cucumber/godog" + "github.com/google/uuid" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +// Session contains the information of a MongoDB session. +type Session struct { + + // Save MongoDB login credentials: username, password, and AuthSource + credentials options.Credential + + // Saves the host from accessing MongoDB + host string + + // Save the MongoDB database + database string + + // Set the host and credentials for the connection + clientOptions *options.ClientOptions + + // Create the mongo client with the MongoDB connection + client *mongo.Client + + // Points to a record in a collection + singleResult *mongo.SingleResult + + // Saves the collection to be used + collection *mongo.Collection + + // Save the name of the collectionName fields + fieldsCollectionName []string + + // Save collection items as JSON + dataCollectionJSONBytes []byte + + // Access MongoDB features + MongoClientService ClientFunctions +} + +// FUNCTIONS CALLED BY STEPS + +// CheckMongoFieldExistOrEmptyStep check that a field does not exist or it does exist and is empty +func (s *Session) CheckMongoFieldExistOrEmptyStep( + ctx context.Context, fieldSearched, collectionName, idCollection string, + ) error { + // 1-Setting the Collection Name in the Session + s.SetCollection(collectionName) + // 2-Set fields collection name in Session: s.fieldsCollectionName + err := s.SetFieldsCollectionName(ctx, idCollection, s.collection) + if err != nil { return err } - - // CheckMongoFieldNameStep check if the name of the field searched of the mongo user collection is correct - func (s *Session) CheckMongoFieldNameStep(ctx context.Context, collectionName string, fieldSearched string, exist string, idCollection string) error { - - // 1-Set collection name and fields collection name in Session - s.SetCollection(ctx, collectionName) - s.SetFieldsCollectionName(ctx, idCollection, s.collection) - - // 2-Get boolean if field exist and must exist in collection - existField := s.ExistFieldCollection(ctx, fieldSearched) - mustExistField := VerifyMustExist(exist) - - // 3-Verify exist and must exist - return s.VerifyExistAndMustExistValue(existField, mustExistField, nil) - } - - // CheckMongoValueIDStep checks if the past idCollection exists in the collection - func (s *Session) CheckMongoValueIDStep(ctx context.Context, collectionName string, idCollection string, exist string) error { - - // 1-Set collection name and fields collection name in Session - s.SetCollection(ctx, collectionName) - - // 2-Get boolean if _id exist and must exist in collection - existId, err := s.VerifyExistId(ctx, idCollection) - mustExistId := VerifyMustExist(exist) - - // 3-Verify exist and must exist - return s.VerifyExistAndMustExistValue(existId, mustExistId, err) - } - - // CheckMongoValuesStep checks the value of the MongoDB fields in the specified collection - func (s *Session) CheckMongoValuesStep(ctx context.Context, collectionName string, idCollection string, exist string, t *godog.Table) error { - - // 1-Set collection name and fields collection name in Session - s.SetCollection(ctx, collectionName) - - // 2-Get value of specified table - props, err := golium.ConvertTableToMap(ctx, t) - if err != nil { - return fmt.Errorf("ERROR: failed processing the table for validating the response body: %w", err) - } - - // 3-Get boolean if data exist and must exist in collection - existValue, err := s.ValidateDataMongo(ctx, idCollection, props) - mustExistValue := VerifyMustExist(exist) - - // 4-Verify exist and must exist - return s.VerifyExistAndMustExistValue(existValue, mustExistValue, err) - } - - // MongoConnectionStep establishes a connection in MongoDB. The connection data is saved in s.clientOptions, the client in s.client, and the database in s.database - func (s *Session) MongoConnectionStep(ctx context.Context) error { - - // 1-Set credentials and host in session - s.SetCredentials(ctx) - s.SetHost(ctx) - - // 2-Set clientOptions in session - s.clientOptions = options.Client().SetHosts(strings.Split(s.host, ",")).SetAuth(s.credentials) - - // 3-Connect to the MongoDB server and set client in session - var err error - s.client, err = mongo.Connect(context.Background(), s.clientOptions) - if err != nil { - return fmt.Errorf("Error with the client options or with the context. %s", err) - } - - // 4-Check the connection to the MongoDB server - err = s.MongoClientService.Ping(ctx, s.client) - if err != nil { - return fmt.Errorf("Error connecting to MongoDB. %s", err) - } - - // 5-Set the database in session - s.SetDatabase(ctx) - - return nil + + // 3-If fieldSearched exists, check that the value of the fieldSearched is null + if s.ExistFieldCollection(fieldSearched) { + err = s.SetSingleResult(ctx, fieldSearched, nil) } - // CreateDocumentcollectionNameStep creates a number of documents in the specified collection - func (s *Session) CreateDocumentscollectionNameStep(ctx context.Context, num int, collectionName string) error { - - // 1-The collection to which the insertion is to be made is set. If it doesn't exist, it's created. - s.SetCollection(ctx, collectionName) - - // 2-The documents to be inserted are created - allDocuments := s.CreateDocumentsCollection(ctx, num, collectionName) - - // 3-Insert the documents into the "collectionName" collection of the database - _, err := s.collection.InsertMany(context.TODO(), allDocuments) - if err != nil { - return err - } - - return nil + return err +} + +// CheckMongoFieldNameStep check if the name of the field searched of the user collection is correct +func (s *Session) CheckMongoFieldNameStep( + ctx context.Context, collectionName, fieldSearched, exist, idCollection string, + ) error { + // 1-Set collection name and fields collection name in Session + s.SetCollection(collectionName) + s.SetFieldsCollectionName(ctx, idCollection, s.collection) + + // 2-Get boolean if field exist and must exist in collection + existField := s.ExistFieldCollection(fieldSearched) + mustExistField := VerifyMustExist(exist) + + // 3-Verify exist and must exist + return s.VerifyExistAndMustExistValue(existField, mustExistField, nil) +} + +// CheckMongoValueIDStep checks if the past idCollection exists in the collection +func (s *Session) CheckMongoValueIDStep( + ctx context.Context, collectionName, idCollection, exist string, + ) error { + // 1-Set collection name and fields collection name in Session + s.SetCollection(collectionName) + + // 2-Get boolean if _id exist and must exist in collection + existID, err := s.VerifyExistID(ctx, idCollection) + mustExistID := VerifyMustExist(exist) + + // 3-Verify exist and must exist + return s.VerifyExistAndMustExistValue(existID, mustExistID, err) +} + +// CheckMongoValuesStep checks the value of the MongoDB fields in the specified collection +func (s *Session) CheckMongoValuesStep( + ctx context.Context, collectionName, idCollection, exist string, t *godog.Table, + ) error { + // 1-Set collection name and fields collection name in Session + s.SetCollection(collectionName) + + // 2-Get value of specified table + props, err := golium.ConvertTableToMap(ctx, t) + if err != nil { + return fmt.Errorf("ERROR: failed processing the table for validating the body: %w", err) } - - // DeleteDocumentscollectionNameStep delete a document from the MongoDB collection - func (s *Session) DeleteDocumentscollectionNameStep(ctx context.Context, collectionName string, field string, value string) error { - - // 1-The collection in which the deletion is to be made is established. - s.SetCollection(ctx, collectionName) - - //2-Performs the deletion of documents that match the filter after the data type is converted. You can only filter by string, int, float, or boolean values, also in slices and maps. - _, err := s.collection.DeleteMany(ctx, GetFilterConverted(field, value) ) - if err != nil { - return err - } - - return nil + + // 3-Get boolean if data exist and must exist in collection + existValue, err := s.ValidateDataMongo(ctx, idCollection, props) + mustExistValue := VerifyMustExist(exist) + + // 4-Verify exist and must exist + return s.VerifyExistAndMustExistValue(existValue, mustExistValue, err) +} + +// MongoConnectionStep establishes a connection in MongoDB. +// The connection, client and database data are saved in s.clientOptions, s.client, and s.database +func (s *Session) MongoConnectionStep(ctx context.Context) error { + // 1-Set credentials and host in session + s.SetCredentials(ctx) + s.SetHost(ctx) + + // 2-Set clientOptions in session + s.clientOptions = options.Client().SetHosts(strings.Split(s.host, ",")).SetAuth(s.credentials) + + // 3-Connect to the MongoDB server and set client in session + var err error + s.client, err = mongo.Connect(context.Background(), s.clientOptions) + if err != nil { + return fmt.Errorf("error: problems with the client options or with the context. %s", err) } - - // CheckNumberDocumentscollectionNameStep verify the number of documents in collection - func (s *Session) CheckNumberDocumentscollectionNameStep(ctx context.Context, collectionName string, num int) error { - - // 1-The collection from which the documents are to be counted is established - s.SetCollection(ctx, collectionName) - - // 2-Make a query to get all the documents in the collection - cursor, err := s.collection.Find(context.Background(), bson.D{}) - if err != nil { - return errors.New(fmt.Sprintf("Query error: %s", err)) - } - // 3-Iterate through the documents and count the ones that are there - count := 0 - for cursor.Next(context.Background()) { - count++ - } + // 4-Check the connection to the MongoDB server + err = s.MongoClientService.Ping(s.client) + if err != nil { + return fmt.Errorf("error: problems with connection to MongoDB. %s", err) + } - // 4-Check the result - if count != num { - return errors.New(fmt.Sprintf("ERROR: The number of documents is '%d' and should be '%d'", count, num)) - } - return nil + // 5-Set the database in session + s.SetDatabase(ctx) + + return nil +} + +// CreateDocumentcollectionNameStep creates a number of documents in the specified collection +func (s *Session) CreateDocumentscollectionNameStep( + ctx context.Context, num int, collectionName string, + ) error { + // 1-collection in which the insertion will be made, if it does not exist it is created + s.SetCollection(collectionName) + + // 2-The documents to be inserted are created + allDocuments := s.CreateDocumentsCollection(ctx, num, collectionName) + + // 3-Insert the documents into the "collectionName" collection of the database + _, err := s.collection.InsertMany(context.TODO(), allDocuments) + if err != nil { + return err } - - - // GENERIC FUNCTIONS - - // ContainsElement check if an item exists in a slice - func ContainsElement(expectedElement interface{}, sliceElements interface{}) bool { - - // 1-Create a reflection object from the slice - sliceValue := reflect.ValueOf(sliceElements) - - // 2-It is verified that the object of reflection is of the "slice" type - if sliceValue.Kind() != reflect.Slice { - return false - } - - for i := 0; i < sliceValue.Len(); i++ { - // 3-The slice element converted into an interface is compared with the searched element. The comparison is made in value and type - if reflect.DeepEqual(sliceValue.Index(i).Interface(), expectedElement) { - return true - } - } - + + return nil +} + +// DeleteDocumentscollectionNameStep delete a document from the MongoDB collection +func (s *Session) DeleteDocumentscollectionNameStep( + ctx context.Context, collectionName, field, value string, + ) error { + // 1-The collection in which the deletion is to be made is established. + s.SetCollection(collectionName) + + // 2-Performs the deletion of documents that match the filter after the data type is converted. + // Only it is possible filter by string, int, float, or boolean values, also in slices and maps. + _, err := s.collection.DeleteMany(ctx, GetFilterConverted(field, value)) + if err != nil { + return err + } + + return nil +} + +// CheckNumberDocumentscollectionNameStep verify the number of documents in collection +func (s *Session) CheckNumberDocumentscollectionNameStep( + ctx context.Context, collectionName string, num int, + ) error { + // 1-The collection from which the documents are to be counted is established + s.SetCollection(collectionName) + + // 2-Make a query to get all the documents in the collection + cursor, err := s.collection.Find(context.Background(), bson.D{}) + if err != nil { + return fmt.Errorf("error: query error: %s", err) + } + + // 3-Iterate through the documents and count the ones that are there + count := 0 + for cursor.Next(context.Background()) { + count++ + } + + // 4-Check the result + if count != num { + return fmt.Errorf("error: the number of documents is '%d' and should be '%d'", count, num) + } + return nil +} + +// GENERIC FUNCTIONS + +// ContainsElement check if an item exists in a slice +func ContainsElement(expectedElement interface{}, sliceElements interface{}) bool { + // 1-Create a reflection object from the slice + sliceValue := reflect.ValueOf(sliceElements) + + // 2-It is verified that the object of reflection is of the "slice" type + if sliceValue.Kind() != reflect.Slice { return false } - - // GetFilter returns a filter to search for a record from a field - func GetFilter(key string, value interface{}) primitive.M { - if value == nil { - return bson.M{key: nil} - } else { - return bson.M{key: value} - } - } - - // GetFilterConverted returns a filter with the field and data type required for the deletion of a record - func GetFilterConverted(field string, value string) primitive.M { - // In Golang, the values "1", "true", "t", "T", "TRUE", "True" and "0", "false", "f", "F", "FALSE", "False" are interpreted as Booleans. - // To force only a few values in a cell to be considered Boolean, this slice is created. - boolSlice := []string{"true", "TRUE", "True", "false", "FALSE", "False"} - - // var filter bson.M - - // Try to convert to bool - if ContainsElement(value, boolSlice) { - convertedValue, err := strconv.ParseBool(value) - if err == nil { - fmt.Println("bool: ", bson.M{field: convertedValue}) - return bson.M{field: convertedValue} - } - } - - // Try to convert to int - if convertedValue, err := strconv.Atoi(value); err == nil { - return bson.M{field: convertedValue} - } - - // Try converting to float64 - if convertedValue, err := strconv.ParseFloat(value, 64); err == nil { - return bson.M{field: convertedValue} - } - - // If the passed value is "[EMPTY]" or "[NULL]", it evaluates to nil - if value == "[EMPTY]" || value == "[NULL]" { - return bson.M{field: nil} - } - - // If none of the above is true, the value remains as the original type (string) - return bson.M{field: value} - } - - - // GetOptionsSearchAllFields create an "Options" that states that the search will be done in all fields of the collection - func GetOptionsSearchAllFields() *options.FindOneOptions { - return options.FindOne().SetProjection(bson.M{}) - } - - // VerifyMustExist returns a boolean indicating whether the element should exist - func VerifyMustExist(exist string) bool { - if strings.Contains(strings.ToLower(exist), "not") { - return false - } else { + + for i := 0; i < sliceValue.Len(); i++ { + // 3-The slice element converted into an interface is compared with the searched element. + // The comparison is made in value and type + if reflect.DeepEqual(sliceValue.Index(i).Interface(), expectedElement) { return true } } - - - // SESSION FUNCTIONS - - // CreateDocumentsCollection creates num documents in a slice and inserts them into a MongoDB collection - func (s *Session) CreateDocumentsCollection(ctx context.Context, num int, collectionName string) []interface{}{ - // 1-Initialize the document slice - allDocuments := []interface{}{} - - // 2-Obtaining the _id of the context, if it does not exist it is created - id := golium.GetContext(ctx).Get("_ID") - if id == nil { - var err error - id , err = uuid.NewRandom() - if err != nil { - return nil - } - // Transforming id into an interface - id = id.(uuid.UUID).String() - } - // 3-Creating Documents and Inserting Into the Slice - for i:=1; i<=num; i++ { - // Defines the document to be inserted. The _id will be the same across all + _ + iteration number - document := map[string]interface{}{ - "_id" : id.(string) + "_"+ strconv.Itoa(i), - "fieldString": "Example field string " +strconv.Itoa(i), - "fieldInt": i, - "fieldFloat": 3.14, - "fieldBool": true, - "fieldSlice": []string{"itemSlice_"+ strconv.Itoa(i), "itemSlice20", "itemSlice30"}, - "fieldEmpty": nil, - "fieldMap": map[string]interface{}{ - "fieldString": "Example field in map string " +strconv.Itoa(i), - "fieldInt": i*10, - "fieldFloat": 1974.1976, - "fieldBool": false, - "fieldSliceEmpty": []string{}, - "fieldMap2": map[string]interface{}{ - "fieldString": "Example field in map map string " +strconv.Itoa(i), - "fieldInt": i*100, - "fieldFloat": 1974.1976, - "fieldBool": false, - "fieldEmpty": nil, - "fieldEmptyText": "", - }, - }, - } - allDocuments = append(allDocuments, document) - } - return allDocuments - } - - // SetCredentials set an Options element. Credential with MongoDB access credentials - func (s *Session) SetCredentials(ctx context.Context) { - credentials := options.Credential{ - Username: golium.ValueAsString(ctx, fmt.Sprintf("[CONF:mongoUsername]")), - Password: golium.ValueAsString(ctx, fmt.Sprintf("[CONF:mongoPassword]")), - AuthSource: golium.ValueAsString(ctx, fmt.Sprintf("[CONF:mongoAuthSource]")), + + return false +} + +// GetFilter returns a filter to search for a record from a field +func GetFilter(key string, value interface{}) primitive.M { + if value == nil { + return bson.M{key: nil} + } + return bson.M{key: value} +} + +// GetFilterConverted returns a filter with field and data type required for delete a record +func GetFilterConverted(field, value string) primitive.M { + /* In Golang: + - the values "1", "true", "t", "T", "TRUE", "True" are interpreted as true + - the values "0", "false", "f", "F", "FALSE", "False" are interpreted as false. + To force only a few values in a cell to be considered Boolean, this slice is created. + */ + boolSlice := []string{"true", "TRUE", "True", "false", "FALSE", "False"} + + // Try to convert to bool + if ContainsElement(value, boolSlice) { + convertedValue, err := strconv.ParseBool(value) + if err == nil { + return bson.M{field: convertedValue} } - s.credentials = credentials } - - // SetHost set a string with the host - func (s *Session) SetHost(ctx context.Context) { - s.host = golium.ValueAsString(ctx, fmt.Sprintf("[CONF:mongoHost]")) + + // Try to convert to int + if convertedValue, err := strconv.Atoi(value); err == nil { + return bson.M{field: convertedValue} } - - // SetDatabase set a string with the database - func (s *Session) SetDatabase(ctx context.Context) { - s.database = golium.ValueAsString(ctx, fmt.Sprintf("[CONF:mongoDatabase]")) + + // Try converting to float64 + if convertedValue, err := strconv.ParseFloat(value, 64); err == nil { + return bson.M{field: convertedValue} } - - // SetSingleResult set a Single Result from a Filter Search (GetFilter(...) function) - func (s *Session) SetSingleResult(ctx context.Context, fieldSearched string, value interface{}) error { - s.singleResult = s.collection.FindOne(ctx, GetFilter(fieldSearched, value), GetOptionsSearchAllFields()) - if s.singleResult.Err() != nil { - return errors.New(fmt.Sprintf("ERROR. The searched field (%s) does not have the value (%s) in the collection (%s)", fieldSearched, value, s.collection.Name())) - } - return nil + // If the passed value is "[EMPTY]" or "[NULL]", it evaluates to nil + if value == "[EMPTY]" || value == "[NULL]" { + return bson.M{field: nil} } - - // SetCollection sets the collection. If the collection does not exist, no error is returned. Collections are created dynamically when you insert a document - func (s *Session) SetCollection(ctx context.Context, collectionName string) { - s.collection = s.client.Database(s.database).Collection(collectionName) - } - - // ExistFieldCollection evaluate whether or not the searched field exists - func (s *Session) ExistFieldCollection(ctx context.Context, fieldSearched string) bool { - existField := false - for _, element := range s.fieldsCollectionName { - if element == fieldSearched { - existField = true - } - } - return existField - } - - // GetDecodeDocument decodes the BSON document in the bsonDoc variable - func (s *Session) GetDecodeDocument(singleResult mongo.SingleResult) (bson.D, error) { - var bsonDoc bson.D - if err := s.singleResult.Decode(&bsonDoc); err != nil { - err = fmt.Errorf(fmt.Sprintf("ERROR. The decoding of the BSON has been erroneous: %s", err)) - return nil, err - } - return bsonDoc, nil + + // If none of the above is true, the value remains as the original type (string) + return bson.M{field: value} +} + +// GetOptionsSearchAllFields creates an "Options" to search all fields in the collection +func GetOptionsSearchAllFields() *options.FindOneOptions { + return options.FindOne().SetProjection(bson.M{}) +} + +// VerifyMustExist returns a boolean indicating whether the element should exist +func VerifyMustExist(exist string) bool { + if strings.Contains(strings.ToLower(exist), "not") { + return false } - - // SetDataCollectionJSONBytes convert BSON object to JSON - func (s *Session) SetDataCollectionJSONBytes(bsonDoc bson.D) error { + return true +} + +// SESSION FUNCTIONS + +// CreateDocumentsCollection creates num documents in a slice and inserts them into a collection +func (s *Session) CreateDocumentsCollection( + ctx context.Context, num int, collectionName string, + ) []interface{} { + // 1-Initialize the document slice + allDocuments := []interface{}{} + + // 2-Obtaining the _id of the context, if it does not exist it is created + id := golium.GetContext(ctx).Get("_ID") + if id == nil { var err error - s.dataCollectionJSONBytes, err = bson.MarshalExtJSON(bsonDoc, false, false) + id, err = uuid.NewRandom() if err != nil { - return errors.New(fmt.Sprintf("ERROR. The conversion from BSON to JSON has been erroneous: %s", err)) + return nil } - return nil + // Transforming id into an interface + id = id.(uuid.UUID).String() } - - // SetFieldsCollectionName save a string slice with the names of the fields in the collection in s.fieldsCollectionName - func (s *Session) SetFieldsCollectionName(ctx context.Context, idCollection string, collectionName *mongo.Collection) error { - // Make a query to find past _id's document - var document bson.M - err := s.collection.FindOne(ctx, GetFilter("_id", idCollection)).Decode(&document) - if err == mongo.ErrNoDocuments { - return errors.New(fmt.Sprintf("ERROR: No documents matching the filter were found.")) - } else if err != nil { - return errors.New(fmt.Sprintf("ERROR: %s", err)) - } else { - // The s.fieldsCollectionName collection is flushed, and then the names of the fields in the document are added - s.fieldsCollectionName = s.fieldsCollectionName[:0] - for fieldName := range document { - s.fieldsCollectionName = append(s.fieldsCollectionName, fieldName) - } + // 3-Creating Documents and Inserting Into the Slice + for i := 1; i <= num; i++ { + // Defines the document to be inserted. + //The _id will be the same across all + _ + iteration number + document := map[string]interface{}{ + "_id": id.(string) + "_" + strconv.Itoa(i), + "fieldString": "Example field string " + strconv.Itoa(i), + "fieldInt": i, + "fieldFloat": 3.14, + "fieldBool": true, + "fieldSlice": []string{"itemSlice_" + strconv.Itoa(i), "itemSlice20", "itemSlice30"}, + "fieldEmpty": nil, + "fieldMap": map[string]interface{}{ + "fieldString": "Example field in map string " + strconv.Itoa(i), + "fieldInt": i * 10, + "fieldFloat": 1974.1976, + "fieldBool": false, + "fieldSliceEmpty": []string{}, + "fieldMap2": map[string]interface{}{ + "fieldString": "Example field in map map string " + strconv.Itoa(i), + "fieldInt": i * 100, + "fieldFloat": 1974.1976, + "fieldBool": false, + "fieldEmpty": nil, + "fieldEmptyText": "", + }, + }, } - return nil + allDocuments = append(allDocuments, document) } - - // VerifyExistId returns a boolean indicating whether the _id searched exists in the collection - func (s *Session) VerifyExistId(ctx context.Context, idCollection string) (bool, error) { - //Perform the search and get the result as singleResult - err := s.SetSingleResult(ctx, "_id", idCollection) - if err != nil { - return false, errors.New(fmt.Sprintf("ERROR. The searched _id (%s) does not exist in the '%s' collection", idCollection, s.collection.Name())) - } - return true, nil - } - - // VerifyExistAndMustExistValue check if the values exist and should exist - func (s *Session) VerifyExistAndMustExistValue(exist bool, mustExist bool, err error) error { - // If Exist and should NOT exist or NOT exist and should exist return error - // If Exist and shoud exist OR not exist and should not exist return nil - if exist && mustExist || !exist && !mustExist { - return nil - } else { - if err != nil { - return err - } else { - return errors.New(fmt.Sprintf("ERROR. The value DOES NOT EXIST and SHOULD, or EXIST and SHOULD NOT, in '%s' collection", s.collection.Name())) - } - } + return allDocuments +} + +// SetCredentials set an Options element. Credential with MongoDB access credentials +func (s *Session) SetCredentials(ctx context.Context) { + credentials := options.Credential{ + Username: golium.ValueAsString(ctx, "[CONF:mongoUsername]"), + Password: golium.ValueAsString(ctx, "[CONF:mongoPassword]"), + AuthSource: golium.ValueAsString(ctx, "[CONF:mongoAuthSource]"), } - - // ValidateDataMongo verifies that the feature table data exists in the MongoDB collection - func (s *Session) ValidateDataMongo(ctx context.Context, idCollection string, props map[string]interface{}) (bool, error) { - // 1-Sets a document to s.singleResult from a filter search - s.SetSingleResult(ctx, "_id", idCollection) - - // 2-Decodes the singleResult document into a BSON (bsonDoc) - bsonDoc, err := s.GetDecodeDocument(*s.singleResult) - if err != nil { - return false, err + s.credentials = credentials +} + +// SetHost set a string with the host +func (s *Session) SetHost(ctx context.Context) { + s.host = golium.ValueAsString(ctx, "[CONF:mongoHost]") +} + +// SetDatabase set a string with the database +func (s *Session) SetDatabase(ctx context.Context) { + s.database = golium.ValueAsString(ctx, "[CONF:mongoDatabase]") +} + +// SetSingleResult set a Single Result from a Filter Search (GetFilter(...) function) +func (s *Session) SetSingleResult( + ctx context.Context, fieldSearched string, value interface{}, + ) error { + s.singleResult = s.collection.FindOne( + ctx, GetFilter(fieldSearched, value), GetOptionsSearchAllFields()) + if s.singleResult.Err() != nil { + return fmt.Errorf("error: the searched field (%s) does not have the value (%s) "+ + "in the collection (%s)", fieldSearched, value, s.collection) + } + return nil +} + +// SetCollection sets the collection. If the collection does not exist, no error is returned. +// Collections are created dynamically when you insert a document +func (s *Session) SetCollection(collectionName string) { + s.collection = s.client.Database(s.database).Collection(collectionName) +} + +// ExistFieldCollection evaluate whether or not the searched field exists +func (s *Session) ExistFieldCollection(fieldSearched string) bool { + existField := false + for _, element := range s.fieldsCollectionName { + if element == fieldSearched { + existField = true } - - // 3-Convert the bsonDoc object to JSON - err = s.SetDataCollectionJSONBytes(bsonDoc) - if err != nil { - return false, err + } + return existField +} + +// GetDecodeDocument decodes the BSON document in the bsonDoc variable +func (s *Session) GetDecodeDocument(singleResult mongo.SingleResult) (bson.D, error) { + var bsonDoc bson.D + if err := singleResult.Decode(&bsonDoc); err != nil { + err = fmt.Errorf("erro: the decoding of the BSON has been erroneous: %s", err) + return nil, err + } + return bsonDoc, nil +} + +// SetDataCollectionJSONBytes convert BSON object to JSON +func (s *Session) SetDataCollectionJSONBytes(bsonDoc bson.D) error { + var err error + s.dataCollectionJSONBytes, err = bson.MarshalExtJSON(bsonDoc, false, false) + if err != nil { + return fmt.Errorf("error: the conversion from BSON to JSON has been erroneous: %s", err) + } + return nil +} + +// SetFieldsCollectionName save a slice with the names of the fields in s.fieldsCollectionName +func (s *Session) SetFieldsCollectionName( + ctx context.Context, idCollection string, collectionName *mongo.Collection, + ) error { + // Make a query to find past _id's document + var document bson.M + err := s.collection.FindOne(ctx, GetFilter("_id", idCollection)).Decode(&document) + if err == mongo.ErrNoDocuments { + return fmt.Errorf("error: no documents matching the filter were found.") + } else if err != nil { + return fmt.Errorf("error: %s", err) + } else { + // s.fieldsCollectionName is flushed, and the names of the fields in the document are added + s.fieldsCollectionName = s.fieldsCollectionName[:0] + for fieldName := range document { + s.fieldsCollectionName = append(s.fieldsCollectionName, fieldName) } - - // 4-Set the list of fields in the document to fieldsCollectionName - s.SetFieldsCollectionName(ctx, idCollection, s.collection) + } + return nil +} + +// VerifyExistID returns a boolean indicating whether the _id searched exists in the collection +func (s *Session) VerifyExistID(ctx context.Context, idCollection string) (bool, error) { + // Perform the search and get the result as singleResult + err := s.SetSingleResult(ctx, "_id", idCollection) + if err != nil { + return false, fmt.Errorf("error: searched _id (%s) does not exist in the '%s' collection", + idCollection, s.collection.Name()) + } + return true, nil +} + +// VerifyExistAndMustExistValue check if the values exist and should exist +func (s *Session) VerifyExistAndMustExistValue(exist, mustExist bool, err error) error { + // If Exist and should NOT exist or NOT exist and should exist return error + // If Exist and shoud exist OR not exist and should not exist return nil + if exist && mustExist || !exist && !mustExist { + return nil + } else { if err != nil { - return false, err + return err } - - // 5-Navigate through the feature table and check the data - m := golium.NewMapFromJSONBytes(s.dataCollectionJSONBytes) - for key, expectedValue := range props { - value := m.Get(key) - // Verify that the name of the clean field (fieldTableFeature) exists in the list of fields in the collection (s.fieldsCollectionName) - fieldTableFeature := strings.Split(key, ".")[0] - if ContainsElement(fieldTableFeature, s.fieldsCollectionName) { - if value == nil && expectedValue == "" { - //The value of the field in MongoDB is null and expectedValue is [EMPTY] - continue - } else if value != expectedValue { - return false, errors.New(fmt.Sprintf("ERROR. Mismatch of mongo field '%s': expected '%s', actual '%s'", key, expectedValue, value)) - } - } else { - return false, errors.New(fmt.Sprintf("ERROR. The mongo field '%s': does not exist in '%s' collection", key, s.collection.Name())) + return fmt.Errorf("error: the value DOES NOT EXIST and SHOULD, or EXIST and SHOULD NOT, "+ + "in '%s' collection", s.collection.Name()) + } +} + +// ValidateDataMongo verifies that the feature table data exists in the MongoDB collection +func (s *Session) ValidateDataMongo( + ctx context.Context, idCollection string, props map[string]interface{}, + ) (bool, error) { + // 1-Sets a document to s.singleResult from a filter search + s.SetSingleResult(ctx, "_id", idCollection) + + // 2-Decodes the singleResult document into a BSON (bsonDoc) + bsonDoc, err := s.GetDecodeDocument(*s.singleResult) + if err != nil { + return false, err + } + + // 3-Convert the bsonDoc object to JSON + err = s.SetDataCollectionJSONBytes(bsonDoc) + if err != nil { + return false, err + } + + // 4-Set the list of fields in the document to fieldsCollectionName + s.SetFieldsCollectionName(ctx, idCollection, s.collection) + if err != nil { + return false, err + } + + // 5-Navigate through the feature table and check the data + m := golium.NewMapFromJSONBytes(s.dataCollectionJSONBytes) + for key, expectedValue := range props { + value := m.Get(key) + // Verify that the name of the clean field (fieldTableFeature) exists + // in the list of fields in the collection (s.fieldsCollectionName) + fieldTableFeature := strings.Split(key, ".")[0] + if ContainsElement(fieldTableFeature, s.fieldsCollectionName) { + if value == nil && expectedValue == "" { + //The value of the field in MongoDB is null and expectedValue is [EMPTY] + continue + } else if value != expectedValue { + return false, fmt.Errorf("error: mismatch of mongo field '%s': expected '%s',"+ + "actual '%s'", key, expectedValue, value) } + } else { + return false, fmt.Errorf("error: the field '%s': does not exist in '%s' collection", + key, s.collection) } - return true, nil } + return true, nil +} - // MongoDisconnection closes the connection to MongoDB if it exists - func (s *Session) MongoDisconnection(ctx context.Context) { - if s.client != nil{ - s.client.Disconnect(context.Background()) - } +// MongoDisconnection closes the connection to MongoDB if it exists +func (s *Session) MongoDisconnection() error { + if s.client != nil { + err := s.client.Disconnect(context.Background()) + if err != nil { + return fmt.Errorf("error: problem in MongoDB disconnection: %s\n", err) + } } - \ No newline at end of file + return nil +} diff --git a/steps/mongo/steps.go b/steps/mongo/steps.go index b665fd32..f069bf3e 100755 --- a/steps/mongo/steps.go +++ b/steps/mongo/steps.go @@ -19,20 +19,13 @@ import ( "github.com/TelefonicaTC2Tech/golium" "github.com/cucumber/godog" - "github.com/cucumber/messages-go/v16" - - "go.mongodb.org/mongo-driver/mongo" - ) -var client *mongo.Client -var collection *mongo.Collection - -type MongoSteps struct { +type Steps struct { } // InitializeSteps initializes all the steps -func (us MongoSteps) InitializeSteps(ctx context.Context, scenCtx *godog.ScenarioContext) context.Context { +func (us Steps) InitializeSteps(ctx context.Context, scenCtx *godog.ScenarioContext) context.Context { // Initialize the HTTP session in the context ctx = InitializeContext(ctx) session := GetSession(ctx) @@ -62,9 +55,9 @@ func (us MongoSteps) InitializeSteps(ctx context.Context, scenCtx *godog.Scenari return session.CheckNumberDocumentscollectionNameStep(ctx, golium.ValueAsString(ctx, collectionName), num) }) - scenCtx.AfterScenario(func(sc *messages.Pickle, err error) { - session.MongoDisconnection(ctx) + scenCtx.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) { + return ctx, session.MongoDisconnection() }) - + return ctx } From 3be37077c85edc85ee4394330efddf2a455369ab Mon Sep 17 00:00:00 2001 From: antoniodiazplaza Date: Mon, 23 Oct 2023 15:06:08 +0200 Subject: [PATCH 05/27] 4727_Golium_MongoDB_Repairs_4 --- steps/mongo/session.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/steps/mongo/session.go b/steps/mongo/session.go index d507a505..50a82dcb 100644 --- a/steps/mongo/session.go +++ b/steps/mongo/session.go @@ -129,7 +129,7 @@ func (s *Session) CheckMongoValuesStep( // 2-Get value of specified table props, err := golium.ConvertTableToMap(ctx, t) if err != nil { - return fmt.Errorf("ERROR: failed processing the table for validating the body: %w", err) + return fmt.Errorf("ERROR: failed processing the table for validating the body: '%w'", err) } // 3-Get boolean if data exist and must exist in collection @@ -154,13 +154,13 @@ func (s *Session) MongoConnectionStep(ctx context.Context) error { var err error s.client, err = mongo.Connect(context.Background(), s.clientOptions) if err != nil { - return fmt.Errorf("error: problems with the client options or with the context. %s", err) + return fmt.Errorf("error: problems with the client options or with the context. '%s'", err) } // 4-Check the connection to the MongoDB server err = s.MongoClientService.Ping(s.client) if err != nil { - return fmt.Errorf("error: problems with connection to MongoDB. %s", err) + return fmt.Errorf("error: problems with connection to MongoDB. '%s'", err) } // 5-Set the database in session @@ -215,7 +215,7 @@ func (s *Session) CheckNumberDocumentscollectionNameStep( // 2-Make a query to get all the documents in the collection cursor, err := s.collection.Find(context.Background(), bson.D{}) if err != nil { - return fmt.Errorf("error: query error: %s", err) + return fmt.Errorf("error: query error: '%s'", err) } // 3-Iterate through the documents and count the ones that are there @@ -391,8 +391,8 @@ func (s *Session) SetSingleResult( s.singleResult = s.collection.FindOne( ctx, GetFilter(fieldSearched, value), GetOptionsSearchAllFields()) if s.singleResult.Err() != nil { - return fmt.Errorf("error: the searched field (%s) does not have the value (%s) "+ - "in the collection (%s)", fieldSearched, value, s.collection) + return fmt.Errorf("error: the searched '%s' field does not have the '%s' value "+ + "in the '%s' collection", fieldSearched, value, s.collection.Name()) } return nil } @@ -418,7 +418,7 @@ func (s *Session) ExistFieldCollection(fieldSearched string) bool { func (s *Session) GetDecodeDocument(singleResult mongo.SingleResult) (bson.D, error) { var bsonDoc bson.D if err := singleResult.Decode(&bsonDoc); err != nil { - err = fmt.Errorf("erro: the decoding of the BSON has been erroneous: %s", err) + err = fmt.Errorf("error: the decoding of the BSON has been erroneous: '%s'", err) return nil, err } return bsonDoc, nil @@ -429,7 +429,7 @@ func (s *Session) SetDataCollectionJSONBytes(bsonDoc bson.D) error { var err error s.dataCollectionJSONBytes, err = bson.MarshalExtJSON(bsonDoc, false, false) if err != nil { - return fmt.Errorf("error: the conversion from BSON to JSON has been erroneous: %s", err) + return fmt.Errorf("error: the conversion from BSON to JSON has been erroneous: '%s'", err) } return nil } @@ -444,7 +444,7 @@ func (s *Session) SetFieldsCollectionName( if err == mongo.ErrNoDocuments { return fmt.Errorf("error: no documents matching the filter were found.") } else if err != nil { - return fmt.Errorf("error: %s", err) + return fmt.Errorf("error: '%s'", err) } else { // s.fieldsCollectionName is flushed, and the names of the fields in the document are added s.fieldsCollectionName = s.fieldsCollectionName[:0] @@ -460,7 +460,7 @@ func (s *Session) VerifyExistID(ctx context.Context, idCollection string) (bool, // Perform the search and get the result as singleResult err := s.SetSingleResult(ctx, "_id", idCollection) if err != nil { - return false, fmt.Errorf("error: searched _id (%s) does not exist in the '%s' collection", + return false, fmt.Errorf("error: searched _id '%s' does not exist in the '%s' collection", idCollection, s.collection.Name()) } return true, nil @@ -523,7 +523,7 @@ func (s *Session) ValidateDataMongo( } } else { return false, fmt.Errorf("error: the field '%s': does not exist in '%s' collection", - key, s.collection) + key, s.collection.Name()) } } return true, nil @@ -534,7 +534,7 @@ func (s *Session) MongoDisconnection() error { if s.client != nil { err := s.client.Disconnect(context.Background()) if err != nil { - return fmt.Errorf("error: problem in MongoDB disconnection: %s\n", err) + return fmt.Errorf("error: problem in MongoDB disconnection: '%s'\n", err) } } return nil From e408fbe9b71792b07f801f352dd7e58acbd603fa Mon Sep 17 00:00:00 2001 From: antoniodiazplaza Date: Mon, 23 Oct 2023 15:45:20 +0200 Subject: [PATCH 06/27] 4727_Golium_MongoDB_Repairs_5 --- steps/mongo/session.go | 48 +++++++++++++++++------------------------- steps/mongo/steps.go | 2 +- 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/steps/mongo/session.go b/steps/mongo/session.go index 50a82dcb..a862eb77 100644 --- a/steps/mongo/session.go +++ b/steps/mongo/session.go @@ -75,7 +75,7 @@ func (s *Session) CheckMongoFieldExistOrEmptyStep( s.SetCollection(collectionName) // 2-Set fields collection name in Session: s.fieldsCollectionName - err := s.SetFieldsCollectionName(ctx, idCollection, s.collection) + err := s.SetFieldsCollectionName(ctx, idCollection) if err != nil { return err } @@ -94,7 +94,7 @@ func (s *Session) CheckMongoFieldNameStep( ) error { // 1-Set collection name and fields collection name in Session s.SetCollection(collectionName) - s.SetFieldsCollectionName(ctx, idCollection, s.collection) + s.SetFieldsCollectionName(ctx, idCollection) // 2-Get boolean if field exist and must exist in collection existField := s.ExistFieldCollection(fieldSearched) @@ -177,7 +177,7 @@ func (s *Session) CreateDocumentscollectionNameStep( s.SetCollection(collectionName) // 2-The documents to be inserted are created - allDocuments := s.CreateDocumentsCollection(ctx, num, collectionName) + allDocuments := s.CreateDocumentsCollection(ctx, num) // 3-Insert the documents into the "collectionName" collection of the database _, err := s.collection.InsertMany(context.TODO(), allDocuments) @@ -206,9 +206,7 @@ func (s *Session) DeleteDocumentscollectionNameStep( } // CheckNumberDocumentscollectionNameStep verify the number of documents in collection -func (s *Session) CheckNumberDocumentscollectionNameStep( - ctx context.Context, collectionName string, num int, - ) error { +func (s *Session) CheckNumberDocumentscollectionNameStep(collectionName string, num int) error { // 1-The collection from which the documents are to be counted is established s.SetCollection(collectionName) @@ -234,7 +232,7 @@ func (s *Session) CheckNumberDocumentscollectionNameStep( // GENERIC FUNCTIONS // ContainsElement check if an item exists in a slice -func ContainsElement(expectedElement interface{}, sliceElements interface{}) bool { +func ContainsElement(expectedElement, sliceElements interface{}) bool { // 1-Create a reflection object from the slice sliceValue := reflect.ValueOf(sliceElements) @@ -305,18 +303,13 @@ func GetOptionsSearchAllFields() *options.FindOneOptions { // VerifyMustExist returns a boolean indicating whether the element should exist func VerifyMustExist(exist string) bool { - if strings.Contains(strings.ToLower(exist), "not") { - return false - } - return true + return !strings.Contains(strings.ToLower(exist), "not") } // SESSION FUNCTIONS // CreateDocumentsCollection creates num documents in a slice and inserts them into a collection -func (s *Session) CreateDocumentsCollection( - ctx context.Context, num int, collectionName string, - ) []interface{} { +func (s *Session) CreateDocumentsCollection(ctx context.Context, num int) []interface{} { // 1-Initialize the document slice allDocuments := []interface{}{} @@ -334,7 +327,7 @@ func (s *Session) CreateDocumentsCollection( // 3-Creating Documents and Inserting Into the Slice for i := 1; i <= num; i++ { // Defines the document to be inserted. - //The _id will be the same across all + _ + iteration number + // The _id will be the same across all + _ + iteration number document := map[string]interface{}{ "_id": id.(string) + "_" + strconv.Itoa(i), "fieldString": "Example field string " + strconv.Itoa(i), @@ -435,14 +428,12 @@ func (s *Session) SetDataCollectionJSONBytes(bsonDoc bson.D) error { } // SetFieldsCollectionName save a slice with the names of the fields in s.fieldsCollectionName -func (s *Session) SetFieldsCollectionName( - ctx context.Context, idCollection string, collectionName *mongo.Collection, - ) error { +func (s *Session) SetFieldsCollectionName(ctx context.Context, idCollection string) error { // Make a query to find past _id's document var document bson.M err := s.collection.FindOne(ctx, GetFilter("_id", idCollection)).Decode(&document) if err == mongo.ErrNoDocuments { - return fmt.Errorf("error: no documents matching the filter were found.") + return fmt.Errorf("error: no documents matching the filter were found") } else if err != nil { return fmt.Errorf("error: '%s'", err) } else { @@ -470,15 +461,14 @@ func (s *Session) VerifyExistID(ctx context.Context, idCollection string) (bool, func (s *Session) VerifyExistAndMustExistValue(exist, mustExist bool, err error) error { // If Exist and should NOT exist or NOT exist and should exist return error // If Exist and shoud exist OR not exist and should not exist return nil - if exist && mustExist || !exist && !mustExist { + if exist == mustExist { return nil - } else { - if err != nil { - return err - } - return fmt.Errorf("error: the value DOES NOT EXIST and SHOULD, or EXIST and SHOULD NOT, "+ - "in '%s' collection", s.collection.Name()) } + if err != nil { + return err + } + return fmt.Errorf("error: the value DOES NOT EXIST and SHOULD, or EXIST and SHOULD NOT, "+ + "in '%s' collection", s.collection.Name()) } // ValidateDataMongo verifies that the feature table data exists in the MongoDB collection @@ -501,7 +491,7 @@ func (s *Session) ValidateDataMongo( } // 4-Set the list of fields in the document to fieldsCollectionName - s.SetFieldsCollectionName(ctx, idCollection, s.collection) + s.SetFieldsCollectionName(ctx, idCollection) if err != nil { return false, err } @@ -515,7 +505,7 @@ func (s *Session) ValidateDataMongo( fieldTableFeature := strings.Split(key, ".")[0] if ContainsElement(fieldTableFeature, s.fieldsCollectionName) { if value == nil && expectedValue == "" { - //The value of the field in MongoDB is null and expectedValue is [EMPTY] + // The value of the field in MongoDB is null and expectedValue is [EMPTY] continue } else if value != expectedValue { return false, fmt.Errorf("error: mismatch of mongo field '%s': expected '%s',"+ @@ -534,7 +524,7 @@ func (s *Session) MongoDisconnection() error { if s.client != nil { err := s.client.Disconnect(context.Background()) if err != nil { - return fmt.Errorf("error: problem in MongoDB disconnection: '%s'\n", err) + return fmt.Errorf("error: problem in MongoDB disconnection: '%s'", err) } } return nil diff --git a/steps/mongo/steps.go b/steps/mongo/steps.go index f069bf3e..e04d9e42 100755 --- a/steps/mongo/steps.go +++ b/steps/mongo/steps.go @@ -52,7 +52,7 @@ func (us Steps) InitializeSteps(ctx context.Context, scenCtx *godog.ScenarioCont return session.DeleteDocumentscollectionNameStep(ctx, golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, field), value) }) scenCtx.Step(`^I check that the number of documents in collection "([^"]*)" is "(\d+)"$`, func(collectionName string, num int) error { - return session.CheckNumberDocumentscollectionNameStep(ctx, golium.ValueAsString(ctx, collectionName), num) + return session.CheckNumberDocumentscollectionNameStep(golium.ValueAsString(ctx, collectionName), num) }) scenCtx.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) { From ba92933535dd08ca61879d314b7cb282f70aa37c Mon Sep 17 00:00:00 2001 From: antoniodiazplaza Date: Mon, 23 Oct 2023 15:58:16 +0200 Subject: [PATCH 07/27] 4727_Golium_MongoDB_Repairs_6 --- steps/mongo/session.go | 42 +++++++++++++++++++++--------------------- steps/mongo/steps.go | 8 ++++---- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/steps/mongo/session.go b/steps/mongo/session.go index a862eb77..8a7263f1 100644 --- a/steps/mongo/session.go +++ b/steps/mongo/session.go @@ -70,7 +70,7 @@ type Session struct { // CheckMongoFieldExistOrEmptyStep check that a field does not exist or it does exist and is empty func (s *Session) CheckMongoFieldExistOrEmptyStep( ctx context.Context, fieldSearched, collectionName, idCollection string, - ) error { +) error { // 1-Setting the Collection Name in the Session s.SetCollection(collectionName) @@ -91,7 +91,7 @@ func (s *Session) CheckMongoFieldExistOrEmptyStep( // CheckMongoFieldNameStep check if the name of the field searched of the user collection is correct func (s *Session) CheckMongoFieldNameStep( ctx context.Context, collectionName, fieldSearched, exist, idCollection string, - ) error { +) error { // 1-Set collection name and fields collection name in Session s.SetCollection(collectionName) s.SetFieldsCollectionName(ctx, idCollection) @@ -107,7 +107,7 @@ func (s *Session) CheckMongoFieldNameStep( // CheckMongoValueIDStep checks if the past idCollection exists in the collection func (s *Session) CheckMongoValueIDStep( ctx context.Context, collectionName, idCollection, exist string, - ) error { +) error { // 1-Set collection name and fields collection name in Session s.SetCollection(collectionName) @@ -122,7 +122,7 @@ func (s *Session) CheckMongoValueIDStep( // CheckMongoValuesStep checks the value of the MongoDB fields in the specified collection func (s *Session) CheckMongoValuesStep( ctx context.Context, collectionName, idCollection, exist string, t *godog.Table, - ) error { +) error { // 1-Set collection name and fields collection name in Session s.SetCollection(collectionName) @@ -140,7 +140,7 @@ func (s *Session) CheckMongoValuesStep( return s.VerifyExistAndMustExistValue(existValue, mustExistValue, err) } -// MongoConnectionStep establishes a connection in MongoDB. +// MongoConnectionStep establishes a connection in MongoDB. // The connection, client and database data are saved in s.clientOptions, s.client, and s.database func (s *Session) MongoConnectionStep(ctx context.Context) error { // 1-Set credentials and host in session @@ -172,7 +172,7 @@ func (s *Session) MongoConnectionStep(ctx context.Context) error { // CreateDocumentcollectionNameStep creates a number of documents in the specified collection func (s *Session) CreateDocumentscollectionNameStep( ctx context.Context, num int, collectionName string, - ) error { +) error { // 1-collection in which the insertion will be made, if it does not exist it is created s.SetCollection(collectionName) @@ -191,7 +191,7 @@ func (s *Session) CreateDocumentscollectionNameStep( // DeleteDocumentscollectionNameStep delete a document from the MongoDB collection func (s *Session) DeleteDocumentscollectionNameStep( ctx context.Context, collectionName, field, value string, - ) error { +) error { // 1-The collection in which the deletion is to be made is established. s.SetCollection(collectionName) @@ -242,7 +242,7 @@ func ContainsElement(expectedElement, sliceElements interface{}) bool { } for i := 0; i < sliceValue.Len(); i++ { - // 3-The slice element converted into an interface is compared with the searched element. + // 3-The slice element converted into an interface is compared with the searched element. // The comparison is made in value and type if reflect.DeepEqual(sliceValue.Index(i).Interface(), expectedElement) { return true @@ -263,10 +263,10 @@ func GetFilter(key string, value interface{}) primitive.M { // GetFilterConverted returns a filter with field and data type required for delete a record func GetFilterConverted(field, value string) primitive.M { /* In Golang: - - the values "1", "true", "t", "T", "TRUE", "True" are interpreted as true - - the values "0", "false", "f", "F", "FALSE", "False" are interpreted as false. - To force only a few values in a cell to be considered Boolean, this slice is created. - */ + - the values "1", "true", "t", "T", "TRUE", "True" are interpreted as true + - the values "0", "false", "f", "F", "FALSE", "False" are interpreted as false. + To force only a few values in a cell to be considered Boolean, this slice is created. + */ boolSlice := []string{"true", "TRUE", "True", "false", "FALSE", "False"} // Try to convert to bool @@ -326,7 +326,7 @@ func (s *Session) CreateDocumentsCollection(ctx context.Context, num int) []inte } // 3-Creating Documents and Inserting Into the Slice for i := 1; i <= num; i++ { - // Defines the document to be inserted. + // Defines the document to be inserted. // The _id will be the same across all + _ + iteration number document := map[string]interface{}{ "_id": id.(string) + "_" + strconv.Itoa(i), @@ -380,17 +380,17 @@ func (s *Session) SetDatabase(ctx context.Context) { // SetSingleResult set a Single Result from a Filter Search (GetFilter(...) function) func (s *Session) SetSingleResult( ctx context.Context, fieldSearched string, value interface{}, - ) error { +) error { s.singleResult = s.collection.FindOne( ctx, GetFilter(fieldSearched, value), GetOptionsSearchAllFields()) if s.singleResult.Err() != nil { return fmt.Errorf("error: the searched '%s' field does not have the '%s' value "+ - "in the '%s' collection", fieldSearched, value, s.collection.Name()) + "in the '%s' collection", fieldSearched, value, s.collection.Name()) } return nil } -// SetCollection sets the collection. If the collection does not exist, no error is returned. +// SetCollection sets the collection. If the collection does not exist, no error is returned. // Collections are created dynamically when you insert a document func (s *Session) SetCollection(collectionName string) { s.collection = s.client.Database(s.database).Collection(collectionName) @@ -452,7 +452,7 @@ func (s *Session) VerifyExistID(ctx context.Context, idCollection string) (bool, err := s.SetSingleResult(ctx, "_id", idCollection) if err != nil { return false, fmt.Errorf("error: searched _id '%s' does not exist in the '%s' collection", - idCollection, s.collection.Name()) + idCollection, s.collection.Name()) } return true, nil } @@ -468,13 +468,13 @@ func (s *Session) VerifyExistAndMustExistValue(exist, mustExist bool, err error) return err } return fmt.Errorf("error: the value DOES NOT EXIST and SHOULD, or EXIST and SHOULD NOT, "+ - "in '%s' collection", s.collection.Name()) + "in '%s' collection", s.collection.Name()) } // ValidateDataMongo verifies that the feature table data exists in the MongoDB collection func (s *Session) ValidateDataMongo( ctx context.Context, idCollection string, props map[string]interface{}, - ) (bool, error) { +) (bool, error) { // 1-Sets a document to s.singleResult from a filter search s.SetSingleResult(ctx, "_id", idCollection) @@ -509,11 +509,11 @@ func (s *Session) ValidateDataMongo( continue } else if value != expectedValue { return false, fmt.Errorf("error: mismatch of mongo field '%s': expected '%s',"+ - "actual '%s'", key, expectedValue, value) + "actual '%s'", key, expectedValue, value) } } else { return false, fmt.Errorf("error: the field '%s': does not exist in '%s' collection", - key, s.collection.Name()) + key, s.collection.Name()) } } return true, nil diff --git a/steps/mongo/steps.go b/steps/mongo/steps.go index e04d9e42..91ba7486 100755 --- a/steps/mongo/steps.go +++ b/steps/mongo/steps.go @@ -50,14 +50,14 @@ func (us Steps) InitializeSteps(ctx context.Context, scenCtx *godog.ScenarioCont }) scenCtx.Step(`^I delete documents from the MongoDB "([^"]*)" collection whose "([^"]*)" field is "([^"]*)" value$`, func(collectionName string, field string, value string) error { return session.DeleteDocumentscollectionNameStep(ctx, golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, field), value) - }) + }) scenCtx.Step(`^I check that the number of documents in collection "([^"]*)" is "(\d+)"$`, func(collectionName string, num int) error { return session.CheckNumberDocumentscollectionNameStep(golium.ValueAsString(ctx, collectionName), num) - }) + }) scenCtx.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) { - return ctx, session.MongoDisconnection() + return ctx, session.MongoDisconnection() }) - + return ctx } From dddc93e585c83db2b0772a477665f035aae52273 Mon Sep 17 00:00:00 2001 From: Mario LG Date: Sat, 28 Oct 2023 14:07:35 +0200 Subject: [PATCH 08/27] feat: add mongo to ci --- docker-compose.yml | 6 ++++++ test/acceptance/environments/ci.yml | 7 +++++++ test/acceptance/environments/local.yml | 7 +++++++ test/acceptance/features/mongo.feature | 11 +++++++++++ 4 files changed, 31 insertions(+) create mode 100644 test/acceptance/features/mongo.feature diff --git a/docker-compose.yml b/docker-compose.yml index 038800a8..1bdc497f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,11 @@ version: "3.4" services: + mongo: + image: mongo:4.4.4 + environment: + MONGO_INITDB_ROOT_USERNAME: mongoadmin + MONGO_INITDB_ROOT_PASSWORD: mongoadmin redis: image: redis:alpine rabbit: @@ -30,6 +35,7 @@ services: AWS_SECRET_ACCESS_KEY: minioadmin AWS_REGION: eu-west-1 depends_on: + - mongo - redis - rabbit - elasticsearch diff --git a/test/acceptance/environments/ci.yml b/test/acceptance/environments/ci.yml index 7d7ab1f6..aea889a2 100755 --- a/test/acceptance/environments/ci.yml +++ b/test/acceptance/environments/ci.yml @@ -117,9 +117,16 @@ elasticsearch: addresses: - http://localhost:9200 +# MongoDB settings +mongoHost: mongo:27017 +mongoUsername: mongoadmin +mongoPassword: mongoadmin +mongoDatabase: golium-demo + # Redis redis: endpoint: localhost:6379 + # s3 s3Autoclean: true s3Bucket: golium-demo diff --git a/test/acceptance/environments/local.yml b/test/acceptance/environments/local.yml index 6f222fa4..94d51f1b 100755 --- a/test/acceptance/environments/local.yml +++ b/test/acceptance/environments/local.yml @@ -121,9 +121,16 @@ elasticsearch: addresses: - http://elasticsearch:9200 +# MongoDB settings +mongoHost: mongo:27017 +mongoUsername: mongoadmin +mongoPassword: mongoadmin +mongoDatabase: golium-demo + # Redis redis: endpoint: redis:6379 + # s3 s3Autoclean: true s3Bucket: golium-demo diff --git a/test/acceptance/features/mongo.feature b/test/acceptance/features/mongo.feature new file mode 100644 index 00000000..a14730f8 --- /dev/null +++ b/test/acceptance/features/mongo.feature @@ -0,0 +1,11 @@ +Feature: MongoDB client + + @mongodb + Scenario: Create a collection, check it and delete it. + Given I connect to MongoDB + When I create "2" documents in the MongoDB "test-colection" collection + Then I check that the number of documents in collection "test-colection" is "2" + When I delete documents from the MongoDB "test-colection" collection whose "fieldstring" field is "Example field string 1" value + Then I check that the number of documents in collection "test-colection" is "1" + When I delete documents from the MongoDB "test-colection" collection whose "fieldstring" field is "Example field string 2" value + Then I check that the number of documents in collection "test-colection" is "0" From 7a960e645a6a937a2c5314b76bb2848ee485bc66 Mon Sep 17 00:00:00 2001 From: Mario LG Date: Sat, 28 Oct 2023 14:16:06 +0200 Subject: [PATCH 09/27] feat: initialize scenario with mongo steps --- test/acceptance/golium_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/acceptance/golium_test.go b/test/acceptance/golium_test.go index 91f575ef..83ee4de1 100755 --- a/test/acceptance/golium_test.go +++ b/test/acceptance/golium_test.go @@ -26,6 +26,7 @@ import ( "github.com/TelefonicaTC2Tech/golium/steps/elasticsearch" "github.com/TelefonicaTC2Tech/golium/steps/http" "github.com/TelefonicaTC2Tech/golium/steps/jwt" + "github.com/TelefonicaTC2Tech/golium/steps/mongo" "github.com/TelefonicaTC2Tech/golium/steps/rabbit" "github.com/TelefonicaTC2Tech/golium/steps/redis" @@ -56,6 +57,7 @@ func InitializeScenario(ctx context.Context, scenarioCtx *godog.ScenarioContext) common.Steps{}, jwt.Steps{}, dns.Steps{}, + mongo.Steps{}, redis.Steps{}, rabbit.Steps{}, mockhttp.Steps{}, From 0c66a53dfaf20f73118ad61777b8a946e5336743 Mon Sep 17 00:00:00 2001 From: Mario LG Date: Sat, 28 Oct 2023 14:25:56 +0200 Subject: [PATCH 10/27] feat: add mongo checks --- .github/workflows/ci.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b920e678..000f5cd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,6 +24,16 @@ jobs: ENVIRONMENT: ci services: + mongo: + image: mongo + options: >- + --health-cmd "echo 'db.stats().ok' | mongo localhost:27017/hodor --quiet" + --health-interval 10s + --health-timeout 10s + --health-retries 10 + ports: + - 27017:27017 + redis: image: redis options: >- From 54c80db9ea7bc2e92c1e99a47acb750f9a0eba69 Mon Sep 17 00:00:00 2001 From: Mario LG Date: Sat, 28 Oct 2023 14:31:09 +0200 Subject: [PATCH 11/27] feat: fix mongo connection string --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 000f5cd0..5f8d11d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: mongo: image: mongo options: >- - --health-cmd "echo 'db.stats().ok' | mongo localhost:27017/hodor --quiet" + --health-cmd "echo 'db.stats().ok' | mongo localhost:27017/mongoadmin --quiet" --health-interval 10s --health-timeout 10s --health-retries 10 From dee1c8fa43fb06bd1bfd3b210af843bf115d65bf Mon Sep 17 00:00:00 2001 From: Mario LG Date: Sat, 28 Oct 2023 14:42:48 +0200 Subject: [PATCH 12/27] feat: fix mongo environment for ci --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f8d11d4..50e08205 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,10 @@ jobs: services: mongo: - image: mongo + image: mongo:4.4.4 + env: + MONGO_INITDB_ROOT_USERNAME: mongoadmin + MONGO_INITDB_ROOT_PASSWORD: mongoadmin options: >- --health-cmd "echo 'db.stats().ok' | mongo localhost:27017/mongoadmin --quiet" --health-interval 10s From f10ef17532ea796aeb8a27b1423843ab592fbe90 Mon Sep 17 00:00:00 2001 From: Mario LG Date: Sat, 28 Oct 2023 15:23:02 +0200 Subject: [PATCH 13/27] feat: fix mongo connection --- test/acceptance/environments/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/acceptance/environments/ci.yml b/test/acceptance/environments/ci.yml index aea889a2..92272c53 100755 --- a/test/acceptance/environments/ci.yml +++ b/test/acceptance/environments/ci.yml @@ -118,7 +118,7 @@ elasticsearch: - http://localhost:9200 # MongoDB settings -mongoHost: mongo:27017 +mongoHost: localhost:27017 mongoUsername: mongoadmin mongoPassword: mongoadmin mongoDatabase: golium-demo @@ -126,7 +126,7 @@ mongoDatabase: golium-demo # Redis redis: endpoint: localhost:6379 - + # s3 s3Autoclean: true s3Bucket: golium-demo From 52ca2a154a2538efbdecf3a44915f0e0c9ca1910 Mon Sep 17 00:00:00 2001 From: ruben-garciad Date: Tue, 31 Oct 2023 11:34:32 +0100 Subject: [PATCH 14/27] feat: fix mongodb config and test scenario --- test/acceptance/environments/ci.yml | 5 +++-- test/acceptance/environments/local.yml | 7 ++++--- test/acceptance/features/mongo.feature | 12 ++++++------ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/test/acceptance/environments/ci.yml b/test/acceptance/environments/ci.yml index 92272c53..a3567e8f 100755 --- a/test/acceptance/environments/ci.yml +++ b/test/acceptance/environments/ci.yml @@ -12,14 +12,14 @@ endpoints: posts: api-endpoint: posts/ api-key: "valid_apiKey" - files-path: "./test_data" + files-path: "./test_data" users: api-endpoint: users/ api-key: "valid_apiKey" bin-empty: api-endpoint: "" api-key: "" - files-path: "./test_data" + files-path: "./test_data" # DNS settings dns: dns.google:53 @@ -121,6 +121,7 @@ elasticsearch: mongoHost: localhost:27017 mongoUsername: mongoadmin mongoPassword: mongoadmin +mongoAuthSource: admin mongoDatabase: golium-demo # Redis diff --git a/test/acceptance/environments/local.yml b/test/acceptance/environments/local.yml index 94d51f1b..6c0de295 100755 --- a/test/acceptance/environments/local.yml +++ b/test/acceptance/environments/local.yml @@ -12,14 +12,14 @@ endpoints: posts: api-endpoint: posts/ api-key: "valid_apiKey" - files-path: "./test_data" + files-path: "./test_data" users: api-endpoint: users/ api-key: "valid_apiKey" bin-empty: api-endpoint: "" api-key: "" - files-path: "./test_data" + files-path: "./test_data" # DNS settings dns: dns.google:53 @@ -125,12 +125,13 @@ elasticsearch: mongoHost: mongo:27017 mongoUsername: mongoadmin mongoPassword: mongoadmin +mongoAuthSource: admin mongoDatabase: golium-demo # Redis redis: endpoint: redis:6379 - + # s3 s3Autoclean: true s3Bucket: golium-demo diff --git a/test/acceptance/features/mongo.feature b/test/acceptance/features/mongo.feature index a14730f8..a16ba2f2 100644 --- a/test/acceptance/features/mongo.feature +++ b/test/acceptance/features/mongo.feature @@ -3,9 +3,9 @@ Feature: MongoDB client @mongodb Scenario: Create a collection, check it and delete it. Given I connect to MongoDB - When I create "2" documents in the MongoDB "test-colection" collection - Then I check that the number of documents in collection "test-colection" is "2" - When I delete documents from the MongoDB "test-colection" collection whose "fieldstring" field is "Example field string 1" value - Then I check that the number of documents in collection "test-colection" is "1" - When I delete documents from the MongoDB "test-colection" collection whose "fieldstring" field is "Example field string 2" value - Then I check that the number of documents in collection "test-colection" is "0" + When I create "2" documents in the MongoDB "test-colection" collection + Then I check that the number of documents in collection "test-colection" is "2" + When I delete documents from the MongoDB "test-colection" collection whose "fieldString" field is "Example field string 1" value + Then I check that the number of documents in collection "test-colection" is "1" + When I delete documents from the MongoDB "test-colection" collection whose "fieldString" field is "Example field string 2" value + Then I check that the number of documents in collection "test-colection" is "0" From 8fd2e2219bf954875f25782ab7d6262bf685954a Mon Sep 17 00:00:00 2001 From: ruben-garciad Date: Thu, 2 Nov 2023 11:14:02 +0100 Subject: [PATCH 15/27] feat: fix use of hard-coded credentials --- test/acceptance/environments/ci.yml | 4 +- test/acceptance/environments/local.yml | 4 +- test/acceptance/features/rabbit.feature | 210 ++++++++++++------------ 3 files changed, 111 insertions(+), 107 deletions(-) diff --git a/test/acceptance/environments/ci.yml b/test/acceptance/environments/ci.yml index a3567e8f..d1b4ee40 100755 --- a/test/acceptance/environments/ci.yml +++ b/test/acceptance/environments/ci.yml @@ -28,7 +28,9 @@ dot: tls://dns.google:853 timeout: 2000 # RabbitMQ settings -rabbitmq: amqp://guest:guest@localhost:5672/ +rabbitmqSchema: amqp:// +rabbitmqCredentials: guest:guest +rabbitmqHost: "@localhost:5672/" # JWT settings signSymmetricKey: sign_symmetric_key_that_is_long_enough_for_algorithm_HS512_(with_more_than 256 bits!) diff --git a/test/acceptance/environments/local.yml b/test/acceptance/environments/local.yml index 6c0de295..4dd08824 100755 --- a/test/acceptance/environments/local.yml +++ b/test/acceptance/environments/local.yml @@ -28,7 +28,9 @@ dot: tls://dns.google:853 timeout: 2000 # RabbitMQ settings -rabbitmq: amqp://guest:guest@rabbit:5672/ +rabbitmqSchema: amqp:// +rabbitmqCredentials: guest:guest +rabbitmqHost: "@rabbit:5672/" # JWT settings signSymmetricKey: sign_symmetric_key_that_is_long_enough_for_algorithm_HS512_(with_more_than 256 bits!) diff --git a/test/acceptance/features/rabbit.feature b/test/acceptance/features/rabbit.feature index f70bf27d..c8183d3f 100755 --- a/test/acceptance/features/rabbit.feature +++ b/test/acceptance/features/rabbit.feature @@ -2,139 +2,139 @@ Feature: Rabbit client @rabbit Scenario: Publish and subscribe a text message - Given the rabbit endpoint "[CONF:rabbitmq]" - And I subscribe to the rabbit topic "test-rabbit-text-properties-topic" - When I publish a message to the rabbit topic "test-rabbit-text-properties-topic" with the text + Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + And I subscribe to the rabbit topic "test-rabbit-text-properties-topic" + When I publish a message to the rabbit topic "test-rabbit-text-properties-topic" with the text """ This is a test message """ - Then I wait up to "3" seconds for a rabbit message with the text + Then I wait up to "3" seconds for a rabbit message with the text """ This is a test message """ @rabbit Scenario: Publish and subscribe a JSON message - Given the rabbit endpoint "[CONF:rabbitmq]" - And I subscribe to the rabbit topic "test-rabbit-json-properties-topic" - And I set standard rabbit properties - | param | value | - | ContentType | application/json | - | CorrelationId | [CTXT:CorrelationId] | - When I publish a message to the rabbit topic "test-rabbit-json-properties-topic" with the JSON properties - | param | value | - | id | abc | - | name | Golium | - Then I wait up to "3" seconds for a rabbit message with the JSON properties - | param | value | - | id | abc | - | name | Golium | + Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + And I subscribe to the rabbit topic "test-rabbit-json-properties-topic" + And I set standard rabbit properties + | param | value | + | ContentType | application/json | + | CorrelationId | [CTXT:CorrelationId] | + When I publish a message to the rabbit topic "test-rabbit-json-properties-topic" with the JSON properties + | param | value | + | id | abc | + | name | Golium | + Then I wait up to "3" seconds for a rabbit message with the JSON properties + | param | value | + | id | abc | + | name | Golium | @rabbit Scenario: Publish and subscribe a JSON message. Use standard properties Given I generate a UUID and store it in context "CorrelationId" - Given the rabbit endpoint "[CONF:rabbitmq]" - And I subscribe to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" - And I set standard rabbit properties - | param | value | - | ContentType | application/json | - | CorrelationId | [CTXT:CorrelationId] | - When I publish a message to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" with the JSON properties - | param | value | - | id | abc | - | name | Golium | - Then I wait up to "3" seconds for a rabbit message with the standard properties - | param | value | - | ContentType | application/json | - | CorrelationId | [CTXT:CorrelationId] | - And the rabbit message body has the JSON properties - | param | value | - | id | abc | - | name | Golium | + Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + And I subscribe to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" + And I set standard rabbit properties + | param | value | + | ContentType | application/json | + | CorrelationId | [CTXT:CorrelationId] | + When I publish a message to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" with the JSON properties + | param | value | + | id | abc | + | name | Golium | + Then I wait up to "3" seconds for a rabbit message with the standard properties + | param | value | + | ContentType | application/json | + | CorrelationId | [CTXT:CorrelationId] | + And the rabbit message body has the JSON properties + | param | value | + | id | abc | + | name | Golium | @rabbit Scenario: Publish and subscribe three JSON messages. Use standard properties Given I generate a UUID and store it in context "CorrelationId" - Given the rabbit endpoint "[CONF:rabbitmq]" - And I subscribe to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" - And I set standard rabbit properties - | param | value | - | ContentType | application/json | - | CorrelationId | [CTXT:CorrelationId] | - When I publish a message to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" with the JSON properties - | param | value | - | id0 | abc0 | - | name0 | Golium0 | - When I publish a message to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" with the JSON properties - | param | value | - | id1 | abc1 | - | name1 | Golium1 | - When I publish a message to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" with the JSON properties - | param | value | - | id2 | abc2 | - | name2 | Golium2 | - Then I wait up to "5" seconds for exactly "3" rabbit messages with the standard properties - | param | value | - | ContentType | application/json | - | CorrelationId | [CTXT:CorrelationId] | - And the body of the rabbit message in position "0" has the JSON properties - | param | value | - | id0 | abc0 | - | name0 | Golium0 | - And the body of the rabbit message in position "1" has the JSON properties - | param | value | - | id1 | abc1 | - | name1 | Golium1 | - And the body of the rabbit message in position "2" has the JSON properties - | param | value | - | id2 | abc2 | - | name2 | Golium2 | + Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + And I subscribe to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" + And I set standard rabbit properties + | param | value | + | ContentType | application/json | + | CorrelationId | [CTXT:CorrelationId] | + When I publish a message to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" with the JSON properties + | param | value | + | id0 | abc0 | + | name0 | Golium0 | + When I publish a message to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" with the JSON properties + | param | value | + | id1 | abc1 | + | name1 | Golium1 | + When I publish a message to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" with the JSON properties + | param | value | + | id2 | abc2 | + | name2 | Golium2 | + Then I wait up to "5" seconds for exactly "3" rabbit messages with the standard properties + | param | value | + | ContentType | application/json | + | CorrelationId | [CTXT:CorrelationId] | + And the body of the rabbit message in position "0" has the JSON properties + | param | value | + | id0 | abc0 | + | name0 | Golium0 | + And the body of the rabbit message in position "1" has the JSON properties + | param | value | + | id1 | abc1 | + | name1 | Golium1 | + And the body of the rabbit message in position "2" has the JSON properties + | param | value | + | id2 | abc2 | + | name2 | Golium2 | @rabbit Scenario: Publish and subscribe a JSON message with rabbit headers and standard properties - Given the rabbit endpoint "[CONF:rabbitmq]" - And I subscribe to the rabbit topic "test-rabbit-headers-properties-topic" - And I set rabbit headers - | param | value | - | Header1 | value1 | - | Header2 | value2 | - When I publish a message to the rabbit topic "test-rabbit-headers-properties-topic" with the JSON properties - | param | value | - | id | abc | - | name | Golium | - Then I wait up to "3" seconds for a rabbit message with the JSON properties - | param | value | - | id | abc | - | name | Golium | - And the rabbit message has the rabbit headers - | param | value | - | Header1 | value1 | - | Header2 | value2 | + Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + And I subscribe to the rabbit topic "test-rabbit-headers-properties-topic" + And I set rabbit headers + | param | value | + | Header1 | value1 | + | Header2 | value2 | + When I publish a message to the rabbit topic "test-rabbit-headers-properties-topic" with the JSON properties + | param | value | + | id | abc | + | name | Golium | + Then I wait up to "3" seconds for a rabbit message with the JSON properties + | param | value | + | id | abc | + | name | Golium | + And the rabbit message has the rabbit headers + | param | value | + | Header1 | value1 | + | Header2 | value2 | @rabbit Scenario: Publish and subscribe a text message with rabbit headers - Given the rabbit endpoint "[CONF:rabbitmq]" - And I subscribe to the rabbit topic "test-rabbit-headers-topic" - And I set rabbit headers - | param | value | - | Header1 | value1 | - | Header2 | value2 | - When I publish a message to the rabbit topic "test-rabbit-headers-topic" with the text + Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + And I subscribe to the rabbit topic "test-rabbit-headers-topic" + And I set rabbit headers + | param | value | + | Header1 | value1 | + | Header2 | value2 | + When I publish a message to the rabbit topic "test-rabbit-headers-topic" with the text """ """ - Then I wait up to "3" seconds for a rabbit message with the text + Then I wait up to "3" seconds for a rabbit message with the text """ """ - And the rabbit message has the rabbit headers - | param | value | - | Header1 | value1 | - | Header2 | value2 | + And the rabbit message has the rabbit headers + | param | value | + | Header1 | value1 | + | Header2 | value2 | @rabbit Scenario: Subscribe and waits for no message Given I generate a UUID and store it in context "CorrelationId" - Given the rabbit endpoint "[CONF:rabbitmq]" - When I subscribe to the rabbit topic "test-rabbit-empty-topic" - Then I wait up to "3" seconds without a rabbit message with the standard properties - | param | value | - | CorrelationId | [CTXT:CorrelationId] | + Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + When I subscribe to the rabbit topic "test-rabbit-empty-topic" + Then I wait up to "3" seconds without a rabbit message with the standard properties + | param | value | + | CorrelationId | [CTXT:CorrelationId] | From 2aab838d49ffedcfbba15f76d82fe2c8f450a1d9 Mon Sep 17 00:00:00 2001 From: ruben-garciad Date: Thu, 2 Nov 2023 14:41:13 +0100 Subject: [PATCH 16/27] feat: change config variables --- test/acceptance/environments/ci.yml | 7 ++++--- test/acceptance/environments/local.yml | 7 ++++--- test/acceptance/features/rabbit.feature | 14 +++++++------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/test/acceptance/environments/ci.yml b/test/acceptance/environments/ci.yml index d1b4ee40..b5e29c75 100755 --- a/test/acceptance/environments/ci.yml +++ b/test/acceptance/environments/ci.yml @@ -28,9 +28,10 @@ dot: tls://dns.google:853 timeout: 2000 # RabbitMQ settings -rabbitmqSchema: amqp:// -rabbitmqCredentials: guest:guest -rabbitmqHost: "@localhost:5672/" +rabbitmq: + schema: amqp:// + credentials: guest:guest + host: "@localhost:5672/" # JWT settings signSymmetricKey: sign_symmetric_key_that_is_long_enough_for_algorithm_HS512_(with_more_than 256 bits!) diff --git a/test/acceptance/environments/local.yml b/test/acceptance/environments/local.yml index 4dd08824..167ad383 100755 --- a/test/acceptance/environments/local.yml +++ b/test/acceptance/environments/local.yml @@ -28,9 +28,10 @@ dot: tls://dns.google:853 timeout: 2000 # RabbitMQ settings -rabbitmqSchema: amqp:// -rabbitmqCredentials: guest:guest -rabbitmqHost: "@rabbit:5672/" +rabbitmq: + schema: amqp:// + credentials: guest:guest + host: "@rabbit:5672/" # JWT settings signSymmetricKey: sign_symmetric_key_that_is_long_enough_for_algorithm_HS512_(with_more_than 256 bits!) diff --git a/test/acceptance/features/rabbit.feature b/test/acceptance/features/rabbit.feature index c8183d3f..82df7891 100755 --- a/test/acceptance/features/rabbit.feature +++ b/test/acceptance/features/rabbit.feature @@ -2,7 +2,7 @@ Feature: Rabbit client @rabbit Scenario: Publish and subscribe a text message - Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + Given the rabbit endpoint "[CONF:rabbitmq.schema][CONF:rabbitmq.credentials][CONF:rabbitmq.host]" And I subscribe to the rabbit topic "test-rabbit-text-properties-topic" When I publish a message to the rabbit topic "test-rabbit-text-properties-topic" with the text """ @@ -15,7 +15,7 @@ Feature: Rabbit client @rabbit Scenario: Publish and subscribe a JSON message - Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + Given the rabbit endpoint "[CONF:rabbitmq.schema][CONF:rabbitmq.credentials][CONF:rabbitmq.host]" And I subscribe to the rabbit topic "test-rabbit-json-properties-topic" And I set standard rabbit properties | param | value | @@ -33,7 +33,7 @@ Feature: Rabbit client @rabbit Scenario: Publish and subscribe a JSON message. Use standard properties Given I generate a UUID and store it in context "CorrelationId" - Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + Given the rabbit endpoint "[CONF:rabbitmq.schema][CONF:rabbitmq.credentials][CONF:rabbitmq.host]" And I subscribe to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" And I set standard rabbit properties | param | value | @@ -55,7 +55,7 @@ Feature: Rabbit client @rabbit Scenario: Publish and subscribe three JSON messages. Use standard properties Given I generate a UUID and store it in context "CorrelationId" - Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + Given the rabbit endpoint "[CONF:rabbitmq.schema][CONF:rabbitmq.credentials][CONF:rabbitmq.host]" And I subscribe to the rabbit topic "test-rabbit-json-properties-[CTXT:CorrelationId]" And I set standard rabbit properties | param | value | @@ -92,7 +92,7 @@ Feature: Rabbit client @rabbit Scenario: Publish and subscribe a JSON message with rabbit headers and standard properties - Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + Given the rabbit endpoint "[CONF:rabbitmq.schema][CONF:rabbitmq.credentials][CONF:rabbitmq.host]" And I subscribe to the rabbit topic "test-rabbit-headers-properties-topic" And I set rabbit headers | param | value | @@ -113,7 +113,7 @@ Feature: Rabbit client @rabbit Scenario: Publish and subscribe a text message with rabbit headers - Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + Given the rabbit endpoint "[CONF:rabbitmq.schema][CONF:rabbitmq.credentials][CONF:rabbitmq.host]" And I subscribe to the rabbit topic "test-rabbit-headers-topic" And I set rabbit headers | param | value | @@ -133,7 +133,7 @@ Feature: Rabbit client @rabbit Scenario: Subscribe and waits for no message Given I generate a UUID and store it in context "CorrelationId" - Given the rabbit endpoint "[CONF:rabbitmqSchema][CONF:rabbitmqCredentials][CONF:rabbitmqHost]" + Given the rabbit endpoint "[CONF:rabbitmq.schema][CONF:rabbitmq.credentials][CONF:rabbitmq.host]" When I subscribe to the rabbit topic "test-rabbit-empty-topic" Then I wait up to "3" seconds without a rabbit message with the standard properties | param | value | From a103e1c9b9b082b2249e5a76e53c5b2db2b6d668 Mon Sep 17 00:00:00 2001 From: antoniodiazplaza Date: Fri, 10 Nov 2023 10:31:00 +0100 Subject: [PATCH 17/27] feat: Subida tests unitarios, pendientes de usar un mock valido --- steps/mongo/client.go | 15 +- steps/mongo/session.go | 273 ++++---- steps/mongo/session_test.go | 840 +++++++++++++++++++++++++ steps/mongo/steps.go | 27 +- test/acceptance/features/mongo.feature | 149 +++++ 5 files changed, 1145 insertions(+), 159 deletions(-) create mode 100644 steps/mongo/session_test.go diff --git a/steps/mongo/client.go b/steps/mongo/client.go index 513658e1..4c505502 100644 --- a/steps/mongo/client.go +++ b/steps/mongo/client.go @@ -14,22 +14,9 @@ package mongo -import ( - "context" - - "go.mongodb.org/mongo-driver/mongo" -) - -type ClientFunctions interface { - Ping(client *mongo.Client) error -} +type ClientFunctions interface{} type ClientService struct{} func NewMongoClientService() *ClientService { return &ClientService{} } - -// Ping check that there is a connection to MongoDB -func (c ClientService) Ping(client *mongo.Client) error { - return client.Ping(context.Background(), nil) -} diff --git a/steps/mongo/session.go b/steps/mongo/session.go index 8a7263f1..cfbac140 100644 --- a/steps/mongo/session.go +++ b/steps/mongo/session.go @@ -34,13 +34,7 @@ import ( // Session contains the information of a MongoDB session. type Session struct { - // Save MongoDB login credentials: username, password, and AuthSource - credentials options.Credential - - // Saves the host from accessing MongoDB - host string - - // Save the MongoDB database + // Set the MongoDB database database string // Set the host and credentials for the connection @@ -52,10 +46,13 @@ type Session struct { // Points to a record in a collection singleResult *mongo.SingleResult + // Saves the _id collection to be used + idCollection string + // Saves the collection to be used collection *mongo.Collection - // Save the name of the collectionName fields + // Save the names of the collection fields fieldsCollectionName []string // Save collection items as JSON @@ -67,9 +64,9 @@ type Session struct { // FUNCTIONS CALLED BY STEPS -// CheckMongoFieldExistOrEmptyStep check that a field does not exist or it does exist and is empty -func (s *Session) CheckMongoFieldExistOrEmptyStep( - ctx context.Context, fieldSearched, collectionName, idCollection string, +// CheckMongoFieldDoesNotExistOrEmptyStep check that a field does not exist or it does exist and is empty +func (s *Session) CheckMongoFieldDoesNotExistOrEmptyStep( + ctx context.Context, collectionName, fieldSearched, idCollection string, ) error { // 1-Setting the Collection Name in the Session s.SetCollection(collectionName) @@ -140,39 +137,33 @@ func (s *Session) CheckMongoValuesStep( return s.VerifyExistAndMustExistValue(existValue, mustExistValue, err) } -// MongoConnectionStep establishes a connection in MongoDB. -// The connection, client and database data are saved in s.clientOptions, s.client, and s.database -func (s *Session) MongoConnectionStep(ctx context.Context) error { - // 1-Set credentials and host in session - s.SetCredentials(ctx) - s.SetHost(ctx) - - // 2-Set clientOptions in session - s.clientOptions = options.Client().SetHosts(strings.Split(s.host, ",")).SetAuth(s.credentials) +// CheckNumberDocumentscollectionNameStep verify the number of documents in collection +func (s *Session) CheckNumberDocumentscollectionNameStep(collectionName string, num int) error { + // 1-The collection from which the documents are to be counted is established + s.SetCollection(collectionName) - // 3-Connect to the MongoDB server and set client in session - var err error - s.client, err = mongo.Connect(context.Background(), s.clientOptions) + // 2-Make a query to get all the documents in the collection + cursor, err := s.collection.Find(context.Background(), bson.D{}) if err != nil { - return fmt.Errorf("error: problems with the client options or with the context. '%s'", err) + return fmt.Errorf("error: query error: '%s'", err) } - // 4-Check the connection to the MongoDB server - err = s.MongoClientService.Ping(s.client) - if err != nil { - return fmt.Errorf("error: problems with connection to MongoDB. '%s'", err) + // 3-Iterate through the documents and count the ones that are there + count := 0 + for cursor.Next(context.Background()) { + count++ } - // 5-Set the database in session - s.SetDatabase(ctx) - + // 4-Check the result + if count != num { + return fmt.Errorf("error: the number of documents is '%d' and should be '%d'", count, num) + } return nil } // CreateDocumentcollectionNameStep creates a number of documents in the specified collection func (s *Session) CreateDocumentscollectionNameStep( - ctx context.Context, num int, collectionName string, -) error { + ctx context.Context, num int, collectionName string) error { // 1-collection in which the insertion will be made, if it does not exist it is created s.SetCollection(collectionName) @@ -188,10 +179,24 @@ func (s *Session) CreateDocumentscollectionNameStep( return nil } +// DeleteDocumentscollectionNameStep delete a document from the MongoDB collection +func (s *Session) DeleteAllDocumentscollectionNameStep(ctx context.Context, collectionName string, + ) error { + // 1-The collection in which the deletion is to be made is established. + s.SetCollection(collectionName) + + // 2-Delete all documents + _, err := s.collection.DeleteMany(ctx, bson.D{}) + if err != nil { + return err + } + + return nil +} + // DeleteDocumentscollectionNameStep delete a document from the MongoDB collection func (s *Session) DeleteDocumentscollectionNameStep( - ctx context.Context, collectionName, field, value string, -) error { + ctx context.Context, collectionName, field, value string) error { // 1-The collection in which the deletion is to be made is established. s.SetCollection(collectionName) @@ -205,34 +210,66 @@ func (s *Session) DeleteDocumentscollectionNameStep( return nil } -// CheckNumberDocumentscollectionNameStep verify the number of documents in collection -func (s *Session) CheckNumberDocumentscollectionNameStep(collectionName string, num int) error { - // 1-The collection from which the documents are to be counted is established - s.SetCollection(collectionName) +// GenerateUUIDStoreIt create uuid in string format like _id and save in struct and context like _ID +func (s *Session) GenerateUUIDStoreItStep(ctx context.Context) error { + guid, err := uuid.NewRandom() + if err != nil { + return fmt.Errorf("failed generating UUID: %w", err) + } + s.idCollection = guid.String() + golium.GetContext(ctx).Put("_ID", s.idCollection) - // 2-Make a query to get all the documents in the collection - cursor, err := s.collection.Find(context.Background(), bson.D{}) + return nil +} + +// MongoConnectionStep establishes a connection in MongoDB. +// The connection, client and database data are saved in s.clientOptions, s.client, and s.database +func (s *Session) MongoConnectionStep(ctx context.Context, t *godog.Table) error { + // 1-Set credentials and host in session + var err error + props, err := golium.ConvertTableToMap(ctx, t) if err != nil { - return fmt.Errorf("error: query error: '%s'", err) + return fmt.Errorf("ERROR: failed processing the table for validating the body: '%w'", err) } + uri := fmt.Sprintf("mongodb://%s:%s@%s/%s", + props["User"], props["Password"], props["Host"], props["AuthSource"]) - // 3-Iterate through the documents and count the ones that are there - count := 0 - for cursor.Next(context.Background()) { - count++ + // 2-Set clientOptions in session + s.clientOptions = options.Client().ApplyURI(uri) + + // 3-Connect to the MongoDB server and set client in session + s.client, err = mongo.Connect(ctx, s.clientOptions) + if err != nil { + return fmt.Errorf("error: problems with the client options or with the context. '%s'", err) } - // 4-Check the result - if count != num { - return fmt.Errorf("error: the number of documents is '%d' and should be '%d'", count, num) + // 4-Check the connection to the MongoDB server + err = s.client.Ping(ctx, nil) + if err != nil { + return fmt.Errorf("error: problems with connection to MongoDB. '%s'", err) + } + + // 5-Set the database in session + s.database = props["Database"].(string) + + return nil +} + +// MongoDisconnection closes the connection to MongoDB if it exists +func (s *Session) MongoDisconnectionStep() error { + if s.client != nil { + err := s.client.Disconnect(context.Background()) + if err != nil { + return fmt.Errorf("error: problem in MongoDB disconnection: '%s'", err) + } } return nil } // GENERIC FUNCTIONS -// ContainsElement check if an item exists in a slice -func ContainsElement(expectedElement, sliceElements interface{}) bool { +// ContainsElements check if an item exists in a slice +func ContainsElements(expectedElement, sliceElements interface{}) bool { // 1-Create a reflection object from the slice sliceValue := reflect.ValueOf(sliceElements) @@ -270,7 +307,7 @@ func GetFilterConverted(field, value string) primitive.M { boolSlice := []string{"true", "TRUE", "True", "false", "FALSE", "False"} // Try to convert to bool - if ContainsElement(value, boolSlice) { + if ContainsElements(value, boolSlice) { convertedValue, err := strconv.ParseBool(value) if err == nil { return bson.M{field: convertedValue} @@ -296,7 +333,7 @@ func GetFilterConverted(field, value string) primitive.M { return bson.M{field: value} } -// GetOptionsSearchAllFields creates an "Options" to search all fields in the collection +// GetOptionsSearchAllFields creates an "options" to search all fields in the collection func GetOptionsSearchAllFields() *options.FindOneOptions { return options.FindOne().SetProjection(bson.M{}) } @@ -313,36 +350,34 @@ func (s *Session) CreateDocumentsCollection(ctx context.Context, num int) []inte // 1-Initialize the document slice allDocuments := []interface{}{} - // 2-Obtaining the _id of the context, if it does not exist it is created - id := golium.GetContext(ctx).Get("_ID") - if id == nil { - var err error - id, err = uuid.NewRandom() + //2-Obtaining the _id of the struct, if it does not exist it is created + id := s.idCollection + if id == "" { + newUUID, err := uuid.NewRandom() if err != nil { return nil } - // Transforming id into an interface - id = id.(uuid.UUID).String() + id = newUUID.String() } // 3-Creating Documents and Inserting Into the Slice for i := 1; i <= num; i++ { // Defines the document to be inserted. // The _id will be the same across all + _ + iteration number document := map[string]interface{}{ - "_id": id.(string) + "_" + strconv.Itoa(i), + "_id": id + "_" + strconv.Itoa(i), "fieldString": "Example field string " + strconv.Itoa(i), "fieldInt": i, "fieldFloat": 3.14, "fieldBool": true, "fieldSlice": []string{"itemSlice_" + strconv.Itoa(i), "itemSlice20", "itemSlice30"}, "fieldEmpty": nil, - "fieldMap": map[string]interface{}{ + "fieldMap": map[string]interface{}{ "fieldString": "Example field in map string " + strconv.Itoa(i), "fieldInt": i * 10, "fieldFloat": 1974.1976, "fieldBool": false, "fieldSliceEmpty": []string{}, - "fieldMap2": map[string]interface{}{ + "fieldMap2": map[string]interface{}{ "fieldString": "Example field in map map string " + strconv.Itoa(i), "fieldInt": i * 100, "fieldFloat": 1974.1976, @@ -357,45 +392,6 @@ func (s *Session) CreateDocumentsCollection(ctx context.Context, num int) []inte return allDocuments } -// SetCredentials set an Options element. Credential with MongoDB access credentials -func (s *Session) SetCredentials(ctx context.Context) { - credentials := options.Credential{ - Username: golium.ValueAsString(ctx, "[CONF:mongoUsername]"), - Password: golium.ValueAsString(ctx, "[CONF:mongoPassword]"), - AuthSource: golium.ValueAsString(ctx, "[CONF:mongoAuthSource]"), - } - s.credentials = credentials -} - -// SetHost set a string with the host -func (s *Session) SetHost(ctx context.Context) { - s.host = golium.ValueAsString(ctx, "[CONF:mongoHost]") -} - -// SetDatabase set a string with the database -func (s *Session) SetDatabase(ctx context.Context) { - s.database = golium.ValueAsString(ctx, "[CONF:mongoDatabase]") -} - -// SetSingleResult set a Single Result from a Filter Search (GetFilter(...) function) -func (s *Session) SetSingleResult( - ctx context.Context, fieldSearched string, value interface{}, -) error { - s.singleResult = s.collection.FindOne( - ctx, GetFilter(fieldSearched, value), GetOptionsSearchAllFields()) - if s.singleResult.Err() != nil { - return fmt.Errorf("error: the searched '%s' field does not have the '%s' value "+ - "in the '%s' collection", fieldSearched, value, s.collection.Name()) - } - return nil -} - -// SetCollection sets the collection. If the collection does not exist, no error is returned. -// Collections are created dynamically when you insert a document -func (s *Session) SetCollection(collectionName string) { - s.collection = s.client.Database(s.database).Collection(collectionName) -} - // ExistFieldCollection evaluate whether or not the searched field exists func (s *Session) ExistFieldCollection(fieldSearched string) bool { existField := false @@ -417,6 +413,12 @@ func (s *Session) GetDecodeDocument(singleResult mongo.SingleResult) (bson.D, er return bsonDoc, nil } +// SetCollection sets the collection. If the collection does not exist, no error is returned. +// Collections are created dynamically when you insert a document +func (s *Session) SetCollection(collectionName string) { + s.collection = s.client.Database(s.database).Collection(collectionName) +} + // SetDataCollectionJSONBytes convert BSON object to JSON func (s *Session) SetDataCollectionJSONBytes(bsonDoc bson.D) error { var err error @@ -443,38 +445,25 @@ func (s *Session) SetFieldsCollectionName(ctx context.Context, idCollection stri s.fieldsCollectionName = append(s.fieldsCollectionName, fieldName) } } - return nil -} -// VerifyExistID returns a boolean indicating whether the _id searched exists in the collection -func (s *Session) VerifyExistID(ctx context.Context, idCollection string) (bool, error) { - // Perform the search and get the result as singleResult - err := s.SetSingleResult(ctx, "_id", idCollection) - if err != nil { - return false, fmt.Errorf("error: searched _id '%s' does not exist in the '%s' collection", - idCollection, s.collection.Name()) - } - return true, nil + return nil } -// VerifyExistAndMustExistValue check if the values exist and should exist -func (s *Session) VerifyExistAndMustExistValue(exist, mustExist bool, err error) error { - // If Exist and should NOT exist or NOT exist and should exist return error - // If Exist and shoud exist OR not exist and should not exist return nil - if exist == mustExist { - return nil - } - if err != nil { - return err +// SetSingleResult set a Single Result from a Filter Search (GetFilter(...) function) +func (s *Session) SetSingleResult( + ctx context.Context, fieldSearched string, value interface{}) error { + s.singleResult = s.collection.FindOne( + ctx, GetFilter(fieldSearched, value), GetOptionsSearchAllFields()) + if s.singleResult.Err() != nil { + return fmt.Errorf("error: the searched '%s' field does not have the '%s' value "+ + "in the '%s' collection", fieldSearched, value, s.collection.Name()) } - return fmt.Errorf("error: the value DOES NOT EXIST and SHOULD, or EXIST and SHOULD NOT, "+ - "in '%s' collection", s.collection.Name()) + return nil } // ValidateDataMongo verifies that the feature table data exists in the MongoDB collection func (s *Session) ValidateDataMongo( - ctx context.Context, idCollection string, props map[string]interface{}, -) (bool, error) { + ctx context.Context, idCollection string, props map[string]interface{}) (bool, error) { // 1-Sets a document to s.singleResult from a filter search s.SetSingleResult(ctx, "_id", idCollection) @@ -503,7 +492,7 @@ func (s *Session) ValidateDataMongo( // Verify that the name of the clean field (fieldTableFeature) exists // in the list of fields in the collection (s.fieldsCollectionName) fieldTableFeature := strings.Split(key, ".")[0] - if ContainsElement(fieldTableFeature, s.fieldsCollectionName) { + if ContainsElements(fieldTableFeature, s.fieldsCollectionName) { if value == nil && expectedValue == "" { // The value of the field in MongoDB is null and expectedValue is [EMPTY] continue @@ -519,13 +508,27 @@ func (s *Session) ValidateDataMongo( return true, nil } -// MongoDisconnection closes the connection to MongoDB if it exists -func (s *Session) MongoDisconnection() error { - if s.client != nil { - err := s.client.Disconnect(context.Background()) - if err != nil { - return fmt.Errorf("error: problem in MongoDB disconnection: '%s'", err) - } +// VerifyExistAndMustExistValue check if the values exist and should exist +func (s *Session) VerifyExistAndMustExistValue(exist, mustExist bool, err error) error { + // If Exist and should NOT exist or NOT exist and should exist return error + // If Exist and shoud exist OR not exist and should not exist return nil + if exist == mustExist { + return nil } - return nil + if err != nil { + return err + } + return fmt.Errorf("error: the value DOES NOT EXIST and SHOULD, or EXIST and SHOULD NOT, "+ + "in the collection") +} + +// VerifyExistID returns a boolean indicating whether the _id searched exists in the collection +func (s *Session) VerifyExistID(ctx context.Context, idCollection string) (bool, error) { + // Perform the search and get the result as singleResult + err := s.SetSingleResult(ctx, "_id", idCollection) + if err != nil { + return false, fmt.Errorf("error: searched _id '%s' does not exist in the '%s' collection", + idCollection, s.collection.Name()) + } + return true, nil } diff --git a/steps/mongo/session_test.go b/steps/mongo/session_test.go new file mode 100644 index 00000000..ea61d19a --- /dev/null +++ b/steps/mongo/session_test.go @@ -0,0 +1,840 @@ +// Copyright 2021 Telefonica Cybersecurity & Cloud Tech SL +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mongo + +import ( + "context" + "errors" + "reflect" + "testing" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + + "github.com/TelefonicaTC2Tech/golium" +) + + +// FUNCTIONS CALLED BY STEPS + +func TestCheckMongoFieldDoesNotExistOrEmptyStep(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check if the field names do not exist or are empty + t.Run("Checking that the 'fieldEmpty' field does not exist or is empty in the MongoDB collection", func(t *testing.T) { + fieldSearched := "fieldEmpty" + err := s.CheckMongoFieldDoesNotExistOrEmptyStep(ctx, collectionName, fieldSearched, s.idCollection+"_1") + if err != nil { + t.Error(err) + } + }) + t.Run("Checking that the 'fieldUnexist' field does not exist in the MongoDB collection", func(t *testing.T) { + fieldSearched := "fieldUnexist" + err := s.CheckMongoFieldDoesNotExistOrEmptyStep(ctx, collectionName, fieldSearched, s.idCollection+"_1") + if err != nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestCheckMongoFieldNameStep(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check whether or not the name of the searched field exists + // If you want to check that it doesn't exist, you have to pass "not" as a parameter + t.Run("Verify that the 'fieldString' field exists in the MongoDB collection", func(t *testing.T) { + fieldSearched := "fieldString" + err := s.CheckMongoFieldNameStep(ctx, collectionName, fieldSearched, "yes", s.idCollection+"_1") + if err != nil { + t.Error(err) + } + }) + t.Run("Verify that the 'fieldEmpty' field exists in the MongoDB collection", func(t *testing.T) { + fieldSearched := "fieldEmpty" + err := s.CheckMongoFieldNameStep(ctx, collectionName, fieldSearched, "does", s.idCollection+"_1") + if err != nil { + t.Error(err) + } + }) + t.Run("Verify that the 'fieldUnexist' field does not exist in the MongoDB collection", func(t *testing.T) { + fieldSearched := "fieldUnexist" + err := s.CheckMongoFieldNameStep(ctx, collectionName, fieldSearched, "not", s.idCollection+"_1") + if err != nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestCheckMongoValueIDStep(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check whether or not the _id sought exists + // If you want to check that it doesn't exist, you have to pass "not" as a parameter + t.Run("Verify that the '_id' exists in the MongoDB collection", func(t *testing.T) { + err := s.CheckMongoValueIDStep(ctx, collectionName, s.idCollection+"_1", "yes") + if err != nil { + t.Error(err) + } + }) + t.Run("Verify that the '_id' does not exist in the MongoDB collection", func(t *testing.T) { + err := s.CheckMongoValueIDStep(ctx, collectionName, "123456_id_unexist", "not") + if err != nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestCheckMongoValuesStep(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check whether or not the values you are looking for exist + // If you want to check that it doesn't exist, you have to pass "not" as a parameter + t.Run("Verify that the searched values exist in the MongoDB collection", func(t *testing.T) { + // Data that will be searched in the collection and that will be found + propTableYes := golium.NewTable([][]string{ + {"field","value"}, + {"_id","[CTXT:_ID]_1"}, + {"fieldString","Example field string 1"}, + {"fieldInt","[NUMBER:1]"}, + {"fieldFloat","[NUMBER:3.14]"}, + {"fieldBool","[TRUE]"}, + {"fieldSlice.#","[NUMBER:3]"}, + {"fieldSlice.0","itemSlice_1"}, + {"fieldSlice.1","itemSlice20"}, + {"fieldSlice.2","itemSlice30"}, + {"fieldEmpty","[EMPTY]"}, + {"fieldMap.fieldString","Example field in map string 1"}, + {"fieldMap.fieldInt","[NUMBER:10]"}, + {"fieldMap.fieldFloat","[NUMBER:1974.1976]"}, + {"fieldMap.fieldBool","[FALSE]"}, + {"fieldMap.fieldSliceEmpty.#","[NUMBER:0]"}, + {"fieldMap.fieldSliceEmpty.0","[NULL]"}, + {"fieldMap.fieldSliceEmpty.1",""}, + {"fieldMap.fieldSliceEmpty.2","[EMPTY]"}, + {"fieldMap.fieldMap2.fieldString","Example field in map map string 1"}, + {"fieldMap.fieldMap2.fieldInt","[NUMBER:100]"}, + {"fieldMap.fieldMap2.fieldFloat","[NUMBER:1974.1976]"}, + {"fieldMap.fieldMap2.fieldBool","[FALSE]"}, + {"fieldMap.fieldMap2.fieldEmpty","[NULL]"}, + {"fieldMap.fieldMap2.fieldEmptyText","[EMPTY]"}, + }) + err := s.CheckMongoValuesStep(ctx, collectionName, s.idCollection+"_1", "yes", propTableYes) + if err != nil { + t.Error(err) + } + }) + t.Run("Verify that the searched values do not exist in the MongoDB collection", func(t *testing.T) { + // Data that will be searched in the collection and will not be found + propTableNot := golium.NewTable([][]string{ + {"field","value"}, + {"_id","123456_id_unexist"}, + }) + err := s.CheckMongoValuesStep(ctx, collectionName, s.idCollection+"_1", "not", propTableNot) + if err != nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestCheckNumberDocumentscollectionNameStep(t *testing.T) { + // 1-Establish a Session instance, context, and MongoDB collection + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + + // 2-Create a connection and create 10 documents from the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 10, collectionName) + + // 3-Count all the documents + t.Run("Contar los documentos de una colección de MongoDB", func(t *testing.T) { + err:= s.CheckNumberDocumentscollectionNameStep(collectionName, 10) + if err != nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestCreateDocumentscollectionNameStep(t *testing.T) { + // 1-Establish a Session instance, context, and MongoDB collection + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + + // 2-Create a connection and delete all documents in the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + err := s.CheckNumberDocumentscollectionNameStep(collectionName, 0) + if err != nil { + t.Error(err) + } + + // 3-Insert a document + err = s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + if err != nil { + t.Error(err) + } + + // 4-Check that it has been inserted and then delete all documents + t.Run("Verify that the document has been inserted into MongoDB", func(t *testing.T) { + err := s.CheckNumberDocumentscollectionNameStep(collectionName, 1) + if err != nil { + t.Error(err) + } + }) + + // 5-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestDeleteAllDocumentscollectionNameStep(t *testing.T) { + // 1-Establish a Session instance, context, and MongoDB collection + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + + // 2-Create a connection and insert 10 documents into the "example" collection + mongoConnection(s, t) + s.CreateDocumentscollectionNameStep(ctx, 10, collectionName) + + // 3-Delete all documents + t.Run("Deleting all documents in a MongoDB collection", func(t *testing.T) { + err := s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + if err != nil { + t.Error(err) + } + }) + + // 4-Verify that all documents have been deleted + err := s.CheckNumberDocumentscollectionNameStep(collectionName, 0) + if err != nil { + t.Error(err) + } +} + +func TestDeleteDocumentscollectionNameStep(t *testing.T) { + // 1-Establish a Session instance, context, and MongoDB collection + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + + // 2-Create a connection and 3 documents from the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 3, collectionName) + + // 3-Delete a document + t.Run("Deleting a document in MongoDB", func(t *testing.T) { + err := s.DeleteDocumentscollectionNameStep(ctx, collectionName, "fieldInt", "1") + if err != nil { + t.Error(err) + } + }) + + // 4-Verify that it has been deleted, delete all documents and close connection + err:= s.CheckNumberDocumentscollectionNameStep(collectionName, 2) + if err != nil { + t.Error(err) + } + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestGenerateUUIDStoreItStep(t *testing.T) { + // 1-Establish a Session instance and context + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + + // 2-Generating a Random UUID + t.Run("Generating a Random UUID", func(t *testing.T) { + if s.GenerateUUIDStoreItStep(ctx) != nil { + t.Errorf("Error generating a random UUID") + } + }) + + // 3-Verifying that a UUID has been created + if len(s.idCollection) != 36 { + t.Errorf("s.idCollection was not created") + } +} + +func mongoConnection(s *Session, t *testing.T) { + propTable := golium.NewTable([][]string{ + {"field", "value"}, + {"User", "mongoadmin"}, + {"Password", "mongoadmin"}, + {"Host", "localhost:27017"}, + {"AuthSource", "admin"}, + {"Database", "golium-demo"}, + }) + t.Run("Connecting to MongoDB", func(t *testing.T) { + err := s.MongoConnectionStep(context.Background(), propTable) + if err != nil { + t.Error(err) + } + }) +} + +func TestMongoConnectionStep(t *testing.T) { + s := &Session{} + mongoConnection(s, t) + s.MongoDisconnectionStep() +} + +func TestMongoDisconnectionStep(t *testing.T) { + // 1-Establish a Session instance, context, and MongoDB collection + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + + // 2-Create a connection and insert 3 collections + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 3, collectionName) + err := s.CheckNumberDocumentscollectionNameStep(collectionName, 3) + if err != nil { + t.Errorf("Error al contar los documentos de la colección '%s'", collectionName) + } + + // 3-Close the connection to MongoDB + t.Run("Close the connection to MongoDB", func(t *testing.T) { + err := s.MongoDisconnectionStep() + if err != nil { + t.Error(err) + } + }) + + // 4-Verify that the connection to MongoDB has been closed + errString := s.CheckNumberDocumentscollectionNameStep(collectionName, 3).Error() + if errString != "error: query error: 'client is disconnected'" { + t.Errorf("Connection to MongoDB is still open") + } +} + + +// GENERIC FUNCTIONS + +func TestContainsElements(t *testing.T) { + t.Run("Element exists in slice", func(t *testing.T) { + slice := []int{1, 2, 3, 4, 5} + element := 3 + result := ContainsElements(element, slice) + if !result { + t.Errorf("Expected %v to be in the slice, but it wasn't.", element) + } + }) + t.Run("Element does not exist in slice", func(t *testing.T) { + slice := []string{"Alcorcon", "Madrid", "Barcelona"} + element := "Valladolid" + result := ContainsElements(element, slice) + if result { + t.Errorf("Expected %v not to be in the slice, but it was.", element) + } + }) +} + +func TestGetFilter(t *testing.T) { + t.Run("Create filter with non-nil value", func(t *testing.T) { + key := "age" + value := 30 + filter := GetFilter(key, value) + expectedFilter := bson.M{"age": 30} + if !reflect.DeepEqual(filter, expectedFilter) { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Create filter with nil value", func(t *testing.T) { + key := "name" + var value interface{} = nil + filter := GetFilter(key, value) + expectedFilter := bson.M{"name": nil} + if !reflect.DeepEqual(filter, expectedFilter) { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) +} + +func TestGetFilterConverted(t *testing.T) { + t.Run("Convert to boolean (true)", func(t *testing.T) { + field := "is_boolean" + value := "true" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: true} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Convert to boolean (false)", func(t *testing.T) { + field := "is_boolean" + value := "false" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: false} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Convert to integer", func(t *testing.T) { + field := "quantity number" + value := "42" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: 42} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Convert to float64", func(t *testing.T) { + field := "quantity decimal number" + value := "99.99" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: 99.99} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Convert to nil (empty)", func(t *testing.T) { + field := "nil or empty" + value := "[EMPTY]" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: nil} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("No conversion (string)", func(t *testing.T) { + field := "Nadie" + value := "Juan" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: value} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) +} + +func TestGetOptionsSearchAllFields(t *testing.T) { + t.Run("Check creates an 'Options' to search all fields in the collection", func(t *testing.T) { + options := GetOptionsSearchAllFields() + if options.Projection == nil { + t.Errorf("Expected Projection to be nil, but got: %v", options.Projection) + } + }) +} + +func TestVerifyMustExist(t *testing.T) { + t.Run("exist is true", func(t *testing.T) { + if VerifyMustExist("does exist") != true { + t.Errorf("Expected true, but got false") + } + }) + t.Run("exist is false", func(t *testing.T) { + if VerifyMustExist("does not exist") != false { + t.Errorf("Expected false, but got true") + } + }) +} + + +// SESSION FUNCTIONS + +func TestCreateDocumentsCollection(t *testing.T) { + // 1-Establish a Session instance and context + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + + // 2-Checks if the function can create an array with the correct number of interfaces + // and if the values within the array are as expected + t.Run("Create array with 3 interfaces", func(t *testing.T) { + count := 3 + result := s.CreateDocumentsCollection(ctx, count) + if len(result) != count { + t.Errorf("Expected array length of %d, but got %d", count, len(result)) + } + for i := 0; i < count; i++ { + if result[i].(map[string]interface{})["fieldInt"] != i+1 { + t.Errorf("Expected value at index %d to be %d, but got %v", i, i, result[i]) + } + } + }) + t.Run("Create empty array", func(t *testing.T) { + count := 0 + result := s.CreateDocumentsCollection(ctx, count) + if len(result) != count { + t.Errorf("Expected empty array, but got an array of length %d", len(result)) + } + }) +} + +func TestExistFieldCollection(t *testing.T) { + s := &Session{} + s.fieldsCollectionName = []string{"Alcorcon", "Madrid", "Barcelona"} + + t.Run("Verify that an element exists in fieldsCollectionName", func(t *testing.T) { + if s.ExistFieldCollection("Alcorcon") != true { + t.Errorf("'Alcorcon' exist in fieldsCollectionName") + } + }) + t.Run("Verify that an item does not exist in fieldsCollectionName", func(t *testing.T) { + if s.ExistFieldCollection("Valladolid") != false { + t.Errorf("'Valladolid' does not exist in fieldsCollectionName") + } + }) +} + +func TestGetDecodeDocument(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + fieldSearched := "_id" + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Create the s.singleResult and get the document decoded + t.Run("Check GetDecodeDocument decodes the BSON document in the bsonDoc variable", func(t *testing.T) { + searchedValue := s.idCollection+"_1" + s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) + _, err := s.GetDecodeDocument(*s.singleResult) + if err != nil { + t.Error(err) + } + }) + t.Run("Check GetDecodeDocument does not decode the BSON document in the bsonDoc variable", func(t *testing.T) { + searchedValue := s.idCollection+"_2" + s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) + _, err := s.GetDecodeDocument(*s.singleResult) + if err == nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + + +func TestSetCollection(t *testing.T) { + // 1-Establish a Session instance, context, and MongoDB collection + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Verify that the collection is created + t.Run("Verify that the collection is created", func(t *testing.T) { + s.SetCollection(collectionName) + if s.collection.Name() != collectionName { + t.Errorf("s.collection is not %s, it is %s", collectionName, s.collection.Name()) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestSetDataCollectionJSONBytes(t *testing.T) { + // 1-Establish a Session instance + s := &Session{} + + // 2- Check converts BSON to JSON + t.Run("Check convert correct BSON object to JSON", func(t *testing.T) { + doc := bson.D{ + {Key: "name", Value: "Juan Nadie"}, + {Key: "age", Value: 30}, + } + err := s.SetDataCollectionJSONBytes(doc) + if err != nil { + t.Error(err) + } + }) + t.Run("Check convert incorrect BSON object to JSON", func(t *testing.T) { + // A function in the value, which is not serializable in JSON + doc := bson.D{ + {"name", func() {}}, + } + err := s.SetDataCollectionJSONBytes(doc) + if err == nil { + t.Error(err) + } + }) +} + +func TestSetFieldsCollectionName(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Verify that the s.fieldsCollectionName slice is empty + if len(s.fieldsCollectionName) != 0 { + t.Error("s.fieldsCollectionName is not empty: ",s.fieldsCollectionName) + } + + // 4-Verify that a slice with field names is saved in s.fieldsCollectionName + t.Run("Verify that a slice is saved", func(t *testing.T) { + err := s.SetFieldsCollectionName(ctx, s.idCollection+"_1" ) + if err != nil { + t.Error(err) + } + if len(s.fieldsCollectionName) == 0 { + t.Error("s.fieldsCollectionName is empty: ",s.fieldsCollectionName) + } + }) + t.Run("Verify that a slice is not saved if the searched value does not exist", func(t *testing.T) { + err := s.SetFieldsCollectionName(ctx, s.idCollection+"_2" ) + if err == nil { + t.Error(err) + } + }) + + // 5-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + + +func TestSetSingleResult(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + fieldSearched := "_id" + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check for s.singleResult + t.Run("Verify that the s.singleResult exists", func(t *testing.T) { + searchedValue := s.idCollection+"_1" + err := s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) + if err != nil { + t.Error(err) + } + }) + t.Run("Checking that the s.singleResult does not exist", func(t *testing.T) { + searchedValue := s.idCollection+"_2" + err := s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) + if err == nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestValidateDataMongo(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check the existence of the searched values + t.Run("Verify that the searched values exist in the MongoDB collection", func(t *testing.T) { + // Data that will be searched in the collection and that will be found + propTable := golium.NewTable([][]string{ + {"field","value"}, + {"_id",s.idCollection+"_1"}, + {"fieldString","Example field string 1"}, + }) + props, _ := golium.ConvertTableToMap(ctx, propTable) + exist, errValidate := s.ValidateDataMongo(ctx, s.idCollection+"_1", props) + if !exist || errValidate != nil { + t.Error(errValidate) + } + }) + t.Run("Verify that the searched values do not exist in the MongoDB collection", func(t *testing.T) { + // Data that will be searched in the collection and that will not be found + propTable := golium.NewTable([][]string{ + {"field","value"}, + {"_id","123456_id_unexist"}, + }) + props, _ := golium.ConvertTableToMap(ctx, propTable) + exist, errValidate := s.ValidateDataMongo(ctx, s.idCollection+"_1", props) + if exist || errValidate == nil { + t.Error(errValidate) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestVerifyExistAndMustExistValue(t *testing.T) { + // 1-Establish a Session instance + s := &Session{} + + //2-Creating test combinations + t.Run("Checking that values exist and should exist", func(t *testing.T) { + exist := true + mustExist := true + var errFunction error + err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) + if err != nil { + t.Error(err) + } + }) + t.Run("Checking that values exist and should not exist", func(t *testing.T) { + exist := true + mustExist := false + var errFunction error + err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) + if err == nil { + t.Error(err) + } + }) + t.Run("Checking that values do not exist and should exist", func(t *testing.T) { + exist := false + mustExist := true + var errFunction error + err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) + if err == nil { + t.Error(err) + } + }) + t.Run("Checking that values don't exist and shouldn't exist", func(t *testing.T) { + exist := false + mustExist := false + var errFunction error + err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) + if err != nil { + t.Error(err) + } + }) + t.Run("Checking for a previous error", func(t *testing.T) { + exist := false + mustExist := true + errFunction := errors.New("errorFunction is not nil") + err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) + if err == nil { + t.Error(err) + } + }) +} + +func TestVerifyExistID(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check if the s.idCollection exists + t.Run("Verify that the value exists in the _id field", func(t *testing.T) { + _, err := s.VerifyExistID(ctx, s.idCollection+"_1") + if err != nil { + t.Error(err) + } + }) + t.Run("Verify that the value does not exist in the _id field", func(t *testing.T) { + _, err := s.VerifyExistID(ctx, s.idCollection+"_2") + if err == nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} diff --git a/steps/mongo/steps.go b/steps/mongo/steps.go index 91ba7486..6d8b3ed8 100755 --- a/steps/mongo/steps.go +++ b/steps/mongo/steps.go @@ -30,33 +30,40 @@ func (us Steps) InitializeSteps(ctx context.Context, scenCtx *godog.ScenarioCont ctx = InitializeContext(ctx) session := GetSession(ctx) - scenCtx.Step(`^I connect to MongoDB$`, func() error { - return session.MongoConnectionStep(ctx) + scenCtx.Step(`^I connect to MongoDB$`, func(t *godog.Table) error { + return session.MongoConnectionStep(ctx, t) }) - scenCtx.Step(`^I check that these values of the MongoDB "([^"]*)" collection with "([^"]*)" _id "([^"]*)" exist$`, func(collectionName string, idCollection string, exist string, t *godog.Table) error { + scenCtx.Step(`^I check that these values of the MongoDB "([^"]*)" collection with "([^"]*)" _id "([^"]*)" exist$`, func(collectionName, idCollection, exist string, t *godog.Table) error { return session.CheckMongoValuesStep(ctx, golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, idCollection), golium.ValueAsString(ctx, exist), t) }) - scenCtx.Step(`^I check that the MongoDB "([^"]*)" collection with "([^"]*)" _id "([^"]*)" exist$`, func(collectionName string, idCollection string, exist string) error { + scenCtx.Step(`^I check that the MongoDB "([^"]*)" collection with "([^"]*)" _id "([^"]*)" exist$`, func(collectionName, idCollection, exist string) error { return session.CheckMongoValueIDStep(ctx, golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, idCollection), golium.ValueAsString(ctx, exist)) }) - scenCtx.Step(`^I check that in the MongoDB "([^"]*)" collection, "([^"]*)" field "([^"]*)" exist for the "([^"]*)" _id$`, func(collectionName string, fieldSearched string, exist string, idCollection string) error { + scenCtx.Step(`^I check that in the MongoDB "([^"]*)" collection, "([^"]*)" field "([^"]*)" exist for the "([^"]*)" _id$`, func(collectionName, fieldSearched, exist, idCollection string) error { return session.CheckMongoFieldNameStep(ctx, golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, fieldSearched), golium.ValueAsString(ctx, exist), golium.ValueAsString(ctx, idCollection)) }) - scenCtx.Step(`^I check that the "([^"]*)" field in the MongoDB "([^"]*)" collection does not exist or is empty for the "([^"]*)" _id$`, func(fieldSearched string, collectionName string, idCollection string) error { - return session.CheckMongoFieldExistOrEmptyStep(ctx, golium.ValueAsString(ctx, fieldSearched), golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, idCollection)) - }) + scenCtx.Step(`^I check that in the MongoDB "([^"]*)" collection, "([^"]*)" field does not exist or is empty for the "([^"]*)" _id$`, func(collectionName, fieldSearched, idCollection string) error { + return session.CheckMongoFieldDoesNotExistOrEmptyStep(ctx, golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, fieldSearched), golium.ValueAsString(ctx, idCollection)) + }) scenCtx.Step(`^I create "(\d+)" documents in the MongoDB "([^"]*)" collection$`, func(num int, collectionName string) error { return session.CreateDocumentscollectionNameStep(ctx, num, golium.ValueAsString(ctx, collectionName)) }) - scenCtx.Step(`^I delete documents from the MongoDB "([^"]*)" collection whose "([^"]*)" field is "([^"]*)" value$`, func(collectionName string, field string, value string) error { + scenCtx.Step(`^I delete documents from the MongoDB "([^"]*)" collection whose "([^"]*)" field is "([^"]*)" value$`, func(collectionName, field, value string) error { return session.DeleteDocumentscollectionNameStep(ctx, golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, field), value) }) + scenCtx.Step(`^I delete all documents from the MongoDB "([^"]*)" collection$`, func(collectionName string) error { + return session.DeleteAllDocumentscollectionNameStep(ctx, golium.ValueAsString(ctx, collectionName)) + }) scenCtx.Step(`^I check that the number of documents in collection "([^"]*)" is "(\d+)"$`, func(collectionName string, num int) error { return session.CheckNumberDocumentscollectionNameStep(golium.ValueAsString(ctx, collectionName), num) }) + scenCtx.Step(`^I generate a UUID and store it$`, func() error { + return session.GenerateUUIDStoreItStep(ctx) + }) + scenCtx.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) { - return ctx, session.MongoDisconnection() + return ctx, session.MongoDisconnectionStep() }) return ctx diff --git a/test/acceptance/features/mongo.feature b/test/acceptance/features/mongo.feature index a16ba2f2..044ae6b4 100644 --- a/test/acceptance/features/mongo.feature +++ b/test/acceptance/features/mongo.feature @@ -1,4 +1,30 @@ +# Copyright (c) Telefónica Cybersecurity & Cloud Tech S.L. +# SDET Team + Feature: MongoDB client + Examples of MongoDB access and data processing. It is possible to: + - Creation of documents. + - Deletion of documents. + - Checking the number of documents. + - Verification of the existence or not of the _id in the documents. + - Checking the existence or not of certain data in documents (texts, numbers, booleans, lists, objects). + - Checking the existence or not of fields in the collection. + - Checking null, empty and non-existent values. + + + Background: + # Prepare data: Collection "example" empty and create "_id" field + Given I connect to MongoDB + | field | value | + | User | [CONF:mongoUsername] | + | Password | [CONF:mongoPassword] | + | Host | [CONF:mongoHost] | + | AuthSource | [CONF:mongoAuthSource] | + | Database | [CONF:mongoDatabase] | + And I delete all documents from the MongoDB "example" collection + And I check that the number of documents in collection "example" is "0" + And I generate a UUID and store it + @mongodb Scenario: Create a collection, check it and delete it. @@ -9,3 +35,126 @@ Feature: MongoDB client Then I check that the number of documents in collection "test-colection" is "1" When I delete documents from the MongoDB "test-colection" collection whose "fieldString" field is "Example field string 2" value Then I check that the number of documents in collection "test-colection" is "0" + + + @mongodb + Scenario: Creating documents in the "Example" Collection + Given I create "2" documents in the MongoDB "example" collection + Then I check that the number of documents in collection "example" is "2" + + + @mongodb + Scenario: Delete documents from the "example" collection + Given I create "10" documents in the MongoDB "example" collection + When I check that the number of documents in collection "example" is "10" + # Delete a document by searching for a string + When I delete documents from the MongoDB "example" collection whose "fieldString" field is "Example field string 1" value + Then I check that the number of documents in collection "example" is "9" + # Delete a document by searching for an int + When I delete documents from the MongoDB "example" collection whose "fieldInt" field is "2" value + Then I check that the number of documents in collection "example" is "8" + # Delete a document by searching for an item in a slice + When I delete documents from the MongoDB "example" collection whose "fieldSlice.0" field is "itemSlice_3" value + Then I check that the number of documents in collection "example" is "7" + # Delete a document by searching for a string element in a map + When I delete documents from the MongoDB "example" collection whose "fieldMap.fieldString" field is "Example field in map string 4" value + Then I check that the number of documents in collection "example" is "6" + # Delete a document by searching for an int element in a map + When I delete documents from the MongoDB "example" collection whose "fieldMap.fieldInt" field is "50" value + Then I check that the number of documents in collection "example" is "5" + # Delete a document by searching for a string element on a map within another map + When I delete documents from the MongoDB "example" collection whose "fieldMap.fieldMap2.fieldString" field is "Example field in map map string 6" value + Then I check that the number of documents in collection "example" is "4" + # Delete a document by searching for an int element on a map within another map + When I delete documents from the MongoDB "example" collection whose "fieldMap.fieldMap2.fieldInt" field is "700" value + Then I check that the number of documents in collection "example" is "3" + # Delete a document by searching for an empty item on a map within another map + When I delete documents from the MongoDB "example" collection whose "fieldMap.fieldMap2.fieldEmptyText" field is "" value + Then I check that the number of documents in collection "example" is "0" + + + @mongodb + Scenario: Check the number of documents in the "example" collection + Given I create "5" documents in the MongoDB "example" collection + Then I check that the number of documents in collection "example" is "5" + When I delete documents from the MongoDB "example" collection whose "fieldInt" field is "1" value + Then I check that the number of documents in collection "example" is "4" + + + @mongodb + Scenario: Check that the _id "[CTXT:_ID]_1" exists in the "example" collection + Given I create "1" documents in the MongoDB "example" collection + Then I check that in the MongoDB "example" collection, "_id" field "does" exist for the "[CTXT:_ID]_1" _id + + + @mongodb + Scenario: Check that the "[CTXT:_ID]_0" _id does not exist in the "example" collection + Given I create "1" documents in the MongoDB "example" collection + When I check that the number of documents in collection "example" is "1" + Then I check that in the MongoDB "example" collection, "_id" field "does not" exist for the "[CTXT:_ID]_0" _id + + + @mongodb + Scenario: Check that there is some data in the "example" collection through a table in the feature + Given I create "1" documents in the MongoDB "example" collection + Then I check that these values of the MongoDB "example" collection with "[CTXT:_ID]_1" _id "do" exist + | field | value | + # General values + | _id | [CTXT:_ID]_1 | + | fieldString | Example field string 1 | + | fieldInt | [NUMBER:1] | + | fieldFloat | [NUMBER:3.14] | + | fieldBool | [TRUE] | + # Slice with data + | fieldSlice.# | [NUMBER:3] | + | fieldSlice.0 | itemSlice_1 | + | fieldSlice.1 | itemSlice20 | + | fieldSlice.2 | itemSlice30 | + | fieldEmpty | [EMPTY] | + # Map with data + | fieldMap.fieldString | Example field in map string 1 | + | fieldMap.fieldInt | [NUMBER:10] | + | fieldMap.fieldFloat | [NUMBER:1974.1976] | + | fieldMap.fieldBool | [FALSE] | + # Slice empty in map. It is possible to compare empty items + | fieldMap.fieldSliceEmpty.# | [NUMBER:0] | + | fieldMap.fieldSliceEmpty.0 | [NULL] | + | fieldMap.fieldSliceEmpty.1 | | + | fieldMap.fieldSliceEmpty.2 | [EMPTY] | + # Map in map with similar data + | fieldMap.fieldMap2.fieldString | Example field in map map string 1 | + | fieldMap.fieldMap2.fieldInt | [NUMBER:100] | + | fieldMap.fieldMap2.fieldFloat | [NUMBER:1974.1976] | + | fieldMap.fieldMap2.fieldBool | [FALSE] | + | fieldMap.fieldMap2.fieldEmpty | [NULL] | + | fieldMap.fieldMap2.fieldEmptyText | [EMPTY] | + + + @mongodb + Scenario: Check that there is no data in the "example" collection through a table in the feature + Given I create "1" documents in the MongoDB "example" collection + And I check that the number of documents in collection "example" is "1" + Then I check that these values of the MongoDB "example" collection with "[CTXT:_ID]_1" _id "do not" exist + | field | value | + | fieldString | Value does not exist | + + + @mongodb + Scenario: Check that the "fieldString" field exists in the "example" collection + Given I create "1" documents in the MongoDB "example" collection + Then I check that in the MongoDB "example" collection, "fieldString" field "does" exist for the "[CTXT:_ID]_1" _id + + + @mongodb + Scenario: Check that the "campoInexistente" field does not exist in the "example" collection + Given I create "1" documents in the MongoDB "example" collection + And I check that the number of documents in collection "example" is "1" + Then I check that in the MongoDB "example" collection, "campoInexistente" field "does not" exist for the "[CTXT:_ID]_1" _id + And I check that in the MongoDB "example" collection, "campoInexistente" field does not exist or is empty for the "[CTXT:_ID]_1" _id + + + @mongodb + Scenario: Check that the value of the "fiedlEmpty" field in the "example" collection does not exist or is null + Given I create "1" documents in the MongoDB "example" collection + When I check that in the MongoDB "example" collection, "_id" field "does" exist for the "[CTXT:_ID]_1" _id + Then I check that in the MongoDB "example" collection, "fieldEmpty" field does not exist or is empty for the "[CTXT:_ID]_1" _id From 4c5827bffda449bb1f5b42214457a4ab882ac418 Mon Sep 17 00:00:00 2001 From: mariolg Date: Wed, 15 Nov 2023 18:59:12 +0100 Subject: [PATCH 18/27] feat: add mongo collection and client mock functions --- sonar-project.properties | 2 +- steps/mongo/client.go | 26 +- steps/mongo/client_mock.go | 42 ++ steps/mongo/collection.go | 61 ++ steps/mongo/collection_mock.go | 60 ++ steps/mongo/context.go | 4 +- steps/mongo/session.go | 30 +- steps/mongo/session_refactor.go | 835 ++++++++++++++++++++++++ steps/mongo/session_test.go | 1050 ++++++++----------------------- steps/mongo/steps.go | 4 +- steps/redis/steps.go | 2 +- 11 files changed, 1304 insertions(+), 812 deletions(-) create mode 100644 steps/mongo/client_mock.go create mode 100644 steps/mongo/collection.go create mode 100644 steps/mongo/collection_mock.go create mode 100644 steps/mongo/session_refactor.go diff --git a/sonar-project.properties b/sonar-project.properties index a77a6a43..aea79972 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -5,7 +5,7 @@ sonar.organization=telefonicatc2tech sonar.go.tests.reportPaths=test-report.out sonar.go.coverage.reportPaths=coverage.txt sonar.go.golangci-lint.reportPaths=golangci-report.xml -sonar.coverage.exclusions=**/*context.go,**/*logger.go,**/*steps.go,**/*client.go,**/mock/**/*.go +sonar.coverage.exclusions=**/*context.go,**/*logger.go,**/*steps.go,**/*client.go,**/*collection.go,**/mock/**/*.go sonar.sources=. sonar.exclusions=**/*_test.go diff --git a/steps/mongo/client.go b/steps/mongo/client.go index 4c505502..c6333c7c 100644 --- a/steps/mongo/client.go +++ b/steps/mongo/client.go @@ -14,9 +14,33 @@ package mongo -type ClientFunctions interface{} +import ( + "context" + + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/readpref" +) + +type ClientFunctions interface { + Ping(ctx context.Context, rp *readpref.ReadPref, client *mongo.Client) error + Disconnect(ctx context.Context, client *mongo.Client) error + Database(name string, client *mongo.Client) *mongo.Database +} + type ClientService struct{} func NewMongoClientService() *ClientService { return &ClientService{} } + +func (c ClientService) Ping(ctx context.Context, rp *readpref.ReadPref, client *mongo.Client) error { + return client.Ping(ctx, rp) +} + +func (c ClientService) Disconnect(ctx context.Context, client *mongo.Client) error { + return client.Disconnect(ctx) +} + +func (c ClientService) Database(name string, client *mongo.Client) *mongo.Database { + return client.Database(name) +} diff --git a/steps/mongo/client_mock.go b/steps/mongo/client_mock.go new file mode 100644 index 00000000..528c05f9 --- /dev/null +++ b/steps/mongo/client_mock.go @@ -0,0 +1,42 @@ +// Copyright (c) Telefónica Cybersecurity & Cloud Tech S.L. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mongo + +import ( + "context" + + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/readpref" +) + +var ( + PingError error + DisconnectError error + DatabaseDatabase *mongo.Database +) + +type ClientServiceFuncMock struct{} + +func (c ClientServiceFuncMock) Ping(ctx context.Context, rp *readpref.ReadPref, client *mongo.Client) error { + return PingError +} + +func (c ClientServiceFuncMock) Disconnect(ctx context.Context, client *mongo.Client) error { + return DisconnectError +} + +func (c ClientServiceFuncMock) Database(name string, client *mongo.Client) *mongo.Database { + return DatabaseDatabase +} diff --git a/steps/mongo/collection.go b/steps/mongo/collection.go new file mode 100644 index 00000000..692efc77 --- /dev/null +++ b/steps/mongo/collection.go @@ -0,0 +1,61 @@ +// Copyright (c) Telefónica Cybersecurity & Cloud Tech S.L. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mongo + +import ( + "context" + + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type CollectionFunctions interface { + Collection(name string, database *mongo.Database) *mongo.Collection + Name(collection *mongo.Collection) string + Find(ctx context.Context, filter interface{}, collection *mongo.Collection, opts ...*options.FindOptions) (*mongo.Cursor, error) + FindOne(ctx context.Context, filter interface{}, collection *mongo.Collection, opt ...*options.FindOneOptions) *mongo.SingleResult + InsertMany(ctx context.Context, documents []interface{}, collection *mongo.Collection) (*mongo.InsertManyResult, error) + DeleteMany(ctx context.Context, filter interface{}, opt *options.DeleteOptions, collection *mongo.Collection) (*mongo.DeleteResult, error) +} + +type CollectionService struct{} + +func NewMongoCollectionService() *CollectionService { + return &CollectionService{} +} + +func (c CollectionService) Collection(name string, database *mongo.Database) *mongo.Collection { + return database.Collection(name) +} + +func (c CollectionService) Name(collection *mongo.Collection) string { + return collection.Name() +} + +func (c CollectionService) FindOne(ctx context.Context, filter interface{}, collection *mongo.Collection, opts ...*options.FindOneOptions) *mongo.SingleResult { + return collection.FindOne(ctx, filter, opts...) +} + +func (c CollectionService) Find(ctx context.Context, filter interface{}, collection *mongo.Collection, opts ...*options.FindOptions) (*mongo.Cursor, error) { + return collection.Find(ctx, filter, opts...) +} + +func (c CollectionService) InsertMany(ctx context.Context, documents []interface{}, collection *mongo.Collection) (*mongo.InsertManyResult, error) { + return collection.InsertMany(ctx, documents) +} + +func (c CollectionService) DeleteMany(ctx context.Context, filter interface{}, opt *options.DeleteOptions, collection *mongo.Collection) (*mongo.DeleteResult, error) { + return collection.DeleteMany(ctx, filter, opt) +} diff --git a/steps/mongo/collection_mock.go b/steps/mongo/collection_mock.go new file mode 100644 index 00000000..21157e94 --- /dev/null +++ b/steps/mongo/collection_mock.go @@ -0,0 +1,60 @@ +// Copyright (c) Telefónica Cybersecurity & Cloud Tech S.L. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mongo + +import ( + "context" + + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +var ( + CollectionCollection *mongo.Collection + NameString string + FindOneSingleResult *mongo.SingleResult + FindCursor *mongo.Cursor + FindError error + InsertManyInsertManyResult *mongo.InsertManyResult + InsertManyError error + DeleteResultDeleteResult *mongo.DeleteResult + DeleteResultError error +) + +type CollectionServiceFuncMock struct{} + +func (c CollectionServiceFuncMock) Collection(name string, database *mongo.Database) *mongo.Collection { + return CollectionCollection +} + +func (c CollectionServiceFuncMock) Name(collection *mongo.Collection) string { + return NameString +} + +func (c CollectionServiceFuncMock) FindOne(ctx context.Context, filter interface{}, collection *mongo.Collection, opts ...*options.FindOneOptions) *mongo.SingleResult { + return FindOneSingleResult +} + +func (c CollectionServiceFuncMock) Find(ctx context.Context, filter interface{}, collection *mongo.Collection, opts ...*options.FindOptions) (*mongo.Cursor, error) { + return FindCursor, FindError +} + +func (c CollectionServiceFuncMock) InsertMany(ctx context.Context, documents []interface{}, collection *mongo.Collection) (*mongo.InsertManyResult, error) { + return InsertManyInsertManyResult, InsertManyError +} + +func (c CollectionServiceFuncMock) DeleteMany(ctx context.Context, filter interface{}, opt *options.DeleteOptions, collection *mongo.Collection) (*mongo.DeleteResult, error) { + return DeleteResultDeleteResult, DeleteResultError +} diff --git a/steps/mongo/context.go b/steps/mongo/context.go index 6d480b55..59b5153c 100755 --- a/steps/mongo/context.go +++ b/steps/mongo/context.go @@ -26,7 +26,9 @@ const contextKey ContextKey = "mongoSession" // InitializeContext adds the mongo session to the context. // The new context is returned because context is immutable. func InitializeContext(ctx context.Context) context.Context { - return context.WithValue(ctx, contextKey, &Session{MongoClientService: *NewMongoClientService()}) + return context.WithValue(ctx, contextKey, &Session{ + MongoClientService: *NewMongoClientService(), + MongoCollectionService: *NewMongoCollectionService()}) } // GetSession returns the mongo session stored in context. diff --git a/steps/mongo/session.go b/steps/mongo/session.go index cfbac140..1eaf77e2 100644 --- a/steps/mongo/session.go +++ b/steps/mongo/session.go @@ -58,8 +58,11 @@ type Session struct { // Save collection items as JSON dataCollectionJSONBytes []byte - // Access MongoDB features + // Access MongoDB Client features MongoClientService ClientFunctions + + // Access MongoDB Colleciton features + MongoCollectionService CollectionFunctions } // FUNCTIONS CALLED BY STEPS @@ -143,7 +146,7 @@ func (s *Session) CheckNumberDocumentscollectionNameStep(collectionName string, s.SetCollection(collectionName) // 2-Make a query to get all the documents in the collection - cursor, err := s.collection.Find(context.Background(), bson.D{}) + cursor, err := s.MongoCollectionService.Find(context.Background(), bson.D{}, s.collection, &options.FindOptions{}) if err != nil { return fmt.Errorf("error: query error: '%s'", err) } @@ -171,7 +174,7 @@ func (s *Session) CreateDocumentscollectionNameStep( allDocuments := s.CreateDocumentsCollection(ctx, num) // 3-Insert the documents into the "collectionName" collection of the database - _, err := s.collection.InsertMany(context.TODO(), allDocuments) + _, err := s.MongoCollectionService.InsertMany(context.TODO(), allDocuments, s.collection) if err != nil { return err } @@ -181,7 +184,7 @@ func (s *Session) CreateDocumentscollectionNameStep( // DeleteDocumentscollectionNameStep delete a document from the MongoDB collection func (s *Session) DeleteAllDocumentscollectionNameStep(ctx context.Context, collectionName string, - ) error { +) error { // 1-The collection in which the deletion is to be made is established. s.SetCollection(collectionName) @@ -244,7 +247,7 @@ func (s *Session) MongoConnectionStep(ctx context.Context, t *godog.Table) error } // 4-Check the connection to the MongoDB server - err = s.client.Ping(ctx, nil) + err = s.MongoClientService.Ping(ctx, nil, s.client) if err != nil { return fmt.Errorf("error: problems with connection to MongoDB. '%s'", err) } @@ -258,7 +261,7 @@ func (s *Session) MongoConnectionStep(ctx context.Context, t *godog.Table) error // MongoDisconnection closes the connection to MongoDB if it exists func (s *Session) MongoDisconnectionStep() error { if s.client != nil { - err := s.client.Disconnect(context.Background()) + err := s.MongoClientService.Disconnect(context.Background(), s.client) if err != nil { return fmt.Errorf("error: problem in MongoDB disconnection: '%s'", err) } @@ -371,13 +374,13 @@ func (s *Session) CreateDocumentsCollection(ctx context.Context, num int) []inte "fieldBool": true, "fieldSlice": []string{"itemSlice_" + strconv.Itoa(i), "itemSlice20", "itemSlice30"}, "fieldEmpty": nil, - "fieldMap": map[string]interface{}{ + "fieldMap": map[string]interface{}{ "fieldString": "Example field in map string " + strconv.Itoa(i), "fieldInt": i * 10, "fieldFloat": 1974.1976, "fieldBool": false, "fieldSliceEmpty": []string{}, - "fieldMap2": map[string]interface{}{ + "fieldMap2": map[string]interface{}{ "fieldString": "Example field in map map string " + strconv.Itoa(i), "fieldInt": i * 100, "fieldFloat": 1974.1976, @@ -416,7 +419,8 @@ func (s *Session) GetDecodeDocument(singleResult mongo.SingleResult) (bson.D, er // SetCollection sets the collection. If the collection does not exist, no error is returned. // Collections are created dynamically when you insert a document func (s *Session) SetCollection(collectionName string) { - s.collection = s.client.Database(s.database).Collection(collectionName) + database := s.MongoClientService.Database(s.database, s.client) + s.collection = s.MongoCollectionService.Collection(collectionName, database) } // SetDataCollectionJSONBytes convert BSON object to JSON @@ -433,7 +437,7 @@ func (s *Session) SetDataCollectionJSONBytes(bsonDoc bson.D) error { func (s *Session) SetFieldsCollectionName(ctx context.Context, idCollection string) error { // Make a query to find past _id's document var document bson.M - err := s.collection.FindOne(ctx, GetFilter("_id", idCollection)).Decode(&document) + err := s.MongoCollectionService.FindOne(ctx, GetFilter("_id", idCollection), s.collection, &options.FindOneOptions{}).Decode(&document) if err == mongo.ErrNoDocuments { return fmt.Errorf("error: no documents matching the filter were found") } else if err != nil { @@ -452,8 +456,8 @@ func (s *Session) SetFieldsCollectionName(ctx context.Context, idCollection stri // SetSingleResult set a Single Result from a Filter Search (GetFilter(...) function) func (s *Session) SetSingleResult( ctx context.Context, fieldSearched string, value interface{}) error { - s.singleResult = s.collection.FindOne( - ctx, GetFilter(fieldSearched, value), GetOptionsSearchAllFields()) + s.singleResult = s.MongoCollectionService.FindOne( + ctx, GetFilter(fieldSearched, value), s.collection, GetOptionsSearchAllFields()) if s.singleResult.Err() != nil { return fmt.Errorf("error: the searched '%s' field does not have the '%s' value "+ "in the '%s' collection", fieldSearched, value, s.collection.Name()) @@ -518,7 +522,7 @@ func (s *Session) VerifyExistAndMustExistValue(exist, mustExist bool, err error) if err != nil { return err } - return fmt.Errorf("error: the value DOES NOT EXIST and SHOULD, or EXIST and SHOULD NOT, "+ + return fmt.Errorf("error: the value DOES NOT EXIST and SHOULD, or EXIST and SHOULD NOT, " + "in the collection") } diff --git a/steps/mongo/session_refactor.go b/steps/mongo/session_refactor.go new file mode 100644 index 00000000..4c4b6d0e --- /dev/null +++ b/steps/mongo/session_refactor.go @@ -0,0 +1,835 @@ +// Copyright 2021 Telefonica Cybersecurity & Cloud Tech SL +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mongo + +import ( + "context" + "errors" + "reflect" + "testing" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + + "github.com/TelefonicaTC2Tech/golium" +) + +// FUNCTIONS CALLED BY STEPS + +func TestCheckMongoFieldDoesNotExistOrEmptyStep(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check if the field names do not exist or are empty + t.Run("Checking that the 'fieldEmpty' field does not exist or is empty in the MongoDB collection", func(t *testing.T) { + fieldSearched := "fieldEmpty" + err := s.CheckMongoFieldDoesNotExistOrEmptyStep(ctx, collectionName, fieldSearched, s.idCollection+"_1") + if err != nil { + t.Error(err) + } + }) + t.Run("Checking that the 'fieldUnexist' field does not exist in the MongoDB collection", func(t *testing.T) { + fieldSearched := "fieldUnexist" + err := s.CheckMongoFieldDoesNotExistOrEmptyStep(ctx, collectionName, fieldSearched, s.idCollection+"_1") + if err != nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestCheckMongoFieldNameStep(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check whether or not the name of the searched field exists + // If you want to check that it doesn't exist, you have to pass "not" as a parameter + t.Run("Verify that the 'fieldString' field exists in the MongoDB collection", func(t *testing.T) { + fieldSearched := "fieldString" + err := s.CheckMongoFieldNameStep(ctx, collectionName, fieldSearched, "yes", s.idCollection+"_1") + if err != nil { + t.Error(err) + } + }) + t.Run("Verify that the 'fieldEmpty' field exists in the MongoDB collection", func(t *testing.T) { + fieldSearched := "fieldEmpty" + err := s.CheckMongoFieldNameStep(ctx, collectionName, fieldSearched, "does", s.idCollection+"_1") + if err != nil { + t.Error(err) + } + }) + t.Run("Verify that the 'fieldUnexist' field does not exist in the MongoDB collection", func(t *testing.T) { + fieldSearched := "fieldUnexist" + err := s.CheckMongoFieldNameStep(ctx, collectionName, fieldSearched, "not", s.idCollection+"_1") + if err != nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestCheckMongoValueIDStep(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check whether or not the _id sought exists + // If you want to check that it doesn't exist, you have to pass "not" as a parameter + t.Run("Verify that the '_id' exists in the MongoDB collection", func(t *testing.T) { + err := s.CheckMongoValueIDStep(ctx, collectionName, s.idCollection+"_1", "yes") + if err != nil { + t.Error(err) + } + }) + t.Run("Verify that the '_id' does not exist in the MongoDB collection", func(t *testing.T) { + err := s.CheckMongoValueIDStep(ctx, collectionName, "123456_id_unexist", "not") + if err != nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestCheckMongoValuesStep(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check whether or not the values you are looking for exist + // If you want to check that it doesn't exist, you have to pass "not" as a parameter + t.Run("Verify that the searched values exist in the MongoDB collection", func(t *testing.T) { + // Data that will be searched in the collection and that will be found + propTableYes := golium.NewTable([][]string{ + {"field", "value"}, + {"_id", "[CTXT:_ID]_1"}, + {"fieldString", "Example field string 1"}, + {"fieldInt", "[NUMBER:1]"}, + {"fieldFloat", "[NUMBER:3.14]"}, + {"fieldBool", "[TRUE]"}, + {"fieldSlice.#", "[NUMBER:3]"}, + {"fieldSlice.0", "itemSlice_1"}, + {"fieldSlice.1", "itemSlice20"}, + {"fieldSlice.2", "itemSlice30"}, + {"fieldEmpty", "[EMPTY]"}, + {"fieldMap.fieldString", "Example field in map string 1"}, + {"fieldMap.fieldInt", "[NUMBER:10]"}, + {"fieldMap.fieldFloat", "[NUMBER:1974.1976]"}, + {"fieldMap.fieldBool", "[FALSE]"}, + {"fieldMap.fieldSliceEmpty.#", "[NUMBER:0]"}, + {"fieldMap.fieldSliceEmpty.0", "[NULL]"}, + {"fieldMap.fieldSliceEmpty.1", ""}, + {"fieldMap.fieldSliceEmpty.2", "[EMPTY]"}, + {"fieldMap.fieldMap2.fieldString", "Example field in map map string 1"}, + {"fieldMap.fieldMap2.fieldInt", "[NUMBER:100]"}, + {"fieldMap.fieldMap2.fieldFloat", "[NUMBER:1974.1976]"}, + {"fieldMap.fieldMap2.fieldBool", "[FALSE]"}, + {"fieldMap.fieldMap2.fieldEmpty", "[NULL]"}, + {"fieldMap.fieldMap2.fieldEmptyText", "[EMPTY]"}, + }) + err := s.CheckMongoValuesStep(ctx, collectionName, s.idCollection+"_1", "yes", propTableYes) + if err != nil { + t.Error(err) + } + }) + t.Run("Verify that the searched values do not exist in the MongoDB collection", func(t *testing.T) { + // Data that will be searched in the collection and will not be found + propTableNot := golium.NewTable([][]string{ + {"field", "value"}, + {"_id", "123456_id_unexist"}, + }) + err := s.CheckMongoValuesStep(ctx, collectionName, s.idCollection+"_1", "not", propTableNot) + if err != nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestCheckNumberDocumentscollectionNameStep(t *testing.T) { + // 1-Establish a Session instance, context, and MongoDB collection + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + + // 2-Create a connection and create 10 documents from the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 10, collectionName) + + // 3-Count all the documents + t.Run("Contar los documentos de una colección de MongoDB", func(t *testing.T) { + err := s.CheckNumberDocumentscollectionNameStep(collectionName, 10) + if err != nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestCreateDocumentscollectionNameStep(t *testing.T) { + // 1-Establish a Session instance, context, and MongoDB collection + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + + // 2-Create a connection and delete all documents in the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + err := s.CheckNumberDocumentscollectionNameStep(collectionName, 0) + if err != nil { + t.Error(err) + } + + // 3-Insert a document + err = s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + if err != nil { + t.Error(err) + } + + // 4-Check that it has been inserted and then delete all documents + t.Run("Verify that the document has been inserted into MongoDB", func(t *testing.T) { + err := s.CheckNumberDocumentscollectionNameStep(collectionName, 1) + if err != nil { + t.Error(err) + } + }) + + // 5-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestDeleteAllDocumentscollectionNameStep(t *testing.T) { + // 1-Establish a Session instance, context, and MongoDB collection + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + + // 2-Create a connection and insert 10 documents into the "example" collection + mongoConnection(s, t) + s.CreateDocumentscollectionNameStep(ctx, 10, collectionName) + + // 3-Delete all documents + t.Run("Deleting all documents in a MongoDB collection", func(t *testing.T) { + err := s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + if err != nil { + t.Error(err) + } + }) + + // 4-Verify that all documents have been deleted + err := s.CheckNumberDocumentscollectionNameStep(collectionName, 0) + if err != nil { + t.Error(err) + } +} + +func TestDeleteDocumentscollectionNameStep(t *testing.T) { + // 1-Establish a Session instance, context, and MongoDB collection + ctx := InitializeContext(context.Background()) + s := GetSession(ctx) + collectionName := "example" + + // 2-Create a connection and 3 documents from the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 3, collectionName) + + // 3-Delete a document + t.Run("Deleting a document in MongoDB", func(t *testing.T) { + err := s.DeleteDocumentscollectionNameStep(ctx, collectionName, "fieldInt", "1") + if err != nil { + t.Error(err) + } + }) + + // 4-Verify that it has been deleted, delete all documents and close connection + err := s.CheckNumberDocumentscollectionNameStep(collectionName, 2) + if err != nil { + t.Error(err) + } + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestGenerateUUIDStoreItStep(t *testing.T) { + // 1-Establish a Session instance and context + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + + // 2-Generating a Random UUID + t.Run("Generating a Random UUID", func(t *testing.T) { + if s.GenerateUUIDStoreItStep(ctx) != nil { + t.Errorf("Error generating a random UUID") + } + }) + + // 3-Verifying that a UUID has been created + if len(s.idCollection) != 36 { + t.Errorf("s.idCollection was not created") + } +} + +func mongoConnection(s *Session, t *testing.T) { + propTable := golium.NewTable([][]string{ + {"field", "value"}, + {"User", "mongoadmin"}, + {"Password", "mongoadmin"}, + {"Host", "localhost:27017"}, + {"AuthSource", "admin"}, + {"Database", "golium-demo"}, + }) + t.Run("Connecting to MongoDB", func(t *testing.T) { + err := s.MongoConnectionStep(context.Background(), propTable) + if err != nil { + t.Error(err) + } + }) +} + +func TestMongoConnectionStep(t *testing.T) { + s := &Session{} + mongoConnection(s, t) + s.MongoDisconnectionStep() +} + +func TestMongoDisconnectionStep(t *testing.T) { + // 1-Establish a Session instance, context, and MongoDB collection + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + + // 2-Create a connection and insert 3 collections + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 3, collectionName) + err := s.CheckNumberDocumentscollectionNameStep(collectionName, 3) + if err != nil { + t.Errorf("Error al contar los documentos de la colección '%s'", collectionName) + } + + // 3-Close the connection to MongoDB + t.Run("Close the connection to MongoDB", func(t *testing.T) { + err := s.MongoDisconnectionStep() + if err != nil { + t.Error(err) + } + }) + + // 4-Verify that the connection to MongoDB has been closed + errString := s.CheckNumberDocumentscollectionNameStep(collectionName, 3).Error() + if errString != "error: query error: 'client is disconnected'" { + t.Errorf("Connection to MongoDB is still open") + } +} + +// GENERIC FUNCTIONS + +func TestContainsElements(t *testing.T) { + t.Run("Element exists in slice", func(t *testing.T) { + slice := []int{1, 2, 3, 4, 5} + element := 3 + result := ContainsElements(element, slice) + if !result { + t.Errorf("Expected %v to be in the slice, but it wasn't.", element) + } + }) + t.Run("Element does not exist in slice", func(t *testing.T) { + slice := []string{"Alcorcon", "Madrid", "Barcelona"} + element := "Valladolid" + result := ContainsElements(element, slice) + if result { + t.Errorf("Expected %v not to be in the slice, but it was.", element) + } + }) +} + +func TestGetFilter(t *testing.T) { + t.Run("Create filter with non-nil value", func(t *testing.T) { + key := "age" + value := 30 + filter := GetFilter(key, value) + expectedFilter := bson.M{"age": 30} + if !reflect.DeepEqual(filter, expectedFilter) { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Create filter with nil value", func(t *testing.T) { + key := "name" + var value interface{} = nil + filter := GetFilter(key, value) + expectedFilter := bson.M{"name": nil} + if !reflect.DeepEqual(filter, expectedFilter) { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) +} + +func TestGetFilterConverted(t *testing.T) { + t.Run("Convert to boolean (true)", func(t *testing.T) { + field := "is_boolean" + value := "true" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: true} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Convert to boolean (false)", func(t *testing.T) { + field := "is_boolean" + value := "false" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: false} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Convert to integer", func(t *testing.T) { + field := "quantity number" + value := "42" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: 42} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Convert to float64", func(t *testing.T) { + field := "quantity decimal number" + value := "99.99" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: 99.99} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Convert to nil (empty)", func(t *testing.T) { + field := "nil or empty" + value := "[EMPTY]" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: nil} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("No conversion (string)", func(t *testing.T) { + field := "Nadie" + value := "Juan" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: value} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) +} + +func TestGetOptionsSearchAllFields(t *testing.T) { + t.Run("Check creates an 'Options' to search all fields in the collection", func(t *testing.T) { + options := GetOptionsSearchAllFields() + if options.Projection == nil { + t.Errorf("Expected Projection to be nil, but got: %v", options.Projection) + } + }) +} + +func TestVerifyMustExist(t *testing.T) { + t.Run("exist is true", func(t *testing.T) { + if VerifyMustExist("does exist") != true { + t.Errorf("Expected true, but got false") + } + }) + t.Run("exist is false", func(t *testing.T) { + if VerifyMustExist("does not exist") != false { + t.Errorf("Expected false, but got true") + } + }) +} + +// SESSION FUNCTIONS + +func TestCreateDocumentsCollection(t *testing.T) { + // 1-Establish a Session instance and context + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + + // 2-Checks if the function can create an array with the correct number of interfaces + // and if the values within the array are as expected + t.Run("Create array with 3 interfaces", func(t *testing.T) { + count := 3 + result := s.CreateDocumentsCollection(ctx, count) + if len(result) != count { + t.Errorf("Expected array length of %d, but got %d", count, len(result)) + } + for i := 0; i < count; i++ { + if result[i].(map[string]interface{})["fieldInt"] != i+1 { + t.Errorf("Expected value at index %d to be %d, but got %v", i, i, result[i]) + } + } + }) + t.Run("Create empty array", func(t *testing.T) { + count := 0 + result := s.CreateDocumentsCollection(ctx, count) + if len(result) != count { + t.Errorf("Expected empty array, but got an array of length %d", len(result)) + } + }) +} + +func TestExistFieldCollection(t *testing.T) { + s := &Session{} + s.fieldsCollectionName = []string{"Alcorcon", "Madrid", "Barcelona"} + + t.Run("Verify that an element exists in fieldsCollectionName", func(t *testing.T) { + if s.ExistFieldCollection("Alcorcon") != true { + t.Errorf("'Alcorcon' exist in fieldsCollectionName") + } + }) + t.Run("Verify that an item does not exist in fieldsCollectionName", func(t *testing.T) { + if s.ExistFieldCollection("Valladolid") != false { + t.Errorf("'Valladolid' does not exist in fieldsCollectionName") + } + }) +} + +func TestGetDecodeDocument(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + fieldSearched := "_id" + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Create the s.singleResult and get the document decoded + t.Run("Check GetDecodeDocument decodes the BSON document in the bsonDoc variable", func(t *testing.T) { + searchedValue := s.idCollection + "_1" + s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) + _, err := s.GetDecodeDocument(*s.singleResult) + if err != nil { + t.Error(err) + } + }) + t.Run("Check GetDecodeDocument does not decode the BSON document in the bsonDoc variable", func(t *testing.T) { + searchedValue := s.idCollection + "_2" + s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) + _, err := s.GetDecodeDocument(*s.singleResult) + if err == nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestSetCollection(t *testing.T) { + // 1-Establish a Session instance, context, and MongoDB collection + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Verify that the collection is created + t.Run("Verify that the collection is created", func(t *testing.T) { + s.SetCollection(collectionName) + if s.collection.Name() != collectionName { + t.Errorf("s.collection is not %s, it is %s", collectionName, s.collection.Name()) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestSetDataCollectionJSONBytes(t *testing.T) { + // 1-Establish a Session instance + s := &Session{} + + // 2- Check converts BSON to JSON + t.Run("Check convert correct BSON object to JSON", func(t *testing.T) { + doc := bson.D{ + {Key: "name", Value: "Juan Nadie"}, + {Key: "age", Value: 30}, + } + err := s.SetDataCollectionJSONBytes(doc) + if err != nil { + t.Error(err) + } + }) + t.Run("Check convert incorrect BSON object to JSON", func(t *testing.T) { + // A function in the value, which is not serializable in JSON + doc := bson.D{ + {"name", func() {}}, + } + err := s.SetDataCollectionJSONBytes(doc) + if err == nil { + t.Error(err) + } + }) +} + +func TestSetFieldsCollectionName(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Verify that the s.fieldsCollectionName slice is empty + if len(s.fieldsCollectionName) != 0 { + t.Error("s.fieldsCollectionName is not empty: ", s.fieldsCollectionName) + } + + // 4-Verify that a slice with field names is saved in s.fieldsCollectionName + t.Run("Verify that a slice is saved", func(t *testing.T) { + err := s.SetFieldsCollectionName(ctx, s.idCollection+"_1") + if err != nil { + t.Error(err) + } + if len(s.fieldsCollectionName) == 0 { + t.Error("s.fieldsCollectionName is empty: ", s.fieldsCollectionName) + } + }) + t.Run("Verify that a slice is not saved if the searched value does not exist", func(t *testing.T) { + err := s.SetFieldsCollectionName(ctx, s.idCollection+"_2") + if err == nil { + t.Error(err) + } + }) + + // 5-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestSetSingleResult(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + fieldSearched := "_id" + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check for s.singleResult + t.Run("Verify that the s.singleResult exists", func(t *testing.T) { + searchedValue := s.idCollection + "_1" + err := s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) + if err != nil { + t.Error(err) + } + }) + t.Run("Checking that the s.singleResult does not exist", func(t *testing.T) { + searchedValue := s.idCollection + "_2" + err := s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) + if err == nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestValidateDataMongo(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check the existence of the searched values + t.Run("Verify that the searched values exist in the MongoDB collection", func(t *testing.T) { + // Data that will be searched in the collection and that will be found + propTable := golium.NewTable([][]string{ + {"field", "value"}, + {"_id", s.idCollection + "_1"}, + {"fieldString", "Example field string 1"}, + }) + props, _ := golium.ConvertTableToMap(ctx, propTable) + exist, errValidate := s.ValidateDataMongo(ctx, s.idCollection+"_1", props) + if !exist || errValidate != nil { + t.Error(errValidate) + } + }) + t.Run("Verify that the searched values do not exist in the MongoDB collection", func(t *testing.T) { + // Data that will be searched in the collection and that will not be found + propTable := golium.NewTable([][]string{ + {"field", "value"}, + {"_id", "123456_id_unexist"}, + }) + props, _ := golium.ConvertTableToMap(ctx, propTable) + exist, errValidate := s.ValidateDataMongo(ctx, s.idCollection+"_1", props) + if exist || errValidate == nil { + t.Error(errValidate) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} + +func TestVerifyExistAndMustExistValue(t *testing.T) { + // 1-Establish a Session instance + s := &Session{} + + //2-Creating test combinations + t.Run("Checking that values exist and should exist", func(t *testing.T) { + exist := true + mustExist := true + var errFunction error + err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) + if err != nil { + t.Error(err) + } + }) + t.Run("Checking that values exist and should not exist", func(t *testing.T) { + exist := true + mustExist := false + var errFunction error + err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) + if err == nil { + t.Error(err) + } + }) + t.Run("Checking that values do not exist and should exist", func(t *testing.T) { + exist := false + mustExist := true + var errFunction error + err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) + if err == nil { + t.Error(err) + } + }) + t.Run("Checking that values don't exist and shouldn't exist", func(t *testing.T) { + exist := false + mustExist := false + var errFunction error + err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) + if err != nil { + t.Error(err) + } + }) + t.Run("Checking for a previous error", func(t *testing.T) { + exist := false + mustExist := true + errFunction := errors.New("errorFunction is not nil") + err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) + if err == nil { + t.Error(err) + } + }) +} + +func TestVerifyExistID(t *testing.T) { + // 1-Establish a Session instance, a context, a MongoDB collection, and a _id + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + collectionName := "example" + s.GenerateUUIDStoreItStep(ctx) + + // 2-Create a connection and insert a document into the "example" collection + mongoConnection(s, t) + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) + + // 3-Check if the s.idCollection exists + t.Run("Verify that the value exists in the _id field", func(t *testing.T) { + _, err := s.VerifyExistID(ctx, s.idCollection+"_1") + if err != nil { + t.Error(err) + } + }) + t.Run("Verify that the value does not exist in the _id field", func(t *testing.T) { + _, err := s.VerifyExistID(ctx, s.idCollection+"_2") + if err == nil { + t.Error(err) + } + }) + + // 4-Delete all documents and close connection + s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) + s.MongoDisconnectionStep() +} diff --git a/steps/mongo/session_test.go b/steps/mongo/session_test.go index ea61d19a..de366896 100644 --- a/steps/mongo/session_test.go +++ b/steps/mongo/session_test.go @@ -16,825 +16,289 @@ package mongo import ( "context" - "errors" - "reflect" + "fmt" "testing" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - - "github.com/TelefonicaTC2Tech/golium" + "go.mongodb.org/mongo-driver/mongo" ) - -// FUNCTIONS CALLED BY STEPS - -func TestCheckMongoFieldDoesNotExistOrEmptyStep(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check if the field names do not exist or are empty - t.Run("Checking that the 'fieldEmpty' field does not exist or is empty in the MongoDB collection", func(t *testing.T) { - fieldSearched := "fieldEmpty" - err := s.CheckMongoFieldDoesNotExistOrEmptyStep(ctx, collectionName, fieldSearched, s.idCollection+"_1") - if err != nil { - t.Error(err) - } - }) - t.Run("Checking that the 'fieldUnexist' field does not exist in the MongoDB collection", func(t *testing.T) { - fieldSearched := "fieldUnexist" - err := s.CheckMongoFieldDoesNotExistOrEmptyStep(ctx, collectionName, fieldSearched, s.idCollection+"_1") - if err != nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestCheckMongoFieldNameStep(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check whether or not the name of the searched field exists - // If you want to check that it doesn't exist, you have to pass "not" as a parameter - t.Run("Verify that the 'fieldString' field exists in the MongoDB collection", func(t *testing.T) { - fieldSearched := "fieldString" - err := s.CheckMongoFieldNameStep(ctx, collectionName, fieldSearched, "yes", s.idCollection+"_1") - if err != nil { - t.Error(err) - } - }) - t.Run("Verify that the 'fieldEmpty' field exists in the MongoDB collection", func(t *testing.T) { - fieldSearched := "fieldEmpty" - err := s.CheckMongoFieldNameStep(ctx, collectionName, fieldSearched, "does", s.idCollection+"_1") - if err != nil { - t.Error(err) - } - }) - t.Run("Verify that the 'fieldUnexist' field does not exist in the MongoDB collection", func(t *testing.T) { - fieldSearched := "fieldUnexist" - err := s.CheckMongoFieldNameStep(ctx, collectionName, fieldSearched, "not", s.idCollection+"_1") - if err != nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestCheckMongoValueIDStep(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check whether or not the _id sought exists - // If you want to check that it doesn't exist, you have to pass "not" as a parameter - t.Run("Verify that the '_id' exists in the MongoDB collection", func(t *testing.T) { - err := s.CheckMongoValueIDStep(ctx, collectionName, s.idCollection+"_1", "yes") - if err != nil { - t.Error(err) - } - }) - t.Run("Verify that the '_id' does not exist in the MongoDB collection", func(t *testing.T) { - err := s.CheckMongoValueIDStep(ctx, collectionName, "123456_id_unexist", "not") - if err != nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestCheckMongoValuesStep(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check whether or not the values you are looking for exist - // If you want to check that it doesn't exist, you have to pass "not" as a parameter - t.Run("Verify that the searched values exist in the MongoDB collection", func(t *testing.T) { - // Data that will be searched in the collection and that will be found - propTableYes := golium.NewTable([][]string{ - {"field","value"}, - {"_id","[CTXT:_ID]_1"}, - {"fieldString","Example field string 1"}, - {"fieldInt","[NUMBER:1]"}, - {"fieldFloat","[NUMBER:3.14]"}, - {"fieldBool","[TRUE]"}, - {"fieldSlice.#","[NUMBER:3]"}, - {"fieldSlice.0","itemSlice_1"}, - {"fieldSlice.1","itemSlice20"}, - {"fieldSlice.2","itemSlice30"}, - {"fieldEmpty","[EMPTY]"}, - {"fieldMap.fieldString","Example field in map string 1"}, - {"fieldMap.fieldInt","[NUMBER:10]"}, - {"fieldMap.fieldFloat","[NUMBER:1974.1976]"}, - {"fieldMap.fieldBool","[FALSE]"}, - {"fieldMap.fieldSliceEmpty.#","[NUMBER:0]"}, - {"fieldMap.fieldSliceEmpty.0","[NULL]"}, - {"fieldMap.fieldSliceEmpty.1",""}, - {"fieldMap.fieldSliceEmpty.2","[EMPTY]"}, - {"fieldMap.fieldMap2.fieldString","Example field in map map string 1"}, - {"fieldMap.fieldMap2.fieldInt","[NUMBER:100]"}, - {"fieldMap.fieldMap2.fieldFloat","[NUMBER:1974.1976]"}, - {"fieldMap.fieldMap2.fieldBool","[FALSE]"}, - {"fieldMap.fieldMap2.fieldEmpty","[NULL]"}, - {"fieldMap.fieldMap2.fieldEmptyText","[EMPTY]"}, - }) - err := s.CheckMongoValuesStep(ctx, collectionName, s.idCollection+"_1", "yes", propTableYes) - if err != nil { - t.Error(err) - } - }) - t.Run("Verify that the searched values do not exist in the MongoDB collection", func(t *testing.T) { - // Data that will be searched in the collection and will not be found - propTableNot := golium.NewTable([][]string{ - {"field","value"}, - {"_id","123456_id_unexist"}, - }) - err := s.CheckMongoValuesStep(ctx, collectionName, s.idCollection+"_1", "not", propTableNot) - if err != nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestCheckNumberDocumentscollectionNameStep(t *testing.T) { - // 1-Establish a Session instance, context, and MongoDB collection - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - - // 2-Create a connection and create 10 documents from the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 10, collectionName) - - // 3-Count all the documents - t.Run("Contar los documentos de una colección de MongoDB", func(t *testing.T) { - err:= s.CheckNumberDocumentscollectionNameStep(collectionName, 10) - if err != nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestCreateDocumentscollectionNameStep(t *testing.T) { - // 1-Establish a Session instance, context, and MongoDB collection - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - - // 2-Create a connection and delete all documents in the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - err := s.CheckNumberDocumentscollectionNameStep(collectionName, 0) - if err != nil { - t.Error(err) +func TestPing(t *testing.T) { + tests := []struct { + name string + pingErr error + wantErr bool + }{ + { + name: "Ping error", + pingErr: fmt.Errorf("ping error"), + wantErr: true, + }, + { + name: "Ping done", + pingErr: nil, + wantErr: false, + }, } - - // 3-Insert a document - err = s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - if err != nil { - t.Error(err) - } - - // 4-Check that it has been inserted and then delete all documents - t.Run("Verify that the document has been inserted into MongoDB", func(t *testing.T) { - err := s.CheckNumberDocumentscollectionNameStep(collectionName, 1) - if err != nil { - t.Error(err) - } - }) - - // 5-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestDeleteAllDocumentscollectionNameStep(t *testing.T) { - // 1-Establish a Session instance, context, and MongoDB collection - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - - // 2-Create a connection and insert 10 documents into the "example" collection - mongoConnection(s, t) - s.CreateDocumentscollectionNameStep(ctx, 10, collectionName) - - // 3-Delete all documents - t.Run("Deleting all documents in a MongoDB collection", func(t *testing.T) { - err := s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - if err != nil { - t.Error(err) - } - }) - - // 4-Verify that all documents have been deleted - err := s.CheckNumberDocumentscollectionNameStep(collectionName, 0) - if err != nil { - t.Error(err) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Session{} + s.MongoClientService = ClientServiceFuncMock{} + PingError = tt.pingErr + if err := s.MongoClientService.Ping(context.Background(), nil, s.client); (err != nil) != tt.wantErr { + t.Errorf("Session.Ping() error = %v, wantErr %v", err, tt.wantErr) + } + }) } } -func TestDeleteDocumentscollectionNameStep(t *testing.T) { - // 1-Establish a Session instance, context, and MongoDB collection - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - - // 2-Create a connection and 3 documents from the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 3, collectionName) - - // 3-Delete a document - t.Run("Deleting a document in MongoDB", func(t *testing.T) { - err := s.DeleteDocumentscollectionNameStep(ctx, collectionName, "fieldInt", "1") - if err != nil { - t.Error(err) - } - }) - - // 4-Verify that it has been deleted, delete all documents and close connection - err:= s.CheckNumberDocumentscollectionNameStep(collectionName, 2) - if err != nil { - t.Error(err) +func TestDatabase(t *testing.T) { + tests := []struct { + name string + database *mongo.Database + wantErr bool + }{ + { + name: "Database error", + database: nil, + wantErr: true, + }, + { + name: "Database done", + database: &mongo.Database{}, + wantErr: false, + }, } - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestGenerateUUIDStoreItStep(t *testing.T) { - // 1-Establish a Session instance and context - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - - // 2-Generating a Random UUID - t.Run("Generating a Random UUID", func(t *testing.T) { - if s.GenerateUUIDStoreItStep(ctx) != nil { - t.Errorf("Error generating a random UUID") - } - }) - - // 3-Verifying that a UUID has been created - if len(s.idCollection) != 36 { - t.Errorf("s.idCollection was not created") + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Session{} + s.MongoClientService = ClientServiceFuncMock{} + DatabaseDatabase = tt.database + if d := s.MongoClientService.Database("test", s.client); (d != nil) == tt.wantErr { + t.Errorf("Session.Database() error, wantErr %v", tt.wantErr) + } + }) } } -func mongoConnection(s *Session, t *testing.T) { - propTable := golium.NewTable([][]string{ - {"field", "value"}, - {"User", "mongoadmin"}, - {"Password", "mongoadmin"}, - {"Host", "localhost:27017"}, - {"AuthSource", "admin"}, - {"Database", "golium-demo"}, - }) - t.Run("Connecting to MongoDB", func(t *testing.T) { - err := s.MongoConnectionStep(context.Background(), propTable) - if err != nil { - t.Error(err) - } - }) -} - -func TestMongoConnectionStep(t *testing.T) { - s := &Session{} - mongoConnection(s, t) - s.MongoDisconnectionStep() -} - -func TestMongoDisconnectionStep(t *testing.T) { - // 1-Establish a Session instance, context, and MongoDB collection - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - - // 2-Create a connection and insert 3 collections - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 3, collectionName) - err := s.CheckNumberDocumentscollectionNameStep(collectionName, 3) - if err != nil { - t.Errorf("Error al contar los documentos de la colección '%s'", collectionName) +func TestDisconnect(t *testing.T) { + tests := []struct { + name string + disconnectErr error + wantErr bool + }{ + { + name: "Disconnect error", + disconnectErr: fmt.Errorf("Disconnect error"), + wantErr: true, + }, + { + name: "Disconnect done", + disconnectErr: nil, + wantErr: false, + }, } - - // 3-Close the connection to MongoDB - t.Run("Close the connection to MongoDB", func(t *testing.T) { - err := s.MongoDisconnectionStep() - if err != nil { - t.Error(err) - } - }) - - // 4-Verify that the connection to MongoDB has been closed - errString := s.CheckNumberDocumentscollectionNameStep(collectionName, 3).Error() - if errString != "error: query error: 'client is disconnected'" { - t.Errorf("Connection to MongoDB is still open") + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Session{} + s.MongoClientService = ClientServiceFuncMock{} + DisconnectError = tt.disconnectErr + if err := s.MongoClientService.Disconnect(context.Background(), s.client); (err != nil) != tt.wantErr { + t.Errorf("Session.Disconnect() error = %v, wantErr %v", err, tt.wantErr) + } + }) } } - -// GENERIC FUNCTIONS - -func TestContainsElements(t *testing.T) { - t.Run("Element exists in slice", func(t *testing.T) { - slice := []int{1, 2, 3, 4, 5} - element := 3 - result := ContainsElements(element, slice) - if !result { - t.Errorf("Expected %v to be in the slice, but it wasn't.", element) - } - }) - t.Run("Element does not exist in slice", func(t *testing.T) { - slice := []string{"Alcorcon", "Madrid", "Barcelona"} - element := "Valladolid" - result := ContainsElements(element, slice) - if result { - t.Errorf("Expected %v not to be in the slice, but it was.", element) - } - }) -} - -func TestGetFilter(t *testing.T) { - t.Run("Create filter with non-nil value", func(t *testing.T) { - key := "age" - value := 30 - filter := GetFilter(key, value) - expectedFilter := bson.M{"age": 30} - if !reflect.DeepEqual(filter, expectedFilter) { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) - t.Run("Create filter with nil value", func(t *testing.T) { - key := "name" - var value interface{} = nil - filter := GetFilter(key, value) - expectedFilter := bson.M{"name": nil} - if !reflect.DeepEqual(filter, expectedFilter) { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) -} - -func TestGetFilterConverted(t *testing.T) { - t.Run("Convert to boolean (true)", func(t *testing.T) { - field := "is_boolean" - value := "true" - filter := GetFilterConverted(field, value) - expectedFilter := primitive.M{field: true} - if filter[field] != expectedFilter[field] { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) - t.Run("Convert to boolean (false)", func(t *testing.T) { - field := "is_boolean" - value := "false" - filter := GetFilterConverted(field, value) - expectedFilter := primitive.M{field: false} - if filter[field] != expectedFilter[field] { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) - t.Run("Convert to integer", func(t *testing.T) { - field := "quantity number" - value := "42" - filter := GetFilterConverted(field, value) - expectedFilter := primitive.M{field: 42} - if filter[field] != expectedFilter[field] { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) - t.Run("Convert to float64", func(t *testing.T) { - field := "quantity decimal number" - value := "99.99" - filter := GetFilterConverted(field, value) - expectedFilter := primitive.M{field: 99.99} - if filter[field] != expectedFilter[field] { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) - t.Run("Convert to nil (empty)", func(t *testing.T) { - field := "nil or empty" - value := "[EMPTY]" - filter := GetFilterConverted(field, value) - expectedFilter := primitive.M{field: nil} - if filter[field] != expectedFilter[field] { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) - t.Run("No conversion (string)", func(t *testing.T) { - field := "Nadie" - value := "Juan" - filter := GetFilterConverted(field, value) - expectedFilter := primitive.M{field: value} - if filter[field] != expectedFilter[field] { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) -} - -func TestGetOptionsSearchAllFields(t *testing.T) { - t.Run("Check creates an 'Options' to search all fields in the collection", func(t *testing.T) { - options := GetOptionsSearchAllFields() - if options.Projection == nil { - t.Errorf("Expected Projection to be nil, but got: %v", options.Projection) - } - }) -} - -func TestVerifyMustExist(t *testing.T) { - t.Run("exist is true", func(t *testing.T) { - if VerifyMustExist("does exist") != true { - t.Errorf("Expected true, but got false") - } - }) - t.Run("exist is false", func(t *testing.T) { - if VerifyMustExist("does not exist") != false { - t.Errorf("Expected false, but got true") - } - }) -} - - -// SESSION FUNCTIONS - -func TestCreateDocumentsCollection(t *testing.T) { - // 1-Establish a Session instance and context - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - - // 2-Checks if the function can create an array with the correct number of interfaces - // and if the values within the array are as expected - t.Run("Create array with 3 interfaces", func(t *testing.T) { - count := 3 - result := s.CreateDocumentsCollection(ctx, count) - if len(result) != count { - t.Errorf("Expected array length of %d, but got %d", count, len(result)) - } - for i := 0; i < count; i++ { - if result[i].(map[string]interface{})["fieldInt"] != i+1 { - t.Errorf("Expected value at index %d to be %d, but got %v", i, i, result[i]) +func TestCollectionCollection(t *testing.T) { + tests := []struct { + name string + collection *mongo.Collection + wantErr bool + }{ + { + name: "Collection error", + collection: nil, + wantErr: true, + }, + { + name: "Collection done", + collection: &mongo.Collection{}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Session{} + s.MongoCollectionService = CollectionServiceFuncMock{} + CollectionCollection = tt.collection + if d := s.MongoCollectionService.Collection("test", &mongo.Database{}); (d != nil) == tt.wantErr { + t.Errorf("Session.Collection() error, wantErr %v", tt.wantErr) } - } - }) - t.Run("Create empty array", func(t *testing.T) { - count := 0 - result := s.CreateDocumentsCollection(ctx, count) - if len(result) != count { - t.Errorf("Expected empty array, but got an array of length %d", len(result)) - } - }) -} - -func TestExistFieldCollection(t *testing.T) { - s := &Session{} - s.fieldsCollectionName = []string{"Alcorcon", "Madrid", "Barcelona"} - - t.Run("Verify that an element exists in fieldsCollectionName", func(t *testing.T) { - if s.ExistFieldCollection("Alcorcon") != true { - t.Errorf("'Alcorcon' exist in fieldsCollectionName") - } - }) - t.Run("Verify that an item does not exist in fieldsCollectionName", func(t *testing.T) { - if s.ExistFieldCollection("Valladolid") != false { - t.Errorf("'Valladolid' does not exist in fieldsCollectionName") - } - }) -} - -func TestGetDecodeDocument(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - fieldSearched := "_id" - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Create the s.singleResult and get the document decoded - t.Run("Check GetDecodeDocument decodes the BSON document in the bsonDoc variable", func(t *testing.T) { - searchedValue := s.idCollection+"_1" - s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) - _, err := s.GetDecodeDocument(*s.singleResult) - if err != nil { - t.Error(err) - } - }) - t.Run("Check GetDecodeDocument does not decode the BSON document in the bsonDoc variable", func(t *testing.T) { - searchedValue := s.idCollection+"_2" - s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) - _, err := s.GetDecodeDocument(*s.singleResult) - if err == nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - - -func TestSetCollection(t *testing.T) { - // 1-Establish a Session instance, context, and MongoDB collection - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Verify that the collection is created - t.Run("Verify that the collection is created", func(t *testing.T) { - s.SetCollection(collectionName) - if s.collection.Name() != collectionName { - t.Errorf("s.collection is not %s, it is %s", collectionName, s.collection.Name()) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestSetDataCollectionJSONBytes(t *testing.T) { - // 1-Establish a Session instance - s := &Session{} - - // 2- Check converts BSON to JSON - t.Run("Check convert correct BSON object to JSON", func(t *testing.T) { - doc := bson.D{ - {Key: "name", Value: "Juan Nadie"}, - {Key: "age", Value: 30}, - } - err := s.SetDataCollectionJSONBytes(doc) - if err != nil { - t.Error(err) - } - }) - t.Run("Check convert incorrect BSON object to JSON", func(t *testing.T) { - // A function in the value, which is not serializable in JSON - doc := bson.D{ - {"name", func() {}}, - } - err := s.SetDataCollectionJSONBytes(doc) - if err == nil { - t.Error(err) - } - }) + }) + } } -func TestSetFieldsCollectionName(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Verify that the s.fieldsCollectionName slice is empty - if len(s.fieldsCollectionName) != 0 { - t.Error("s.fieldsCollectionName is not empty: ",s.fieldsCollectionName) +func TestCollectionName(t *testing.T) { + tests := []struct { + name string + nameString string + wantErr bool + }{ + { + name: "Collection name error", + nameString: "", + wantErr: true, + }, + { + name: "Collection name done", + nameString: "test-collection", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Session{} + s.collection = &mongo.Collection{} + s.MongoCollectionService = CollectionServiceFuncMock{} + NameString = tt.nameString + if n := s.MongoCollectionService.Name(s.collection); (len(n) == 0) != tt.wantErr { + t.Errorf("Session.Name() error, wantErr %v", tt.wantErr) + } + }) } - - // 4-Verify that a slice with field names is saved in s.fieldsCollectionName - t.Run("Verify that a slice is saved", func(t *testing.T) { - err := s.SetFieldsCollectionName(ctx, s.idCollection+"_1" ) - if err != nil { - t.Error(err) - } - if len(s.fieldsCollectionName) == 0 { - t.Error("s.fieldsCollectionName is empty: ",s.fieldsCollectionName) - } - }) - t.Run("Verify that a slice is not saved if the searched value does not exist", func(t *testing.T) { - err := s.SetFieldsCollectionName(ctx, s.idCollection+"_2" ) - if err == nil { - t.Error(err) - } - }) - - // 5-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() } - -func TestSetSingleResult(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - fieldSearched := "_id" - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check for s.singleResult - t.Run("Verify that the s.singleResult exists", func(t *testing.T) { - searchedValue := s.idCollection+"_1" - err := s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) - if err != nil { - t.Error(err) - } - }) - t.Run("Checking that the s.singleResult does not exist", func(t *testing.T) { - searchedValue := s.idCollection+"_2" - err := s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) - if err == nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() +func TestCollectionFind(t *testing.T) { + tests := []struct { + name string + findCursor *mongo.Cursor + findError error + wantErr bool + }{ + { + name: "Collection find error", + findCursor: nil, + findError: fmt.Errorf("find error"), + wantErr: true, + }, + { + name: "Collection find done", + findCursor: &mongo.Cursor{}, + findError: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Session{} + s.collection = &mongo.Collection{} + s.MongoCollectionService = CollectionServiceFuncMock{} + FindCursor = tt.findCursor + FindError = tt.findError + _, err := s.MongoCollectionService.Find(context.Background(), nil, s.collection) + if (err != nil) != tt.wantErr { + t.Errorf("Session.Find() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } } -func TestValidateDataMongo(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check the existence of the searched values - t.Run("Verify that the searched values exist in the MongoDB collection", func(t *testing.T) { - // Data that will be searched in the collection and that will be found - propTable := golium.NewTable([][]string{ - {"field","value"}, - {"_id",s.idCollection+"_1"}, - {"fieldString","Example field string 1"}, - }) - props, _ := golium.ConvertTableToMap(ctx, propTable) - exist, errValidate := s.ValidateDataMongo(ctx, s.idCollection+"_1", props) - if !exist || errValidate != nil { - t.Error(errValidate) - } - }) - t.Run("Verify that the searched values do not exist in the MongoDB collection", func(t *testing.T) { - // Data that will be searched in the collection and that will not be found - propTable := golium.NewTable([][]string{ - {"field","value"}, - {"_id","123456_id_unexist"}, - }) - props, _ := golium.ConvertTableToMap(ctx, propTable) - exist, errValidate := s.ValidateDataMongo(ctx, s.idCollection+"_1", props) - if exist || errValidate == nil { - t.Error(errValidate) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() +func TestCollectionFindOne(t *testing.T) { + tests := []struct { + name string + findOneSingleResult *mongo.SingleResult + wantErr bool + }{ + { + name: "Collection find one error", + findOneSingleResult: nil, + wantErr: true, + }, + { + name: "Collection find one done", + findOneSingleResult: &mongo.SingleResult{}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Session{} + s.collection = &mongo.Collection{} + s.MongoCollectionService = CollectionServiceFuncMock{} + FindOneSingleResult = tt.findOneSingleResult + if f := s.MongoCollectionService.FindOne(context.Background(), nil, s.collection); (f != nil) == tt.wantErr { + t.Errorf("Session.FindOne() error, wantErr %v", tt.wantErr) + } + }) + } } -func TestVerifyExistAndMustExistValue(t *testing.T) { - // 1-Establish a Session instance - s := &Session{} - - //2-Creating test combinations - t.Run("Checking that values exist and should exist", func(t *testing.T) { - exist := true - mustExist := true - var errFunction error - err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) - if err != nil { - t.Error(err) - } - }) - t.Run("Checking that values exist and should not exist", func(t *testing.T) { - exist := true - mustExist := false - var errFunction error - err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) - if err == nil { - t.Error(err) - } - }) - t.Run("Checking that values do not exist and should exist", func(t *testing.T) { - exist := false - mustExist := true - var errFunction error - err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) - if err == nil { - t.Error(err) - } - }) - t.Run("Checking that values don't exist and shouldn't exist", func(t *testing.T) { - exist := false - mustExist := false - var errFunction error - err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) - if err != nil { - t.Error(err) - } - }) - t.Run("Checking for a previous error", func(t *testing.T) { - exist := false - mustExist := true - errFunction := errors.New("errorFunction is not nil") - err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) - if err == nil { - t.Error(err) - } - }) +func TestCollectionInsertMany(t *testing.T) { + tests := []struct { + name string + insertManyResult *mongo.InsertManyResult + insertManyError error + wantErr bool + }{ + { + name: "Collection insert many error", + insertManyResult: nil, + insertManyError: fmt.Errorf("insert many error"), + wantErr: true, + }, + { + name: "Collection insert many done", + insertManyResult: &mongo.InsertManyResult{}, + insertManyError: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Session{} + s.collection = &mongo.Collection{} + s.MongoCollectionService = CollectionServiceFuncMock{} + InsertManyInsertManyResult = tt.insertManyResult + InsertManyError = tt.insertManyError + _, err := s.MongoCollectionService.InsertMany(context.Background(), nil, s.collection) + if (err != nil) != tt.wantErr { + t.Errorf("Session.InsertMany() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } } - -func TestVerifyExistID(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check if the s.idCollection exists - t.Run("Verify that the value exists in the _id field", func(t *testing.T) { - _, err := s.VerifyExistID(ctx, s.idCollection+"_1") - if err != nil { - t.Error(err) - } - }) - t.Run("Verify that the value does not exist in the _id field", func(t *testing.T) { - _, err := s.VerifyExistID(ctx, s.idCollection+"_2") - if err == nil { - t.Error(err) - } - }) - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() +func TestCollectionDeletetMany(t *testing.T) { + tests := []struct { + name string + deleteResult *mongo.DeleteResult + deleteResultError error + wantErr bool + }{ + { + name: "Collection delete many error", + deleteResult: nil, + deleteResultError: fmt.Errorf("delete many error"), + wantErr: true, + }, + { + name: "Collection delete many done", + deleteResult: &mongo.DeleteResult{}, + deleteResultError: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Session{} + s.collection = &mongo.Collection{} + s.MongoCollectionService = CollectionServiceFuncMock{} + DeleteResultDeleteResult = tt.deleteResult + DeleteResultError = tt.deleteResultError + _, err := s.MongoCollectionService.DeleteMany(context.Background(), nil, nil, s.collection) + if (err != nil) != tt.wantErr { + t.Errorf("Session.DeleteMany() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } } diff --git a/steps/mongo/steps.go b/steps/mongo/steps.go index 6d8b3ed8..6ceee043 100755 --- a/steps/mongo/steps.go +++ b/steps/mongo/steps.go @@ -26,7 +26,7 @@ type Steps struct { // InitializeSteps initializes all the steps func (us Steps) InitializeSteps(ctx context.Context, scenCtx *godog.ScenarioContext) context.Context { - // Initialize the HTTP session in the context + // Initialize the Mongo session in the context ctx = InitializeContext(ctx) session := GetSession(ctx) @@ -44,7 +44,7 @@ func (us Steps) InitializeSteps(ctx context.Context, scenCtx *godog.ScenarioCont }) scenCtx.Step(`^I check that in the MongoDB "([^"]*)" collection, "([^"]*)" field does not exist or is empty for the "([^"]*)" _id$`, func(collectionName, fieldSearched, idCollection string) error { return session.CheckMongoFieldDoesNotExistOrEmptyStep(ctx, golium.ValueAsString(ctx, collectionName), golium.ValueAsString(ctx, fieldSearched), golium.ValueAsString(ctx, idCollection)) - }) + }) scenCtx.Step(`^I create "(\d+)" documents in the MongoDB "([^"]*)" collection$`, func(num int, collectionName string) error { return session.CreateDocumentscollectionNameStep(ctx, num, golium.ValueAsString(ctx, collectionName)) }) diff --git a/steps/redis/steps.go b/steps/redis/steps.go index 5e67e461..448cc149 100755 --- a/steps/redis/steps.go +++ b/steps/redis/steps.go @@ -30,7 +30,7 @@ type Steps struct { // InitializeSteps initializes all the steps. func (cs Steps) InitializeSteps(ctx context.Context, scenCtx *godog.ScenarioContext) context.Context { - // Initialize the HTTP session in the context + // Initialize the Redis session in the context ctx = InitializeContext(ctx) session := GetSession(ctx) // Initialize the steps From eb12310a4e75b5a9ff09b0a2ad132dce0febb210 Mon Sep 17 00:00:00 2001 From: mariolg Date: Wed, 15 Nov 2023 19:11:07 +0100 Subject: [PATCH 19/27] feat: fix feature --- go.mod | 4 ++-- test/acceptance/features/mongo.feature | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 151a15f4..4243ecf7 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,8 @@ require ( github.com/tidwall/gjson v1.13.0 github.com/tidwall/sjson v1.2.4 github.com/xeipuuv/gojsonschema v1.2.0 + go.mongodb.org/mongo-driver v1.12.1 + golang.org/x/exp v0.0.0-20230306221820-f0f767cdffd6 gopkg.in/yaml.v3 v3.0.1 ) @@ -85,9 +87,7 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect - go.mongodb.org/mongo-driver v1.12.1 // indirect golang.org/x/crypto v0.5.0 // indirect - golang.org/x/exp v0.0.0-20230306221820-f0f767cdffd6 // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/net v0.8.0 // indirect golang.org/x/sync v0.1.0 // indirect diff --git a/test/acceptance/features/mongo.feature b/test/acceptance/features/mongo.feature index 044ae6b4..23ed3a90 100644 --- a/test/acceptance/features/mongo.feature +++ b/test/acceptance/features/mongo.feature @@ -2,7 +2,7 @@ # SDET Team Feature: MongoDB client - Examples of MongoDB access and data processing. It is possible to: + Examples of MongoDB access and data processing. It is possible to: - Creation of documents. - Deletion of documents. - Checking the number of documents. @@ -28,8 +28,7 @@ Feature: MongoDB client @mongodb Scenario: Create a collection, check it and delete it. - Given I connect to MongoDB - When I create "2" documents in the MongoDB "test-colection" collection + Given I create "2" documents in the MongoDB "test-colection" collection Then I check that the number of documents in collection "test-colection" is "2" When I delete documents from the MongoDB "test-colection" collection whose "fieldString" field is "Example field string 1" value Then I check that the number of documents in collection "test-colection" is "1" From 81b7382e11f219ede5ab0bf270bb2c22b8f4b76d Mon Sep 17 00:00:00 2001 From: mariolg Date: Wed, 15 Nov 2023 19:15:09 +0100 Subject: [PATCH 20/27] feat: avoid lint in files to remove --- sonar-project.properties | 2 +- steps/mongo/{session_refactor.go => session_toremove.go} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename steps/mongo/{session_refactor.go => session_toremove.go} (100%) diff --git a/sonar-project.properties b/sonar-project.properties index aea79972..f1d21162 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -5,7 +5,7 @@ sonar.organization=telefonicatc2tech sonar.go.tests.reportPaths=test-report.out sonar.go.coverage.reportPaths=coverage.txt sonar.go.golangci-lint.reportPaths=golangci-report.xml -sonar.coverage.exclusions=**/*context.go,**/*logger.go,**/*steps.go,**/*client.go,**/*collection.go,**/mock/**/*.go +sonar.coverage.exclusions=**/*context.go,**/*logger.go,**/*steps.go,**/*client.go,**/*collection.go,**/mock/**/*.go,**/*toremove.go sonar.sources=. sonar.exclusions=**/*_test.go diff --git a/steps/mongo/session_refactor.go b/steps/mongo/session_toremove.go similarity index 100% rename from steps/mongo/session_refactor.go rename to steps/mongo/session_toremove.go From 0a2bc1f1358437c4ccacbef2fb1a05c54d068850 Mon Sep 17 00:00:00 2001 From: mariolg Date: Wed, 15 Nov 2023 19:24:44 +0100 Subject: [PATCH 21/27] feat: fix sonar problems --- sonar-project.properties | 2 +- steps/mongo/session_test.go | 7 +- steps/mongo/session_toremove.go | 835 -------------------------------- 3 files changed, 4 insertions(+), 840 deletions(-) delete mode 100644 steps/mongo/session_toremove.go diff --git a/sonar-project.properties b/sonar-project.properties index f1d21162..aea79972 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -5,7 +5,7 @@ sonar.organization=telefonicatc2tech sonar.go.tests.reportPaths=test-report.out sonar.go.coverage.reportPaths=coverage.txt sonar.go.golangci-lint.reportPaths=golangci-report.xml -sonar.coverage.exclusions=**/*context.go,**/*logger.go,**/*steps.go,**/*client.go,**/*collection.go,**/mock/**/*.go,**/*toremove.go +sonar.coverage.exclusions=**/*context.go,**/*logger.go,**/*steps.go,**/*client.go,**/*collection.go,**/mock/**/*.go sonar.sources=. sonar.exclusions=**/*_test.go diff --git a/steps/mongo/session_test.go b/steps/mongo/session_test.go index de366896..acf93ea7 100644 --- a/steps/mongo/session_test.go +++ b/steps/mongo/session_test.go @@ -191,13 +191,12 @@ func TestCollectionFind(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s := &Session{} - s.collection = &mongo.Collection{} s.MongoCollectionService = CollectionServiceFuncMock{} FindCursor = tt.findCursor FindError = tt.findError - _, err := s.MongoCollectionService.Find(context.Background(), nil, s.collection) - if (err != nil) != tt.wantErr { - t.Errorf("Session.Find() error = %v, wantErr %v", err, tt.wantErr) + c, _ := s.MongoCollectionService.Find(context.Background(), nil, &mongo.Collection{}) + if (c != nil) != tt.wantErr { + t.Errorf("Session.Find() error, wantErr %v", tt.wantErr) } }) } diff --git a/steps/mongo/session_toremove.go b/steps/mongo/session_toremove.go deleted file mode 100644 index 4c4b6d0e..00000000 --- a/steps/mongo/session_toremove.go +++ /dev/null @@ -1,835 +0,0 @@ -// Copyright 2021 Telefonica Cybersecurity & Cloud Tech SL -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package mongo - -import ( - "context" - "errors" - "reflect" - "testing" - - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - - "github.com/TelefonicaTC2Tech/golium" -) - -// FUNCTIONS CALLED BY STEPS - -func TestCheckMongoFieldDoesNotExistOrEmptyStep(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check if the field names do not exist or are empty - t.Run("Checking that the 'fieldEmpty' field does not exist or is empty in the MongoDB collection", func(t *testing.T) { - fieldSearched := "fieldEmpty" - err := s.CheckMongoFieldDoesNotExistOrEmptyStep(ctx, collectionName, fieldSearched, s.idCollection+"_1") - if err != nil { - t.Error(err) - } - }) - t.Run("Checking that the 'fieldUnexist' field does not exist in the MongoDB collection", func(t *testing.T) { - fieldSearched := "fieldUnexist" - err := s.CheckMongoFieldDoesNotExistOrEmptyStep(ctx, collectionName, fieldSearched, s.idCollection+"_1") - if err != nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestCheckMongoFieldNameStep(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check whether or not the name of the searched field exists - // If you want to check that it doesn't exist, you have to pass "not" as a parameter - t.Run("Verify that the 'fieldString' field exists in the MongoDB collection", func(t *testing.T) { - fieldSearched := "fieldString" - err := s.CheckMongoFieldNameStep(ctx, collectionName, fieldSearched, "yes", s.idCollection+"_1") - if err != nil { - t.Error(err) - } - }) - t.Run("Verify that the 'fieldEmpty' field exists in the MongoDB collection", func(t *testing.T) { - fieldSearched := "fieldEmpty" - err := s.CheckMongoFieldNameStep(ctx, collectionName, fieldSearched, "does", s.idCollection+"_1") - if err != nil { - t.Error(err) - } - }) - t.Run("Verify that the 'fieldUnexist' field does not exist in the MongoDB collection", func(t *testing.T) { - fieldSearched := "fieldUnexist" - err := s.CheckMongoFieldNameStep(ctx, collectionName, fieldSearched, "not", s.idCollection+"_1") - if err != nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestCheckMongoValueIDStep(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check whether or not the _id sought exists - // If you want to check that it doesn't exist, you have to pass "not" as a parameter - t.Run("Verify that the '_id' exists in the MongoDB collection", func(t *testing.T) { - err := s.CheckMongoValueIDStep(ctx, collectionName, s.idCollection+"_1", "yes") - if err != nil { - t.Error(err) - } - }) - t.Run("Verify that the '_id' does not exist in the MongoDB collection", func(t *testing.T) { - err := s.CheckMongoValueIDStep(ctx, collectionName, "123456_id_unexist", "not") - if err != nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestCheckMongoValuesStep(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check whether or not the values you are looking for exist - // If you want to check that it doesn't exist, you have to pass "not" as a parameter - t.Run("Verify that the searched values exist in the MongoDB collection", func(t *testing.T) { - // Data that will be searched in the collection and that will be found - propTableYes := golium.NewTable([][]string{ - {"field", "value"}, - {"_id", "[CTXT:_ID]_1"}, - {"fieldString", "Example field string 1"}, - {"fieldInt", "[NUMBER:1]"}, - {"fieldFloat", "[NUMBER:3.14]"}, - {"fieldBool", "[TRUE]"}, - {"fieldSlice.#", "[NUMBER:3]"}, - {"fieldSlice.0", "itemSlice_1"}, - {"fieldSlice.1", "itemSlice20"}, - {"fieldSlice.2", "itemSlice30"}, - {"fieldEmpty", "[EMPTY]"}, - {"fieldMap.fieldString", "Example field in map string 1"}, - {"fieldMap.fieldInt", "[NUMBER:10]"}, - {"fieldMap.fieldFloat", "[NUMBER:1974.1976]"}, - {"fieldMap.fieldBool", "[FALSE]"}, - {"fieldMap.fieldSliceEmpty.#", "[NUMBER:0]"}, - {"fieldMap.fieldSliceEmpty.0", "[NULL]"}, - {"fieldMap.fieldSliceEmpty.1", ""}, - {"fieldMap.fieldSliceEmpty.2", "[EMPTY]"}, - {"fieldMap.fieldMap2.fieldString", "Example field in map map string 1"}, - {"fieldMap.fieldMap2.fieldInt", "[NUMBER:100]"}, - {"fieldMap.fieldMap2.fieldFloat", "[NUMBER:1974.1976]"}, - {"fieldMap.fieldMap2.fieldBool", "[FALSE]"}, - {"fieldMap.fieldMap2.fieldEmpty", "[NULL]"}, - {"fieldMap.fieldMap2.fieldEmptyText", "[EMPTY]"}, - }) - err := s.CheckMongoValuesStep(ctx, collectionName, s.idCollection+"_1", "yes", propTableYes) - if err != nil { - t.Error(err) - } - }) - t.Run("Verify that the searched values do not exist in the MongoDB collection", func(t *testing.T) { - // Data that will be searched in the collection and will not be found - propTableNot := golium.NewTable([][]string{ - {"field", "value"}, - {"_id", "123456_id_unexist"}, - }) - err := s.CheckMongoValuesStep(ctx, collectionName, s.idCollection+"_1", "not", propTableNot) - if err != nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestCheckNumberDocumentscollectionNameStep(t *testing.T) { - // 1-Establish a Session instance, context, and MongoDB collection - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - - // 2-Create a connection and create 10 documents from the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 10, collectionName) - - // 3-Count all the documents - t.Run("Contar los documentos de una colección de MongoDB", func(t *testing.T) { - err := s.CheckNumberDocumentscollectionNameStep(collectionName, 10) - if err != nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestCreateDocumentscollectionNameStep(t *testing.T) { - // 1-Establish a Session instance, context, and MongoDB collection - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - - // 2-Create a connection and delete all documents in the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - err := s.CheckNumberDocumentscollectionNameStep(collectionName, 0) - if err != nil { - t.Error(err) - } - - // 3-Insert a document - err = s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - if err != nil { - t.Error(err) - } - - // 4-Check that it has been inserted and then delete all documents - t.Run("Verify that the document has been inserted into MongoDB", func(t *testing.T) { - err := s.CheckNumberDocumentscollectionNameStep(collectionName, 1) - if err != nil { - t.Error(err) - } - }) - - // 5-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestDeleteAllDocumentscollectionNameStep(t *testing.T) { - // 1-Establish a Session instance, context, and MongoDB collection - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - - // 2-Create a connection and insert 10 documents into the "example" collection - mongoConnection(s, t) - s.CreateDocumentscollectionNameStep(ctx, 10, collectionName) - - // 3-Delete all documents - t.Run("Deleting all documents in a MongoDB collection", func(t *testing.T) { - err := s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - if err != nil { - t.Error(err) - } - }) - - // 4-Verify that all documents have been deleted - err := s.CheckNumberDocumentscollectionNameStep(collectionName, 0) - if err != nil { - t.Error(err) - } -} - -func TestDeleteDocumentscollectionNameStep(t *testing.T) { - // 1-Establish a Session instance, context, and MongoDB collection - ctx := InitializeContext(context.Background()) - s := GetSession(ctx) - collectionName := "example" - - // 2-Create a connection and 3 documents from the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 3, collectionName) - - // 3-Delete a document - t.Run("Deleting a document in MongoDB", func(t *testing.T) { - err := s.DeleteDocumentscollectionNameStep(ctx, collectionName, "fieldInt", "1") - if err != nil { - t.Error(err) - } - }) - - // 4-Verify that it has been deleted, delete all documents and close connection - err := s.CheckNumberDocumentscollectionNameStep(collectionName, 2) - if err != nil { - t.Error(err) - } - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestGenerateUUIDStoreItStep(t *testing.T) { - // 1-Establish a Session instance and context - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - - // 2-Generating a Random UUID - t.Run("Generating a Random UUID", func(t *testing.T) { - if s.GenerateUUIDStoreItStep(ctx) != nil { - t.Errorf("Error generating a random UUID") - } - }) - - // 3-Verifying that a UUID has been created - if len(s.idCollection) != 36 { - t.Errorf("s.idCollection was not created") - } -} - -func mongoConnection(s *Session, t *testing.T) { - propTable := golium.NewTable([][]string{ - {"field", "value"}, - {"User", "mongoadmin"}, - {"Password", "mongoadmin"}, - {"Host", "localhost:27017"}, - {"AuthSource", "admin"}, - {"Database", "golium-demo"}, - }) - t.Run("Connecting to MongoDB", func(t *testing.T) { - err := s.MongoConnectionStep(context.Background(), propTable) - if err != nil { - t.Error(err) - } - }) -} - -func TestMongoConnectionStep(t *testing.T) { - s := &Session{} - mongoConnection(s, t) - s.MongoDisconnectionStep() -} - -func TestMongoDisconnectionStep(t *testing.T) { - // 1-Establish a Session instance, context, and MongoDB collection - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - - // 2-Create a connection and insert 3 collections - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 3, collectionName) - err := s.CheckNumberDocumentscollectionNameStep(collectionName, 3) - if err != nil { - t.Errorf("Error al contar los documentos de la colección '%s'", collectionName) - } - - // 3-Close the connection to MongoDB - t.Run("Close the connection to MongoDB", func(t *testing.T) { - err := s.MongoDisconnectionStep() - if err != nil { - t.Error(err) - } - }) - - // 4-Verify that the connection to MongoDB has been closed - errString := s.CheckNumberDocumentscollectionNameStep(collectionName, 3).Error() - if errString != "error: query error: 'client is disconnected'" { - t.Errorf("Connection to MongoDB is still open") - } -} - -// GENERIC FUNCTIONS - -func TestContainsElements(t *testing.T) { - t.Run("Element exists in slice", func(t *testing.T) { - slice := []int{1, 2, 3, 4, 5} - element := 3 - result := ContainsElements(element, slice) - if !result { - t.Errorf("Expected %v to be in the slice, but it wasn't.", element) - } - }) - t.Run("Element does not exist in slice", func(t *testing.T) { - slice := []string{"Alcorcon", "Madrid", "Barcelona"} - element := "Valladolid" - result := ContainsElements(element, slice) - if result { - t.Errorf("Expected %v not to be in the slice, but it was.", element) - } - }) -} - -func TestGetFilter(t *testing.T) { - t.Run("Create filter with non-nil value", func(t *testing.T) { - key := "age" - value := 30 - filter := GetFilter(key, value) - expectedFilter := bson.M{"age": 30} - if !reflect.DeepEqual(filter, expectedFilter) { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) - t.Run("Create filter with nil value", func(t *testing.T) { - key := "name" - var value interface{} = nil - filter := GetFilter(key, value) - expectedFilter := bson.M{"name": nil} - if !reflect.DeepEqual(filter, expectedFilter) { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) -} - -func TestGetFilterConverted(t *testing.T) { - t.Run("Convert to boolean (true)", func(t *testing.T) { - field := "is_boolean" - value := "true" - filter := GetFilterConverted(field, value) - expectedFilter := primitive.M{field: true} - if filter[field] != expectedFilter[field] { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) - t.Run("Convert to boolean (false)", func(t *testing.T) { - field := "is_boolean" - value := "false" - filter := GetFilterConverted(field, value) - expectedFilter := primitive.M{field: false} - if filter[field] != expectedFilter[field] { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) - t.Run("Convert to integer", func(t *testing.T) { - field := "quantity number" - value := "42" - filter := GetFilterConverted(field, value) - expectedFilter := primitive.M{field: 42} - if filter[field] != expectedFilter[field] { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) - t.Run("Convert to float64", func(t *testing.T) { - field := "quantity decimal number" - value := "99.99" - filter := GetFilterConverted(field, value) - expectedFilter := primitive.M{field: 99.99} - if filter[field] != expectedFilter[field] { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) - t.Run("Convert to nil (empty)", func(t *testing.T) { - field := "nil or empty" - value := "[EMPTY]" - filter := GetFilterConverted(field, value) - expectedFilter := primitive.M{field: nil} - if filter[field] != expectedFilter[field] { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) - t.Run("No conversion (string)", func(t *testing.T) { - field := "Nadie" - value := "Juan" - filter := GetFilterConverted(field, value) - expectedFilter := primitive.M{field: value} - if filter[field] != expectedFilter[field] { - t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) - } - }) -} - -func TestGetOptionsSearchAllFields(t *testing.T) { - t.Run("Check creates an 'Options' to search all fields in the collection", func(t *testing.T) { - options := GetOptionsSearchAllFields() - if options.Projection == nil { - t.Errorf("Expected Projection to be nil, but got: %v", options.Projection) - } - }) -} - -func TestVerifyMustExist(t *testing.T) { - t.Run("exist is true", func(t *testing.T) { - if VerifyMustExist("does exist") != true { - t.Errorf("Expected true, but got false") - } - }) - t.Run("exist is false", func(t *testing.T) { - if VerifyMustExist("does not exist") != false { - t.Errorf("Expected false, but got true") - } - }) -} - -// SESSION FUNCTIONS - -func TestCreateDocumentsCollection(t *testing.T) { - // 1-Establish a Session instance and context - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - - // 2-Checks if the function can create an array with the correct number of interfaces - // and if the values within the array are as expected - t.Run("Create array with 3 interfaces", func(t *testing.T) { - count := 3 - result := s.CreateDocumentsCollection(ctx, count) - if len(result) != count { - t.Errorf("Expected array length of %d, but got %d", count, len(result)) - } - for i := 0; i < count; i++ { - if result[i].(map[string]interface{})["fieldInt"] != i+1 { - t.Errorf("Expected value at index %d to be %d, but got %v", i, i, result[i]) - } - } - }) - t.Run("Create empty array", func(t *testing.T) { - count := 0 - result := s.CreateDocumentsCollection(ctx, count) - if len(result) != count { - t.Errorf("Expected empty array, but got an array of length %d", len(result)) - } - }) -} - -func TestExistFieldCollection(t *testing.T) { - s := &Session{} - s.fieldsCollectionName = []string{"Alcorcon", "Madrid", "Barcelona"} - - t.Run("Verify that an element exists in fieldsCollectionName", func(t *testing.T) { - if s.ExistFieldCollection("Alcorcon") != true { - t.Errorf("'Alcorcon' exist in fieldsCollectionName") - } - }) - t.Run("Verify that an item does not exist in fieldsCollectionName", func(t *testing.T) { - if s.ExistFieldCollection("Valladolid") != false { - t.Errorf("'Valladolid' does not exist in fieldsCollectionName") - } - }) -} - -func TestGetDecodeDocument(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - fieldSearched := "_id" - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Create the s.singleResult and get the document decoded - t.Run("Check GetDecodeDocument decodes the BSON document in the bsonDoc variable", func(t *testing.T) { - searchedValue := s.idCollection + "_1" - s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) - _, err := s.GetDecodeDocument(*s.singleResult) - if err != nil { - t.Error(err) - } - }) - t.Run("Check GetDecodeDocument does not decode the BSON document in the bsonDoc variable", func(t *testing.T) { - searchedValue := s.idCollection + "_2" - s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) - _, err := s.GetDecodeDocument(*s.singleResult) - if err == nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestSetCollection(t *testing.T) { - // 1-Establish a Session instance, context, and MongoDB collection - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Verify that the collection is created - t.Run("Verify that the collection is created", func(t *testing.T) { - s.SetCollection(collectionName) - if s.collection.Name() != collectionName { - t.Errorf("s.collection is not %s, it is %s", collectionName, s.collection.Name()) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestSetDataCollectionJSONBytes(t *testing.T) { - // 1-Establish a Session instance - s := &Session{} - - // 2- Check converts BSON to JSON - t.Run("Check convert correct BSON object to JSON", func(t *testing.T) { - doc := bson.D{ - {Key: "name", Value: "Juan Nadie"}, - {Key: "age", Value: 30}, - } - err := s.SetDataCollectionJSONBytes(doc) - if err != nil { - t.Error(err) - } - }) - t.Run("Check convert incorrect BSON object to JSON", func(t *testing.T) { - // A function in the value, which is not serializable in JSON - doc := bson.D{ - {"name", func() {}}, - } - err := s.SetDataCollectionJSONBytes(doc) - if err == nil { - t.Error(err) - } - }) -} - -func TestSetFieldsCollectionName(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Verify that the s.fieldsCollectionName slice is empty - if len(s.fieldsCollectionName) != 0 { - t.Error("s.fieldsCollectionName is not empty: ", s.fieldsCollectionName) - } - - // 4-Verify that a slice with field names is saved in s.fieldsCollectionName - t.Run("Verify that a slice is saved", func(t *testing.T) { - err := s.SetFieldsCollectionName(ctx, s.idCollection+"_1") - if err != nil { - t.Error(err) - } - if len(s.fieldsCollectionName) == 0 { - t.Error("s.fieldsCollectionName is empty: ", s.fieldsCollectionName) - } - }) - t.Run("Verify that a slice is not saved if the searched value does not exist", func(t *testing.T) { - err := s.SetFieldsCollectionName(ctx, s.idCollection+"_2") - if err == nil { - t.Error(err) - } - }) - - // 5-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestSetSingleResult(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - fieldSearched := "_id" - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check for s.singleResult - t.Run("Verify that the s.singleResult exists", func(t *testing.T) { - searchedValue := s.idCollection + "_1" - err := s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) - if err != nil { - t.Error(err) - } - }) - t.Run("Checking that the s.singleResult does not exist", func(t *testing.T) { - searchedValue := s.idCollection + "_2" - err := s.SetSingleResult(ctx, fieldSearched, interface{}(searchedValue)) - if err == nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestValidateDataMongo(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check the existence of the searched values - t.Run("Verify that the searched values exist in the MongoDB collection", func(t *testing.T) { - // Data that will be searched in the collection and that will be found - propTable := golium.NewTable([][]string{ - {"field", "value"}, - {"_id", s.idCollection + "_1"}, - {"fieldString", "Example field string 1"}, - }) - props, _ := golium.ConvertTableToMap(ctx, propTable) - exist, errValidate := s.ValidateDataMongo(ctx, s.idCollection+"_1", props) - if !exist || errValidate != nil { - t.Error(errValidate) - } - }) - t.Run("Verify that the searched values do not exist in the MongoDB collection", func(t *testing.T) { - // Data that will be searched in the collection and that will not be found - propTable := golium.NewTable([][]string{ - {"field", "value"}, - {"_id", "123456_id_unexist"}, - }) - props, _ := golium.ConvertTableToMap(ctx, propTable) - exist, errValidate := s.ValidateDataMongo(ctx, s.idCollection+"_1", props) - if exist || errValidate == nil { - t.Error(errValidate) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} - -func TestVerifyExistAndMustExistValue(t *testing.T) { - // 1-Establish a Session instance - s := &Session{} - - //2-Creating test combinations - t.Run("Checking that values exist and should exist", func(t *testing.T) { - exist := true - mustExist := true - var errFunction error - err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) - if err != nil { - t.Error(err) - } - }) - t.Run("Checking that values exist and should not exist", func(t *testing.T) { - exist := true - mustExist := false - var errFunction error - err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) - if err == nil { - t.Error(err) - } - }) - t.Run("Checking that values do not exist and should exist", func(t *testing.T) { - exist := false - mustExist := true - var errFunction error - err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) - if err == nil { - t.Error(err) - } - }) - t.Run("Checking that values don't exist and shouldn't exist", func(t *testing.T) { - exist := false - mustExist := false - var errFunction error - err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) - if err != nil { - t.Error(err) - } - }) - t.Run("Checking for a previous error", func(t *testing.T) { - exist := false - mustExist := true - errFunction := errors.New("errorFunction is not nil") - err := s.VerifyExistAndMustExistValue(exist, mustExist, errFunction) - if err == nil { - t.Error(err) - } - }) -} - -func TestVerifyExistID(t *testing.T) { - // 1-Establish a Session instance, a context, a MongoDB collection, and a _id - s := &Session{} - ctx := golium.InitializeContext(context.Background()) - collectionName := "example" - s.GenerateUUIDStoreItStep(ctx) - - // 2-Create a connection and insert a document into the "example" collection - mongoConnection(s, t) - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.CreateDocumentscollectionNameStep(ctx, 1, collectionName) - - // 3-Check if the s.idCollection exists - t.Run("Verify that the value exists in the _id field", func(t *testing.T) { - _, err := s.VerifyExistID(ctx, s.idCollection+"_1") - if err != nil { - t.Error(err) - } - }) - t.Run("Verify that the value does not exist in the _id field", func(t *testing.T) { - _, err := s.VerifyExistID(ctx, s.idCollection+"_2") - if err == nil { - t.Error(err) - } - }) - - // 4-Delete all documents and close connection - s.DeleteAllDocumentscollectionNameStep(ctx, collectionName) - s.MongoDisconnectionStep() -} From e9ffc50590d98b3ad6e17efed4dc5e54d46b1684 Mon Sep 17 00:00:00 2001 From: mariolg Date: Wed, 15 Nov 2023 19:28:18 +0100 Subject: [PATCH 22/27] feat: fix UT --- steps/mongo/session_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/steps/mongo/session_test.go b/steps/mongo/session_test.go index acf93ea7..7e0dc340 100644 --- a/steps/mongo/session_test.go +++ b/steps/mongo/session_test.go @@ -195,7 +195,7 @@ func TestCollectionFind(t *testing.T) { FindCursor = tt.findCursor FindError = tt.findError c, _ := s.MongoCollectionService.Find(context.Background(), nil, &mongo.Collection{}) - if (c != nil) != tt.wantErr { + if (c != nil) == tt.wantErr { t.Errorf("Session.Find() error, wantErr %v", tt.wantErr) } }) From fca0daaa2a701764c08bca7a2cea894efa4f36c5 Mon Sep 17 00:00:00 2001 From: mariolg Date: Wed, 15 Nov 2023 19:40:22 +0100 Subject: [PATCH 23/27] feat: fix lint errors --- steps/mongo/client.go | 3 ++- steps/mongo/client_mock.go | 3 ++- steps/mongo/collection.go | 24 ++++++++++++++++-------- steps/mongo/collection_mock.go | 15 ++++++++++----- steps/mongo/session.go | 13 ++++++++----- steps/mongo/session_test.go | 14 +++++++++----- 6 files changed, 47 insertions(+), 25 deletions(-) diff --git a/steps/mongo/client.go b/steps/mongo/client.go index c6333c7c..bfc7fe3e 100644 --- a/steps/mongo/client.go +++ b/steps/mongo/client.go @@ -33,7 +33,8 @@ func NewMongoClientService() *ClientService { return &ClientService{} } -func (c ClientService) Ping(ctx context.Context, rp *readpref.ReadPref, client *mongo.Client) error { +func (c ClientService) Ping(ctx context.Context, rp *readpref.ReadPref, + client *mongo.Client) error { return client.Ping(ctx, rp) } diff --git a/steps/mongo/client_mock.go b/steps/mongo/client_mock.go index 528c05f9..24f7a592 100644 --- a/steps/mongo/client_mock.go +++ b/steps/mongo/client_mock.go @@ -29,7 +29,8 @@ var ( type ClientServiceFuncMock struct{} -func (c ClientServiceFuncMock) Ping(ctx context.Context, rp *readpref.ReadPref, client *mongo.Client) error { +func (c ClientServiceFuncMock) Ping(ctx context.Context, rp *readpref.ReadPref, + client *mongo.Client) error { return PingError } diff --git a/steps/mongo/collection.go b/steps/mongo/collection.go index 692efc77..c6e7b55b 100644 --- a/steps/mongo/collection.go +++ b/steps/mongo/collection.go @@ -24,10 +24,14 @@ import ( type CollectionFunctions interface { Collection(name string, database *mongo.Database) *mongo.Collection Name(collection *mongo.Collection) string - Find(ctx context.Context, filter interface{}, collection *mongo.Collection, opts ...*options.FindOptions) (*mongo.Cursor, error) - FindOne(ctx context.Context, filter interface{}, collection *mongo.Collection, opt ...*options.FindOneOptions) *mongo.SingleResult - InsertMany(ctx context.Context, documents []interface{}, collection *mongo.Collection) (*mongo.InsertManyResult, error) - DeleteMany(ctx context.Context, filter interface{}, opt *options.DeleteOptions, collection *mongo.Collection) (*mongo.DeleteResult, error) + Find(ctx context.Context, filter interface{}, collection *mongo.Collection, + opts ...*options.FindOptions) (*mongo.Cursor, error) + FindOne(ctx context.Context, filter interface{}, collection *mongo.Collection, + opt ...*options.FindOneOptions) *mongo.SingleResult + InsertMany(ctx context.Context, documents []interface{}, + collection *mongo.Collection) (*mongo.InsertManyResult, error) + DeleteMany(ctx context.Context, filter interface{}, + opt *options.DeleteOptions, collection *mongo.Collection) (*mongo.DeleteResult, error) } type CollectionService struct{} @@ -44,18 +48,22 @@ func (c CollectionService) Name(collection *mongo.Collection) string { return collection.Name() } -func (c CollectionService) FindOne(ctx context.Context, filter interface{}, collection *mongo.Collection, opts ...*options.FindOneOptions) *mongo.SingleResult { +func (c CollectionService) FindOne(ctx context.Context, filter interface{}, + collection *mongo.Collection, opts ...*options.FindOneOptions) *mongo.SingleResult { return collection.FindOne(ctx, filter, opts...) } -func (c CollectionService) Find(ctx context.Context, filter interface{}, collection *mongo.Collection, opts ...*options.FindOptions) (*mongo.Cursor, error) { +func (c CollectionService) Find(ctx context.Context, filter interface{}, + collection *mongo.Collection, opts ...*options.FindOptions) (*mongo.Cursor, error) { return collection.Find(ctx, filter, opts...) } -func (c CollectionService) InsertMany(ctx context.Context, documents []interface{}, collection *mongo.Collection) (*mongo.InsertManyResult, error) { +func (c CollectionService) InsertMany(ctx context.Context, documents []interface{}, + collection *mongo.Collection) (*mongo.InsertManyResult, error) { return collection.InsertMany(ctx, documents) } -func (c CollectionService) DeleteMany(ctx context.Context, filter interface{}, opt *options.DeleteOptions, collection *mongo.Collection) (*mongo.DeleteResult, error) { +func (c CollectionService) DeleteMany(ctx context.Context, filter interface{}, + opt *options.DeleteOptions, collection *mongo.Collection) (*mongo.DeleteResult, error) { return collection.DeleteMany(ctx, filter, opt) } diff --git a/steps/mongo/collection_mock.go b/steps/mongo/collection_mock.go index 21157e94..3ad5dd29 100644 --- a/steps/mongo/collection_mock.go +++ b/steps/mongo/collection_mock.go @@ -35,7 +35,8 @@ var ( type CollectionServiceFuncMock struct{} -func (c CollectionServiceFuncMock) Collection(name string, database *mongo.Database) *mongo.Collection { +func (c CollectionServiceFuncMock) Collection(name string, + database *mongo.Database) *mongo.Collection { return CollectionCollection } @@ -43,18 +44,22 @@ func (c CollectionServiceFuncMock) Name(collection *mongo.Collection) string { return NameString } -func (c CollectionServiceFuncMock) FindOne(ctx context.Context, filter interface{}, collection *mongo.Collection, opts ...*options.FindOneOptions) *mongo.SingleResult { +func (c CollectionServiceFuncMock) FindOne(ctx context.Context, filter interface{}, + collection *mongo.Collection, opts ...*options.FindOneOptions) *mongo.SingleResult { return FindOneSingleResult } -func (c CollectionServiceFuncMock) Find(ctx context.Context, filter interface{}, collection *mongo.Collection, opts ...*options.FindOptions) (*mongo.Cursor, error) { +func (c CollectionServiceFuncMock) Find(ctx context.Context, filter interface{}, + collection *mongo.Collection, opts ...*options.FindOptions) (*mongo.Cursor, error) { return FindCursor, FindError } -func (c CollectionServiceFuncMock) InsertMany(ctx context.Context, documents []interface{}, collection *mongo.Collection) (*mongo.InsertManyResult, error) { +func (c CollectionServiceFuncMock) InsertMany(ctx context.Context, documents []interface{}, + collection *mongo.Collection) (*mongo.InsertManyResult, error) { return InsertManyInsertManyResult, InsertManyError } -func (c CollectionServiceFuncMock) DeleteMany(ctx context.Context, filter interface{}, opt *options.DeleteOptions, collection *mongo.Collection) (*mongo.DeleteResult, error) { +func (c CollectionServiceFuncMock) DeleteMany(ctx context.Context, filter interface{}, + opt *options.DeleteOptions, collection *mongo.Collection) (*mongo.DeleteResult, error) { return DeleteResultDeleteResult, DeleteResultError } diff --git a/steps/mongo/session.go b/steps/mongo/session.go index 1eaf77e2..d6caf5bb 100644 --- a/steps/mongo/session.go +++ b/steps/mongo/session.go @@ -61,13 +61,14 @@ type Session struct { // Access MongoDB Client features MongoClientService ClientFunctions - // Access MongoDB Colleciton features + // Access MongoDB Collecti on features MongoCollectionService CollectionFunctions } // FUNCTIONS CALLED BY STEPS -// CheckMongoFieldDoesNotExistOrEmptyStep check that a field does not exist or it does exist and is empty +// CheckMongoFieldDoesNotExistOrEmptyStep check that a field +// does not exist or it does exist and is empty func (s *Session) CheckMongoFieldDoesNotExistOrEmptyStep( ctx context.Context, collectionName, fieldSearched, idCollection string, ) error { @@ -146,7 +147,8 @@ func (s *Session) CheckNumberDocumentscollectionNameStep(collectionName string, s.SetCollection(collectionName) // 2-Make a query to get all the documents in the collection - cursor, err := s.MongoCollectionService.Find(context.Background(), bson.D{}, s.collection, &options.FindOptions{}) + cursor, err := s.MongoCollectionService.Find(context.Background(), + bson.D{}, s.collection, &options.FindOptions{}) if err != nil { return fmt.Errorf("error: query error: '%s'", err) } @@ -353,7 +355,7 @@ func (s *Session) CreateDocumentsCollection(ctx context.Context, num int) []inte // 1-Initialize the document slice allDocuments := []interface{}{} - //2-Obtaining the _id of the struct, if it does not exist it is created + // 2-Obtaining the _id of the struct, if it does not exist it is created id := s.idCollection if id == "" { newUUID, err := uuid.NewRandom() @@ -437,7 +439,8 @@ func (s *Session) SetDataCollectionJSONBytes(bsonDoc bson.D) error { func (s *Session) SetFieldsCollectionName(ctx context.Context, idCollection string) error { // Make a query to find past _id's document var document bson.M - err := s.MongoCollectionService.FindOne(ctx, GetFilter("_id", idCollection), s.collection, &options.FindOneOptions{}).Decode(&document) + err := s.MongoCollectionService.FindOne(ctx, + GetFilter("_id", idCollection), s.collection, &options.FindOneOptions{}).Decode(&document) if err == mongo.ErrNoDocuments { return fmt.Errorf("error: no documents matching the filter were found") } else if err != nil { diff --git a/steps/mongo/session_test.go b/steps/mongo/session_test.go index 7e0dc340..ad5e0612 100644 --- a/steps/mongo/session_test.go +++ b/steps/mongo/session_test.go @@ -44,7 +44,8 @@ func TestPing(t *testing.T) { s := &Session{} s.MongoClientService = ClientServiceFuncMock{} PingError = tt.pingErr - if err := s.MongoClientService.Ping(context.Background(), nil, s.client); (err != nil) != tt.wantErr { + if err := s.MongoClientService.Ping(context.Background(), + nil, s.client); (err != nil) != tt.wantErr { t.Errorf("Session.Ping() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -102,7 +103,8 @@ func TestDisconnect(t *testing.T) { s := &Session{} s.MongoClientService = ClientServiceFuncMock{} DisconnectError = tt.disconnectErr - if err := s.MongoClientService.Disconnect(context.Background(), s.client); (err != nil) != tt.wantErr { + if err := s.MongoClientService.Disconnect(context.Background(), + s.client); (err != nil) != tt.wantErr { t.Errorf("Session.Disconnect() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -131,7 +133,8 @@ func TestCollectionCollection(t *testing.T) { s := &Session{} s.MongoCollectionService = CollectionServiceFuncMock{} CollectionCollection = tt.collection - if d := s.MongoCollectionService.Collection("test", &mongo.Database{}); (d != nil) == tt.wantErr { + if d := s.MongoCollectionService.Collection("test", + &mongo.Database{}); (d != nil) == tt.wantErr { t.Errorf("Session.Collection() error, wantErr %v", tt.wantErr) } }) @@ -161,7 +164,7 @@ func TestCollectionName(t *testing.T) { s.collection = &mongo.Collection{} s.MongoCollectionService = CollectionServiceFuncMock{} NameString = tt.nameString - if n := s.MongoCollectionService.Name(s.collection); (len(n) == 0) != tt.wantErr { + if n := s.MongoCollectionService.Name(s.collection); (n == "") != tt.wantErr { t.Errorf("Session.Name() error, wantErr %v", tt.wantErr) } }) @@ -225,7 +228,8 @@ func TestCollectionFindOne(t *testing.T) { s.collection = &mongo.Collection{} s.MongoCollectionService = CollectionServiceFuncMock{} FindOneSingleResult = tt.findOneSingleResult - if f := s.MongoCollectionService.FindOne(context.Background(), nil, s.collection); (f != nil) == tt.wantErr { + if f := s.MongoCollectionService.FindOne(context.Background(), + nil, s.collection); (f != nil) == tt.wantErr { t.Errorf("Session.FindOne() error, wantErr %v", tt.wantErr) } }) From 10a71877e88216237cf65f573483194f4a2be276 Mon Sep 17 00:00:00 2001 From: mariolg Date: Wed, 15 Nov 2023 20:20:12 +0100 Subject: [PATCH 24/27] feat: fix sonar-lint --- steps/mongo/client_mock.go | 9 +++++++++ steps/mongo/collection.go | 6 +++--- steps/mongo/collection_mock.go | 29 ++++++++++++++++++++++++++++- steps/mongo/session.go | 1 + steps/mongo/session_test.go | 2 +- 5 files changed, 42 insertions(+), 5 deletions(-) diff --git a/steps/mongo/client_mock.go b/steps/mongo/client_mock.go index 24f7a592..46284cfc 100644 --- a/steps/mongo/client_mock.go +++ b/steps/mongo/client_mock.go @@ -25,19 +25,28 @@ var ( PingError error DisconnectError error DatabaseDatabase *mongo.Database + ContextCliFake context.Context + ClientCliFake *mongo.Client + NameCliFake string ) type ClientServiceFuncMock struct{} func (c ClientServiceFuncMock) Ping(ctx context.Context, rp *readpref.ReadPref, client *mongo.Client) error { + ContextCliFake = ctx + ClientCliFake = client return PingError } func (c ClientServiceFuncMock) Disconnect(ctx context.Context, client *mongo.Client) error { + ContextCliFake = ctx + ClientCliFake = client return DisconnectError } func (c ClientServiceFuncMock) Database(name string, client *mongo.Client) *mongo.Database { + NameCliFake = name + ClientCliFake = client return DatabaseDatabase } diff --git a/steps/mongo/collection.go b/steps/mongo/collection.go index c6e7b55b..c8d6f35f 100644 --- a/steps/mongo/collection.go +++ b/steps/mongo/collection.go @@ -31,7 +31,7 @@ type CollectionFunctions interface { InsertMany(ctx context.Context, documents []interface{}, collection *mongo.Collection) (*mongo.InsertManyResult, error) DeleteMany(ctx context.Context, filter interface{}, - opt *options.DeleteOptions, collection *mongo.Collection) (*mongo.DeleteResult, error) + collection *mongo.Collection, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error) } type CollectionService struct{} @@ -64,6 +64,6 @@ func (c CollectionService) InsertMany(ctx context.Context, documents []interface } func (c CollectionService) DeleteMany(ctx context.Context, filter interface{}, - opt *options.DeleteOptions, collection *mongo.Collection) (*mongo.DeleteResult, error) { - return collection.DeleteMany(ctx, filter, opt) + collection *mongo.Collection, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error) { + return collection.DeleteMany(ctx, filter, opts...) } diff --git a/steps/mongo/collection_mock.go b/steps/mongo/collection_mock.go index 3ad5dd29..97d3970b 100644 --- a/steps/mongo/collection_mock.go +++ b/steps/mongo/collection_mock.go @@ -31,35 +31,62 @@ var ( InsertManyError error DeleteResultDeleteResult *mongo.DeleteResult DeleteResultError error + ContextColFake context.Context + CollectionColFake *mongo.Collection + FindOptsColFake []*options.FindOptions + FindOneOptsColFake []*options.FindOneOptions + DeleteOptsColFake []*options.DeleteOptions + DatabaseColFake *mongo.Database + NameColFake string + FilterColFake interface{} + DocumentsColFake interface{} ) type CollectionServiceFuncMock struct{} func (c CollectionServiceFuncMock) Collection(name string, database *mongo.Database) *mongo.Collection { + NameColFake = name + DatabaseColFake = database return CollectionCollection } func (c CollectionServiceFuncMock) Name(collection *mongo.Collection) string { + CollectionColFake = collection return NameString } func (c CollectionServiceFuncMock) FindOne(ctx context.Context, filter interface{}, collection *mongo.Collection, opts ...*options.FindOneOptions) *mongo.SingleResult { + ContextColFake = ctx + FilterColFake = filter + CollectionColFake = collection + FindOneOptsColFake = opts return FindOneSingleResult } func (c CollectionServiceFuncMock) Find(ctx context.Context, filter interface{}, collection *mongo.Collection, opts ...*options.FindOptions) (*mongo.Cursor, error) { + ContextColFake = ctx + FilterColFake = filter + CollectionColFake = collection + FindOptsColFake = opts return FindCursor, FindError } func (c CollectionServiceFuncMock) InsertMany(ctx context.Context, documents []interface{}, collection *mongo.Collection) (*mongo.InsertManyResult, error) { + ContextColFake = ctx + DocumentsColFake = documents + CollectionColFake = collection return InsertManyInsertManyResult, InsertManyError } func (c CollectionServiceFuncMock) DeleteMany(ctx context.Context, filter interface{}, - opt *options.DeleteOptions, collection *mongo.Collection) (*mongo.DeleteResult, error) { + collection *mongo.Collection, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error) { + ContextColFake = ctx + FilterColFake = filter + CollectionColFake = collection + DeleteOptsColFake = opts return DeleteResultDeleteResult, DeleteResultError } diff --git a/steps/mongo/session.go b/steps/mongo/session.go index d6caf5bb..21eca3d0 100644 --- a/steps/mongo/session.go +++ b/steps/mongo/session.go @@ -352,6 +352,7 @@ func VerifyMustExist(exist string) bool { // CreateDocumentsCollection creates num documents in a slice and inserts them into a collection func (s *Session) CreateDocumentsCollection(ctx context.Context, num int) []interface{} { + ctx = nil // 1-Initialize the document slice allDocuments := []interface{}{} diff --git a/steps/mongo/session_test.go b/steps/mongo/session_test.go index ad5e0612..7f53ea75 100644 --- a/steps/mongo/session_test.go +++ b/steps/mongo/session_test.go @@ -298,7 +298,7 @@ func TestCollectionDeletetMany(t *testing.T) { s.MongoCollectionService = CollectionServiceFuncMock{} DeleteResultDeleteResult = tt.deleteResult DeleteResultError = tt.deleteResultError - _, err := s.MongoCollectionService.DeleteMany(context.Background(), nil, nil, s.collection) + _, err := s.MongoCollectionService.DeleteMany(context.Background(), nil, s.collection) if (err != nil) != tt.wantErr { t.Errorf("Session.DeleteMany() error = %v, wantErr %v", err, tt.wantErr) } From b75acf564ec71db44d9756f389b7beff0b5fcb36 Mon Sep 17 00:00:00 2001 From: mariolg Date: Wed, 15 Nov 2023 20:31:58 +0100 Subject: [PATCH 25/27] feat: fix sonarlint --- steps/mongo/client_mock.go | 2 ++ steps/mongo/session.go | 3 ++- steps/mongo/session_test.go | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/steps/mongo/client_mock.go b/steps/mongo/client_mock.go index 46284cfc..8b05d79d 100644 --- a/steps/mongo/client_mock.go +++ b/steps/mongo/client_mock.go @@ -28,6 +28,7 @@ var ( ContextCliFake context.Context ClientCliFake *mongo.Client NameCliFake string + ReadPrefCliFake *readpref.ReadPref ) type ClientServiceFuncMock struct{} @@ -35,6 +36,7 @@ type ClientServiceFuncMock struct{} func (c ClientServiceFuncMock) Ping(ctx context.Context, rp *readpref.ReadPref, client *mongo.Client) error { ContextCliFake = ctx + ReadPrefCliFake = rp ClientCliFake = client return PingError } diff --git a/steps/mongo/session.go b/steps/mongo/session.go index 21eca3d0..daaea82d 100644 --- a/steps/mongo/session.go +++ b/steps/mongo/session.go @@ -352,7 +352,8 @@ func VerifyMustExist(exist string) bool { // CreateDocumentsCollection creates num documents in a slice and inserts them into a collection func (s *Session) CreateDocumentsCollection(ctx context.Context, num int) []interface{} { - ctx = nil + ContextCliFake = ctx + // 1-Initialize the document slice allDocuments := []interface{}{} diff --git a/steps/mongo/session_test.go b/steps/mongo/session_test.go index 7f53ea75..9b9189c8 100644 --- a/steps/mongo/session_test.go +++ b/steps/mongo/session_test.go @@ -298,9 +298,9 @@ func TestCollectionDeletetMany(t *testing.T) { s.MongoCollectionService = CollectionServiceFuncMock{} DeleteResultDeleteResult = tt.deleteResult DeleteResultError = tt.deleteResultError - _, err := s.MongoCollectionService.DeleteMany(context.Background(), nil, s.collection) - if (err != nil) != tt.wantErr { - t.Errorf("Session.DeleteMany() error = %v, wantErr %v", err, tt.wantErr) + d, _ := s.MongoCollectionService.DeleteMany(context.Background(), nil, s.collection) + if (d == nil) != tt.wantErr { + t.Errorf("Session.DeleteMany() error, wantErr %v", tt.wantErr) } }) } From 7fbafc77bb1a1915f738c9bf16a8dafad727833d Mon Sep 17 00:00:00 2001 From: mariolg Date: Wed, 15 Nov 2023 20:52:44 +0100 Subject: [PATCH 26/27] feat: add some old tests --- steps/mongo/session_test.go | 145 ++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/steps/mongo/session_test.go b/steps/mongo/session_test.go index 9b9189c8..fbcd62fb 100644 --- a/steps/mongo/session_test.go +++ b/steps/mongo/session_test.go @@ -17,8 +17,12 @@ package mongo import ( "context" "fmt" + "reflect" "testing" + "github.com/TelefonicaTC2Tech/golium" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" ) @@ -305,3 +309,144 @@ func TestCollectionDeletetMany(t *testing.T) { }) } } + +// FUNCTIONS CALLED BY STEPS + +func TestGenerateUUIDStoreItStep(t *testing.T) { + // 1-Establish a Session instance and context + s := &Session{} + ctx := golium.InitializeContext(context.Background()) + + // 2-Generating a Random UUID + t.Run("Generating a Random UUID", func(t *testing.T) { + if s.GenerateUUIDStoreItStep(ctx) != nil { + t.Errorf("Error generating a random UUID") + } + }) + + // 3-Verifying that a UUID has been created + if len(s.idCollection) != 36 { + t.Errorf("s.idCollection was not created") + } +} + +// GENERIC FUNCTIONS + +func TestContainsElements(t *testing.T) { + t.Run("Element exists in slice", func(t *testing.T) { + slice := []int{1, 2, 3, 4, 5} + element := 3 + result := ContainsElements(element, slice) + if !result { + t.Errorf("Expected %v to be in the slice, but it wasn't.", element) + } + }) + t.Run("Element does not exist in slice", func(t *testing.T) { + slice := []string{"Alcorcon", "Madrid", "Barcelona"} + element := "Valladolid" + result := ContainsElements(element, slice) + if result { + t.Errorf("Expected %v not to be in the slice, but it was.", element) + } + }) +} + +func TestGetFilter(t *testing.T) { + t.Run("Create filter with non-nil value", func(t *testing.T) { + key := "age" + value := 30 + filter := GetFilter(key, value) + expectedFilter := bson.M{"age": 30} + if !reflect.DeepEqual(filter, expectedFilter) { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Create filter with nil value", func(t *testing.T) { + key := "name" + var value interface{} = nil + filter := GetFilter(key, value) + expectedFilter := bson.M{"name": nil} + if !reflect.DeepEqual(filter, expectedFilter) { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) +} + +func TestGetFilterConverted(t *testing.T) { + t.Run("Convert to boolean (true)", func(t *testing.T) { + field := "is_boolean" + value := "true" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: true} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Convert to boolean (false)", func(t *testing.T) { + field := "is_boolean" + value := "false" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: false} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Convert to integer", func(t *testing.T) { + field := "quantity number" + value := "42" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: 42} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Convert to float64", func(t *testing.T) { + field := "quantity decimal number" + value := "99.99" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: 99.99} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("Convert to nil (empty)", func(t *testing.T) { + field := "nil or empty" + value := "[EMPTY]" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: nil} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) + t.Run("No conversion (string)", func(t *testing.T) { + field := "Nadie" + value := "Juan" + filter := GetFilterConverted(field, value) + expectedFilter := primitive.M{field: value} + if filter[field] != expectedFilter[field] { + t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) + } + }) +} + +func TestGetOptionsSearchAllFields(t *testing.T) { + t.Run("Check creates an 'Options' to search all fields in the collection", func(t *testing.T) { + options := GetOptionsSearchAllFields() + if options.Projection == nil { + t.Errorf("Expected Projection to be nil, but got: %v", options.Projection) + } + }) +} + +func TestVerifyMustExist(t *testing.T) { + t.Run("exist is true", func(t *testing.T) { + if VerifyMustExist("does exist") != true { + t.Errorf("Expected true, but got false") + } + }) + t.Run("exist is false", func(t *testing.T) { + if VerifyMustExist("does not exist") != false { + t.Errorf("Expected false, but got true") + } + }) +} From 977c3967efb0cd3995b1857950f5d903dbb73faa Mon Sep 17 00:00:00 2001 From: mariolg Date: Wed, 15 Nov 2023 20:58:49 +0100 Subject: [PATCH 27/27] feat: fix sonarlint --- steps/mongo/session.go | 7 ++++++- steps/mongo/session_test.go | 11 ++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/steps/mongo/session.go b/steps/mongo/session.go index daaea82d..66ceea89 100644 --- a/steps/mongo/session.go +++ b/steps/mongo/session.go @@ -31,6 +31,11 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) +var ( + EMPTY = "[EMPTY]" + NULL = "[NULL]" +) + // Session contains the information of a MongoDB session. type Session struct { @@ -330,7 +335,7 @@ func GetFilterConverted(field, value string) primitive.M { } // If the passed value is "[EMPTY]" or "[NULL]", it evaluates to nil - if value == "[EMPTY]" || value == "[NULL]" { + if value == EMPTY || value == NULL { return bson.M{field: nil} } diff --git a/steps/mongo/session_test.go b/steps/mongo/session_test.go index fbcd62fb..245ee6a4 100644 --- a/steps/mongo/session_test.go +++ b/steps/mongo/session_test.go @@ -26,6 +26,8 @@ import ( "go.mongodb.org/mongo-driver/mongo" ) +var ISBOOLEAN = "is_boolean" + func TestPing(t *testing.T) { tests := []struct { name string @@ -363,8 +365,7 @@ func TestGetFilter(t *testing.T) { }) t.Run("Create filter with nil value", func(t *testing.T) { key := "name" - var value interface{} = nil - filter := GetFilter(key, value) + filter := GetFilter(key, nil) expectedFilter := bson.M{"name": nil} if !reflect.DeepEqual(filter, expectedFilter) { t.Errorf("Expected filter: %v, but got: %v", expectedFilter, filter) @@ -374,7 +375,7 @@ func TestGetFilter(t *testing.T) { func TestGetFilterConverted(t *testing.T) { t.Run("Convert to boolean (true)", func(t *testing.T) { - field := "is_boolean" + field := ISBOOLEAN value := "true" filter := GetFilterConverted(field, value) expectedFilter := primitive.M{field: true} @@ -383,7 +384,7 @@ func TestGetFilterConverted(t *testing.T) { } }) t.Run("Convert to boolean (false)", func(t *testing.T) { - field := "is_boolean" + field := ISBOOLEAN value := "false" filter := GetFilterConverted(field, value) expectedFilter := primitive.M{field: false} @@ -411,7 +412,7 @@ func TestGetFilterConverted(t *testing.T) { }) t.Run("Convert to nil (empty)", func(t *testing.T) { field := "nil or empty" - value := "[EMPTY]" + value := EMPTY filter := GetFilterConverted(field, value) expectedFilter := primitive.M{field: nil} if filter[field] != expectedFilter[field] {