changeset 154:6604947e0369

test_integration: Start implementing first API call test
author Lewin Bormann <lbo@spheniscida.de>
date Tue, 27 Oct 2020 19:54:34 +0100
parents 87e951988e86
children 30e5944e74de
files test_integration/Cargo.lock test_integration/Cargo.toml test_integration/src/integration_test_v1_types.rs test_integration/src/lib.rs
diffstat 4 files changed, 100 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/test_integration/Cargo.lock	Tue Oct 27 19:23:13 2020 +0100
+++ b/test_integration/Cargo.lock	Tue Oct 27 19:54:34 2020 +0100
@@ -1062,6 +1062,7 @@
  "anyhow",
  "async-google-apis-common",
  "env_logger",
+ "futures",
  "hyper",
  "hyper-rustls",
  "mockito",
--- a/test_integration/Cargo.toml	Tue Oct 27 19:23:13 2020 +0100
+++ b/test_integration/Cargo.toml	Tue Oct 27 19:54:34 2020 +0100
@@ -12,6 +12,7 @@
 anyhow = "~1.0"
 serde = "~1.0"
 env_logger = "~0.8"
+futures = "~0.3"
 hyper = "~0.13"
 hyper-rustls = "~0.20"
 mockito = "~0.27"
--- a/test_integration/src/integration_test_v1_types.rs	Tue Oct 27 19:23:13 2020 +0100
+++ b/test_integration/src/integration_test_v1_types.rs	Tue Oct 27 19:54:34 2020 +0100
@@ -17,7 +17,7 @@
 
 /// Scopes of this API. Convertible to their string representation with `AsRef`.
 #[derive(Debug, Clone, Copy)]
