diff --git a/.gitignore b/.gitignore index 606767879..ea419b21f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,7 @@ coverage.out /node_modules /assets + +# test artifacts +pkg/server/http/accounts-store/ +pkg/server/http/settings-store/ diff --git a/go.mod b/go.mod index cecb26d54..f24ae360b 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/cs3org/reva v1.1.0 github.com/go-chi/chi v4.1.2+incompatible github.com/go-chi/render v1.0.1 + github.com/golang/protobuf v1.4.2 github.com/google/uuid v1.1.2 // indirect github.com/micro/cli/v2 v2.1.2 github.com/micro/go-micro/v2 v2.9.1 @@ -18,9 +19,11 @@ require ( github.com/owncloud/ocis-accounts v0.4.2-0.20200828150703-2ca83cf4ac20 github.com/owncloud/ocis-hello v0.1.0-alpha1 // indirect github.com/owncloud/ocis-pkg/v2 v2.4.0 + github.com/owncloud/ocis-settings v0.3.2-0.20200828130413-0cc0f5bf26fe github.com/owncloud/ocis-store v0.0.0-20200716140351-f9670592fb7b github.com/restic/calens v0.2.0 github.com/spf13/viper v1.7.0 + github.com/stretchr/testify v1.6.1 go.opencensus.io v0.22.4 golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect google.golang.org/protobuf v1.25.0 diff --git a/go.sum b/go.sum index df0c37e03..fd9113bac 100644 --- a/go.sum +++ b/go.sum @@ -26,6 +26,7 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= contrib.go.opencensus.io/exporter/jaeger v0.2.0 h1:nhTv/Ry3lGmqbJ/JGvCjWxBl5ozRfqo86Ngz59UAlfk= contrib.go.opencensus.io/exporter/jaeger v0.2.0/go.mod h1:ukdzwIYYHgZ7QYtwVFQUjiT28BJHiMhTERo32s6qVgM= +contrib.go.opencensus.io/exporter/jaeger v0.2.1 h1:yGBYzYMewVL0yO9qqJv3Z5+IRhPdU7e9o/2oKpX4YvI= contrib.go.opencensus.io/exporter/jaeger v0.2.1/go.mod h1:Y8IsLgdxqh1QxYxPC5IgXVmBaeLUeQFfBeBi9PbeZd0= contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= @@ -280,9 +281,11 @@ github.com/cs3org/go-cs3apis v0.0.0-20200306065539-29abc33f5be0 h1:jTKILSBtDm0GE github.com/cs3org/go-cs3apis v0.0.0-20200306065539-29abc33f5be0/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= github.com/cs3org/go-cs3apis v0.0.0-20200611124600-7a1be2026543 h1:ykZiNI0yHDdIJPI4L+VB6inTUBJh9t9AZLDeXq7/8+Q= github.com/cs3org/go-cs3apis v0.0.0-20200611124600-7a1be2026543/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= +github.com/cs3org/go-cs3apis v0.0.0-20200730121022-c4f3d4f7ddfd h1:uMaudkC7znaiIKT9rxIhoRYzrhTg1Nc78X7XEqhmjSk= github.com/cs3org/go-cs3apis v0.0.0-20200730121022-c4f3d4f7ddfd/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= github.com/cs3org/reva v0.1.0 h1:PYzDejKm/+xG3OTS2WgzBxcksVogEGmPgjJVegwSR2c= github.com/cs3org/reva v0.1.0/go.mod h1:8j6QyyAq9Kjj7RPfJb7M1aEmw5DmsuCJKUULXxYOyRo= +github.com/cs3org/reva v1.1.0 h1:Gih6ECHvMMGSx523SFluFlDmNMuhYelXYShdWvjvW38= github.com/cs3org/reva v1.1.0/go.mod h1:fBzTrNuAKdQ62ybjpdu8nyhBin90/3/3s6DGQDCdBp4= github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8= github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= @@ -385,6 +388,7 @@ github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg= github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA= +github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEssk= github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -956,11 +960,13 @@ github.com/micro/go-micro/v2 v2.0.0 h1:bMx549RwJ9Yuiui8cDVlfYhVNP8I8KBJTMyLthEXp github.com/micro/go-micro/v2 v2.0.0/go.mod h1:v7QP5UhKRt37ixjJe8DouWmg0/eE6dltr5h0idJ9BpE= github.com/micro/go-micro/v2 v2.6.0 h1:HH6uEqTu6pkBtAlwAqQW2sf33640iEa1s9puGIctpO0= github.com/micro/go-micro/v2 v2.6.0/go.mod h1:60HMKlDN4ShZDJRrlgdcAmkCWNhQbYv+CDG3r7iLE34= +github.com/micro/go-micro/v2 v2.9.1 h1:+S9koIrNWARjpP6k2TZ7kt0uC9zUJtNXzIdZTZRms7Q= github.com/micro/go-micro/v2 v2.9.1/go.mod h1:x55ZM3Puy0FyvvkR3e0ha0xsE9DFwfPSUMWAIbFY0SY= github.com/micro/go-plugins v1.5.1 h1:swcFD7ynCTUo98APqIEIbPu2XMd6yVGTnI8PqdnCwOQ= github.com/micro/go-plugins v1.5.1/go.mod h1:jcxejzJCAMH731cQHbS/hncyKe0rxAbzKkibj8glad4= github.com/micro/go-plugins/wrapper/trace/opencensus/v2 v2.0.1 h1:7IkXfl94MdLZQwk0lNmu9Cg5WP42Zak9EtQMeN4SvVs= github.com/micro/go-plugins/wrapper/trace/opencensus/v2 v2.0.1/go.mod h1:QrkcwcDtIs2hIJpIEhozekyf6Rfz5C36kFI8+zzCpX0= +github.com/micro/go-plugins/wrapper/trace/opencensus/v2 v2.9.1 h1:IaZUsLp0Omb/ozDnRKEvVY56C0UocBdPxxg2S2Pk2j0= github.com/micro/go-plugins/wrapper/trace/opencensus/v2 v2.9.1/go.mod h1:26UmOLM/I487NqTg3n6zJiBrYmIb684M2Zp4WH98XzU= github.com/micro/mdns v0.3.0 h1:bYycYe+98AXR3s8Nq5qvt6C573uFTDPIYzJemWON0QE= github.com/micro/mdns v0.3.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= @@ -998,6 +1004,7 @@ github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -1121,11 +1128,13 @@ github.com/owncloud/ocis-pkg/v2 v2.2.2-0.20200527082518-5641fa4a4c8c h1:hYhKSfMk github.com/owncloud/ocis-pkg/v2 v2.2.2-0.20200527082518-5641fa4a4c8c/go.mod h1:s894msGwDsULmsROHkbsXFCP/eSqDcteDFUntZOiJdc= github.com/owncloud/ocis-pkg/v2 v2.2.2-0.20200602070144-cd0620668170 h1:MYfyffPyTZbTofJjAz3LSQUIaKKcjjBBBIJGaEAkP8g= github.com/owncloud/ocis-pkg/v2 v2.2.2-0.20200602070144-cd0620668170/go.mod h1:s894msGwDsULmsROHkbsXFCP/eSqDcteDFUntZOiJdc= +github.com/owncloud/ocis-pkg/v2 v2.4.0 h1:/3ZOd4txtwjiNKJA9iLT9BjrJw5YgHSX13fQR4BYfGY= github.com/owncloud/ocis-pkg/v2 v2.4.0/go.mod h1:FSzIvhx9HcZcq4jgNaDowNvM7PTX/XCyoMvyfzidUpE= github.com/owncloud/ocis-settings v0.0.0-20200522101320-46ea31026363/go.mod h1:/h0ceztOoFc3KAnm8nqZI4zwsaaZK9q4MTgtintwsXc= github.com/owncloud/ocis-settings v0.0.0-20200629120229-69693c5f8f43 h1:IekDKhkoaOhUnpIHSG5d02hGMOW5u4tZEEfxVC1KGgk= github.com/owncloud/ocis-settings v0.0.0-20200629120229-69693c5f8f43/go.mod h1:AeXZVHKEU+9Xt4+/lkHE5rx+sJH2if9dIrUGLhe+JOY= github.com/owncloud/ocis-settings v0.3.0/go.mod h1:vRge9QDkOsc6j76gPBmZs1Z5uOPrV4DIkZCgZCEFwBA= +github.com/owncloud/ocis-settings v0.3.2-0.20200828130413-0cc0f5bf26fe h1:kiU5lz12R0LNJE1/zI2vxesZPWm6BvSO7hvZC8yOoAc= github.com/owncloud/ocis-settings v0.3.2-0.20200828130413-0cc0f5bf26fe/go.mod h1:vRge9QDkOsc6j76gPBmZs1Z5uOPrV4DIkZCgZCEFwBA= github.com/owncloud/ocis-store v0.0.0-20200716140351-f9670592fb7b h1:tjfH02oEawuMdMt3pJdCjFyuWgNRUjV7rdjoTF56Mrw= github.com/owncloud/ocis-store v0.0.0-20200716140351-f9670592fb7b/go.mod h1:7WRMnx4ffwtckNl4qD2Gj/d5fvl84jyydOV2FbUUu3A= @@ -1140,6 +1149,7 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg= github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= @@ -1170,6 +1180,7 @@ github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvls github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U= github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -1291,6 +1302,7 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -1323,6 +1335,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho= github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8= github.com/subosito/gotenv v1.1.1/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= @@ -1358,6 +1371,7 @@ github.com/tus/tusd v1.1.1-0.20200416115059-9deabf9d80c2/go.mod h1:ygrT4B9ZSb27d github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= github.com/uber/jaeger-client-go v2.15.0+incompatible h1:NP3qsSqNxh8VYr956ur1N/1C1PjvOJnJykCzcD5QHbk= github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-client-go v2.25.0+incompatible h1:IxcNZ7WRY1Y3G4poYlx24szfsn/3LvK9QHCq9oQw8+U= github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v1.5.0/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -1569,6 +1583,7 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1589,6 +1604,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1772,6 +1788,7 @@ google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/ google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.25.0 h1:LodzhlzZEUfhXzNUMIfVlf9Gr6Ua5MMtoFWh7+f47qA= google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0 h1:BaiDisFir8O4IJxvAabCGGkQ6yCJegNQqSVoYUNAnbk= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1880,6 +1897,7 @@ gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4 gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.4.0 h1:0kXPskUMGAXXWJlP05ktEMOV0vmzFQUWw6d+aZJQU8A= gopkg.in/square/go-jose.v2 v2.4.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.0 h1:OZ4sdq+Y+SHfYB7vfthi1Ei8b0vkP8ZPQgUfUwdUSqo= gopkg.in/square/go-jose.v2 v2.5.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= @@ -1898,9 +1916,11 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/server/http/svc_test.go b/pkg/server/http/svc_test.go new file mode 100644 index 000000000..74d54f0f0 --- /dev/null +++ b/pkg/server/http/svc_test.go @@ -0,0 +1,1123 @@ +package http + +import ( + "context" + "encoding/base64" + "encoding/json" + "encoding/xml" + "fmt" + "io/ioutil" + "log" + "net/http" + "net/http/httptest" + "net/url" + "path/filepath" + "strings" + "testing" + + "github.com/golang/protobuf/ptypes/empty" + "github.com/owncloud/ocis-ocs/pkg/config" + svc "github.com/owncloud/ocis-ocs/pkg/service/v0" + ocisLog "github.com/owncloud/ocis-pkg/v2/log" + "github.com/stretchr/testify/assert" + + "github.com/owncloud/ocis-pkg/v2/service/grpc" + + accountsCmd "github.com/owncloud/ocis-accounts/pkg/command" + accountsCfg "github.com/owncloud/ocis-accounts/pkg/config" + accountsProto "github.com/owncloud/ocis-accounts/pkg/proto/v0" + accountsSvc "github.com/owncloud/ocis-accounts/pkg/service/v0" + + "github.com/micro/go-micro/v2/client" + settings "github.com/owncloud/ocis-settings/pkg/proto/v0" +) + +var service = grpc.Service{} + +var mockedRoleAssignment = map[string]string{} + +var ocsVersions = []string{"v1.php", "v2.php"} + +var formats = []string{"json", "xml"} + +const dataPath = "./accounts-store" + +var DefaultUsers = []string{ + "4c510ada-c86b-4815-8820-42cdf82c3d51", + "820ba2a1-3f54-4538-80a4-2d73007e30bf", + "932b4540-8d16-481e-8ef4-588e4b6b151c", + "bc596f3c-c955-4328-80a0-60d018b4ad57", + "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c", + "058bff95-6708-4fe5-91e4-9ea3d377588b", +} + +func getFormatString(format string) string { + if format == "json" { + return "?format=json" + } else if format == "xml" { + return "" + } else { + panic("Invalid format received") + } +} + +type Quota struct { + Free int64 `json:"free" xml:"free"` + Used int64 `json:"used" xml:"used"` + Total int64 `json:"total" xml:"total"` + Relative float32 `json:"relative" xml:"relative"` + Definition string `json:"definition" xml:"definition"` +} + +type User struct { + Enabled string `json:"enabled" xml:"enabled"` + ID string `json:"id" xml:"id"` + Username string `json:"username" xml:"username"` + Email string `json:"email" xml:"email"` + Quota Quota `json:"quota" xml:"quota"` + UIDNumber int `json:"uidnumber" xml:"uidnumber"` + GIDNumber int `json:"gidnumber" xml:"gidnumber"` + Displayname string `json:"displayname" xml:"displayname"` +} + +func (u *User) getUserRequestString() string { + res := url.Values{} + + if u.ID != "" { + res.Add("userid", u.ID) + } + + if u.Username != "" { + res.Add("username", u.Username) + } + + if u.Email != "" { + res.Add("email", u.Email) + } + + if u.Displayname != "" { + res.Add("displayname", u.Displayname) + } + + if u.UIDNumber != 0 { + res.Add("uidnumber", fmt.Sprint(u.UIDNumber)) + } + + if u.GIDNumber != 0 { + res.Add("gidnumber", fmt.Sprint(u.GIDNumber)) + } + + return res.Encode() +} + +type Meta struct { + Status string `json:"status" xml:"status"` + StatusCode int `json:"statuscode" xml:"statuscode"` + Message string `json:"message" xml:"message"` +} + +func (m *Meta) Success(ocsVersion string) bool { + if !(ocsVersion == "v1.php" || ocsVersion == "v2.php") { + return false + } + if m.Status != "ok" { + return false + } + if ocsVersion == "v1.php" && m.StatusCode != 100 { + return false + } else if ocsVersion == "v2.php" && m.StatusCode != 200 { + return false + } else { + return true + } +} + +type SingleUserResponse struct { + Meta Meta `json:"meta" xml:"meta"` + Data User `json:"data" xml:"data"` +} + +type GetUsersResponse struct { + Meta Meta `json:"meta" xml:"meta"` + Data struct { + Users []string `json:"users" xml:"users>element"` + } `json:"data" xml:"data"` +} + +type DeleteUserRespone struct { + Meta Meta `json:"meta" xml:"meta"` + Data struct { + } `json:"data" xml:"data"` +} + +func assertStatusCode(t *testing.T, statusCode int, res *httptest.ResponseRecorder, ocsVersion string) { + if ocsVersion == "v1.php" { + assert.Equal(t, 200, res.Code) + } else { + assert.Equal(t, statusCode, res.Code) + } +} + +func assertResponseMeta(t *testing.T, expected, actual Meta) { + assert.Equal(t, expected.Status, actual.Status, "The status of response doesn't matches") + assert.Equal(t, expected.StatusCode, actual.StatusCode, "The Status code of response doesn't matches") + assert.Equal(t, expected.Message, actual.Message, "The Message of response doesn't matches") +} + +func assertUserSame(t *testing.T, expected, actual User, quotaAvailable bool) { + if expected.ID == "" { + // Check the auto generated userId + assert.Regexp( + t, + "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}", + actual.ID, "the userid is not a valid uuid", + ) + } else { + assert.Equal(t, expected.ID, actual.ID, "UserId doesn't match for user %v", expected.Username) + } + assert.Equal(t, expected.Username, actual.Username, "Username doesn't match for user %v", expected.Username) + assert.Equal(t, expected.Email, actual.Email, "email doesn't match for user %v", expected.Username) + assert.Equal(t, expected.Enabled, actual.Enabled, "enabled doesn't match for user %v", expected.Username) + assert.Equal(t, expected.Displayname, actual.Displayname, "displayname doesn't match for user %v", expected.Username) + if quotaAvailable { + assert.NotZero(t, actual.Quota.Free) + assert.NotZero(t, actual.Quota.Used) + assert.NotZero(t, actual.Quota.Total) + assert.Equal(t, "default", actual.Quota.Definition) + } else { + assert.Equal(t, expected.Quota, actual.Quota, "Quota match for user %v", expected.Username) + } + + // FIXME: gidnumber and Uidnumber are always 0 + // https://github.com/owncloud/ocis-ocs/issues/45 + assert.Equal(t, 0, actual.UIDNumber, "UidNumber doesn't match for user %v", expected.Username) + assert.Equal(t, 0, actual.GIDNumber, "GIDNumber doesn't match for user %v", expected.Username) + +} + +func deleteAccount(t *testing.T, id string) (*empty.Empty, error) { + client := service.Client() + cl := accountsProto.NewAccountsService("com.owncloud.api.accounts", client) + + req := &accountsProto.DeleteAccountRequest{Id: id} + res, err := cl.DeleteAccount(context.Background(), req) + return res, err +} + +func buildRoleServiceMock() settings.RoleService { + return settings.MockRoleService{ + AssignRoleToUserFunc: func(ctx context.Context, req *settings.AssignRoleToUserRequest, opts ...client.CallOption) (res *settings.AssignRoleToUserResponse, err error) { + mockedRoleAssignment[req.AccountUuid] = req.RoleId + return &settings.AssignRoleToUserResponse{ + Assignment: &settings.UserRoleAssignment{ + AccountUuid: req.AccountUuid, + RoleId: req.RoleId, + }, + }, nil + }, + } +} + +func init() { + service = grpc.NewService( + grpc.Namespace("com.owncloud.api"), + grpc.Name("accounts"), + grpc.Address("localhost:9180"), + ) + + c := &accountsCfg.Config{ + Server: accountsCfg.Server{ + AccountsDataPath: dataPath, + }, + Log: accountsCfg.Log{ + Level: "info", + Pretty: true, + Color: true, + }, + } + + var hdlr *accountsSvc.Service + var err error + + if hdlr, err = accountsSvc.New( + accountsSvc.Logger(accountsCmd.NewLogger(c)), + accountsSvc.Config(c), + accountsSvc.RoleService(buildRoleServiceMock())); err != nil { + log.Fatalf("Could not create new service") + } + + hdlr.Client = mockClient{} + + err = accountsProto.RegisterAccountsServiceHandler(service.Server(), hdlr) + if err != nil { + log.Fatal("could not register the Accounts handler") + } + err = accountsProto.RegisterGroupsServiceHandler(service.Server(), hdlr) + if err != nil { + log.Fatal("could not register the Groups handler") + } + + err = service.Server().Start() + if err != nil { + log.Fatalf("could not start server: %v", err) + } +} + +func cleanUp(t *testing.T) { + datastore := filepath.Join(dataPath, "accounts") + + files, err := ioutil.ReadDir(datastore) + if err != nil { + log.Fatal(err) + } + + for _, f := range files { + found := false + for _, defUser := range DefaultUsers { + if f.Name() == defUser { + found = true + break + } + } + + if !found { + deleteAccount(t, f.Name()) + } + } +} + +func sendRequest(method, endpoint, body, auth string) (*httptest.ResponseRecorder, error) { + var reader = strings.NewReader(body) + req, err := http.NewRequest(method, endpoint, reader) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + if auth != "" { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth))) + } + + rr := httptest.NewRecorder() + + service := getService() + service.ServeHTTP(rr, req) + + return rr, nil +} + +func getService() svc.Service { + c := &config.Config{ + HTTP: config.HTTP{ + Root: "/", + Addr: "localhost:9110", + Namespace: "com.owncloud.web", + }, + TokenManager: config.TokenManager{ + JWTSecret: "HELLO-secret", + }, + Log: config.Log{ + Level: "debug", + }, + } + + var logger ocisLog.Logger + + svc := svc.NewService( + svc.Logger(logger), + svc.Config(c), + ) + + return svc +} + +func createUser(u User) error { + _, err := sendRequest( + "POST", + "/v1.php/cloud/users?format=json", + u.getUserRequestString(), + "admin:admin", + ) + + if err != nil { + return err + } + return nil +} + +func TestCreateUser(t *testing.T) { + testData := []struct { + user User + err *Meta + }{ + // A simple user + { + User{ + Enabled: "true", + Username: "rutherford", + ID: "rutherford", + Email: "rutherford@example.com", + Displayname: "ErnestRutherFord", + }, + nil, + }, + + // User with Uid and Gid defined + { + User{ + Enabled: "true", + Username: "thomson", + ID: "thomson", + Email: "thomson@example.com", + Displayname: "J. J. Thomson", + UIDNumber: 20027, + GIDNumber: 30000, + }, + nil, + }, + + // User with different username and Id + { + User{ + Enabled: "true", + Username: "niels", + ID: "bohr", + Email: "bohr@example.com", + Displayname: "Niels Bohr", + }, + nil, + }, + + // User with special character in username + { + User{ + Enabled: "true", + Username: "schrödinger", + ID: "schrödinger", + Email: "schrödinger@example.com", + Displayname: "Erwin Schrödinger", + }, + &Meta{ + Status: "error", + StatusCode: 400, + Message: "preferred_name 'schrödinger' must be at least the local part of an email", + }, + }, + + // User with different userid and email + { + User{ + Enabled: "true", + Username: "planck", + ID: "planck", + Email: "max@example.com", + Displayname: "Max Planck", + }, + nil, + }, + + // User with different userid and email and username + { + User{ + Enabled: "true", + Username: "hisenberg", + ID: "hberg", + Email: "werner@example.com", + Displayname: "Werner Hisenberg", + }, + nil, + }, + + // User without displayname + { + User{ + Enabled: "true", + Username: "oppenheimer", + ID: "oppenheimer", + Email: "robert@example.com", + }, + nil, + }, + + // User wit invalid email + { + User{ + Enabled: "true", + Username: "chadwick", + ID: "chadwick", + Email: "not_a_email", + }, + &Meta{ + Status: "error", + StatusCode: 400, + Message: "mail 'not_a_email' must be a valid email", + }, + }, + + // User without email + { + User{ + Enabled: "true", + Username: "chadwick", + ID: "chadwick", + }, + &Meta{ + Status: "error", + StatusCode: 400, + Message: "mail '' must be a valid email", + }, + }, + + // User without username + { + User{ + Enabled: "true", + ID: "chadwick", + Email: "james@example.com", + }, + &Meta{ + Status: "error", + StatusCode: 400, + Message: "preferred_name '' must be at least the local part of an email", + }, + }, + + // User without userid + { + User{ + Enabled: "true", + Username: "chadwick", + Email: "james@example.com", + }, + nil, + }, + } + + for _, ocsVersion := range ocsVersions { + for _, format := range formats { + for _, data := range testData { + formatpart := getFormatString(format) + res, err := sendRequest( + "POST", + fmt.Sprintf("/%v/cloud/users%v", ocsVersion, formatpart), + data.user.getUserRequestString(), + "admin:admin", + ) + + if err != nil { + t.Fatal(err) + } + + var response SingleUserResponse + + if format == "json" { + if err := json.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } else { + if err := xml.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } + + if data.err == nil { + assert.True(t, response.Meta.Success(ocsVersion), "The response was expected to be successful but was not") + assertStatusCode(t, 200, res, ocsVersion) + assertUserSame(t, data.user, response.Data, false) + } else { + assertStatusCode(t, 400, res, ocsVersion) + assertResponseMeta(t, *data.err, response.Meta) + } + + var id string + if data.user.ID != "" { + id = data.user.ID + } else { + id = response.Data.ID + } + + res, err = sendRequest( + "GET", + "/v1.php/cloud/users?format=json", + "", + "admin:admin", + ) + + if err != nil { + t.Fatal(err) + } + + var usersResponse GetUsersResponse + if err := json.Unmarshal(res.Body.Bytes(), &usersResponse); err != nil { + t.Fatal(err) + } + + assert.True(t, usersResponse.Meta.Success("v1.php"), "The response was expected to be successful but was not") + + if data.err == nil { + assert.Contains(t, usersResponse.Data.Users, id) + } else { + assert.NotContains(t, usersResponse.Data.Users, data.user.ID) + } + } + cleanUp(t) + } + } +} + +func TestGetUsers(t *testing.T) { + users := []User{ + { + Enabled: "true", + Username: "rutherford", + ID: "rutherford", + Email: "rutherford@example.com", + Displayname: "Ernest RutherFord", + }, + { + Enabled: "true", + Username: "thomson", + ID: "thomson", + Email: "thomson@example.com", + Displayname: "J. J. Thomson", + }, + } + + for _, ocsVersion := range ocsVersions { + for _, format := range formats { + for _, user := range users { + err := createUser(user) + if err != nil { + t.Fatal(err) + } + } + + formatpart := getFormatString(format) + res, err := sendRequest( + "GET", + fmt.Sprintf("/%v/cloud/users%v", ocsVersion, formatpart), + "", + "admin:admin", + ) + + if err != nil { + t.Fatal(err) + } + + var response GetUsersResponse + + if format == "json" { + if err := json.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } else { + if err := xml.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } + + assertStatusCode(t, 200, res, ocsVersion) + assert.True(t, response.Meta.Success(ocsVersion), "The response was expected to be successful but was not") + for _, user := range users { + assert.Contains(t, response.Data.Users, user.Username) + } + cleanUp(t) + } + } +} + +func TestGetUsersDefaultUsers(t *testing.T) { + for _, ocsVersion := range ocsVersions { + for _, format := range formats { + formatpart := getFormatString(format) + res, err := sendRequest( + "GET", + fmt.Sprintf("/%v/cloud/users%v", ocsVersion, formatpart), + "", + "admin:admin", + ) + + if err != nil { + t.Fatal(err) + } + + var response GetUsersResponse + + if format == "json" { + if err := json.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } else { + if err := xml.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } + + assertStatusCode(t, 200, res, ocsVersion) + assert.True(t, response.Meta.Success(ocsVersion), "The response was expected to be successful but was not") + for _, user := range DefaultUsers { + assert.Contains(t, response.Data.Users, user) + } + cleanUp(t) + } + } +} + +func TestGetUser(t *testing.T) { + users := []User{ + { + Enabled: "true", + Username: "rutherford", + ID: "rutherford", + Email: "rutherford@example.com", + Displayname: "Ernest RutherFord", + }, + { + Enabled: "true", + Username: "thomson", + ID: "thomson", + Email: "thomson@example.com", + Displayname: "J. J. Thomson", + }, + } + + for _, ocsVersion := range ocsVersions { + for _, format := range formats { + + for _, user := range users { + err := createUser(user) + if err != nil { + t.Fatal(err) + } + } + formatpart := getFormatString(format) + for _, user := range users { + res, err := sendRequest( + "GET", + fmt.Sprintf("/%s/cloud/users/%s%s", ocsVersion, user.ID, formatpart), + "", + "admin:admin", + ) + + if err != nil { + t.Fatal(err) + } + + var response SingleUserResponse + if format == "json" { + if err := json.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } else { + if err := xml.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } + + assertStatusCode(t, 200, res, ocsVersion) + assert.True(t, response.Meta.Success(ocsVersion), "The response was expected to pass but it failed") + assertUserSame(t, user, response.Data, true) + } + cleanUp(t) + } + } +} + +func TestGetUserInvalidId(t *testing.T) { + invalidUsers := []string{ + "1", + "invalid", + "3434234233", + "1am41validUs3r", + "_-@@--$$__", + } + for _, ocsVersion := range ocsVersions { + for _, format := range formats { + formatpart := getFormatString(format) + for _, user := range invalidUsers { + res, err := sendRequest( + "GET", + fmt.Sprintf("/%s/cloud/user/%s%s", ocsVersion, user, formatpart), + "", + "admin:admin", + ) + + if err != nil { + t.Fatal(err) + } + + var response SingleUserResponse + if format == "json" { + if err := json.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } else { + if err := xml.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } + + assertStatusCode(t, 404, res, ocsVersion) + assert.False(t, response.Meta.Success(ocsVersion), "the response was expected to fail but passed") + assertResponseMeta(t, Meta{ + Status: "error", + StatusCode: 998, + Message: "not found", + }, response.Meta) + cleanUp(t) + } + } + } +} +func TestDeleteUser(t *testing.T) { + users := []User{ + { + Enabled: "true", + Username: "rutherford", + ID: "rutherford", + Email: "rutherford@example.com", + Displayname: "Ernest RutherFord", + }, + { + Enabled: "true", + Username: "thomson", + ID: "thomson", + Email: "thomson@example.com", + Displayname: "J. J. Thomson", + }, + } + + for _, ocsVersion := range ocsVersions { + for _, format := range formats { + for _, user := range users { + err := createUser(user) + if err != nil { + t.Fatal(err) + } + } + + formatpart := getFormatString(format) + res, err := sendRequest( + "DELETE", + fmt.Sprintf("/%s/cloud/users/rutherford%s", ocsVersion, formatpart), + "", + "admin:admin", + ) + + if err != nil { + t.Fatal(err) + } + + var response DeleteUserRespone + if format == "json" { + if err := json.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } else { + if err := xml.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } + + assertStatusCode(t, 200, res, ocsVersion) + assert.True(t, response.Meta.Success(ocsVersion), "The response was expected to be successful but was not") + assert.Empty(t, response.Data) + + // Check deleted user doesn't exist and the other user does + res, err = sendRequest( + "GET", + "/v1.php/cloud/users?format=json", + "", + "admin:admin", + ) + + if err != nil { + t.Fatal(err) + } + + var usersResponse GetUsersResponse + if err := json.Unmarshal(res.Body.Bytes(), &usersResponse); err != nil { + t.Fatal(err) + } + + assert.True(t, usersResponse.Meta.Success("v1.php"), "The response was expected to be successful but was not") + assert.Contains(t, usersResponse.Data.Users, "thomson") + assert.NotContains(t, usersResponse.Data.Users, "rutherford") + + cleanUp(t) + } + } +} + +func TestDeleteUserInvalidId(t *testing.T) { + + invalidUsers := []string{ + "1", + "invalid", + "3434234233", + "1am41validUs3r", + "_-@@--$$__", + } + for _, ocsVersion := range ocsVersions { + for _, format := range formats { + for _, user := range invalidUsers { + formatpart := getFormatString(format) + res, err := sendRequest( + "DELETE", + fmt.Sprintf("/%s/cloud/users/%s%s", ocsVersion, user, formatpart), + "", + "admin:admin", + ) + + if err != nil { + t.Fatal(err) + } + + var response DeleteUserRespone + if format == "json" { + if err := json.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } else { + if err := xml.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } + + assertStatusCode(t, 404, res, ocsVersion) + assert.False(t, response.Meta.Success(ocsVersion), "The response was not expected to be successful but was") + assert.Empty(t, response.Data) + + assertResponseMeta(t, Meta{ + Status: "error", + StatusCode: 998, + Message: "The requested user could not be found", + }, response.Meta) + } + } + } +} + +func TestUpdateUser(t *testing.T) { + user := User{ + Enabled: "true", + Username: "rutherford", + ID: "rutherford", + Email: "rutherford@example.com", + Displayname: "Ernest RutherFord", + } + + testData := []struct { + UpdateKey string + UpdateValue string + Error *Meta + }{ + { + "displayname", + "James Chadwick", + nil, + }, + { + "display", + "Neils Bohr", + nil, + }, + { + "email", + "ford@user.org", + nil, + }, + // Invalid email doesn't gives error + // https://github.com/owncloud/ocis-ocs/issues/46 + { + "email", + "not_a_valid_email", + nil, + }, + { + "password", + "strongpass1234", + nil, + }, + { + "username", + "e_rutherford", + nil, + }, + // Empty values doesn't gives error + { + "email", + "", + nil, + }, + { + "username", + "", + nil, + }, + { + "password", + "", + nil, + }, + + // Invalid Keys + { + "invalid_key", + "validvalue", + &Meta{ + Status: "error", + StatusCode: 103, + Message: "unknown key 'invalid_key'", + }, + }, + { + "12345", + "validvalue", + &Meta{ + Status: "error", + StatusCode: 103, + Message: "unknown key '12345'", + }, + }, + { + "", + "validvalue", + &Meta{ + Status: "error", + StatusCode: 103, + Message: "unknown key ''", + }, + }, + { + "", + "", + &Meta{ + Status: "error", + StatusCode: 103, + Message: "unknown key ''", + }, + }, + } + + for _, ocsVersion := range ocsVersions { + for _, format := range formats { + formatpart := getFormatString(format) + for _, data := range testData { + err := createUser(user) + if err != nil { + t.Fatalf("Failed while creating user: %v", err) + } + + params := url.Values{} + + params.Add("key", data.UpdateKey) + params.Add("value", data.UpdateValue) + + res, err := sendRequest( + "PUT", + fmt.Sprintf("/%s/cloud/users/rutherford%s", ocsVersion, formatpart), + params.Encode(), + "admin:admin", + ) + + updatedUser := user + switch data.UpdateKey { + case "username": + updatedUser.Username = data.UpdateValue + case "email": + updatedUser.Email = data.UpdateValue + case "displayname": + updatedUser.Displayname = data.UpdateValue + case "display": + updatedUser.Displayname = data.UpdateValue + } + + if err != nil { + t.Fatal(err) + } + + var response struct { + Meta Meta `json:"meta" xml:"meta"` + } + + if format == "json" { + if err := json.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } else { + if err := xml.Unmarshal(res.Body.Bytes(), &response); err != nil { + t.Fatal(err) + } + } + + if data.Error != nil { + assertResponseMeta(t, *data.Error, response.Meta) + assertStatusCode(t, 400, res, ocsVersion) + } else { + assert.True(t, response.Meta.Success(ocsVersion), "The response was expected to be successful but failed") + assertStatusCode(t, 200, res, ocsVersion) + } + + // Check deleted user doesn't exist and the other user does + res, err = sendRequest( + "GET", + "/v1.php/cloud/users/rutherford?format=json", + "", + "admin:admin", + ) + + if err != nil { + t.Fatal(err) + } + + var usersResponse SingleUserResponse + if err := json.Unmarshal(res.Body.Bytes(), &usersResponse); err != nil { + t.Fatal(err) + } + + assert.True(t, usersResponse.Meta.Success("v1.php"), "The response was expected to be successful but was not") + if data.Error == nil { + assertUserSame(t, updatedUser, usersResponse.Data, true) + } else { + assertUserSame(t, user, usersResponse.Data, true) + } + cleanUp(t) + } + } + } +} + +type mockClient struct{} + +func (c mockClient) Init(option ...client.Option) error { + return nil +} + +func (c mockClient) Options() client.Options { + return client.Options{} +} + +func (c mockClient) NewMessage(topic string, msg interface{}, opts ...client.MessageOption) client.Message { + return nil +} + +func (c mockClient) NewRequest(service, endpoint string, req interface{}, reqOpts ...client.RequestOption) client.Request { + return nil +} + +func (c mockClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { + return nil +} + +func (c mockClient) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) { + return nil, nil +} + +func (c mockClient) Publish(ctx context.Context, msg client.Message, opts ...client.PublishOption) error { + return nil +} + +func (c mockClient) String() string { + return "ClientMock" +}