package handler import ( "bytes" "fmt" "gosimplenpm/internal/config" "gosimplenpm/internal/serviceidos" "gosimplenpm/internal/storage" "io" "net/http" "net/http/httptest" "net/url" "os" "testing" "github.com/gorilla/mux" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" ) func TestUnitPublish(t *testing.T) { t.Run("return `Internal Server` error if index.json cannot be retrieved", func(t *testing.T) { jsonBody := []byte( `{ "_id": "@ookusanya/simplepackone", "name": "@ookusanya/simplepackone", "description": "This is a very rough implementation of a private npm registry.", "dist-tags": { "latest": "1.2.0" }, "versions": { "1.2.0": { "name": "@ookusanya/simplepackone", "version": "1.2.0", "description": "This is a very rough implementation of a private npm registry.", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "license": "MIT", "files": null, "readme": "# Gosimplenpm\n\nThis is a very rough implementation of a private npm registry.\n\n# Features\n\nTODO...\n\n# Enhancements\n\nTODO...\n\n# Work List\n\nTODO...", "_id": "@ookusanya/simplepackone@1.2.0", "_nodeVersion": "16.20.0", "_npmVersion": "8.19.4", "dist": { "integrity": "sha512-coOiU+ywV/do/+HwK91mfuei9491yfQUedLWjspAjDa58RniJvQNTF/cXDp/sooVdpjgEbCqKVyLOju6C1i3pw==", "shasum": "1adafdbe8878372c9f4b554bf30d5bfb1b7896c5", "tarball": "http://localhost:4000/@ookusanya%2Fsimplepackone/-/@ookusanya%2Fsimplepackone-1.2.0.tgz" }, "dependencies": { "eslint": "^7.x", "mocha": "^10.x", "uuid": "^9.x" } } }, "access": "", "_attachments": { "@ookusanya/simplepackone-1.2.0.tgz": { "content_type": "application/octet-stream", "data": "H4sIAAAAAAAC/+1XbWvjOBDuZ/+KwQtLCyZ10pfl+uncRGnMOnawne0VlgXVVmJtHctIcl849r/fSEmb9nof73LcXoaA0Lw9M6PMSG5pcUeX7Jg3JXvsfVcH/wD5vn9+egp/xbc0OIGDk7Nzv98/P/dRz+/7nwY+rgc7oE5pKjGUvyFJJHhZ/yNUiEaJmvVqsTx0J0wy9+hgT/8fajf9v1lxAohmx/1/ev6u//tnZ/19/++CfncA3IaumHsB7q9C3HWKNk/0WPFVWzPzrxANcz2jdc+k4qIxiv3eoOevuSVTheSt3kjWzBXldvd8q6y5a0WFAoOKDM2UNmqsqAR8dYmUQl5AI8AIQLWs4AvOyq8ufPwI7JFr6Lto+cN6o52uhNxi1rxgjbJ5TMP8ObiWYQhNwdkrWKZq3ljgb596j1bTxCyKilpm399yu46X7oX77RdkGWjnh/NT9n9KgtGU9Fbl7u//waD/7v4/Oxns+38X9AGuxLrXm3blOHnFFeCPAnb7E0jRLSuw4hVrNDVdDmKB4lbye6oZoBVItuRKy6ee43yAMaO6k0yhr2SU9HqWSZqKNoX18VZwLeQdRGj9wt1fyf9K/0fhkMQZ6elHveP+H/hng3f3f9/f9/9OyBmK9knyZaXhsDiCgfkYS+rugZZ0xWtRU0g2TwLHmTG54sq8AcyIqPBj4fYJlpI2mpUeLCRjZjbgLSqXzAMtAM2gxVeDGRq3Gt8EvFk6FAqENJraDBslFvqBSobKJVClRMFxrpRQiqLbzpwFr5mCQ10xx802Fu6RBSkZrYE36I3BswgeOD4OOo2jCQcTL4wPD5WKuitNDM/imq/4BsGY2zoo47RTmIGJ04OVKPnCrMym1Xa3NVeV55Rm5vHbTiNTGaZ9fngmj2MhQbG6Nh7w5bHOdRud1UEUpzUF1ZsSWdyHSqzeZoIlWnSyQUhW2nQFlswifmeFNl6M+kLUtXjA1BCyKbnJSF2YcY51vRX3zOayPuZGaAx1HYI5gHZ7qhuRqijGfsucdcEQF8tLX6UjDTz2TaM51r4V0uL9OU0c8PmEQJaM8+sgJRBmMEuTL+GIjMANMty7HlyH+SSZ54AaaRDnN5CMIYhv4HMYjzyH/DZLSZZBkkI4nUUhGXkQxsNoPgrjK7hEuzjJIQrxwYdO8wQM4MZVSNBu7ExJOpzgNrgMozC/8WAc5rHxOUanAcyCNA+H8yhIYTZPZ0lGEH7kxEkcxuMUUciUxHkPUREKyBfcQDYJoshCBXOMPrXxDZPZTRpeTXKYJNGIIPOSOFEYXEZkDYVJDaMgnHowCqbBFbFWCXpJwahtorueEMtCvAB/wzxMYgdrMkziPMWth1mm+YvpdZgRD4I0zExBxmmC7k050SKxTtAuJmsvptTw5kRQxeznGdnGMiJBhL4yY/xaeX8x72lPe9rTT0V/APlm4rcAGAAA", "length": 1089 } } }`, ) req := httptest.NewRequest(http.MethodPut, "/{name}", bytes.NewReader(jsonBody)) wrt := httptest.NewRecorder() lg := &logrus.Logger{ Out: os.Stdout, // Level: "DEBUG", Formatter: &logrus.TextFormatter{ FullTimestamp: true, TimestampFormat: "2009-01-02 15:15:15", }, } cfg := config.Config{ RepoDir: "", } mfs := &storage.MockFs{} mfs.GetIndexJsonFromStoreFunc = func(packageName string, registryPath string, lg *logrus.Logger) (string, bool, error) { return "", false, fmt.Errorf("Filesystem error") } vars := map[string]string{ "name": "@ookusanya%2Fsimplepackone", } req = mux.SetURLVars(req, vars) Publish(lg, cfg, mfs)(wrt, req) rs := wrt.Result() assert.Equal(t, rs.StatusCode, http.StatusInternalServerError) defer rs.Body.Close() body, err := io.ReadAll(rs.Body) if err != nil { t.Fatal(err) } bytes.TrimSpace(body) assert.Equal(t, string(body), "Filesystem error\n") }) t.Run("return `Internal Server` error if index.json cannot be decoded", func(t *testing.T) { jsonBody := []byte( `{ "_id": "@ookusanya/simplepackone", "name": "@ookusanya/simplepackone", "description": "This is a very rough implementation of a private npm registry.", "dist-tags": { "latest": "1.2.0" }, "versions": { "1.2.0": { "name": "@ookusanya/simplepackone", "version": "1.2.0", "description": "This is a very rough implementation of a private npm registry.", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "license": "MIT", "files": null, "readme": "# Gosimplenpm\n\nThis is a very rough implementation of a private npm registry.\n\n# Features\n\nTODO...\n\n# Enhancements\n\nTODO...\n\n# Work List\n\nTODO...", "_id": "@ookusanya/simplepackone@1.2.0", "_nodeVersion": "16.20.0", "_npmVersion": "8.19.4", "dist": { "integrity": "sha512-coOiU+ywV/do/+HwK91mfuei9491yfQUedLWjspAjDa58RniJvQNTF/cXDp/sooVdpjgEbCqKVyLOju6C1i3pw==", "shasum": "1adafdbe8878372c9f4b554bf30d5bfb1b7896c5", "tarball": "http://localhost:4000/@ookusanya%2Fsimplepackone/-/@ookusanya%2Fsimplepackone-1.2.0.tgz" }, "dependencies": { "eslint": "^7.x", "mocha": "^10.x", "uuid": "^9.x" } } }, "access": "", "_attachments": { "@ookusanya/simplepackone-1.2.0.tgz": { "content_type": "application/octet-stream", "data": "H4sIAAAAAAAC/+1XbWvjOBDuZ/+KwQtLCyZ10pfl+uncRGnMOnawne0VlgXVVmJtHctIcl849r/fSEmb9nof73LcXoaA0Lw9M6PMSG5pcUeX7Jg3JXvsfVcH/wD5vn9+egp/xbc0OIGDk7Nzv98/P/dRz+/7nwY+rgc7oE5pKjGUvyFJJHhZ/yNUiEaJmvVqsTx0J0wy9+hgT/8fajf9v1lxAohmx/1/ev6u//tnZ/19/++CfncA3IaumHsB7q9C3HWKNk/0WPFVWzPzrxANcz2jdc+k4qIxiv3eoOevuSVTheSt3kjWzBXldvd8q6y5a0WFAoOKDM2UNmqsqAR8dYmUQl5AI8AIQLWs4AvOyq8ufPwI7JFr6Lto+cN6o52uhNxi1rxgjbJ5TMP8ObiWYQhNwdkrWKZq3ljgb596j1bTxCyKilpm399yu46X7oX77RdkGWjnh/NT9n9KgtGU9Fbl7u//waD/7v4/Oxns+38X9AGuxLrXm3blOHnFFeCPAnb7E0jRLSuw4hVrNDVdDmKB4lbye6oZoBVItuRKy6ee43yAMaO6k0yhr2SU9HqWSZqKNoX18VZwLeQdRGj9wt1fyf9K/0fhkMQZ6elHveP+H/hng3f3f9/f9/9OyBmK9knyZaXhsDiCgfkYS+rugZZ0xWtRU0g2TwLHmTG54sq8AcyIqPBj4fYJlpI2mpUeLCRjZjbgLSqXzAMtAM2gxVeDGRq3Gt8EvFk6FAqENJraDBslFvqBSobKJVClRMFxrpRQiqLbzpwFr5mCQ10xx802Fu6RBSkZrYE36I3BswgeOD4OOo2jCQcTL4wPD5WKuitNDM/imq/4BsGY2zoo47RTmIGJ04OVKPnCrMym1Xa3NVeV55Rm5vHbTiNTGaZ9fngmj2MhQbG6Nh7w5bHOdRud1UEUpzUF1ZsSWdyHSqzeZoIlWnSyQUhW2nQFlswifmeFNl6M+kLUtXjA1BCyKbnJSF2YcY51vRX3zOayPuZGaAx1HYI5gHZ7qhuRqijGfsucdcEQF8tLX6UjDTz2TaM51r4V0uL9OU0c8PmEQJaM8+sgJRBmMEuTL+GIjMANMty7HlyH+SSZ54AaaRDnN5CMIYhv4HMYjzyH/DZLSZZBkkI4nUUhGXkQxsNoPgrjK7hEuzjJIQrxwYdO8wQM4MZVSNBu7ExJOpzgNrgMozC/8WAc5rHxOUanAcyCNA+H8yhIYTZPZ0lGEH7kxEkcxuMUUciUxHkPUREKyBfcQDYJoshCBXOMPrXxDZPZTRpeTXKYJNGIIPOSOFEYXEZkDYVJDaMgnHowCqbBFbFWCXpJwahtorueEMtCvAB/wzxMYgdrMkziPMWth1mm+YvpdZgRD4I0zExBxmmC7k050SKxTtAuJmsvptTw5kRQxeznGdnGMiJBhL4yY/xaeX8x72lPe9rTT0V/APlm4rcAGAAA", "length": 1089 } } }`, ) req := httptest.NewRequest(http.MethodPut, "/{name}", bytes.NewReader(jsonBody)) wrt := httptest.NewRecorder() lg := &logrus.Logger{ Out: os.Stdout, // Level: "DEBUG", Formatter: &logrus.TextFormatter{ FullTimestamp: true, TimestampFormat: "2009-01-02 15:15:15", }, } cfg := config.Config{ RepoDir: "", } mfs := &storage.MockFs{} mfs.GetIndexJsonFromStoreFunc = func(packageName string, registryPath string, lg *logrus.Logger) (string, bool, error) { return string(jsonBody), true, nil } mfs.ReadIndexJsonFunc = func(fPath string, res *serviceidos.IndexJson, lg *logrus.Logger) error { return fmt.Errorf("Filesystem error") } vars := map[string]string{ "name": "@ookusanya%2Fsimplepackone", } req = mux.SetURLVars(req, vars) Publish(lg, cfg, mfs)(wrt, req) rs := wrt.Result() assert.Equal(t, rs.StatusCode, http.StatusInternalServerError) defer rs.Body.Close() body, err := io.ReadAll(rs.Body) if err != nil { t.Fatal(err) } bytes.TrimSpace(body) assert.Equal(t, string(body), "Filesystem error\n") }) t.Run("return `Bad Request` error if version to publish already exists", func(t *testing.T) { jsonBody := []byte( `{ "_id": "@ookusanya/simplepackone", "name": "@ookusanya/simplepackone", "description": "This is a very rough implementation of a private npm registry.", "dist-tags": { "latest": "1.2.0" }, "versions": { "1.2.0": { "name": "@ookusanya/simplepackone", "version": "1.2.0", "description": "This is a very rough implementation of a private npm registry.", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "license": "MIT", "files": null, "readme": "# Gosimplenpm\n\nThis is a very rough implementation of a private npm registry.\n\n# Features\n\nTODO...\n\n# Enhancements\n\nTODO...\n\n# Work List\n\nTODO...", "_id": "@ookusanya/simplepackone@1.2.0", "_nodeVersion": "16.20.0", "_npmVersion": "8.19.4", "dist": { "integrity": "sha512-coOiU+ywV/do/+HwK91mfuei9491yfQUedLWjspAjDa58RniJvQNTF/cXDp/sooVdpjgEbCqKVyLOju6C1i3pw==", "shasum": "1adafdbe8878372c9f4b554bf30d5bfb1b7896c5", "tarball": "http://localhost:4000/@ookusanya%2Fsimplepackone/-/@ookusanya%2Fsimplepackone-1.2.0.tgz" }, "dependencies": { "eslint": "^7.x", "mocha": "^10.x", "uuid": "^9.x" } } }, "access": "", "_attachments": { "@ookusanya/simplepackone-1.2.0.tgz": { "content_type": "application/octet-stream", "data": "H4sIAAAAAAAC/+1XbWvjOBDuZ/+KwQtLCyZ10pfl+uncRGnMOnawne0VlgXVVmJtHctIcl849r/fSEmb9nof73LcXoaA0Lw9M6PMSG5pcUeX7Jg3JXvsfVcH/wD5vn9+egp/xbc0OIGDk7Nzv98/P/dRz+/7nwY+rgc7oE5pKjGUvyFJJHhZ/yNUiEaJmvVqsTx0J0wy9+hgT/8fajf9v1lxAohmx/1/ev6u//tnZ/19/++CfncA3IaumHsB7q9C3HWKNk/0WPFVWzPzrxANcz2jdc+k4qIxiv3eoOevuSVTheSt3kjWzBXldvd8q6y5a0WFAoOKDM2UNmqsqAR8dYmUQl5AI8AIQLWs4AvOyq8ufPwI7JFr6Lto+cN6o52uhNxi1rxgjbJ5TMP8ObiWYQhNwdkrWKZq3ljgb596j1bTxCyKilpm399yu46X7oX77RdkGWjnh/NT9n9KgtGU9Fbl7u//waD/7v4/Oxns+38X9AGuxLrXm3blOHnFFeCPAnb7E0jRLSuw4hVrNDVdDmKB4lbye6oZoBVItuRKy6ee43yAMaO6k0yhr2SU9HqWSZqKNoX18VZwLeQdRGj9wt1fyf9K/0fhkMQZ6elHveP+H/hng3f3f9/f9/9OyBmK9knyZaXhsDiCgfkYS+rugZZ0xWtRU0g2TwLHmTG54sq8AcyIqPBj4fYJlpI2mpUeLCRjZjbgLSqXzAMtAM2gxVeDGRq3Gt8EvFk6FAqENJraDBslFvqBSobKJVClRMFxrpRQiqLbzpwFr5mCQ10xx802Fu6RBSkZrYE36I3BswgeOD4OOo2jCQcTL4wPD5WKuitNDM/imq/4BsGY2zoo47RTmIGJ04OVKPnCrMym1Xa3NVeV55Rm5vHbTiNTGaZ9fngmj2MhQbG6Nh7w5bHOdRud1UEUpzUF1ZsSWdyHSqzeZoIlWnSyQUhW2nQFlswifmeFNl6M+kLUtXjA1BCyKbnJSF2YcY51vRX3zOayPuZGaAx1HYI5gHZ7qhuRqijGfsucdcEQF8tLX6UjDTz2TaM51r4V0uL9OU0c8PmEQJaM8+sgJRBmMEuTL+GIjMANMty7HlyH+SSZ54AaaRDnN5CMIYhv4HMYjzyH/DZLSZZBkkI4nUUhGXkQxsNoPgrjK7hEuzjJIQrxwYdO8wQM4MZVSNBu7ExJOpzgNrgMozC/8WAc5rHxOUanAcyCNA+H8yhIYTZPZ0lGEH7kxEkcxuMUUciUxHkPUREKyBfcQDYJoshCBXOMPrXxDZPZTRpeTXKYJNGIIPOSOFEYXEZkDYVJDaMgnHowCqbBFbFWCXpJwahtorueEMtCvAB/wzxMYgdrMkziPMWth1mm+YvpdZgRD4I0zExBxmmC7k050SKxTtAuJmsvptTw5kRQxeznGdnGMiJBhL4yY/xaeX8x72lPe9rTT0V/APlm4rcAGAAA", "length": 1089 } } }`, ) req := httptest.NewRequest(http.MethodPut, "/{name}", bytes.NewReader(jsonBody)) wrt := httptest.NewRecorder() lg := &logrus.Logger{ Out: os.Stdout, // Level: "DEBUG", Formatter: &logrus.TextFormatter{ FullTimestamp: true, TimestampFormat: "2009-01-02 15:15:15", }, } cfg := config.Config{ RepoDir: "", } mfs := &storage.MockFs{} mfs.GetIndexJsonFromStoreFunc = func(packageName string, registryPath string, lg *logrus.Logger) (string, bool, error) { return string(jsonBody), true, nil } mfs.ReadIndexJsonFunc = func(fPath string, res *serviceidos.IndexJson, lg *logrus.Logger) error { temp := serviceidos.IndexJson{ Versions: map[string]serviceidos.IndexJsonVersions{ "1.2.0": { Version: "1.2.0", Name: "@ookusanya/simplepackone", }, }, } *res = temp return nil } mfs.WriteIndexJsonFunc = func(fPath string, res *serviceidos.IndexJson, lg *logrus.Logger) error { return fmt.Errorf("Filesystem error") } vars := map[string]string{ "name": "@ookusanya%2Fsimplepackone", } req = mux.SetURLVars(req, vars) Publish(lg, cfg, mfs)(wrt, req) rs := wrt.Result() assert.Equal(t, rs.StatusCode, http.StatusBadRequest) defer rs.Body.Close() body, err := io.ReadAll(rs.Body) if err != nil { t.Fatal(err) } bytes.TrimSpace(body) assert.Equal(t, string(body), "Version 1.2.0 of package @ookusanya/simplepackone already exists!!\n\n") }) t.Run("return `Internal Server` error if writing index.json fails", func(t *testing.T) { jsonBody := []byte( `{ "_id": "@ookusanya/simplepackone", "name": "@ookusanya/simplepackone", "description": "This is a very rough implementation of a private npm registry.", "dist-tags": { "latest": "1.3.0" }, "versions": { "1.3.0": { "name": "@ookusanya/simplepackone", "version": "1.3.0", "description": "This is a very rough implementation of a private npm registry.", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "license": "MIT", "files": null, "readme": "# Gosimplenpm\n\nThis is a very rough implementation of a private npm registry.\n\n# Features\n\nTODO...\n\n# Enhancements\n\nTODO...\n\n# Work List\n\nTODO...", "_id": "@ookusanya/simplepackone@1.2.0", "_nodeVersion": "16.20.0", "_npmVersion": "8.19.4", "dist": { "integrity": "sha512-coOiU+ywV/do/+HwK91mfuei9491yfQUedLWjspAjDa58RniJvQNTF/cXDp/sooVdpjgEbCqKVyLOju6C1i3pw==", "shasum": "1adafdbe8878372c9f4b554bf30d5bfb1b7896c5", "tarball": "http://localhost:4000/@ookusanya%2Fsimplepackone/-/@ookusanya%2Fsimplepackone-1.2.0.tgz" }, "dependencies": { "eslint": "^7.x", "mocha": "^10.x", "uuid": "^9.x" } } }, "access": "", "_attachments": { "@ookusanya/simplepackone-1.3.0.tgz": { "content_type": "application/octet-stream", "data": "H4sIAAAAAAAC/+1XbWvjOBDuZ/+KwQtLCyZ10pfl+uncRGnMOnawne0VlgXVVmJtHctIcl849r/fSEmb9nof73LcXoaA0Lw9M6PMSG5pcUeX7Jg3JXvsfVcH/wD5vn9+egp/xbc0OIGDk7Nzv98/P/dRz+/7nwY+rgc7oE5pKjGUvyFJJHhZ/yNUiEaJmvVqsTx0J0wy9+hgT/8fajf9v1lxAohmx/1/ev6u//tnZ/19/++CfncA3IaumHsB7q9C3HWKNk/0WPFVWzPzrxANcz2jdc+k4qIxiv3eoOevuSVTheSt3kjWzBXldvd8q6y5a0WFAoOKDM2UNmqsqAR8dYmUQl5AI8AIQLWs4AvOyq8ufPwI7JFr6Lto+cN6o52uhNxi1rxgjbJ5TMP8ObiWYQhNwdkrWKZq3ljgb596j1bTxCyKilpm399yu46X7oX77RdkGWjnh/NT9n9KgtGU9Fbl7u//waD/7v4/Oxns+38X9AGuxLrXm3blOHnFFeCPAnb7E0jRLSuw4hVrNDVdDmKB4lbye6oZoBVItuRKy6ee43yAMaO6k0yhr2SU9HqWSZqKNoX18VZwLeQdRGj9wt1fyf9K/0fhkMQZ6elHveP+H/hng3f3f9/f9/9OyBmK9knyZaXhsDiCgfkYS+rugZZ0xWtRU0g2TwLHmTG54sq8AcyIqPBj4fYJlpI2mpUeLCRjZjbgLSqXzAMtAM2gxVeDGRq3Gt8EvFk6FAqENJraDBslFvqBSobKJVClRMFxrpRQiqLbzpwFr5mCQ10xx802Fu6RBSkZrYE36I3BswgeOD4OOo2jCQcTL4wPD5WKuitNDM/imq/4BsGY2zoo47RTmIGJ04OVKPnCrMym1Xa3NVeV55Rm5vHbTiNTGaZ9fngmj2MhQbG6Nh7w5bHOdRud1UEUpzUF1ZsSWdyHSqzeZoIlWnSyQUhW2nQFlswifmeFNl6M+kLUtXjA1BCyKbnJSF2YcY51vRX3zOayPuZGaAx1HYI5gHZ7qhuRqijGfsucdcEQF8tLX6UjDTz2TaM51r4V0uL9OU0c8PmEQJaM8+sgJRBmMEuTL+GIjMANMty7HlyH+SSZ54AaaRDnN5CMIYhv4HMYjzyH/DZLSZZBkkI4nUUhGXkQxsNoPgrjK7hEuzjJIQrxwYdO8wQM4MZVSNBu7ExJOpzgNrgMozC/8WAc5rHxOUanAcyCNA+H8yhIYTZPZ0lGEH7kxEkcxuMUUciUxHkPUREKyBfcQDYJoshCBXOMPrXxDZPZTRpeTXKYJNGIIPOSOFEYXEZkDYVJDaMgnHowCqbBFbFWCXpJwahtorueEMtCvAB/wzxMYgdrMkziPMWth1mm+YvpdZgRD4I0zExBxmmC7k050SKxTtAuJmsvptTw5kRQxeznGdnGMiJBhL4yY/xaeX8x72lPe9rTT0V/APlm4rcAGAAA", "length": 1089 } } }`, ) req := httptest.NewRequest(http.MethodPut, "/{name}", bytes.NewReader(jsonBody)) wrt := httptest.NewRecorder() lg := &logrus.Logger{ Out: os.Stdout, // Level: "DEBUG", Formatter: &logrus.TextFormatter{ FullTimestamp: true, TimestampFormat: "2009-01-02 15:15:15", }, } cfg := config.Config{ RepoDir: "", } mfs := &storage.MockFs{} mfs.GetIndexJsonFromStoreFunc = func(packageName string, registryPath string, lg *logrus.Logger) (string, bool, error) { return string(jsonBody), true, nil } mfs.ReadIndexJsonFunc = func(fPath string, res *serviceidos.IndexJson, lg *logrus.Logger) error { temp := serviceidos.IndexJson{ Versions: map[string]serviceidos.IndexJsonVersions{ "1.2.0": { Version: "1.2.0", Name: "@ookusanya/simplepackone", }, }, DistTags: map[string]string{ "latest": "1.2.0", }, TimesPackage: map[string]string{ "modified": "", "created": "", }, } *res = temp return nil } mfs.WriteIndexJsonFunc = func(fPath string, res *serviceidos.IndexJson, lg *logrus.Logger) error { return fmt.Errorf("Filesystem error") } vars := map[string]string{ "name": "@ookusanya%2Fsimplepackone", } req = mux.SetURLVars(req, vars) Publish(lg, cfg, mfs)(wrt, req) rs := wrt.Result() assert.Equal(t, rs.StatusCode, http.StatusInternalServerError) defer rs.Body.Close() body, err := io.ReadAll(rs.Body) if err != nil { t.Fatal(err) } bytes.TrimSpace(body) assert.Equal(t, string(body), "Filesystem error\n") }) t.Run("return `Internal Server` error if writing tar package fails", func(t *testing.T) { jsonBody := []byte( `{ "_id": "@ookusanya/simplepackone", "name": "@ookusanya/simplepackone", "description": "This is a very rough implementation of a private npm registry.", "dist-tags": { "latest": "1.3.0" }, "versions": { "1.3.0": { "name": "@ookusanya/simplepackone", "version": "1.3.0", "description": "This is a very rough implementation of a private npm registry.", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "license": "MIT", "files": null, "readme": "# Gosimplenpm\n\nThis is a very rough implementation of a private npm registry.\n\n# Features\n\nTODO...\n\n# Enhancements\n\nTODO...\n\n# Work List\n\nTODO...", "_id": "@ookusanya/simplepackone@1.2.0", "_nodeVersion": "16.20.0", "_npmVersion": "8.19.4", "dist": { "integrity": "sha512-coOiU+ywV/do/+HwK91mfuei9491yfQUedLWjspAjDa58RniJvQNTF/cXDp/sooVdpjgEbCqKVyLOju6C1i3pw==", "shasum": "1adafdbe8878372c9f4b554bf30d5bfb1b7896c5", "tarball": "http://localhost:4000/@ookusanya%2Fsimplepackone/-/@ookusanya%2Fsimplepackone-1.2.0.tgz" }, "dependencies": { "eslint": "^7.x", "mocha": "^10.x", "uuid": "^9.x" } } }, "access": "", "_attachments": { "@ookusanya/simplepackone-1.3.0.tgz": { "content_type": "application/octet-stream", "data": "H4sIAAAAAAAC/+1XbWvjOBDuZ/+KwQtLCyZ10pfl+uncRGnMOnawne0VlgXVVmJtHctIcl849r/fSEmb9nof73LcXoaA0Lw9M6PMSG5pcUeX7Jg3JXvsfVcH/wD5vn9+egp/xbc0OIGDk7Nzv98/P/dRz+/7nwY+rgc7oE5pKjGUvyFJJHhZ/yNUiEaJmvVqsTx0J0wy9+hgT/8fajf9v1lxAohmx/1/ev6u//tnZ/19/++CfncA3IaumHsB7q9C3HWKNk/0WPFVWzPzrxANcz2jdc+k4qIxiv3eoOevuSVTheSt3kjWzBXldvd8q6y5a0WFAoOKDM2UNmqsqAR8dYmUQl5AI8AIQLWs4AvOyq8ufPwI7JFr6Lto+cN6o52uhNxi1rxgjbJ5TMP8ObiWYQhNwdkrWKZq3ljgb596j1bTxCyKilpm399yu46X7oX77RdkGWjnh/NT9n9KgtGU9Fbl7u//waD/7v4/Oxns+38X9AGuxLrXm3blOHnFFeCPAnb7E0jRLSuw4hVrNDVdDmKB4lbye6oZoBVItuRKy6ee43yAMaO6k0yhr2SU9HqWSZqKNoX18VZwLeQdRGj9wt1fyf9K/0fhkMQZ6elHveP+H/hng3f3f9/f9/9OyBmK9knyZaXhsDiCgfkYS+rugZZ0xWtRU0g2TwLHmTG54sq8AcyIqPBj4fYJlpI2mpUeLCRjZjbgLSqXzAMtAM2gxVeDGRq3Gt8EvFk6FAqENJraDBslFvqBSobKJVClRMFxrpRQiqLbzpwFr5mCQ10xx802Fu6RBSkZrYE36I3BswgeOD4OOo2jCQcTL4wPD5WKuitNDM/imq/4BsGY2zoo47RTmIGJ04OVKPnCrMym1Xa3NVeV55Rm5vHbTiNTGaZ9fngmj2MhQbG6Nh7w5bHOdRud1UEUpzUF1ZsSWdyHSqzeZoIlWnSyQUhW2nQFlswifmeFNl6M+kLUtXjA1BCyKbnJSF2YcY51vRX3zOayPuZGaAx1HYI5gHZ7qhuRqijGfsucdcEQF8tLX6UjDTz2TaM51r4V0uL9OU0c8PmEQJaM8+sgJRBmMEuTL+GIjMANMty7HlyH+SSZ54AaaRDnN5CMIYhv4HMYjzyH/DZLSZZBkkI4nUUhGXkQxsNoPgrjK7hEuzjJIQrxwYdO8wQM4MZVSNBu7ExJOpzgNrgMozC/8WAc5rHxOUanAcyCNA+H8yhIYTZPZ0lGEH7kxEkcxuMUUciUxHkPUREKyBfcQDYJoshCBXOMPrXxDZPZTRpeTXKYJNGIIPOSOFEYXEZkDYVJDaMgnHowCqbBFbFWCXpJwahtorueEMtCvAB/wzxMYgdrMkziPMWth1mm+YvpdZgRD4I0zExBxmmC7k050SKxTtAuJmsvptTw5kRQxeznGdnGMiJBhL4yY/xaeX8x72lPe9rTT0V/APlm4rcAGAAA", "length": 1089 } } }`, ) req := httptest.NewRequest(http.MethodPut, "/{name}", bytes.NewReader(jsonBody)) wrt := httptest.NewRecorder() lg := &logrus.Logger{ Out: os.Stdout, // Level: "DEBUG", Formatter: &logrus.TextFormatter{ FullTimestamp: true, TimestampFormat: "2009-01-02 15:15:15", }, } cfg := config.Config{ RepoDir: "", } mfs := &storage.MockFs{} mfs.GetIndexJsonFromStoreFunc = func(packageName string, registryPath string, lg *logrus.Logger) (string, bool, error) { return string(jsonBody), true, nil } mfs.ReadIndexJsonFunc = func(fPath string, res *serviceidos.IndexJson, lg *logrus.Logger) error { temp := serviceidos.IndexJson{ Versions: map[string]serviceidos.IndexJsonVersions{ "1.2.0": { Version: "1.2.0", Name: "@ookusanya/simplepackone", }, }, DistTags: map[string]string{ "latest": "1.2.0", }, TimesPackage: map[string]string{ "modified": "", "created": "", }, } *res = temp return nil } mfs.WriteIndexJsonFunc = func(fPath string, res *serviceidos.IndexJson, lg *logrus.Logger) error { return nil } mfs.WritePackageToStoreFunc = func(fPath string, data string, lg *logrus.Logger) error { return fmt.Errorf("Filesystem error") } vars := map[string]string{ "name": "@ookusanya%2Fsimplepackone", } req = mux.SetURLVars(req, vars) Publish(lg, cfg, mfs)(wrt, req) rs := wrt.Result() assert.Equal(t, rs.StatusCode, http.StatusInternalServerError) defer rs.Body.Close() body, err := io.ReadAll(rs.Body) if err != nil { t.Fatal(err) } bytes.TrimSpace(body) assert.Equal(t, string(body), "Filesystem error\n") }) t.Run("return 201 Created if publish is successful", func(t *testing.T) { jsonBody := []byte( `{ "_id": "@ookusanya/simplepackone", "name": "@ookusanya/simplepackone", "description": "This is a very rough implementation of a private npm registry.", "dist-tags": { "latest": "1.3.0" }, "versions": { "1.3.0": { "name": "@ookusanya/simplepackone", "version": "1.3.0", "description": "This is a very rough implementation of a private npm registry.", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "license": "MIT", "files": null, "readme": "# Gosimplenpm\n\nThis is a very rough implementation of a private npm registry.\n\n# Features\n\nTODO...\n\n# Enhancements\n\nTODO...\n\n# Work List\n\nTODO...", "_id": "@ookusanya/simplepackone@1.2.0", "_nodeVersion": "16.20.0", "_npmVersion": "8.19.4", "dist": { "integrity": "sha512-coOiU+ywV/do/+HwK91mfuei9491yfQUedLWjspAjDa58RniJvQNTF/cXDp/sooVdpjgEbCqKVyLOju6C1i3pw==", "shasum": "1adafdbe8878372c9f4b554bf30d5bfb1b7896c5", "tarball": "http://localhost:4000/@ookusanya%2Fsimplepackone/-/@ookusanya%2Fsimplepackone-1.2.0.tgz" }, "dependencies": { "eslint": "^7.x", "mocha": "^10.x", "uuid": "^9.x" } } }, "access": "", "_attachments": { "@ookusanya/simplepackone-1.3.0.tgz": { "content_type": "application/octet-stream", "data": "H4sIAAAAAAAC/+1XbWvjOBDuZ/+KwQtLCyZ10pfl+uncRGnMOnawne0VlgXVVmJtHctIcl849r/fSEmb9nof73LcXoaA0Lw9M6PMSG5pcUeX7Jg3JXvsfVcH/wD5vn9+egp/xbc0OIGDk7Nzv98/P/dRz+/7nwY+rgc7oE5pKjGUvyFJJHhZ/yNUiEaJmvVqsTx0J0wy9+hgT/8fajf9v1lxAohmx/1/ev6u//tnZ/19/++CfncA3IaumHsB7q9C3HWKNk/0WPFVWzPzrxANcz2jdc+k4qIxiv3eoOevuSVTheSt3kjWzBXldvd8q6y5a0WFAoOKDM2UNmqsqAR8dYmUQl5AI8AIQLWs4AvOyq8ufPwI7JFr6Lto+cN6o52uhNxi1rxgjbJ5TMP8ObiWYQhNwdkrWKZq3ljgb596j1bTxCyKilpm399yu46X7oX77RdkGWjnh/NT9n9KgtGU9Fbl7u//waD/7v4/Oxns+38X9AGuxLrXm3blOHnFFeCPAnb7E0jRLSuw4hVrNDVdDmKB4lbye6oZoBVItuRKy6ee43yAMaO6k0yhr2SU9HqWSZqKNoX18VZwLeQdRGj9wt1fyf9K/0fhkMQZ6elHveP+H/hng3f3f9/f9/9OyBmK9knyZaXhsDiCgfkYS+rugZZ0xWtRU0g2TwLHmTG54sq8AcyIqPBj4fYJlpI2mpUeLCRjZjbgLSqXzAMtAM2gxVeDGRq3Gt8EvFk6FAqENJraDBslFvqBSobKJVClRMFxrpRQiqLbzpwFr5mCQ10xx802Fu6RBSkZrYE36I3BswgeOD4OOo2jCQcTL4wPD5WKuitNDM/imq/4BsGY2zoo47RTmIGJ04OVKPnCrMym1Xa3NVeV55Rm5vHbTiNTGaZ9fngmj2MhQbG6Nh7w5bHOdRud1UEUpzUF1ZsSWdyHSqzeZoIlWnSyQUhW2nQFlswifmeFNl6M+kLUtXjA1BCyKbnJSF2YcY51vRX3zOayPuZGaAx1HYI5gHZ7qhuRqijGfsucdcEQF8tLX6UjDTz2TaM51r4V0uL9OU0c8PmEQJaM8+sgJRBmMEuTL+GIjMANMty7HlyH+SSZ54AaaRDnN5CMIYhv4HMYjzyH/DZLSZZBkkI4nUUhGXkQxsNoPgrjK7hEuzjJIQrxwYdO8wQM4MZVSNBu7ExJOpzgNrgMozC/8WAc5rHxOUanAcyCNA+H8yhIYTZPZ0lGEH7kxEkcxuMUUciUxHkPUREKyBfcQDYJoshCBXOMPrXxDZPZTRpeTXKYJNGIIPOSOFEYXEZkDYVJDaMgnHowCqbBFbFWCXpJwahtorueEMtCvAB/wzxMYgdrMkziPMWth1mm+YvpdZgRD4I0zExBxmmC7k050SKxTtAuJmsvptTw5kRQxeznGdnGMiJBhL4yY/xaeX8x72lPe9rTT0V/APlm4rcAGAAA", "length": 1089 } } }`, ) req := httptest.NewRequest(http.MethodPut, "/{name}", bytes.NewReader(jsonBody)) wrt := httptest.NewRecorder() lg := &logrus.Logger{ Out: os.Stdout, // Level: "DEBUG", Formatter: &logrus.TextFormatter{ FullTimestamp: true, TimestampFormat: "2009-01-02 15:15:15", }, } cfg := config.Config{ RepoDir: "", } mfs := &storage.MockFs{} mfs.GetIndexJsonFromStoreFunc = func(packageName string, registryPath string, lg *logrus.Logger) (string, bool, error) { return string(jsonBody), false, nil } mfs.WriteIndexJsonFunc = func(fPath string, res *serviceidos.IndexJson, lg *logrus.Logger) error { return nil } mfs.WritePackageToStoreFunc = func(fPath string, data string, lg *logrus.Logger) error { return nil } vars := map[string]string{ "name": "@ookusanya%2Fsimplepackone", } req = mux.SetURLVars(req, vars) Publish(lg, cfg, mfs)(wrt, req) rs := wrt.Result() assert.Equal(t, rs.StatusCode, http.StatusCreated) defer rs.Body.Close() body, err := io.ReadAll(rs.Body) if err != nil { t.Fatal(err) } bytes.TrimSpace(body) assert.Equal(t, string(body), "{\"ok\":true,\"package_name\":\"@ookusanya/simplepackone\"}") }) } func TestIntegrationPublishNormal(t *testing.T) { if testing.Short() { t.Skip("Skipping publishPackage integration test") } token := "0N89nr/hmKXoBzG]R{fKH%YE1X" tmpDir := t.TempDir() t.Logf("Temp Dir: %s", tmpDir) indexJsonFp := "intestdata/publish/normal/index.json" isEmpty := IsDirEmpty(t, tmpDir) assert.Equal(t, true, isEmpty) cfg := config.Config{ RepoDir: tmpDir, Token: token, } app := newTestApp(t, cfg) app.Routes() ts := newTestServer(t, app.Mux) defer ts.Close() dataToSend := readTestFile(t, indexJsonFp) code, _, body := ts.put(t, fmt.Sprintf("/%s", url.PathEscape("@df/simplepackone")), token, string(dataToSend)) assert.Equal(t, code, http.StatusCreated) isEmpty = IsDirEmpty(t, tmpDir) assert.Equal(t, false, isEmpty) // t.Logf("Body ==> %s", string(body)) filePaths := listDir(t, tmpDir, false) assert.Equal(t, true, containsSub(filePaths, "index.json")) assert.Equal(t, true, containsSub(filePaths, "simplepackone-1.0.0")) assert.NotEmpty(t, string(body)) } func TestIntegrationPublishOverwrite(t *testing.T) { if testing.Short() { t.Skip("Skipping publishPackage integration test") } token := "0N89nr/hmKXoBzG]R{fKH%YE1X" tmpDir := t.TempDir() t.Logf("Temp Dir: %s", tmpDir) // Copy initial package indexJsonFp := "intestdata/publish/normal/index.json" tgzFp := "intestdata/get/simplepackone-1.0.0.tgz" mkDir(t, fmt.Sprintf("%s/@df/simplepackone", tmpDir)) cpFile(t, indexJsonFp, fmt.Sprintf("%s/@df/simplepackone/index.json", tmpDir)) cpFile(t, tgzFp, fmt.Sprintf("%s/@df/simplepackone/simplepackone-1.0.0.tgz", tmpDir)) isEmpty := IsDirEmpty(t, tmpDir) assert.Equal(t, false, isEmpty) indexJsonFp = "intestdata/publish/overwrite/index.json" cfg := config.Config{ RepoDir: tmpDir, Token: token, } app := newTestApp(t, cfg) app.Routes() ts := newTestServer(t, app.Mux) defer ts.Close() dataToSend := readTestFile(t, indexJsonFp) code, _, body := ts.put(t, fmt.Sprintf("/%s", url.PathEscape("@df/simplepackone")), token, string(dataToSend)) assert.Equal(t, code, http.StatusCreated) filePaths := listDir(t, tmpDir, false) assert.Equal(t, true, containsSub(filePaths, "index.json")) assert.Equal(t, true, containsSub(filePaths, "simplepackone-1.0.0")) assert.Equal(t, true, containsSub(filePaths, "simplepackone-1.9.0")) assert.NotEmpty(t, string(body)) }