-pub enum Integration_testScopes {
+pub enum IntegrationTestScopes {
     /// See, edit, create, and delete all of your Google integrationtest files
     ///
     /// URL: https://example.borgac.net/auth/integrationtest
@@ -28,13 +28,13 @@
     IntegrationtestMetadata,
 }
 
-impl std::convert::AsRef<str> for Integration_testScopes {
+impl std::convert::AsRef<str> for IntegrationTestScopes {
     fn as_ref(&self) -> &'static str {
         match self {
-            Integration_testScopes::Integrationtest => {
+            IntegrationTestScopes::Integrationtest => {
                 "https://example.borgac.net/auth/integrationtest"
             }
-            Integration_testScopes::IntegrationtestMetadata => {
+            IntegrationTestScopes::IntegrationtestMetadata => {
                 "https://example.borgac.net/auth/integrationtest.metadata"
             }
         }
@@ -90,7 +90,7 @@
 
 ///
 #[derive(Serialize, Deserialize, Debug, Clone, Default)]
-pub struct Integration_testParams {
+pub struct IntegrationTestParams {
     /// Data format for the response.
     #[serde(rename = "alt")]
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -126,7 +126,7 @@
 pub struct FilesCopyParams {
     /// General attributes applying to any API call
     #[serde(flatten)]
-    pub integration_test_params: Option<Integration_testParams>,
+    pub integration_test_params: Option<IntegrationTestParams>,
     /// The ID of the file.
     #[serde(rename = "fileId")]
     pub file_id: String,
@@ -143,7 +143,7 @@
 pub struct FilesCreateParams {
     /// General attributes applying to any API call
     #[serde(flatten)]
-    pub integration_test_params: Option<Integration_testParams>,
+    pub integration_test_params: Option<IntegrationTestParams>,
     /// Whether to use the uploaded content as indexable text.
     #[serde(rename = "useContentAsIndexableText")]
     pub use_content_as_indexable_text: Option<bool>,
@@ -167,7 +167,7 @@
 pub struct FilesDeleteParams {
     /// General attributes applying to any API call
     #[serde(flatten)]
-    pub integration_test_params: Option<Integration_testParams>,
+    pub integration_test_params: Option<IntegrationTestParams>,
     /// Set to true to opt in to API behavior that aims for all items to have exactly one parent. This parameter will only take effect if the item is not in a shared drive. If an item's last parent is deleted but the item itself is not, the item will be placed under its owner's root.
     #[serde(rename = "enforceSingleParent")]
     pub enforce_single_parent: Option<bool>,
@@ -214,7 +214,7 @@
 pub struct FilesEmptyTrashParams {
     /// General attributes applying to any API call
     #[serde(flatten)]
-    pub integration_test_params: Option<Integration_testParams>,
+    pub integration_test_params: Option<IntegrationTestParams>,
     /// Set to true to opt in to API behavior that aims for all items to have exactly one parent. This parameter will only take effect if the item is not in a shared drive. If an item's last parent is deleted but the item itself is not, the item will be placed under its owner's root.
     #[serde(rename = "enforceSingleParent")]
     pub enforce_single_parent: Option<bool>,
@@ -238,7 +238,7 @@
 pub struct FilesExportParams {
     /// General attributes applying to any API call
     #[serde(flatten)]
-    pub integration_test_params: Option<Integration_testParams>,
+    pub integration_test_params: Option<IntegrationTestParams>,
     /// The ID of the file.
     #[serde(rename = "fileId")]
     pub file_id: String,
@@ -258,7 +258,7 @@
     }
 }
 
-impl std::fmt::Display for Integration_testParams {
+impl std::fmt::Display for IntegrationTestParams {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         if let Some(ref v) = self.alt {
             write!(
@@ -335,7 +335,7 @@
             client: client,
             authenticator: Box::new(auth),
             scopes: vec![],
-            base_url: "https://example.borgac.net/invalid".into(),
+            base_url: "https://example.borgac.net/integrationAPI".into(),
             root_url: "https://example.borgac.net/".into(),
         }
     }
@@ -366,7 +366,7 @@
     #[cfg(test)]
     /// Override API URLs. `base` is the base path relative to which (relative) method paths are interpreted,
     /// whereas `root` is the URL relative to which absolute paths are interpreted.
-    fn set_urls(&mut self, base: String, root: String) {
+    pub fn set_urls(&mut self, base: String, root: String) {
         self.base_url = base;
         self.root_url = root;
     }
@@ -390,6 +390,7 @@
             fileId = percent_encode(params.file_id.as_bytes(), NON_ALPHANUMERIC)
         );
         let path = self.format_path(rel_path.as_str());
+        println!("{}", path);
 
         let mut headers = vec![];
         let tok;
--- a/test_integration/src/lib.rs	Tue Oct 27 19:23:13 2020 +0100
+++ b/test_integration/src/lib.rs	Tue Oct 27 19:54:34 2020 +0100
@@ -15,6 +15,22 @@
     const AUTH_PATH: &str = "/oauth2/";
     const TOKEN_PATH: &str = "/token/";
 
+    const API_LOCATION: &str = "/integrationAPI/";
+
+    struct AutoDelegate {}
+
+    impl agac::yup_oauth2::authenticator_delegate::InstalledFlowDelegate for AutoDelegate {
+        fn present_user_url<'a>(
+            &'a self,
+            url: &'a str,
+            _need_code: bool,
+        ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<String, String>> + Send + 'a>>
+        {
+            println!("user directed to: {}", url);
+            return Box::pin(futures::future::ok("returned_code".into()));
+        }
+    }
+
     fn url_for_path(path: &str) -> String {
         if path.starts_with("/") {
             return mockito::server_url() + path;
@@ -35,21 +51,82 @@
         appsec
     }
 
+    async fn authenticator(
+        cl: agac::TlsClient,
+    ) -> agac::yup_oauth2::authenticator::Authenticator<agac::TlsConnr> {
+        let appsec = read_client_secret().await;
+        let auth = agac::yup_oauth2::InstalledFlowAuthenticator::builder(
+            appsec,
+            agac::yup_oauth2::InstalledFlowReturnMethod::Interactive,
+        )
+        .flow_delegate(Box::new(AutoDelegate {}))
+        .hyper_client(cl)
+        .build()
+        .await
+        .unwrap();
+        auth
+    }
+
+    fn oauth_mock() -> mockito::Mock {
+        mockito::mock("POST", "/token/")
+                .with_status(200)
+                .match_header("content-type", "application/x-www-form-urlencoded")
+                .match_body("code=returned_code&client_id=myclientid.apps._dev.borgac.net&client_secret=mysecret&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&grant_type=authorization_code")
+                .with_body(r#" { "access_token": "returned_access_token!", "refresh_token": "returned_refresh_token!", "token_type": "bearer" } "#)
+                .create()
+    }
+
     fn hyper_client() -> agac::TlsClient {
         hyper::Client::builder().build(hyper_rustls::HttpsConnector::new())
     }
 
+    fn files_service(
+        cl: agac::TlsClient,
+        auth: agac::yup_oauth2::authenticator::Authenticator<agac::TlsConnr>,
+    ) -> inttest::FilesService {
+        let mut fs = inttest::FilesService::new(cl, Box::new(auth));
+        fs.set_urls(mockito::server_url() + API_LOCATION, mockito::server_url());
+        fs
+    }
+
     #[tokio::test]
     async fn it_works() {
         mockito::start();
         println!("Mockito running at {}", mockito::server_url());
-        let appsec = read_client_secret().await;
+    }
+
+    #[tokio::test]
+    async fn test_oauth_provider() {
+        mockito::start();
         let cl = hyper_client();
-        let auth = agac::yup_oauth2::InstalledFlowAuthenticator::builder(
-            appsec,
-            agac::yup_oauth2::InstalledFlowReturnMethod::Interactive,
-        )
-        .hyper_client(cl.clone())
-        .build();
+        let auth = authenticator(cl.clone()).await;
+
+        let mock = oauth_mock();
+        let tok = auth
+            .token(&["https://oauth.borgac.net/test"])
+            .await
+            .unwrap();
+        println!("Obtained token: {:?}", tok);
+        mock.assert();
+    }
+
+    #[tokio::test]
+    async fn test_basic_files_api() {
+        mockito::start();
+        let cl = hyper_client();
+        let auth = authenticator(cl.clone()).await;
+        let mut svc = files_service(cl, auth);
+
+        // Mandatory for token fetching.
+        let _om = oauth_mock();
+
+        let mock = mockito::mock("PUT", "/integrationAPI/files/file_id_to_copy/copy").with_status(200).create();
+
+        let mut fsp = inttest::FilesCopyParams::default();
+        fsp.file_id = "file_id_to_copy".into();
+        let f = inttest::File::default();
+        let result = svc.copy(&fsp, &f).await.unwrap();
+
+        mock.assert();
     }
 }