diff --git a/neon_client/client.py b/neon_client/client.py index 2fbb243..af9d412 100644 --- a/neon_client/client.py +++ b/neon_client/client.py @@ -13,7 +13,7 @@ __VERSION__ = "0.1.0" NEON_API_KEY_ENVIRON = "NEON_API_KEY" NEON_API_BASE_URL = "https://console.neon.tech/api/v2/" -ENABLE_PYDANTIC = False +ENABLE_PYDANTIC = True def returns_model(model, is_array=False): @@ -118,9 +118,9 @@ class NeonAPI: return self.request("GET", "api_keys") @returns_model(schema.ApiKeyCreateResponse) - def api_key_create(self, key_name: str) -> t.Dict[str, t.Any]: + def api_key_create(self, **json: dict) -> t.Dict[str, t.Any]: """Create a new API key.""" - return self.request("POST", "api_keys", json={"name": key_name}) + return self.request("POST", "api_keys", json=json) @returns_model(schema.ApiKeyRevokeResponse) def api_key_revoke(self, api_key_id: str) -> t.Dict[str, t.Any]: @@ -170,6 +170,12 @@ class NeonAPI: return self.request("POST", "projects", json=json) + @returns_model(schema.ProjectResponse) + def project_update(self, project_id: str, **json: dict) -> t.Dict[str, t.Any]: + """Updates a project. Accepts all keyword arguments for json body.""" + + return self.request("PATCH", f"projects/{ project_id }", json=json) + @returns_model(schema.ProjectResponse) def project_delete(self, project_id: str) -> t.Dict[str, t.Any]: """Delete a project.""" diff --git a/tests/cassettes/test_integration/test_api_keys.yaml b/tests/cassettes/test_integration/test_api_keys.yaml new file mode 100644 index 0000000..d756121 --- /dev/null +++ b/tests/cassettes/test_integration/test_api_keys.yaml @@ -0,0 +1,114 @@ +interactions: +- request: + body: '{"key_name": "pytest-211"}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '26' + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: POST + uri: https://console.neon.tech/api/v2/api_keys + response: + body: + string: '{"id":768698,"key":"v6z8swftqg5gy5m4ft79qhk4wmfminqw146fgb735cmg84iknyqg06jxit5d6iey","name":"pytest-211","created_at":"2024-01-23T22:17:08Z"}' + headers: + Connection: + - keep-alive + Content-Length: + - '142' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:17:08 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - e1c23f388eb0cfbdac073b1def25c27c + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: GET + uri: https://console.neon.tech/api/v2/api_keys + response: + body: + string: '[{"id":768698,"name":"pytest-211","created_at":"2024-01-23T22:17:08Z","last_used_at":null,"last_used_from_addr":""},{"id":768657,"name":"pytest-330","created_at":"2024-01-23T22:04:59Z","last_used_at":null,"last_used_from_addr":""},{"id":768620,"name":"neon_client","created_at":"2024-01-23T21:56:07Z","last_used_at":"2024-01-23T22:17:08Z","last_used_from_addr":"204.111.161.156"}]' + headers: + Connection: + - keep-alive + Content-Length: + - '380' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:17:08 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - a01651498a31e4c084ebb995e8e5cc96 + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: DELETE + uri: https://console.neon.tech/api/v2/api_keys/768698 + response: + body: + string: '{"id":768698,"name":"pytest-211","revoked":true,"last_used_at":null,"last_used_from_addr":""}' + headers: + Connection: + - keep-alive + Content-Length: + - '93' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:17:08 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - 6b2ed486535a6cfb467e8b9fbc8a6373 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_integration/test_api_keys_crud.yaml b/tests/cassettes/test_integration/test_api_keys_crud.yaml new file mode 100644 index 0000000..6aed693 --- /dev/null +++ b/tests/cassettes/test_integration/test_api_keys_crud.yaml @@ -0,0 +1,78 @@ +interactions: +- request: + body: '{"key_name": "pytest-260"}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '26' + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: POST + uri: https://console.neon.tech/api/v2/api_keys + response: + body: + string: '{"id":768660,"key":"2kqtmmim7jh14cu7xq3cyxlje8k64sz4jq0j35auru81gba1utg2lphr5vui3j1t","name":"pytest-260","created_at":"2024-01-23T22:05:48Z"}' + headers: + Connection: + - keep-alive + Content-Length: + - '142' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:05:48 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - 06cb979ba61f7915ace82fefef0bd2f9 + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: DELETE + uri: https://console.neon.tech/api/v2/api_keys/768660 + response: + body: + string: '{"id":768660,"name":"pytest-260","revoked":true,"last_used_at":null,"last_used_from_addr":""}' + headers: + Connection: + - keep-alive + Content-Length: + - '93' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:05:48 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - 679f5a7704fe0142235c329619c79c58 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_integration/test_create_project.yaml b/tests/cassettes/test_integration/test_create_project.yaml new file mode 100644 index 0000000..55121ef --- /dev/null +++ b/tests/cassettes/test_integration/test_create_project.yaml @@ -0,0 +1,77 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: GET + uri: https://console.neon.tech/api/v2/projects + response: + body: + string: '{"projects":[]}' + headers: + Connection: + - keep-alive + Content-Length: + - '15' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 21:49:05 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - e8e9ff2417bc4c10a2ae697216d03779 + status: + code: 200 + message: OK +- request: + body: '{}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '2' + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: POST + uri: https://console.neon.tech/api/v2/projects + response: + body: + string: '{"code":"","message":"invalid request: decode application/json: invalid: + project (field required)"}' + headers: + Connection: + - keep-alive + Content-Length: + - '99' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 21:49:05 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - b5bb915e7fd45cd3d196e266edd268a2 + status: + code: 400 + message: Bad Request +version: 1 diff --git a/tests/cassettes/test_integration/test_get_project.yaml b/tests/cassettes/test_integration/test_get_project.yaml new file mode 100644 index 0000000..278c178 --- /dev/null +++ b/tests/cassettes/test_integration/test_get_project.yaml @@ -0,0 +1,110 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: GET + uri: https://console.neon.tech/api/v2/projects + response: + body: + string: '{"projects":[{"id":"winter-frost-26518790","platform_id":"aws","region_id":"aws-us-east-2","name":"pytest-480","provisioner":"k8s-neonvm","default_endpoint_settings":{"autoscaling_limit_min_cu":0,"autoscaling_limit_max_cu":0,"suspend_timeout_seconds":0},"settings":{"allowed_ips":{"primary_branch_only":false},"enable_logical_replication":false},"pg_version":15,"proxy_host":"us-east-2.aws.neon.tech","branch_logical_size_limit":3072,"branch_logical_size_limit_bytes":3221225472,"store_passwords":true,"active_time":0,"cpu_used_sec":0,"creation_source":"console","created_at":"2024-01-23T22:02:45Z","updated_at":"2024-01-23T22:04:10Z","synthetic_storage_size":0,"quota_reset_at":"2024-02-01T00:00:00Z","owner_id":"838386f6-b5f1-4c3b-89a2-4f5a130ef3de"}],"pagination":{"cursor":"winter-frost-26518790"}}' + headers: + Connection: + - keep-alive + Content-Length: + - '802' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:17:08 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - 93a87661221a48a5f1790cec7a1f1839 + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: GET + uri: https://console.neon.tech/api/v2/projects + response: + body: + string: '{"projects":[{"id":"winter-frost-26518790","platform_id":"aws","region_id":"aws-us-east-2","name":"pytest-480","provisioner":"k8s-neonvm","default_endpoint_settings":{"autoscaling_limit_min_cu":0,"autoscaling_limit_max_cu":0,"suspend_timeout_seconds":0},"settings":{"allowed_ips":{"primary_branch_only":false},"enable_logical_replication":false},"pg_version":15,"proxy_host":"us-east-2.aws.neon.tech","branch_logical_size_limit":3072,"branch_logical_size_limit_bytes":3221225472,"store_passwords":true,"active_time":0,"cpu_used_sec":0,"creation_source":"console","created_at":"2024-01-23T22:02:45Z","updated_at":"2024-01-23T22:04:10Z","synthetic_storage_size":0,"quota_reset_at":"2024-02-01T00:00:00Z","owner_id":"838386f6-b5f1-4c3b-89a2-4f5a130ef3de"}],"pagination":{"cursor":"winter-frost-26518790"}}' + headers: + Connection: + - keep-alive + Content-Length: + - '802' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:17:08 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - c2239a9162a47fb6c281231f696886ef + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: GET + uri: https://console.neon.tech/api/v2/projects/winter-frost-26518790 + response: + body: + string: '{"project":{"data_storage_bytes_hour":0,"data_transfer_bytes":0,"written_data_bytes":0,"compute_time_seconds":0,"active_time_seconds":0,"cpu_used_sec":0,"id":"winter-frost-26518790","platform_id":"aws","region_id":"aws-us-east-2","name":"pytest-480","provisioner":"k8s-neonvm","default_endpoint_settings":{"autoscaling_limit_min_cu":0.25,"autoscaling_limit_max_cu":0.25,"suspend_timeout_seconds":0},"settings":{"allowed_ips":{"ips":[],"primary_branch_only":false},"enable_logical_replication":false},"pg_version":15,"proxy_host":"us-east-2.aws.neon.tech","branch_logical_size_limit":3072,"branch_logical_size_limit_bytes":3221225472,"store_passwords":true,"creation_source":"console","history_retention_seconds":604800,"created_at":"2024-01-23T22:02:45Z","updated_at":"2024-01-23T22:04:10Z","synthetic_storage_size":0,"consumption_period_start":"2024-01-13T02:10:30Z","consumption_period_end":"2024-02-01T00:00:00Z","quota_reset_at":"2024-02-01T00:00:00Z","owner_id":"838386f6-b5f1-4c3b-89a2-4f5a130ef3de","owner":{"email":"me@kennethreitz.org","branches_limit":10,"subscription_type":"free"},"compute_last_active_at":"2024-01-23T22:04:09Z"}}' + headers: + Connection: + - keep-alive + Content-Length: + - '1142' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:17:09 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - 46bf7973a42429a67279c9898a345070 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_integration/test_get_projects.yaml b/tests/cassettes/test_integration/test_get_projects.yaml new file mode 100644 index 0000000..161b7e0 --- /dev/null +++ b/tests/cassettes/test_integration/test_get_projects.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: GET + uri: https://console.neon.tech/api/v2/projects + response: + body: + string: '{"projects":[{"id":"winter-frost-26518790","platform_id":"aws","region_id":"aws-us-east-2","name":"pytest-480","provisioner":"k8s-neonvm","default_endpoint_settings":{"autoscaling_limit_min_cu":0,"autoscaling_limit_max_cu":0,"suspend_timeout_seconds":0},"settings":{"allowed_ips":{"primary_branch_only":false},"enable_logical_replication":false},"pg_version":15,"proxy_host":"us-east-2.aws.neon.tech","branch_logical_size_limit":3072,"branch_logical_size_limit_bytes":3221225472,"store_passwords":true,"active_time":0,"cpu_used_sec":0,"creation_source":"console","created_at":"2024-01-23T22:02:45Z","updated_at":"2024-01-23T22:04:10Z","synthetic_storage_size":0,"quota_reset_at":"2024-02-01T00:00:00Z","owner_id":"838386f6-b5f1-4c3b-89a2-4f5a130ef3de"}],"pagination":{"cursor":"winter-frost-26518790"}}' + headers: + Connection: + - keep-alive + Content-Length: + - '802' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:05:48 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - a5799bc43c1bab163b924b148fa1fe03 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_integration/test_me.yaml b/tests/cassettes/test_integration/test_me.yaml new file mode 100644 index 0000000..6382762 --- /dev/null +++ b/tests/cassettes/test_integration/test_me.yaml @@ -0,0 +1,40 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: GET + uri: https://console.neon.tech/api/v2/users/me + response: + body: + string: '{"active_seconds_limit":360000,"billing_account":{"payment_source":{"type":""},"subscription_type":"free","quota_reset_at_last":"2024-01-01T00:00:00Z","email":"me@kennethreitz.org","address_city":"","address_country":"","address_line1":"","address_line2":"","address_postal_code":"","address_state":"","orb_portal_url":"https://portal.withorb.com/view?token=Imh4aFpBa1pLNXBUV1BlY0Mi.yPns-bwJIFrQ0Bex_wunQaeVKi0"},"auth_accounts":[{"email":"me@kennethreitz.org","image":"https://avatars.githubusercontent.com/u/119893?v=4","login":"kennethreitz","name":"Kenneth + Reitz","provider":"github"}],"email":"me@kennethreitz.org","id":"838386f6-b5f1-4c3b-89a2-4f5a130ef3de","image":"https://avatars.githubusercontent.com/u/119893?v=4","login":"kennethreitz","name":"Kenneth + Reitz","last_name":"","projects_limit":1,"branches_limit":10,"max_autoscaling_limit":0.25,"plan":"free"}' + headers: + Connection: + - keep-alive + Content-Length: + - '868' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:17:08 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - 5713f0995389212ecfbededa7a5da67b + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_integration/test_project.yaml b/tests/cassettes/test_integration/test_project.yaml new file mode 100644 index 0000000..fecade9 --- /dev/null +++ b/tests/cassettes/test_integration/test_project.yaml @@ -0,0 +1,110 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: GET + uri: https://console.neon.tech/api/v2/projects + response: + body: + string: '{"projects":[{"id":"winter-frost-26518790","platform_id":"aws","region_id":"aws-us-east-2","name":"pytest-480","provisioner":"k8s-neonvm","default_endpoint_settings":{"autoscaling_limit_min_cu":0,"autoscaling_limit_max_cu":0,"suspend_timeout_seconds":0},"settings":{"allowed_ips":{"primary_branch_only":false},"enable_logical_replication":false},"pg_version":15,"proxy_host":"us-east-2.aws.neon.tech","branch_logical_size_limit":3072,"branch_logical_size_limit_bytes":3221225472,"store_passwords":true,"active_time":0,"cpu_used_sec":0,"creation_source":"console","created_at":"2024-01-23T22:02:45Z","updated_at":"2024-01-23T22:04:10Z","synthetic_storage_size":0,"quota_reset_at":"2024-02-01T00:00:00Z","owner_id":"838386f6-b5f1-4c3b-89a2-4f5a130ef3de"}],"pagination":{"cursor":"winter-frost-26518790"}}' + headers: + Connection: + - keep-alive + Content-Length: + - '802' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:17:08 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - 8938099626b4ef0c435ef518ecca4b75 + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: GET + uri: https://console.neon.tech/api/v2/projects + response: + body: + string: '{"projects":[{"id":"winter-frost-26518790","platform_id":"aws","region_id":"aws-us-east-2","name":"pytest-480","provisioner":"k8s-neonvm","default_endpoint_settings":{"autoscaling_limit_min_cu":0,"autoscaling_limit_max_cu":0,"suspend_timeout_seconds":0},"settings":{"allowed_ips":{"primary_branch_only":false},"enable_logical_replication":false},"pg_version":15,"proxy_host":"us-east-2.aws.neon.tech","branch_logical_size_limit":3072,"branch_logical_size_limit_bytes":3221225472,"store_passwords":true,"active_time":0,"cpu_used_sec":0,"creation_source":"console","created_at":"2024-01-23T22:02:45Z","updated_at":"2024-01-23T22:04:10Z","synthetic_storage_size":0,"quota_reset_at":"2024-02-01T00:00:00Z","owner_id":"838386f6-b5f1-4c3b-89a2-4f5a130ef3de"}],"pagination":{"cursor":"winter-frost-26518790"}}' + headers: + Connection: + - keep-alive + Content-Length: + - '802' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:17:08 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - 13a185c8d2e9786288e09b5442e04d02 + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: GET + uri: https://console.neon.tech/api/v2/projects + response: + body: + string: '{"projects":[{"id":"winter-frost-26518790","platform_id":"aws","region_id":"aws-us-east-2","name":"pytest-480","provisioner":"k8s-neonvm","default_endpoint_settings":{"autoscaling_limit_min_cu":0,"autoscaling_limit_max_cu":0,"suspend_timeout_seconds":0},"settings":{"allowed_ips":{"primary_branch_only":false},"enable_logical_replication":false},"pg_version":15,"proxy_host":"us-east-2.aws.neon.tech","branch_logical_size_limit":3072,"branch_logical_size_limit_bytes":3221225472,"store_passwords":true,"active_time":0,"cpu_used_sec":0,"creation_source":"console","created_at":"2024-01-23T22:02:45Z","updated_at":"2024-01-23T22:04:10Z","synthetic_storage_size":0,"quota_reset_at":"2024-02-01T00:00:00Z","owner_id":"838386f6-b5f1-4c3b-89a2-4f5a130ef3de"}],"pagination":{"cursor":"winter-frost-26518790"}}' + headers: + Connection: + - keep-alive + Content-Length: + - '802' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:17:08 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - 2674601d7f8acaded87b12cf1989c661 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_integration/test_project_delete.yaml b/tests/cassettes/test_integration/test_project_delete.yaml new file mode 100644 index 0000000..f964782 --- /dev/null +++ b/tests/cassettes/test_integration/test_project_delete.yaml @@ -0,0 +1,77 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: GET + uri: https://console.neon.tech/api/v2/projects + response: + body: + string: '{"projects":[]}' + headers: + Connection: + - keep-alive + Content-Length: + - '15' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 21:49:06 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - a718c5bcf841f63063cd65a793c68d0b + status: + code: 200 + message: OK +- request: + body: '{}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '2' + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: POST + uri: https://console.neon.tech/api/v2/projects + response: + body: + string: '{"code":"","message":"invalid request: decode application/json: invalid: + project (field required)"}' + headers: + Connection: + - keep-alive + Content-Length: + - '99' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 21:49:06 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - 5e32ba21b25aad1a95df172805aca86a + status: + code: 400 + message: Bad Request +version: 1 diff --git a/tests/cassettes/test_integration/test_update_project.yaml b/tests/cassettes/test_integration/test_update_project.yaml new file mode 100644 index 0000000..c1b7ad6 --- /dev/null +++ b/tests/cassettes/test_integration/test_update_project.yaml @@ -0,0 +1,112 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: GET + uri: https://console.neon.tech/api/v2/projects + response: + body: + string: '{"projects":[{"id":"winter-frost-26518790","platform_id":"aws","region_id":"aws-us-east-2","name":"pytest-480","provisioner":"k8s-neonvm","default_endpoint_settings":{"autoscaling_limit_min_cu":0,"autoscaling_limit_max_cu":0,"suspend_timeout_seconds":0},"settings":{"allowed_ips":{"primary_branch_only":false},"enable_logical_replication":false},"pg_version":15,"proxy_host":"us-east-2.aws.neon.tech","branch_logical_size_limit":3072,"branch_logical_size_limit_bytes":3221225472,"store_passwords":true,"active_time":0,"cpu_used_sec":0,"creation_source":"console","created_at":"2024-01-23T22:02:45Z","updated_at":"2024-01-23T22:04:10Z","synthetic_storage_size":0,"quota_reset_at":"2024-02-01T00:00:00Z","owner_id":"838386f6-b5f1-4c3b-89a2-4f5a130ef3de"}],"pagination":{"cursor":"winter-frost-26518790"}}' + headers: + Connection: + - keep-alive + Content-Length: + - '802' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:17:09 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - f480a6513e5fb5e25c2ec8943df1bf5b + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: GET + uri: https://console.neon.tech/api/v2/projects + response: + body: + string: '{"projects":[{"id":"winter-frost-26518790","platform_id":"aws","region_id":"aws-us-east-2","name":"pytest-480","provisioner":"k8s-neonvm","default_endpoint_settings":{"autoscaling_limit_min_cu":0,"autoscaling_limit_max_cu":0,"suspend_timeout_seconds":0},"settings":{"allowed_ips":{"primary_branch_only":false},"enable_logical_replication":false},"pg_version":15,"proxy_host":"us-east-2.aws.neon.tech","branch_logical_size_limit":3072,"branch_logical_size_limit_bytes":3221225472,"store_passwords":true,"active_time":0,"cpu_used_sec":0,"creation_source":"console","created_at":"2024-01-23T22:02:45Z","updated_at":"2024-01-23T22:04:10Z","synthetic_storage_size":0,"quota_reset_at":"2024-02-01T00:00:00Z","owner_id":"838386f6-b5f1-4c3b-89a2-4f5a130ef3de"}],"pagination":{"cursor":"winter-frost-26518790"}}' + headers: + Connection: + - keep-alive + Content-Length: + - '802' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:17:09 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - 879d47f3f55e6f8d12286b0bd05123e7 + status: + code: 200 + message: OK +- request: + body: '{"project": {"name": "pytest-renamed"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '39' + Content-Type: + - application/json + User-Agent: + - neon-client/python version=(0.1.0) + method: PATCH + uri: https://console.neon.tech/api/v2/projects/winter-frost-26518790 + response: + body: + string: '{"project":{"data_storage_bytes_hour":0,"data_transfer_bytes":0,"written_data_bytes":0,"compute_time_seconds":0,"active_time_seconds":0,"cpu_used_sec":0,"id":"winter-frost-26518790","platform_id":"aws","region_id":"aws-us-east-2","name":"pytest-renamed","provisioner":"k8s-neonvm","default_endpoint_settings":{"autoscaling_limit_min_cu":0.25,"autoscaling_limit_max_cu":0.25,"suspend_timeout_seconds":0},"settings":{"allowed_ips":{"ips":[],"primary_branch_only":false},"enable_logical_replication":false},"pg_version":15,"proxy_host":"us-east-2.aws.neon.tech","branch_logical_size_limit":3072,"branch_logical_size_limit_bytes":3221225472,"store_passwords":true,"creation_source":"console","history_retention_seconds":604800,"created_at":"2024-01-23T22:02:45Z","updated_at":"2024-01-23T22:17:09Z","synthetic_storage_size":0,"consumption_period_start":"0001-01-01T00:00:00Z","consumption_period_end":"0001-01-01T00:00:00Z","owner_id":"838386f6-b5f1-4c3b-89a2-4f5a130ef3de","compute_last_active_at":"2024-01-23T22:04:09Z"},"operations":[]}' + headers: + Connection: + - keep-alive + Content-Length: + - '1035' + Content-Type: + - application/json + Date: + - Tue, 23 Jan 2024 22:17:09 GMT + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Vary: + - Origin + X-Neon-Ret-Request-Id: + - 1c076449af9f8af0228569b63d0e8f62 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/conftest.py b/tests/conftest.py index 92a8d3d..51288ec 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,5 @@ +from random import randint + import pytest @@ -6,3 +8,23 @@ def neon(): from neon_client import NeonAPI return NeonAPI.from_environ() + + +@pytest.fixture +def ensure_project(find_existing=True, *, neon): + def new_project(): + # Return main project if it exists. + if neon.projects().projects: + return neon.projects().projects[0] + + return neon.project_create(project={"name": f"pytest-{randint(0, 1000)}"}) + + return new_project + + +@pytest.fixture +def ensure_new_api_key(*, neon): + def new_api_key(): + return neon.api_key_create(key_name=f"pytest-{randint(0, 1000)}") + + return new_api_key diff --git a/tests/test_integration.py b/tests/test_integration.py index 3130992..3c58d48 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -1,15 +1,70 @@ +import random + import pytest import neon_client +@pytest.fixture(scope="module") +def vcr_config(): + return {"filter_headers": ["authorization"]} + + @pytest.mark.vcr def test_me(neon): me = neon.me() - assert me["email"] == "me@kennethreitz.org" + + assert isinstance(me, neon_client.schema.CurrentUserInfoResponse) + assert me.email == "me@kennethreitz.org" @pytest.mark.vcr +def test_api_keys(neon, ensure_new_api_key): + key = ensure_new_api_key() + + keys = neon.api_keys() + assert len(keys) + + key = neon.api_key_revoke(key.id) + assert key.revoked + + @pytest.mark.vcr -def test_get_projects(neon): - projects = neon.projects() - assert "projects" in projects +def test_project(neon, ensure_project): + project = ensure_project() + + for project in neon.projects().projects: + assert hasattr(project, "id") + + +@pytest.mark.vcr +def test_get_project(neon, ensure_project): + r = ensure_project() + assert neon.project(r.id).project.id == r.id + + +# @pytest.mark.vcr +# def test_create_project(neon, ensure_project): +# r = ensure_project() + +# project_update = {"project": {"name": "pytest-renamed"}} + +# r = neon.project_update(r.id, **project_update) +# assert r.name == "pytest" + + +@pytest.mark.vcr +def test_update_project(neon, ensure_project): + r = ensure_project() + + project_update = {"project": {"name": "pytest-renamed"}} + + r = neon.project_update(r.id, **project_update) + assert r.project.name == "pytest-renamed" + + +# @pytest.mark.vcr +# def test_project_delete(neon, ensure_project): +# r = ensure_project() +# print(r) +# exit() +# r = neon.project_delete(r.id)