package godo import ( "encoding/json" "fmt" "net/http" "testing" "time" "github.com/stretchr/testify/require" ) var privateNetworkUUID = "880b7f98-f062-404d-b33c-458d545696f6" var db = Database{ ID: "da4e0206-d019-41d7-b51f-deadbeefbb8f", Name: "dbtest", EngineSlug: "pg", VersionSlug: "11", Connection: &DatabaseConnection{ URI: "postgres://doadmin:zt91mum075ofzyww@dbtest-do-user-3342561-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require", Database: "defaultdb", Host: "dbtest-do-user-3342561-0.db.ondigitalocean.com", Port: 25060, User: "doadmin", Password: "zt91mum075ofzyww", SSL: true, }, PrivateConnection: &DatabaseConnection{ URI: "postgres://doadmin:zt91mum075ofzyww@private-dbtest-do-user-3342561-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require", Database: "defaultdb", Host: "dbtest-do-user-3342561-0.db.ondigitalocean.com", Port: 25060, User: "doadmin", Password: "zt91mum075ofzyww", SSL: true, }, Users: []DatabaseUser{ DatabaseUser{ Name: "doadmin", Role: "primary", Password: "zt91mum075ofzyww", }, }, DBNames: []string{ "defaultdb", }, NumNodes: 3, RegionSlug: "sfo2", Status: "online", CreatedAt: time.Date(2019, 2, 26, 6, 12, 39, 0, time.UTC), MaintenanceWindow: &DatabaseMaintenanceWindow{ Day: "monday", Hour: "13:51:14", Pending: false, Description: nil, }, SizeSlug: "db-s-2vcpu-4gb", PrivateNetworkUUID: "da4e0206-d019-41d7-b51f-deadbeefbb8f", Tags: []string{"production", "staging"}, } var dbJSON = ` { "id": "da4e0206-d019-41d7-b51f-deadbeefbb8f", "name": "dbtest", "engine": "pg", "version": "11", "connection": { "uri": "postgres://doadmin:zt91mum075ofzyww@dbtest-do-user-3342561-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require", "database": "defaultdb", "host": "dbtest-do-user-3342561-0.db.ondigitalocean.com", "port": 25060, "user": "doadmin", "password": "zt91mum075ofzyww", "ssl": true }, "private_connection": { "uri": "postgres://doadmin:zt91mum075ofzyww@private-dbtest-do-user-3342561-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require", "database": "defaultdb", "host": "dbtest-do-user-3342561-0.db.ondigitalocean.com", "port": 25060, "user": "doadmin", "password": "zt91mum075ofzyww", "ssl": true }, "users": [ { "name": "doadmin", "role": "primary", "password": "zt91mum075ofzyww" } ], "db_names": [ "defaultdb" ], "num_nodes": 3, "region": "sfo2", "status": "online", "created_at": "2019-02-26T06:12:39Z", "maintenance_window": { "day": "monday", "hour": "13:51:14", "pending": false, "description": null }, "size": "db-s-2vcpu-4gb", "private_network_uuid": "da4e0206-d019-41d7-b51f-deadbeefbb8f", "tags": ["production", "staging"] } ` var dbsJSON = fmt.Sprintf(` { "databases": [ %s ] } `, dbJSON) func TestDatabases_List(t *testing.T) { setup() defer teardown() dbSvc := client.Databases want := []Database{db} mux.HandleFunc("/v2/databases", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, dbsJSON) }) got, _, err := dbSvc.List(ctx, nil) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_Get(t *testing.T) { setup() defer teardown() dbID := "da4e0206-d019-41d7-b51f-deadbeefbb8f" body := fmt.Sprintf(` { "database": %s } `, dbJSON) path := fmt.Sprintf("/v2/databases/%s", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, body) }) got, _, err := client.Databases.Get(ctx, dbID) require.NoError(t, err) require.Equal(t, &db, got) } func TestDatabases_Create(t *testing.T) { setup() defer teardown() want := &Database{ ID: "8d91899c-0739-4a1a-acc5-deadbeefbb8f", Name: "backend-test", EngineSlug: "pg", VersionSlug: "10", Connection: &DatabaseConnection{ URI: "postgres://doadmin:zt91mum075ofzyww@dbtest-do-user-3342561-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require", Database: "defaultdb", Host: "dbtest-do-user-3342561-0.db.ondigitalocean.com", Port: 25060, User: "doadmin", Password: "zt91mum075ofzyww", SSL: true, }, PrivateConnection: &DatabaseConnection{ URI: "postgres://doadmin:zt91mum075ofzyww@private-dbtest-do-user-3342561-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require", Database: "defaultdb", Host: "dbtest-do-user-3342561-0.db.ondigitalocean.com", Port: 25060, User: "doadmin", Password: "zt91mum075ofzyww", SSL: true, }, Users: nil, DBNames: nil, NumNodes: 2, RegionSlug: "nyc3", Status: "creating", CreatedAt: time.Date(2019, 2, 26, 6, 12, 39, 0, time.UTC), MaintenanceWindow: nil, SizeSlug: "db-s-2vcpu-4gb", Tags: []string{"production", "staging"}, } createRequest := &DatabaseCreateRequest{ Name: "backend-test", EngineSlug: "pg", Version: "10", Region: "nyc3", SizeSlug: "db-s-2vcpu-4gb", NumNodes: 2, Tags: []string{"production", "staging"}, } body := ` { "database": { "id": "8d91899c-0739-4a1a-acc5-deadbeefbb8f", "name": "backend-test", "engine": "pg", "version": "10", "connection": { "uri": "postgres://doadmin:zt91mum075ofzyww@dbtest-do-user-3342561-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require", "database": "defaultdb", "host": "dbtest-do-user-3342561-0.db.ondigitalocean.com", "port": 25060, "user": "doadmin", "password": "zt91mum075ofzyww", "ssl": true }, "private_connection": { "uri": "postgres://doadmin:zt91mum075ofzyww@private-dbtest-do-user-3342561-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require", "database": "defaultdb", "host": "dbtest-do-user-3342561-0.db.ondigitalocean.com", "port": 25060, "user": "doadmin", "password": "zt91mum075ofzyww", "ssl": true }, "users": null, "db_names": null, "num_nodes": 2, "region": "nyc3", "status": "creating", "created_at": "2019-02-26T06:12:39Z", "maintenance_window": null, "size": "db-s-2vcpu-4gb", "tags": ["production", "staging"] } }` mux.HandleFunc("/v2/databases", func(w http.ResponseWriter, r *http.Request) { v := new(DatabaseCreateRequest) err := json.NewDecoder(r.Body).Decode(v) if err != nil { t.Fatal(err) } testMethod(t, r, http.MethodPost) require.Equal(t, v, createRequest) fmt.Fprint(w, body) }) got, _, err := client.Databases.Create(ctx, createRequest) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_Delete(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodDelete) }) _, err := client.Databases.Delete(ctx, "deadbeef-dead-4aa5-beef-deadbeef347d") require.NoError(t, err) } func TestDatabases_Resize(t *testing.T) { setup() defer teardown() resizeRequest := &DatabaseResizeRequest{ SizeSlug: "db-s-16vcpu-64gb", NumNodes: 3, } dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/resize", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPut) }) _, err := client.Databases.Resize(ctx, "deadbeef-dead-4aa5-beef-deadbeef347d", resizeRequest) require.NoError(t, err) } func TestDatabases_Migrate(t *testing.T) { setup() defer teardown() migrateRequest := &DatabaseMigrateRequest{ Region: "lon1", } dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/migrate", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPut) }) _, err := client.Databases.Migrate(ctx, "deadbeef-dead-4aa5-beef-deadbeef347d", migrateRequest) require.NoError(t, err) } func TestDatabases_Migrate_WithPrivateNet(t *testing.T) { setup() defer teardown() migrateRequest := &DatabaseMigrateRequest{ Region: "lon1", PrivateNetworkUUID: privateNetworkUUID, } dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/migrate", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPut) }) _, err := client.Databases.Migrate(ctx, "deadbeef-dead-4aa5-beef-deadbeef347d", migrateRequest) require.NoError(t, err) } func TestDatabases_UpdateMaintenance(t *testing.T) { setup() defer teardown() maintenanceRequest := &DatabaseUpdateMaintenanceRequest{ Day: "thursday", Hour: "16:00", } dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/maintenance", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPut) }) _, err := client.Databases.UpdateMaintenance(ctx, "deadbeef-dead-4aa5-beef-deadbeef347d", maintenanceRequest) require.NoError(t, err) } func TestDatabases_ListBackups(t *testing.T) { setup() defer teardown() want := []DatabaseBackup{ DatabaseBackup{ CreatedAt: time.Date(2019, 1, 11, 18, 42, 27, 0, time.UTC), SizeGigabytes: 0.03357696, }, DatabaseBackup{ CreatedAt: time.Date(2019, 1, 12, 18, 42, 29, 0, time.UTC), SizeGigabytes: 0.03364864, }, } body := ` { "backups": [ { "created_at": "2019-01-11T18:42:27Z", "size_gigabytes": 0.03357696 }, { "created_at": "2019-01-12T18:42:29Z", "size_gigabytes": 0.03364864 } ] } ` dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/backups", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, body) }) got, _, err := client.Databases.ListBackups(ctx, "deadbeef-dead-4aa5-beef-deadbeef347d", nil) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_GetUser(t *testing.T) { setup() defer teardown() want := &DatabaseUser{ Name: "name", Role: "foo", Password: "pass", } body := ` { "user": { "name": "name", "role": "foo", "password": "pass" } } ` dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/users/name", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, body) }) got, _, err := client.Databases.GetUser(ctx, dbID, "name") require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_ListUsers(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" want := []DatabaseUser{ { Name: "name", Role: "foo", Password: "pass", }, { Name: "bar", Role: "foo", Password: "pass", }, } body := ` { "users": [{ "name": "name", "role": "foo", "password": "pass" }, { "name": "bar", "role": "foo", "password": "pass" }] } ` path := fmt.Sprintf("/v2/databases/%s/users", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, body) }) got, _, err := client.Databases.ListUsers(ctx, dbID, nil) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_CreateUser(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" want := &DatabaseUser{ Name: "name", Role: "foo", Password: "pass", } body := ` { "user": { "name": "name", "role": "foo", "password": "pass" } } ` path := fmt.Sprintf("/v2/databases/%s/users", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPost) fmt.Fprint(w, body) }) got, _, err := client.Databases.CreateUser(ctx, dbID, &DatabaseCreateUserRequest{Name: "user"}) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_DeleteUser(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/users/user", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodDelete) }) _, err := client.Databases.DeleteUser(ctx, dbID, "user") require.NoError(t, err) } func TestDatabases_ResetUserAuth(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/users/user/reset_auth", dbID) body := ` { "user": { "name": "name", "role": "foo", "password": "pass", "mysql_settings": { "auth_plugin": "caching_sha2_password" } } } ` mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPost) fmt.Fprint(w, body) }) want := &DatabaseUser{ Name: "name", Role: "foo", Password: "pass", MySQLSettings: &DatabaseMySQLUserSettings{AuthPlugin: SQLAuthPluginCachingSHA2}, } got, _, err := client.Databases.ResetUserAuth(ctx, dbID, "user", &DatabaseResetUserAuthRequest{ MySQLSettings: &DatabaseMySQLUserSettings{ AuthPlugin: SQLAuthPluginCachingSHA2, }}) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_ListDBs(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" want := []DatabaseDB{ {Name: "foo"}, {Name: "bar"}, } body := ` { "dbs": [{ "name": "foo" }, { "name": "bar" }] } ` path := fmt.Sprintf("/v2/databases/%s/dbs", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, body) }) got, _, err := client.Databases.ListDBs(ctx, dbID, nil) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_CreateDB(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" want := &DatabaseDB{ Name: "foo", } body := ` { "db": { "name": "foo" } } ` path := fmt.Sprintf("/v2/databases/%s/dbs", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPost) fmt.Fprint(w, body) }) got, _, err := client.Databases.CreateDB(ctx, dbID, &DatabaseCreateDBRequest{Name: "foo"}) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_GetDB(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" want := &DatabaseDB{ Name: "foo", } body := ` { "db": { "name": "foo" } } ` path := fmt.Sprintf("/v2/databases/%s/dbs/foo", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, body) }) got, _, err := client.Databases.GetDB(ctx, dbID, "foo") require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_DeleteDB(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" body := ` { "db": { "name": "foo" } } ` path := fmt.Sprintf("/v2/databases/%s/dbs/foo", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodDelete) fmt.Fprint(w, body) }) _, err := client.Databases.DeleteDB(ctx, dbID, "foo") require.NoError(t, err) } func TestDatabases_ListPools(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" want := []DatabasePool{ { Name: "pool", User: "user", Size: 10, Mode: "transaction", Database: "db", Connection: &DatabaseConnection{ URI: "postgresql://user:pass@host.com/db", Host: "host.com", Port: 1234, User: "user", Password: "pass", SSL: true, Database: "db", }, PrivateConnection: &DatabaseConnection{ URI: "postgresql://user:pass@private-host.com/db", Host: "private-host.com", Port: 1234, User: "user", Password: "pass", SSL: true, Database: "db", }, }, } body := ` { "pools": [{ "name": "pool", "user": "user", "size": 10, "mode": "transaction", "db": "db", "connection": { "uri": "postgresql://user:pass@host.com/db", "host": "host.com", "port": 1234, "user": "user", "password": "pass", "database": "db", "ssl": true }, "private_connection": { "uri": "postgresql://user:pass@private-host.com/db", "host": "private-host.com", "port": 1234, "user": "user", "password": "pass", "database": "db", "ssl": true } }] } ` path := fmt.Sprintf("/v2/databases/%s/pools", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, body) }) got, _, err := client.Databases.ListPools(ctx, dbID, nil) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_CreatePool(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" want := &DatabasePool{ Name: "pool", User: "user", Size: 10, Mode: "transaction", Database: "db", Connection: &DatabaseConnection{ URI: "postgresql://user:pass@host.com/db", Host: "host.com", Port: 1234, User: "user", Password: "pass", SSL: true, Database: "db", }, PrivateConnection: &DatabaseConnection{ URI: "postgresql://user:pass@private-host.com/db", Host: "private-host.com", Port: 1234, User: "user", Password: "pass", SSL: true, Database: "db", }, } body := ` { "pool": { "name": "pool", "user": "user", "size": 10, "mode": "transaction", "db": "db", "connection": { "uri": "postgresql://user:pass@host.com/db", "host": "host.com", "port": 1234, "user": "user", "password": "pass", "database": "db", "ssl": true }, "private_connection": { "uri": "postgresql://user:pass@private-host.com/db", "host": "private-host.com", "port": 1234, "user": "user", "password": "pass", "database": "db", "ssl": true } } } ` path := fmt.Sprintf("/v2/databases/%s/pools", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPost) fmt.Fprint(w, body) }) got, _, err := client.Databases.CreatePool(ctx, dbID, &DatabaseCreatePoolRequest{ Name: "pool", Database: "db", Size: 10, User: "foo", Mode: "transaction", }) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_GetPool(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" want := &DatabasePool{ Name: "pool", User: "user", Size: 10, Mode: "transaction", Database: "db", Connection: &DatabaseConnection{ URI: "postgresql://user:pass@host.com/db", Host: "host.com", Port: 1234, User: "user", Password: "pass", SSL: true, Database: "db", }, PrivateConnection: &DatabaseConnection{ URI: "postgresql://user:pass@private-host.com/db", Host: "private-host.com", Port: 1234, User: "user", Password: "pass", SSL: true, Database: "db", }, } body := ` { "pool": { "name": "pool", "user": "user", "size": 10, "mode": "transaction", "db": "db", "connection": { "uri": "postgresql://user:pass@host.com/db", "host": "host.com", "port": 1234, "user": "user", "password": "pass", "database": "db", "ssl": true }, "private_connection": { "uri": "postgresql://user:pass@private-host.com/db", "host": "private-host.com", "port": 1234, "user": "user", "password": "pass", "database": "db", "ssl": true } } } ` path := fmt.Sprintf("/v2/databases/%s/pools/pool", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, body) }) got, _, err := client.Databases.GetPool(ctx, dbID, "pool") require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_DeletePool(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/pools/pool", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodDelete) }) _, err := client.Databases.DeletePool(ctx, dbID, "pool") require.NoError(t, err) } func TestDatabases_GetReplica(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" createdAt := time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC) want := &DatabaseReplica{ Name: "pool", Region: "nyc1", Status: "online", CreatedAt: createdAt, Connection: &DatabaseConnection{ URI: "postgresql://user:pass@host.com/db", Host: "host.com", Port: 1234, User: "user", Password: "pass", SSL: true, Database: "db", }, PrivateConnection: &DatabaseConnection{ URI: "postgresql://user:pass@private-host.com/db", Host: "private-host.com", Port: 1234, User: "user", Password: "pass", SSL: true, Database: "db", }, PrivateNetworkUUID: "deadbeef-dead-4aa5-beef-deadbeef347d", Tags: []string{"production", "staging"}, } body := ` { "replica": { "name": "pool", "region": "nyc1", "status": "online", "created_at": "` + createdAt.Format(time.RFC3339) + `", "connection": { "uri": "postgresql://user:pass@host.com/db", "host": "host.com", "port": 1234, "user": "user", "password": "pass", "database": "db", "ssl": true }, "private_connection": { "uri": "postgresql://user:pass@private-host.com/db", "host": "private-host.com", "port": 1234, "user": "user", "password": "pass", "database": "db", "ssl": true }, "private_network_uuid": "deadbeef-dead-4aa5-beef-deadbeef347d", "tags": ["production", "staging"] } } ` path := fmt.Sprintf("/v2/databases/%s/replicas/replica", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, body) }) got, _, err := client.Databases.GetReplica(ctx, dbID, "replica") require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_ListReplicas(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" createdAt := time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC) want := []DatabaseReplica{ { Name: "pool", Region: "nyc1", Status: "online", CreatedAt: createdAt, Connection: &DatabaseConnection{ URI: "postgresql://user:pass@host.com/db", Host: "host.com", Port: 1234, User: "user", Password: "pass", SSL: true, Database: "db", }, PrivateConnection: &DatabaseConnection{ URI: "postgresql://user:pass@private-host.com/db", Host: "private-host.com", Port: 1234, User: "user", Password: "pass", SSL: true, Database: "db", }, PrivateNetworkUUID: "deadbeef-dead-4aa5-beef-deadbeef347d", Tags: []string{"production", "staging"}, }, } body := ` { "replicas": [{ "name": "pool", "region": "nyc1", "status": "online", "created_at": "` + createdAt.Format(time.RFC3339) + `", "connection": { "uri": "postgresql://user:pass@host.com/db", "host": "host.com", "port": 1234, "user": "user", "password": "pass", "database": "db", "ssl": true }, "private_connection": { "uri": "postgresql://user:pass@private-host.com/db", "host": "private-host.com", "port": 1234, "user": "user", "password": "pass", "database": "db", "ssl": true }, "private_network_uuid": "deadbeef-dead-4aa5-beef-deadbeef347d", "tags": ["production", "staging"] }] } ` path := fmt.Sprintf("/v2/databases/%s/replicas", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, body) }) got, _, err := client.Databases.ListReplicas(ctx, dbID, nil) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_CreateReplica(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" createdAt := time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC) want := &DatabaseReplica{ Name: "pool", Region: "nyc1", Status: "online", CreatedAt: createdAt, Connection: &DatabaseConnection{ URI: "postgresql://user:pass@host.com/db", Host: "host.com", Port: 1234, User: "user", Password: "pass", SSL: true, Database: "db", }, PrivateConnection: &DatabaseConnection{ URI: "postgresql://user:pass@private-host.com/db", Host: "private-host.com", Port: 1234, User: "user", Password: "pass", SSL: true, Database: "db", }, PrivateNetworkUUID: "deadbeef-dead-4aa5-beef-deadbeef347d", Tags: []string{"production", "staging"}, } body := ` { "replica": { "name": "pool", "region": "nyc1", "status": "online", "created_at": "` + createdAt.Format(time.RFC3339) + `", "connection": { "uri": "postgresql://user:pass@host.com/db", "host": "host.com", "port": 1234, "user": "user", "password": "pass", "database": "db", "ssl": true }, "private_connection": { "uri": "postgresql://user:pass@private-host.com/db", "host": "private-host.com", "port": 1234, "user": "user", "password": "pass", "database": "db", "ssl": true }, "private_network_uuid": "deadbeef-dead-4aa5-beef-deadbeef347d", "tags": ["production", "staging"] } } ` path := fmt.Sprintf("/v2/databases/%s/replicas", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPost) fmt.Fprint(w, body) }) got, _, err := client.Databases.CreateReplica(ctx, dbID, &DatabaseCreateReplicaRequest{ Name: "replica", Region: "nyc1", Size: "db-s-2vcpu-4gb", PrivateNetworkUUID: privateNetworkUUID, Tags: []string{"production", "staging"}, }) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_DeleteReplica(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/replicas/replica", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodDelete) }) _, err := client.Databases.DeleteReplica(ctx, dbID, "replica") require.NoError(t, err) } func TestDatabases_SetEvictionPolicy(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/eviction_policy", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPut) }) _, err := client.Databases.SetEvictionPolicy(ctx, dbID, "allkeys_lru") require.NoError(t, err) } func TestDatabases_GetEvictionPolicy(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" want := "allkeys_lru" body := `{ "eviction_policy": "allkeys_lru" }` path := fmt.Sprintf("/v2/databases/%s/eviction_policy", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, body) }) got, _, err := client.Databases.GetEvictionPolicy(ctx, dbID) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_SetSQLMode(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/sql_mode", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPut) w.Write([]byte(`{ "sql_mode": "ONLY_FULL_GROUP_BY" }`)) }) _, err := client.Databases.SetSQLMode(ctx, dbID, "ONLY_FULL_GROUP_BY") require.NoError(t, err) } func TestDatabases_SetSQLMode_Multiple(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/sql_mode", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPut) w.Write([]byte(`{ "sql_mode": "ANSI, ANSI_QUOTES" }`)) }) _, err := client.Databases.SetSQLMode(ctx, dbID, SQLModeANSI, SQLModeANSIQuotes) require.NoError(t, err) } func TestDatabases_GetSQLMode(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" want := "ONLY_FULL_GROUP_BY" body := `{ "sql_mode": "ONLY_FULL_GROUP_BY" }` path := fmt.Sprintf("/v2/databases/%s/sql_mode", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, body) }) got, _, err := client.Databases.GetSQLMode(ctx, dbID) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_GetFirewallRules(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/firewall", dbID) want := []DatabaseFirewallRule{ { Type: "ip_addr", Value: "192.168.1.1", UUID: "deadbeef-dead-4aa5-beef-deadbeef347d", ClusterUUID: "deadbeef-dead-4aa5-beef-deadbeef347d", }, } body := ` {"rules": [{ "type": "ip_addr", "value": "192.168.1.1", "uuid": "deadbeef-dead-4aa5-beef-deadbeef347d", "cluster_uuid": "deadbeef-dead-4aa5-beef-deadbeef347d" }]} ` mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) fmt.Fprint(w, body) }) got, _, err := client.Databases.GetFirewallRules(ctx, dbID) require.NoError(t, err) require.Equal(t, want, got) } func TestDatabases_UpdateFirewallRules(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/firewall", dbID) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPut) }) _, err := client.Databases.UpdateFirewallRules(ctx, dbID, &DatabaseUpdateFirewallRulesRequest{ Rules: []*DatabaseFirewallRule{ { Type: "ip_addr", Value: "192.168.1.1", UUID: "deadbeef-dead-4aa5-beef-deadbeef347d", }, }, }) require.NoError(t, err) } func TestDatabases_CreateDatabaseUserWithMySQLSettings(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/users", dbID) responseJSON := []byte(fmt.Sprintf(`{ "user": { "name": "foo", "mysql_settings": { "auth_plugin": "%s" } } }`, SQLAuthPluginNative)) expectedUser := &DatabaseUser{ Name: "foo", MySQLSettings: &DatabaseMySQLUserSettings{ AuthPlugin: SQLAuthPluginNative, }, } mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodPost) w.WriteHeader(http.StatusOK) w.Write(responseJSON) }) user, _, err := client.Databases.CreateUser(ctx, dbID, &DatabaseCreateUserRequest{ Name: expectedUser.Name, MySQLSettings: expectedUser.MySQLSettings, }) require.NoError(t, err) require.Equal(t, expectedUser, user) } func TestDatabases_ListDatabaseUsersWithMySQLSettings(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" path := fmt.Sprintf("/v2/databases/%s/users", dbID) responseJSON := []byte(fmt.Sprintf(`{ "users": [ { "name": "foo", "mysql_settings": { "auth_plugin": "%s" } } ] }`, SQLAuthPluginNative)) expectedUsers := []DatabaseUser{ { Name: "foo", MySQLSettings: &DatabaseMySQLUserSettings{ AuthPlugin: SQLAuthPluginNative, }, }, } mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) w.WriteHeader(http.StatusOK) w.Write(responseJSON) }) users, _, err := client.Databases.ListUsers(ctx, dbID, &ListOptions{}) require.NoError(t, err) require.Equal(t, expectedUsers, users) } func TestDatabases_GetDatabaseUserWithMySQLSettings(t *testing.T) { setup() defer teardown() dbID := "deadbeef-dead-4aa5-beef-deadbeef347d" userID := "d290a0a0-27da-42bd-a4b2-bcecf43b8832" path := fmt.Sprintf("/v2/databases/%s/users/%s", dbID, userID) responseJSON := []byte(fmt.Sprintf(`{ "user": { "name": "foo", "mysql_settings": { "auth_plugin": "%s" } } }`, SQLAuthPluginNative)) expectedUser := &DatabaseUser{ Name: "foo", MySQLSettings: &DatabaseMySQLUserSettings{ AuthPlugin: SQLAuthPluginNative, }, } mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) w.WriteHeader(http.StatusOK) w.Write(responseJSON) }) user, _, err := client.Databases.GetUser(ctx, dbID, userID) require.NoError(t, err) require.Equal(t, expectedUser, user) }