diff --git a/.github/workflows/check-branch.yml b/.github/workflows/check-branch.yml index 1e2d24a5..8a3a32ab 100644 --- a/.github/workflows/check-branch.yml +++ b/.github/workflows/check-branch.yml @@ -8,13 +8,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Comment PR - if: github.base_ref == 'master' && github.head_ref != 'next' + if: github.base_ref == 'master' && github.head_ref != 'staging' uses: thollander/actions-comment-pull-request@v2 with: message: | - We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the next branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch. + We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the staging branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch. - name: Check branch - if: github.base_ref == 'master' && github.head_ref != 'next' + if: github.base_ref == 'master' && github.head_ref != 'staging' run: | - echo "ERROR: We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the next branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch." + echo "ERROR: We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the staging branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch." exit 1 \ No newline at end of file diff --git a/.github/workflows/sca-scan.yml b/.github/workflows/sca-scan.yml index 6cde2588..ed7912f3 100644 --- a/.github/workflows/sca-scan.yml +++ b/.github/workflows/sca-scan.yml @@ -7,8 +7,19 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@master + - name: Setup local.properties + run: | + cat << EOF >> local.properties + sdk.dir=$ANDROID_HOME + host="${{ secrets.HOST }}" + APIKey="${{ secrets.API_KEY }}" + deliveryToken="${{ secrets.DELIVERY_TOKEN }}" + environment="${{ secrets.ENVIRONMENT }}" + contentType="${{ secrets.CONTENT_TYPE }}" + assetUid="${{ secrets.ASSET_UID }}" + EOF - name: Run Snyk to check for vulnerabilities - uses: snyk/actions/gradle@master + uses: snyk/actions/setup@master env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: diff --git a/.talismanrc b/.talismanrc index e91afa6f..cbad4b45 100644 --- a/.talismanrc +++ b/.talismanrc @@ -4,7 +4,7 @@ fileignoreconfig: - filename: .github/workflows/secrets-scan.yml ignore_detectors: - filecontent - - filename: contentstack/src/main/java/com/contentstack/okhttp/internal/spdy/Spdy3.java - checksum: 5f6979f6336684787ff20dc5ccb0ea31665dcb4801845a34770d3bd30387f129 - - filename: contentstack/src/main/java/com/contentstack/okhttp/internal/DiskLruCache.java - checksum: 54a52cc9b0d897e500087e7cce65bd1c7c2615a82dad8f5942d87964b3ec4ab2 +- filename: contentstack/src/main/java/com/contentstack/okhttp/internal/spdy/Spdy3.java + checksum: 5f6979f6336684787ff20dc5ccb0ea31665dcb4801845a34770d3bd30387f129 +- filename: contentstack/src/main/java/com/contentstack/okhttp/internal/DiskLruCache.java + checksum: 54a52cc9b0d897e500087e7cce65bd1c7c2615a82dad8f5942d87964b3ec4ab2 diff --git a/CHANGELOG.md b/CHANGELOG.md index b5d2e1c1..3b3b585b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # CHANGELOG +## Version 4.0.1 + +### Date: 06-June-2024 + +- Integration tests added +- Global fields support added + +--- +## Version 4.0.0 + +### Date: 12-Sept-2024 + +- Added support for the upcoming Feature + +--- + ## Version 3.16.1 ### Date: 21-August-2024 diff --git a/LICENSE b/LICENSE index 0eb1a11a..c7d34c7c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2012 - 2024 Contentstack +Copyright (c) 2012 - 2025 Contentstack Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/contentstack/build.gradle b/contentstack/build.gradle index eaccd3e0..0d23213f 100755 --- a/contentstack/build.gradle +++ b/contentstack/build.gradle @@ -10,7 +10,7 @@ android.buildFeatures.buildConfig true mavenPublishing { publishToMavenCentral(SonatypeHost.DEFAULT) signAllPublications() - coordinates("com.contentstack.sdk", "android", "4.0.0") + coordinates("com.contentstack.sdk", "android", "4.0.1") pom { name = "contentstack-android" @@ -161,6 +161,8 @@ dependencies { coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test:core:1.5.0' + testImplementation 'org.robolectric:robolectric:4.6.1' + androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { exclude group: 'com.android.support', module: 'support-annotations' }) diff --git a/contentstack/src/androidTest/java/com/contentstack/sdk/AssetTestCase.java b/contentstack/src/androidTest/java/com/contentstack/sdk/AssetTestCase.java index 3f46ad7f..8d5847a4 100644 --- a/contentstack/src/androidTest/java/com/contentstack/sdk/AssetTestCase.java +++ b/contentstack/src/androidTest/java/com/contentstack/sdk/AssetTestCase.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import static junit.framework.Assert.assertTrue; import static junit.framework.TestCase.assertEquals; @@ -26,7 +27,6 @@ public class AssetTestCase { private static Stack stack; private static CountDownLatch latch; - @BeforeClass public static void oneTimeSetUp() throws Exception { Context appContext = ApplicationProvider.getApplicationContext(); @@ -39,125 +39,93 @@ public static void oneTimeSetUp() throws Exception { stack = Contentstack.stack(appContext, DEFAULT_API_KEY, DEFAULT_DELIVERY_TOKEN, DEFAULT_ENV, config); } - - @Test() - public void test_A_getAllAssetsToSetAssetUID() { - final AssetLibrary assetLibrary = stack.assetLibrary(); - assetLibrary.fetchAll(new FetchAssetsCallback() { - @Override - public void onCompletion(ResponseType responseType, List assets, Error error) { - if (error == null) { - Log.d(TAG, "response: " + assets.get(0).getAssetUid()); - assetUid = assets.get(0).getAssetUid(); - Log.e(assetUid, assetUid); - } - } - }); - - } - @Test - public void test_B_VerifyAssetUID() { + public void test_B_VerifyAssetUID() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); final Asset asset = stack.asset(assetUid); asset.fetch(new FetchResultCallback() { @Override public void onCompletion(ResponseType responseType, Error error) { - if (error == null) { - // Success Block. - Log.d(TAG, "response: " + asset.getAssetUid()); - assertEquals(assetUid, asset.getAssetUid()); - } + // Success Block. + Log.d(TAG, "response: " + asset.getAssetUid()); + assertEquals(assetUid, asset.getAssetUid()); + // Unlock the latch to allow the test to proceed + latch.countDown(); } }); + latch.await(5, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); } @Test - public void test_C_Asset_fetch() { + public void test_C_Asset_fetch() throws Exception { + Config config = new Config(); + Context appContext = ApplicationProvider.getApplicationContext(); + stack = Contentstack.stack(appContext, BuildConfig.APIKey, BuildConfig.deliveryToken, BuildConfig.environment, config); + final CountDownLatch latch = new CountDownLatch(1); final Asset asset = stack.asset(assetUid); asset.fetch(new FetchResultCallback() { @Override public void onCompletion(ResponseType responseType, Error error) { - if (error == null) { - assertEquals(BuildConfig.assetUID, asset.getAssetUid()); - assertEquals("image/jpeg", asset.getFileType()); - assertEquals("phoenix2.jpg", asset.getFileName()); - assertEquals("482141", asset.getFileSize()); - } else { - assertEquals(105, error.getErrorCode()); - } + assertEquals(BuildConfig.assetUID, asset.getAssetUid()); + assertEquals("image/jpeg", asset.getFileType()); + assertEquals("phoenix2.jpg", asset.getFileName()); + latch.countDown(); } }); + latch.await(5, TimeUnit.SECONDS); } @Test - public void test_D_AssetLibrary_fetch() { + public void test_E_AssetLibrary_includeCount_fetch() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); final AssetLibrary assetLibrary = stack.assetLibrary(); + assetLibrary.includeCount(); assetLibrary.fetchAll(new FetchAssetsCallback() { @Override public void onCompletion(ResponseType responseType, List assets, Error error) { - if (error == null) { - assets.forEach(asset -> { - Log.d(TAG, "----Test--Asset-D--Success----" + asset.toJSON()); - Log.d(TAG, "----Test--Asset-D--Success----" + asset.getFileType()); - Log.d(TAG, "----Test--Asset-D--Success----" + asset.getCreatedBy()); - Log.d(TAG, "----Test--Asset-D--Success----" + asset.getUpdatedBy()); - Log.d(TAG, "----Test--Asset-D--Success----" + asset.getFileName()); - Log.d(TAG, "----Test--Asset-D--Success----" + asset.getFileSize()); - Log.d(TAG, "----Test--Asset-D--Success----" + asset.getAssetUid()); - Log.d(TAG, "----Test--Asset-D--Success----" + asset.getUrl()); - }); - } + assertEquals(6, assetLibrary.getCount()); + latch.countDown(); } }); + latch.await(5, TimeUnit.SECONDS); } @Test - public void test_E_AssetLibrary_includeCount_fetch() { - final AssetLibrary assetLibrary = stack.assetLibrary(); - assetLibrary.includeCount(); - assetLibrary.fetchAll(new FetchAssetsCallback() { + public void test_G_Include_Dimension() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final Asset asset = stack.asset(assetUid); + asset.includeDimension(); + asset.fetch(new FetchResultCallback() { @Override - public void onCompletion(ResponseType responseType, List assets, Error error) { - if (error == null) { - assertEquals(16, assetLibrary.getCount()); - } + public void onCompletion(ResponseType responseType, Error error) { + assertEquals(assetUid, asset.getAssetUid()); + latch.countDown(); } }); + latch.await(5, TimeUnit.SECONDS); } - @Test - public void test_F_AssetLibrary_includeRelativeUrl_fetch() { - final AssetLibrary assetLibrary = stack.assetLibrary(); - assetLibrary.includeRelativeUrl(); - assetLibrary.fetchAll(new FetchAssetsCallback() { - public void onCompletion(ResponseType responseType, List assets, Error error) { - if (error == null) { - assertTrue(assets.get(0).getUrl().contains("phoenix2.jpg")); - } - } - }); - } @Test - public void test_G_Include_Dimension() { + public void test_H_include_fallback() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); final Asset asset = stack.asset(assetUid); - asset.includeDimension(); + asset.includeFallback(); asset.fetch(new FetchResultCallback() { @Override public void onCompletion(ResponseType responseType, Error error) { - if (error == null) { - Log.d(TAG, asset.getAssetUid()); - assertEquals(assetUid, asset.getAssetUid()); - } + assertEquals(assetUid, asset.getAssetUid()); + latch.countDown(); } }); + latch.await(5, TimeUnit.SECONDS); } - @Test - public void test_H_include_fallback() { + public void test_include_branch() { final Asset asset = stack.asset(assetUid); - asset.includeFallback(); + asset.includeBranch(); asset.fetch(new FetchResultCallback() { @Override public void onCompletion(ResponseType responseType, Error error) { @@ -169,6 +137,7 @@ public void onCompletion(ResponseType responseType, Error error) { }); } + @Test public void test_AZURE_NA() throws Exception { Config config = new Config(); @@ -196,74 +165,17 @@ public void test_GCP_NA() throws Exception { } @Test - public void test_I_fetch_asset_by_title() { - final AssetLibrary assetLibrary = stack.assetLibrary().where("title", "iot-icon.png"); - assetLibrary.fetchAll(new FetchAssetsCallback() { - @Override - public void onCompletion(ResponseType responseType, List assets, Error error) { - if (error == null) { - for (Asset asset : assets) { - Log.d("RESULT:", "resp" + asset.json); - } - } - } - }); - } - - @Test - public void test_J_fetch_asset_by_tags() { - final AssetLibrary assetLibrary = stack.assetLibrary().where("tags","tag1"); - assetLibrary.fetchAll(new FetchAssetsCallback() { - @Override - public void onCompletion(ResponseType responseType, List assets, Error error) { - if (error == null) { - for( Asset asset : assets){ - Log.d("RESULT:", "resp" + asset.json); - } - assertTrue(assets.size()>0); - } - } - }); - } - - @Test - public void test_K_fetch_asset_by_description() { - final AssetLibrary assetLibrary= stack.assetLibrary().where("description","Page1"); - assetLibrary.fetchAll(new FetchAssetsCallback() { - @Override - public void onCompletion(ResponseType responseType, List assets, Error error) { - for(Asset asset : assets){ - Log.d("RESULT:", "resp" + asset.toJSON()); - } - assertTrue(assets.size()>0); - } - }); - } - - @Test - public void test_L_fetch_asset_invalid() { - final AssetLibrary assetLibrary = stack.assetLibrary().where("title",null); - assetLibrary.fetchAll(new FetchAssetsCallback() { - @Override - public void onCompletion(ResponseType responseType, List assets, Error error) { - Log.e("RESULT:", "ERROR:"+ error.errorMessage); - } - }); - - } - - @Test - public void test_M_fetch_asset_empty_title() { + public void test_M_fetch_asset_empty_title() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); final AssetLibrary assetLibrary = stack.assetLibrary().where("title",""); assetLibrary.fetchAll(new FetchAssetsCallback() { @Override public void onCompletion(ResponseType responseType, List assets, Error error) { - for(Asset asset : assets){ - Log.d("RESULT:", "resp: " + asset.toJSON()); - } assertEquals(0, assets.size()); + latch.countDown(); } }); + latch.await(5, TimeUnit.SECONDS); } } diff --git a/contentstack/src/androidTest/java/com/contentstack/sdk/EntryFindTest.java b/contentstack/src/androidTest/java/com/contentstack/sdk/EntryFindTest.java new file mode 100644 index 00000000..0f6f2ada --- /dev/null +++ b/contentstack/src/androidTest/java/com/contentstack/sdk/EntryFindTest.java @@ -0,0 +1,389 @@ +package com.contentstack.sdk; + +import static junit.framework.TestCase.assertEquals; + +import android.content.Context; +import android.util.Log; + +import androidx.test.core.app.ApplicationProvider; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class EntryFindTest { + private Stack stack; + private static final String CONTENT_TYPE_UID = BuildConfig.contentTypeUID; + + @Before + public void setUp() throws Exception { + Context appContext = ApplicationProvider.getApplicationContext(); + Config config = new Config(); + String DEFAULT_HOST = BuildConfig.host; + config.setHost(DEFAULT_HOST); + stack = Contentstack.stack(appContext, BuildConfig.APIKey, BuildConfig.deliveryToken, BuildConfig.environment, config); + } + + @Test + public void testFindEntry() throws InterruptedException { + // Create a latch to wait for the async operation to complete + final CountDownLatch latch = new CountDownLatch(1); + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + assertEquals("variant-base-product", queryResult.getResultObjects().get(0).getTitle()); + // Unlock the latch to allow the test to proceed + latch.countDown(); + } + }); + + // Wait for the latch to be unlocked with a timeout (5 seconds) + latch.await(5, TimeUnit.SECONDS); + + // Optionally fail the test if the latch wasn't counted down (i.e., timeout occurred) + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testFindEntryAsc() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + query.ascending("updated_at"); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + List entries = queryResult.getResultObjects(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); // Modify the format to match the date format used. + try { + Date prevDate = sdf.parse(entries.get(0).getUpdatedAt("updated_at")); + for (int i = 1; i < entries.size(); i++) { + Date currentDate = sdf.parse(entries.get(i).getUpdatedAt("updated_at")); + // Check if previous date is smaller than the current date + assertTrue("Previous date should be smaller than the current date", prevDate.compareTo(currentDate) <= 0); + // Update prevDate for the next iteration + prevDate = currentDate; + } + } catch (ParseException e) { + e.printStackTrace(); + fail("Date parsing failed"); + } + latch.countDown(); + } + }); + latch.await(5, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testFindEntryDesc() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + query.descending("updated_at"); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + List entries = queryResult.getResultObjects(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); // Modify the format to match the date format used. + try { + Date prevDate = sdf.parse(entries.get(0).getUpdatedAt("updated_at")); + for (int i = 1; i < entries.size(); i++) { + Date currentDate = sdf.parse(entries.get(i).getUpdatedAt("updated_at")); + // Check if previous date is smaller than the current date + assertTrue("Previous date should be greater than the current date", prevDate.compareTo(currentDate) >= 0); + // Update prevDate for the next iteration + prevDate = currentDate; + } + } catch (ParseException e) { + e.printStackTrace(); + fail("Date parsing failed"); + } + latch.countDown(); + } + }); + latch.await(5, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testFindLessThan() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + int value = 90; + query.lessThan("price", value); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + List entries = queryResult.getResultObjects(); + for (int i = 0; i < entries.size(); i++) { + Integer currNum = (int)entries.get(i).get("price"); + assertTrue("Curr price should be less than the value", currNum < value); + } + latch.countDown(); + } + }); + latch.await(5, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testFindLessThanOrEqualTo() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + int value = 90; + query.lessThanOrEqualTo("price", value); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + List entries = queryResult.getResultObjects(); + for (int i = 0; i < entries.size(); i++) { + Integer currNum = (int)entries.get(i).get("price"); + assertTrue("Curr price should be less than or equal to the value", currNum <= value); + } + latch.countDown(); + } + }); + latch.await(5, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testFindGreaterThan() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + int value = 90; + query.greaterThan("price", value); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + List entries = queryResult.getResultObjects(); + for (int i = 0; i < entries.size(); i++) { + Integer currNum = (int)entries.get(i).get("price"); + assertTrue("Curr price should be greater than the value", currNum > value); + } + latch.countDown(); + } + }); + latch.await(5, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testFindGreaterThanOREqualTo() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + int value = 90; + query.greaterThanOrEqualTo("price", value); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + List entries = queryResult.getResultObjects(); + for (int i = 0; i < entries.size(); i++) { + Integer currNum = (int)entries.get(i).get("price"); + assertTrue("Curr price should be greater than or equal to the value", currNum >= value); + } + latch.countDown(); + } + }); + latch.await(15, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testFindContainedIn() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + String[] values = {"kids dress"}; + query.containedIn("title", values); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + List entries = queryResult.getResultObjects(); + for (int i = 0; i < entries.size(); i++) { + String title = entries.get(i).getTitle(); + assertTrue("Title should contain the strings provided", title.contains(values[0])); + } + latch.countDown(); + } + }); + latch.await(5, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testFindNotContainedIn() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + String[] values = {"kids dress"}; + query.notContainedIn("title", values); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + List entries = queryResult.getResultObjects(); + for (int i = 0; i < entries.size(); i++) { + String title = entries.get(i).getTitle(); + assertTrue("Title should not contain the strings provided", !title.contains(values[0])); + } + latch.countDown(); + } + }); + latch.await(5, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testFindExists() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + String field = "boolean"; + query.exists(field); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + List entries = queryResult.getResultObjects(); + for (int i = 0; i < entries.size(); i++) { + assertTrue("Field value provided should exist", entries.get(i).contains(field)); + } + latch.countDown(); + } + }); + latch.await(5, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testFindNotExists() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + String field = "isspecial"; + query.notExists(field); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + List entries = queryResult.getResultObjects(); + for (int i = 0; i < entries.size(); i++) { + assertTrue("Field value provided should exist", !entries.get(i).contains(field)); + } + latch.countDown(); + } + }); + latch.await(5, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testFindOr() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + String[] values = {"kids dress"}; + String field = "in_stock"; + final Query query1 = stack.contentType(CONTENT_TYPE_UID).query().containedIn("title", values); + final Query query2 = stack.contentType(CONTENT_TYPE_UID).query().where(field, 300); + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + ArrayList queryList = new ArrayList<>(); + queryList.add(query1); + queryList.add(query2); + query.or(queryList); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + List entries = queryResult.getResultObjects(); + for (int i = 0; i < entries.size(); i++) { + assertTrue("One of or query should be true", (Boolean) entries.get(i).get(field) || entries.get(i).getTitle().equals(values[0])); + } + latch.countDown(); + } + }); + latch.await(5, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testFindAnd() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + String[] values = {"source1"}; + String field = "boolean"; + final Query query1 = stack.contentType(CONTENT_TYPE_UID).query().containedIn("title", values); + final Query query2 = stack.contentType(CONTENT_TYPE_UID).query().where(field, true); + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + ArrayList queryList = new ArrayList<>(); + queryList.add(query1); + queryList.add(query2); + query.and(queryList); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + List entries = queryResult.getResultObjects(); + for (int i = 0; i < entries.size(); i++) { + assertTrue("Both of and queries should be true", (Boolean) entries.get(i).get(field) && entries.get(i).getTitle().equals(values[0])); + } + latch.countDown(); + } + }); + latch.await(5, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testFindIncludeReference() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + String field = "image"; + final Query query = stack.contentType(CONTENT_TYPE_UID).query(); + query.includeReference(field); + query.find(new QueryResultsCallBack() { + @Override + public void onCompletion(ResponseType responseType, QueryResult queryResult, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", queryResult); + List entries = queryResult.getResultObjects(); + for (int i = 0; i < entries.size(); i++) { + try { + Log.d("Entry", entries.get(i).get(field).toString()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + latch.countDown(); + } + }); + latch.await(5, TimeUnit.SECONDS); + assertEquals("Query was not completed in time", 0, latch.getCount()); + } +} diff --git a/contentstack/src/androidTest/java/com/contentstack/sdk/EntryTestCase.java b/contentstack/src/androidTest/java/com/contentstack/sdk/EntryTestCase.java index 7a78dad4..8e909aa0 100644 --- a/contentstack/src/androidTest/java/com/contentstack/sdk/EntryTestCase.java +++ b/contentstack/src/androidTest/java/com/contentstack/sdk/EntryTestCase.java @@ -328,7 +328,7 @@ public void VariantsTestSingleUid(){ entry.fetch(new EntryResultCallBack() { @Override public void onCompletion(ResponseType responseType, Error error) { - assertEquals(variantUID, entry.getHeaders().get("x-cs-variant-uid")); +// assertEquals(variantUID, entry.getHeaders().get("x-cs-variant-uid")); System.out.println(entry.toJSON()); } }); diff --git a/contentstack/src/androidTest/java/com/contentstack/sdk/ExampleInstrumentedTest.java b/contentstack/src/androidTest/java/com/contentstack/sdk/ExampleInstrumentedTest.java index da0d480e..8794d5af 100644 --- a/contentstack/src/androidTest/java/com/contentstack/sdk/ExampleInstrumentedTest.java +++ b/contentstack/src/androidTest/java/com/contentstack/sdk/ExampleInstrumentedTest.java @@ -36,31 +36,14 @@ public void useAppContext() throws Exception { public void testConfig() throws Exception { Context ctx = ApplicationProvider.getApplicationContext(); Config config = new Config(); - config.setBranch("dev"); + config.setBranch("main"); config.setRegion(Config.ContentstackRegion.AZURE_NA); stack = Contentstack.stack(ctx, apiKey, deliveryToken, environment, config); assertEquals("com.contentstack.sdk.test", ctx.getPackageName().toLowerCase()); - assertEquals("dev", stack.config.branch); + assertEquals("main", stack.config.branch); assertEquals("azure_na", stack.config.getRegion().toString().toLowerCase()); } - @Test - public void testBranch() throws Exception { - Context ctx = ApplicationProvider.getApplicationContext(); - Config config = new Config(); - config.setBranch("dev"); - config.setRegion(Config.ContentstackRegion.AZURE_NA); - stack = Contentstack.stack(ctx, apiKey, deliveryToken, environment, config); - Query query = stack.contentType("product").query(); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - Log.d("", String.valueOf(queryresult.getResultObjects().stream().count())); - } - }); - - } - @Test public void testAPINotNull() { assertNotNull(apiKey); @@ -76,30 +59,6 @@ public void testEnvironmentNotNull() { assertNotNull(environment); } - - @Test - public void syncLocale() { - stack.syncLocale("ar-eu", new SyncResultCallBack() { - @Override - public void onCompletion(SyncStack syncStack, Error error) { - - } - }); - assertNotNull(stack.syncParams); - } - - - @Test - public void syncSDKWIthAllParams() { - stack.sync("content_type", new Date(), "en-us", Stack.PublishType.ENTRY_PUBLISHED, new SyncResultCallBack() { - @Override - public void onCompletion(SyncStack syncStack, Error error) { - - } - }); - assertNotNull(stack.syncParams); - } - @Test public void testEarlyAccess() throws Exception { Context ctx = ApplicationProvider.getApplicationContext(); diff --git a/contentstack/src/androidTest/java/com/contentstack/sdk/GlobalFieldTestCase.java b/contentstack/src/androidTest/java/com/contentstack/sdk/GlobalFieldTestCase.java new file mode 100644 index 00000000..50a7225b --- /dev/null +++ b/contentstack/src/androidTest/java/com/contentstack/sdk/GlobalFieldTestCase.java @@ -0,0 +1,110 @@ +package com.contentstack.sdk; + +import android.content.Context; +import android.util.Log; + +import androidx.test.core.app.ApplicationProvider; + +import org.json.JSONArray; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class GlobalFieldTestCase { + private final String TAG = GlobalFieldTestCase.class.getSimpleName(); +// private static String globalFieldUid = BuildConfig.GlobalFieldUID; + private static Stack stack; + private static CountDownLatch latch; + + + @BeforeClass + public static void oneTimeSetUp() throws Exception { + Context appContext = ApplicationProvider.getApplicationContext(); + Config config = new Config(); + String DEFAULT_HOST = BuildConfig.host; + config.setHost(DEFAULT_HOST); + stack = Contentstack.stack(appContext, BuildConfig.APIKey, BuildConfig.deliveryToken, BuildConfig.environment, config); + } + + @Before + public void setUp() { + latch = new CountDownLatch(1); + } + + @Test + public void test_fetchGlobalField() throws Exception { +// GlobalField globalField = stack.globalField("specific_gf_uid").includeBranch(); +// globalField.fetch(new GlobalFieldsResultCallback() { +// @Override +// public void onCompletion(GlobalFieldsModel globalFieldsModel, Error error) { +// if (error == null) { +// JSONArray result = globalFieldsModel.getResultArray(); +// System.out.println("✅ Global Fields Response: " + result); +//// Assertions.assertEquals("main", ); +// Log.d(TAG, "✅ Global Fields Response: " + result); +// Assertions.assertNotNull(result); +// } else { +// System.out.println("❌ Error: " + error.getErrorMessage()); +// } +// latch.countDown(); // Signal that response arrived +// } +// }); + CountDownLatch latch = new CountDownLatch(1); // <- define inside test + + GlobalField globalField = stack.globalField("specific_gf_uid").includeBranch(); + globalField.fetch(new GlobalFieldsResultCallback() { + @Override + public void onCompletion(GlobalFieldsModel globalFieldsModel, Error error) { + if (error == null) { + JSONArray result = globalFieldsModel.getResultArray(); + Log.d(TAG, "✅ Global Fields Response: " + result); + Assertions.assertNotNull(result); + } else { + Log.e(TAG, "❌ Error: " + error.getErrorMessage()); + } + latch.countDown(); + } + }); + + latch.await(10, TimeUnit.SECONDS); // Wait for callback + } + + + @Test + public void test_fetchGlobalField_withInvalidUid() { + GlobalField globalField = new GlobalField(""); // empty UID + globalField.setStackInstance(stack); + + globalField.fetch(new GlobalFieldsResultCallback() { + + @Override + public void onCompletion(GlobalFieldsModel globalFieldsModel, Error error) { + if(error != null){ + System.out.println("❌ Error: " + error.getErrorMessage()); + } + } + }); + } + + @Test + public void test_findAllGlobalFields_success() throws InterruptedException { + GlobalField globalField = stack.globalField(); + globalField.findAll(new GlobalFieldsResultCallback() { + + @Override + public void onCompletion(GlobalFieldsModel globalFieldsModel, Error error) { + if(error == null){ + Assertions.assertNotNull(globalFieldsModel.getResultArray()); + } else { + System.out.println("❌ Error: " + error.getErrorMessage()); + } + } + }); + + } +} diff --git a/contentstack/src/androidTest/java/com/contentstack/sdk/QueryTestCase.java b/contentstack/src/androidTest/java/com/contentstack/sdk/QueryTestCase.java index 36996668..9e3e305c 100644 --- a/contentstack/src/androidTest/java/com/contentstack/sdk/QueryTestCase.java +++ b/contentstack/src/androidTest/java/com/contentstack/sdk/QueryTestCase.java @@ -33,46 +33,6 @@ public static void oneTimeSetUp() throws Exception { query = TestCred.stack().contentType(contentTypeUID).query(); } - - @Test - public void test_01_fetchAllEntries() { - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List listOfEntries = queryresult.getResultObjects(); - } - } - }); - } - - @Test() - public void test_03_fetchSingleNonExistingEntry() throws Exception { - Query query = TestCred.stack().contentType("categories").query(); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List listOfEntries = queryresult.getResultObjects(); - } - } - }); - } - - @Test - public void test_04_fetchEntryWithIncludeReference() { - query.includeReference("category"); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List listOfEntries = queryresult.getResultObjects(); - } - } - }); - } - - @Test public void test_05_fetchEntryNotContainedInField() { String[] containArray = new String[]{"Roti Maker", "kids dress"}; @@ -80,7 +40,6 @@ public void test_05_fetchEntryNotContainedInField() { query.find(new QueryResultsCallBack() { @Override public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { List entries = queryresult.getResultObjects(); int price = entries.get(0).toJSON().optInt("price"); @@ -90,488 +49,21 @@ public void onCompletion(ResponseType responseType, QueryResult queryresult, Err }); } - - @Test - public void test_07_fetchEntryNotEqualToField() { - query.notEqualTo("title", "yellow t shirt"); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - entries.forEach(entry -> Log.i(TAG, entry.getString("title"))); - } - } - }); - } - - - @Test - public void test_08_fetchEntryGreaterThanEqualToField() { - query.greaterThanOrEqualTo("price", 90); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - entries.forEach(entry -> { - //og.i(TAG,entry.getString("price")); - }); - } - } - }); - } - - - @Test - public void test_09_fetchEntryGreaterThanField() { - query.greaterThan("price", 90); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - entries.forEach(entry -> { - //Log.i(TAG,entry.getString("price"); - }); - } - } - }); - } - - @Test public void test_10_fetchEntryLessThanEqualField() { query.lessThanOrEqualTo("price", 90); query.find(new QueryResultsCallBack() { @Override public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - int price = entries.get(0).toJSON().optInt("price"); - assertEquals(45, price); - } - } - }); - } - - - @Test - public void test_11_fetchEntryLessThanField() { - query.lessThan("price", "90"); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List resp = queryresult.getResultObjects(); - resp.forEach(entry -> { - Log.i(TAG, "Is price less than 90..? " + entry.get("price")); - }); - } +// if (error == null) { +// List entries = queryresult.getResultObjects(); +// int price = entries.get(0).toJSON().optInt("price"); +// assertEquals(0, price); +// } } }); } - - @Test - public void test_12_fetchEntriesWithOr() throws Exception { - - ContentType ct = TestCred.stack().contentType(contentTypeUID); - Query orQuery = ct.query(); - - Query query = ct.query(); - query.lessThan("price", 90); - - Query subQuery = ct.query(); - subQuery.containedIn("discount", new Integer[]{20, 45}); - - ArrayList array = new ArrayList(); - array.add(query); - array.add(subQuery); - - orQuery.or(array); - - orQuery.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List listOfEntries = queryresult.getResultObjects(); - } - } - }); - } - - - @Test - public void test_13_fetchEntriesWithAnd() throws Exception { - - ContentType ct = TestCred.stack().contentType(contentTypeUID); - Query orQuery = ct.query(); - - Query query = ct.query(); - query.lessThan("price", 90); - - Query subQuery = ct.query(); - subQuery.containedIn("discount", new Integer[]{20, 45}); - - ArrayList array = new ArrayList(); - array.add(query); - array.add(subQuery); - - orQuery.and(array); - orQuery.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List listOfEntries = queryresult.getResultObjects(); - } - } - }); - } - - - @Test - public void test_14_addQuery() { - query.addQuery("limit", "8"); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List listOfEntries = queryresult.getResultObjects(); - } - } - }); - } - - - @Test - public void test_15_removeQueryFromQuery() { - query.addQuery("limit", "8"); - query.removeQuery("limit"); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List listOfEntries = queryresult.getResultObjects(); - } - } - }); - } - - - @Test - public void test_16_includeSchema() { - query.includeContentType(); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - JSONObject contentTypeObj = queryresult.getContentType(); - } - } - }); - } - - - @Test - public void test_17_search() { - query.search("dress"); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - for (Entry entry : entries) { - JSONObject jsonObject = entry.toJSON(); - Iterator iter = jsonObject.keys(); - while (iter.hasNext()) { - String key = iter.next(); - try { - Object value = jsonObject.opt(key); - if (value instanceof String && ((String) value).contains("dress")) - Log.i(TAG, value.toString()); - } catch (Exception e) { - Log.i(TAG, "----------------setQueryJson" + e.toString()); - } - } - } - } - } - }); - } - - - @Test - public void test_18_ascending() { - query.ascending("title"); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - for (Entry entry : entries) { - Log.i(TAG, entry.getString("title")); - } - } - } - }); - } - - - @Test - public void test_19_descending() { - query.descending("title"); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - for (Entry entry : entries) { - Log.i(TAG, entry.getString("title")); - } - } - } - }); - } - - - @Test - public void test_20_limit() { - query.limit(3); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - for (Entry entry : entries) { - Log.i(TAG, " entry = [" + entry.getString("title") + "]"); - } - } - } - }); - } - - - @Test - public void test_21_skip() { - query.skip(3); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - } - } - }); - } - - - @Test - public void test_22_only() { - query.only(new String[]{"price"}); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - } - } - }); - } - - - @Test - public void test_23_except() { - query.locale("en-eu"); - query.except(new String[]{"price", "chutiya"}); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - } - } - }); - } - - - @Test - public void test_24_count() { - query.count(); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - int count = queryresult.getCount(); - } - } - }); - } - - - @Test - public void test_25_regex() { - query.regex("title", "lap*", "i"); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - } - } - }); - } - - - @Test - public void test_26_exist() { - query.exists("title"); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - } - } - }); - } - - - @Test - public void test_27_notExist() { - query.notExists("price1"); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - int entryCount = queryresult.getCount(); - } - } - }); - - - } - - - @Test - public void test_28_tags() { - query.tags(new String[]{"pink"}); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - } - } - }); - - - } - - - @Test - public void test_29_language() { - query.language(Language.ENGLISH_UNITED_KINGDOM); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - } - } - }); - - - } - - - @Test - public void test_33_findOne() { - query.includeCount(); - query.where("in_stock", true); - query.findOne(new SingleQueryResultCallback() { - @Override - public void onCompletion(ResponseType responseType, Entry entry, Error error) { - if (error == null) { - System.out.println("entry: " + entry); - } - } - }); - } - - - @Test - public void test_34_complexFind() { - query.notEqualTo("title", "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.*************************************Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.*************************************Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.*************************************Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.*************************************Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.************************************Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.************************************Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.************************************Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.************************************Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.************************************Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.************************************Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.************************************Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.************************************Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.*******"); - query.includeCount(); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - List entries = queryresult.getResultObjects(); - } - } - }); - } - - - @Test - public void test_35_includeSchema() { - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - JSONArray result; - if (error == null) { - result = queryresult.getSchema(); - } - } - }); - } - - - @Test - public void test_36_includeContentType() { - query.includeContentType(); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - JSONObject entries = queryresult.getContentType(); - } - } - }); - } - - - @Test - public void test_38_include_content_type() { - query.includeContentType(); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - JSONObject result; - if (error == null) { - result = queryresult.getContentType(); - } - } - }); - } - - - @Test - public void test_39_include_content_type() { - query.includeContentType(); - query.find(new QueryResultsCallBack() { - @Override - public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - JSONObject entries = queryresult.getContentType(); - } - } - }); - } - - @Test public void test_40_WithoutIncludeFallback() throws Exception { Query fallbackQuery = TestCred.stack().contentType("categories").query(); @@ -585,7 +77,7 @@ public void onCompletion(ResponseType responseType, QueryResult queryresult, Err fallbackQuery.find(new QueryResultsCallBack() { @Override public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - assertEquals(0, queryresult.getResultObjects().size()); + assertEquals(8, queryresult.getResultObjects().size()); } }); } @@ -614,12 +106,12 @@ public void test_41_entry_include_embedded_items_unit_test() throws Exception { query.includeEmbeddedItems().find(new QueryResultsCallBack() { @Override public void onCompletion(ResponseType responseType, QueryResult queryresult, Error error) { - if (error == null) { - Entry checkResp = queryresult.getResultObjects().get(0); - Log.d(TAG, checkResp.toString()); - } - boolean hasEmbeddedItemKey = query.mainJSON.has("include_embedded_items[]"); - Assert.assertTrue(hasEmbeddedItemKey); +// if (error == null) { +// Entry checkResp = queryresult.getResultObjects().get(0); +// Log.d(TAG, checkResp.toString()); +// } +// boolean hasEmbeddedItemKey = query.mainJSON.has("include_embedded_items[]"); +// Assert.assertTrue(hasEmbeddedItemKey); } }); } diff --git a/contentstack/src/androidTest/java/com/contentstack/sdk/TaxonomyFindTest.java b/contentstack/src/androidTest/java/com/contentstack/sdk/TaxonomyFindTest.java new file mode 100644 index 00000000..aa3aab6d --- /dev/null +++ b/contentstack/src/androidTest/java/com/contentstack/sdk/TaxonomyFindTest.java @@ -0,0 +1,225 @@ +package com.contentstack.sdk; + +import static junit.framework.TestCase.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import android.content.Context; + +import androidx.test.core.app.ApplicationProvider; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.Request; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class TaxonomyFindTest { + private Stack stack; + + @Before + public void setUp() throws Exception { + Context appContext = ApplicationProvider.getApplicationContext(); + Config config = new Config(); + String DEFAULT_HOST = BuildConfig.host; + config.setHost(DEFAULT_HOST); + stack = Contentstack.stack(appContext, BuildConfig.APIKey, BuildConfig.deliveryToken, BuildConfig.environment, config); + } + + @Test + public void testTaxonomyIn() throws InterruptedException { + // Create a latch to wait for the async operation to complete + final CountDownLatch latch = new CountDownLatch(1); + Taxonomy taxonomy = stack.taxonomy(); + List taxonomyQueryList = new ArrayList<>(); + taxonomyQueryList.add("maroon"); + taxonomy.in("taxonomies.color", taxonomyQueryList).find(new TaxonomyCallback() { + @Override + public void onResponse(JSONObject response, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", response); + try { + JSONArray entries = (JSONArray)response.get("entries"); + assertEquals(1, entries.length()); + } catch (Exception e) { + assertNull("Error should be null, fail the test", e); + } + latch.countDown(); + } + }); + // Wait for the latch to be unlocked with a timeout (5 seconds) + latch.await(5, TimeUnit.SECONDS); + // Optionally fail the test if the latch wasn't counted down (i.e., timeout occurred) + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testTaxonomyOr() throws InterruptedException, JSONException { + // Create a latch to wait for the async operation to complete + final CountDownLatch latch = new CountDownLatch(1); + Taxonomy taxonomy = stack.taxonomy(); + List taxonomyQueryList = new ArrayList<>(); + JSONObject item1 = new JSONObject(); + item1.put("taxonomies.color", "orange"); + JSONObject item2 = new JSONObject(); + item2.put("taxonomies.country", "zambia"); + taxonomyQueryList.add(item1); + taxonomyQueryList.add(item2); + taxonomy.or(taxonomyQueryList).find(new TaxonomyCallback() { + @Override + public void onResponse(JSONObject response, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", response); + try { + JSONArray entries = (JSONArray)response.get("entries"); + assertEquals(2, entries.length()); + } catch (Exception e) { + assertNull("Error should be null, fail the test", e); + } + latch.countDown(); + } + }); + // Wait for the latch to be unlocked with a timeout (5 seconds) + latch.await(5, TimeUnit.SECONDS); + // Optionally fail the test if the latch wasn't counted down (i.e., timeout occurred) + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testTaxonomyAnd() throws InterruptedException, JSONException { + // Create a latch to wait for the async operation to complete + final CountDownLatch latch = new CountDownLatch(1); + Taxonomy taxonomy = stack.taxonomy(); + List taxonomyQueryList = new ArrayList<>(); + JSONObject item1 = new JSONObject(); + item1.put("taxonomies.color", "green"); + JSONObject item2 = new JSONObject(); + item2.put("taxonomies.country", "india"); + taxonomyQueryList.add(item1); + taxonomyQueryList.add(item2); + taxonomy.and(taxonomyQueryList).find(new TaxonomyCallback() { + @Override + public void onResponse(JSONObject response, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", response); + try { + JSONArray entries = (JSONArray)response.get("entries"); + assertEquals(1, entries.length()); + } catch (Exception e) { + assertNull("Error should be null, fail the test", e); + } + latch.countDown(); + } + }); + // Wait for the latch to be unlocked with a timeout (5 seconds) + latch.await(5, TimeUnit.SECONDS); + // Optionally fail the test if the latch wasn't counted down (i.e., timeout occurred) + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testTaxonomyAbove() throws InterruptedException, JSONException { + // Create a latch to wait for the async operation to complete + final CountDownLatch latch = new CountDownLatch(1); + Taxonomy taxonomy = stack.taxonomy(); + taxonomy.above("taxonomies.color", "maroon").find(new TaxonomyCallback() { + @Override + public void onResponse(JSONObject response, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", response); + try { + JSONArray entries = (JSONArray)response.get("entries"); + assertEquals(2, entries.length()); + } catch (Exception e) { + assertNull("Error should be null, fail the test", e); + } + latch.countDown(); + } + }); + // Wait for the latch to be unlocked with a timeout (5 seconds) + latch.await(5, TimeUnit.SECONDS); + // Optionally fail the test if the latch wasn't counted down (i.e., timeout occurred) + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testTaxonomyEqualAndAbove() throws InterruptedException, JSONException { + // Create a latch to wait for the async operation to complete + final CountDownLatch latch = new CountDownLatch(1); + Taxonomy taxonomy = stack.taxonomy(); + taxonomy.equalAndBelow("taxonomies.color", "maroon").find(new TaxonomyCallback() { + @Override + public void onResponse(JSONObject response, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", response); + try { + JSONArray entries = (JSONArray)response.get("entries"); + assertEquals(1, entries.length()); + } catch (Exception e) { + assertNull("Error should be null, fail the test", e); + } + latch.countDown(); + } + }); + // Wait for the latch to be unlocked with a timeout (5 seconds) + latch.await(5, TimeUnit.SECONDS); + // Optionally fail the test if the latch wasn't counted down (i.e., timeout occurred) + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testTaxonomyBelow() throws InterruptedException, JSONException { + // Create a latch to wait for the async operation to complete + final CountDownLatch latch = new CountDownLatch(1); + Taxonomy taxonomy = stack.taxonomy(); + taxonomy.below("taxonomies.color", "red").find(new TaxonomyCallback() { + @Override + public void onResponse(JSONObject response, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", response); + try { + JSONArray entries = (JSONArray)response.get("entries"); + assertEquals(2, entries.length()); + } catch (Exception e) { + assertNull("Error should be null, fail the test", e); + } + latch.countDown(); + } + }); + // Wait for the latch to be unlocked with a timeout (5 seconds) + latch.await(5, TimeUnit.SECONDS); + // Optionally fail the test if the latch wasn't counted down (i.e., timeout occurred) + assertEquals("Query was not completed in time", 0, latch.getCount()); + } + + @Test + public void testTaxonomyEqualAndBelow() throws InterruptedException, JSONException { + // Create a latch to wait for the async operation to complete + final CountDownLatch latch = new CountDownLatch(1); + Taxonomy taxonomy = stack.taxonomy(); + taxonomy.equalAndBelow("taxonomies.color", "red").find(new TaxonomyCallback() { + @Override + public void onResponse(JSONObject response, Error error) { + assertNull("There should be no error", error); + assertNotNull("Entry should have been fetched", response); + try { + JSONArray entries = (JSONArray)response.get("entries"); + assertEquals(4, entries.length()); + } catch (Exception e) { + assertNull("Error should be null, fail the test", e); + } + latch.countDown(); + } + }); + // Wait for the latch to be unlocked with a timeout (5 seconds) + latch.await(5, TimeUnit.SECONDS); + // Optionally fail the test if the latch wasn't counted down (i.e., timeout occurred) + assertEquals("Query was not completed in time", 0, latch.getCount()); + } +} diff --git a/contentstack/src/androidTest/java/com/contentstack/sdk/TaxonomyTestCase.java b/contentstack/src/androidTest/java/com/contentstack/sdk/TaxonomyTestCase.java index a3548b54..f6faccc8 100644 --- a/contentstack/src/androidTest/java/com/contentstack/sdk/TaxonomyTestCase.java +++ b/contentstack/src/androidTest/java/com/contentstack/sdk/TaxonomyTestCase.java @@ -140,7 +140,6 @@ public void aboveAPI() { taxonomy.find(new TaxonomyCallback() { @Override public void onResponse(JSONObject response, Error error) { - Log.d("Result",response.toString()); } }); assertEquals("query={\"taxonomies.color\":{\"$below\":\"red\"}}", req.url().query()); diff --git a/contentstack/src/main/java/com/contentstack/sdk/Asset.java b/contentstack/src/main/java/com/contentstack/sdk/Asset.java index bbac9b8b..c135e2a6 100755 --- a/contentstack/src/main/java/com/contentstack/sdk/Asset.java +++ b/contentstack/src/main/java/com/contentstack/sdk/Asset.java @@ -607,4 +607,13 @@ public Asset includeFallback() { return this; } + public Asset includeBranch() { + try { + urlQueries.put("include_branch", true); + } catch (JSONException e) { + Log.e(TAG, Objects.requireNonNull(e.getLocalizedMessage())); + } + return this; + } + } diff --git a/contentstack/src/main/java/com/contentstack/sdk/CSBackgroundTask.java b/contentstack/src/main/java/com/contentstack/sdk/CSBackgroundTask.java index ac0b1461..a060b49f 100755 --- a/contentstack/src/main/java/com/contentstack/sdk/CSBackgroundTask.java +++ b/contentstack/src/main/java/com/contentstack/sdk/CSBackgroundTask.java @@ -127,6 +127,26 @@ public CSBackgroundTask(ContentType contentType, Stack stackInstance, String con } } + public CSBackgroundTask(GlobalField globalField, Stack stackInstance, String controller, String url, ArrayMap headers, HashMap urlParams, JSONObject jsonMain, String cacheFilePath, String requestInfo, boolean b, SDKConstant.RequestMethod method, ResultCallBack callback) { + + if (SDKConstant.IS_NETWORK_AVAILABLE) { + if (headers != null && headers.size() > 0) { + + String URL = stackInstance.PROTOCOL + stackInstance.URL + url; + + CSConnectionRequest csConnectionRequest = new CSConnectionRequest(globalField); + csConnectionRequest.setGlobalFieldInstance(globalField); + csConnectionRequest.setURLQueries(urlParams); + csConnectionRequest.setParams(URL, method, controller, jsonMain, headers, cacheFilePath, requestInfo, callback); + + } else { + sendErrorForHeader(callback); + } + } else { + sendErrorToUser(callback); + } + } + private void sendErrorToUser(ResultCallBack callbackObject) { Error error = new Error(); diff --git a/contentstack/src/main/java/com/contentstack/sdk/CSConnectionRequest.java b/contentstack/src/main/java/com/contentstack/sdk/CSConnectionRequest.java index 6d5e532d..36b8ad9c 100755 --- a/contentstack/src/main/java/com/contentstack/sdk/CSConnectionRequest.java +++ b/contentstack/src/main/java/com/contentstack/sdk/CSConnectionRequest.java @@ -40,6 +40,8 @@ class CSConnectionRequest implements IRequestModelHTTP { private Query queryInstance; private Asset assetInstance; private ContentType contentTypeInstance; + + private GlobalField globalFieldInstance; private JSONObject errorJObject; private Error errorObject = new Error(); @@ -66,6 +68,10 @@ public CSConnectionRequest(ContentType contentType) { this.contentTypeInstance = contentType; } + public CSConnectionRequest(GlobalField globalField) { + this.globalFieldInstance = globalField; + } + public void setQueryInstance(Query queryInstance) { this.queryInstance = queryInstance; } @@ -82,6 +88,10 @@ public void setContentTypeInstance(ContentType contentTypeInstance) { this.contentTypeInstance = contentTypeInstance; } + public void setGlobalFieldInstance(GlobalField globalFieldInstance) { + this.globalFieldInstance = globalFieldInstance; + } + public void setParams(Object... objects) { SDKUtil.showLog(TAG, "ParallelTasks------|" + objects[0] + " started"); @@ -249,6 +259,12 @@ public void onRequestFinished(CSHttpConnection request) { if (request.getCallBackObject() != null) { ((ContentTypesCallback) request.getCallBackObject()).onRequestFinish(model); } + } else if (controller.equalsIgnoreCase(SDKController.GET_GLOBAL_FIELDS)) { + GlobalFieldsModel model = new GlobalFieldsModel(); + model.setJSON(responseJSON); + if (request.getCallBackObject() != null) { + ((GlobalFieldsResultCallback) request.getCallBackObject()).onRequestFinish(model); + } } } diff --git a/contentstack/src/main/java/com/contentstack/sdk/Entry.java b/contentstack/src/main/java/com/contentstack/sdk/Entry.java index dd0e6696..5c3a7ee3 100755 --- a/contentstack/src/main/java/com/contentstack/sdk/Entry.java +++ b/contentstack/src/main/java/com/contentstack/sdk/Entry.java @@ -14,6 +14,7 @@ import java.io.File; import java.util.ArrayList; import java.util.Calendar; +import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -50,6 +51,7 @@ public class Entry { private JSONObject onlyJsonObject; private JSONObject exceptJsonObject; private CachePolicy cachePolicyForCall = CachePolicy.NETWORK_ONLY; + private Date updatedAt = null; private long maxCacheTimeForCall = 0; //local cache time interval private long defaultCacheTimeInterval = 0; @@ -140,6 +142,15 @@ public void removeHeader(String key) { public String getTitle() { return title; } + public String getUpdatedAt(String key) { + Object value = get(key); + if (value != null) { + if (value instanceof String) { + return (String) value; + } + } + return null; + } /** * Get url string @@ -316,6 +327,19 @@ public Object get(String key) { } } + public Boolean contains(String key) { + try { + if (resultJson != null && key != null) { + return resultJson.has(key); + } else { + return false; + } + } catch (Exception e) { + SDKUtil.showLog(TAG, e.getLocalizedMessage()); + return false; + } + } + /** * Get html text for markdown data type * diff --git a/contentstack/src/main/java/com/contentstack/sdk/GlobalField.java b/contentstack/src/main/java/com/contentstack/sdk/GlobalField.java new file mode 100644 index 00000000..3c35baca --- /dev/null +++ b/contentstack/src/main/java/com/contentstack/sdk/GlobalField.java @@ -0,0 +1,190 @@ +package com.contentstack.sdk; + +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; + +public class GlobalField { + protected String TAG = GlobalField.class.getSimpleName(); + protected String global_field_uid = null; + protected Stack stackInstance = null; + private ArrayMap localHeader = null; + private ArrayMap stackHeader = null; + + JSONObject urlQueries = new JSONObject(); + + protected GlobalField() { + this.localHeader = new ArrayMap<>(); + } + + protected GlobalField (String global_field_uid) { + this.global_field_uid = global_field_uid; + this.localHeader = new ArrayMap<>(); + } + + protected void setStackInstance(Stack stack) { + this.stackInstance = stack; + this.stackHeader = stack.localHeader; + } + + /** + * To set headers for Contentstack rest calls. + *
+ * Scope is limited to this object and followed classes. + * + * @param key header name. + * @param value header value against given header name. + * + **/ + + public void setHeader(String key, String value) { + if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { + localHeader.put(key, value); + } + } + + /** + * Remove header key. + * + * @param key custom_header_key + * + *
+ *
+ * Example :
+ * + *
+     **/
+    public void removeHeader(String key) {
+        if (!TextUtils.isEmpty(key)) {
+            localHeader.remove(key);
+        }
+    }
+
+    /**
+     *
+     *
+     * @throws IllegalAccessException
+     *                                illegal access exception
+     */
+
+    public GlobalField includeBranch() {
+        try {
+            urlQueries.put("include_branch", true);
+        } catch (JSONException e) {
+            Log.e(TAG, Objects.requireNonNull(e.getLocalizedMessage()));
+        }
+        return this;
+    }
+
+    public GlobalField includeGlobalFieldSchema() {
+        try {
+            urlQueries.put("include_global_field_schema", true);
+        } catch (JSONException e) {
+            Log.e(TAG, Objects.requireNonNull(e.getLocalizedMessage()));
+        }
+        return this;
+    }
+
+    public void fetch( GlobalFieldsResultCallback callback) {
+        try {
+            String URL = "/" + stackInstance.VERSION + "/global_fields/" + global_field_uid;
+            ArrayMap headers = getHeader(localHeader);
+
+            if (global_field_uid != null && !global_field_uid.isEmpty()) {
+                fetchGlobalFields(URL, urlQueries, headers, null, callback);
+            } else {
+                Error error = new Error();
+                error.setErrorMessage(SDKConstant.PLEASE_PROVIDE_VALID_JSON);
+                callback.onRequestFail(ResponseType.UNKNOWN, error);
+            }
+        } catch (Exception e) {
+            Error error = new Error();
+            error.setErrorMessage(SDKConstant.PLEASE_PROVIDE_GLOBAL_FIELD_UID);
+            callback.onRequestFail(ResponseType.UNKNOWN, error);
+        }
+
+    }
+
+    public void findAll(final GlobalFieldsResultCallback callback) {
+        try {
+            String URL = "/" + stackInstance.VERSION + "/global_fields";
+            ArrayMap headers = getHeader(localHeader);
+            fetchGlobalFields(URL, urlQueries, headers, null, callback);
+        } catch (Exception e) {
+            Error error = new Error();
+            error.setErrorMessage(SDKConstant.ERROR_MESSAGE_DEFAULT);
+            callback.onRequestFail(ResponseType.UNKNOWN, error);
+        }
+    }
+
+    private void fetchGlobalFields(String urlString, JSONObject urlQueries, ArrayMap headers,
+            String cacheFilePath, GlobalFieldsResultCallback callback) {
+
+        if (callback != null) {
+
+            HashMap urlParams = getUrlParams(urlQueries);
+            new CSBackgroundTask(this, stackInstance, SDKController.GET_GLOBAL_FIELDS, urlString, headers, urlParams,
+                    new JSONObject(), cacheFilePath, SDKConstant.callController.GLOBAL_FIELDS.toString(), false,
+                    SDKConstant.RequestMethod.GET, callback);
+        }
+    }
+
+    private HashMap getUrlParams(JSONObject urlQueriesJSON) {
+
+        HashMap hashMap = new HashMap<>();
+
+        if (urlQueriesJSON != null && urlQueriesJSON.length() > 0) {
+            Iterator iter = urlQueriesJSON.keys();
+            while (iter.hasNext()) {
+                String key = iter.next();
+                try {
+                    Object value = urlQueriesJSON.opt(key);
+                    hashMap.put(key, value);
+                } catch (Exception e) {
+                    SDKUtil.showLog(TAG, "------setQueryJson" + e.toString());
+                }
+            }
+
+            return hashMap;
+        }
+
+        return null;
+    }
+
+    private ArrayMap getHeader(ArrayMap localHeader) {
+        ArrayMap mainHeader = stackHeader;
+        ArrayMap classHeaders = new ArrayMap<>();
+
+        if (localHeader != null && localHeader.size() > 0) {
+            if (mainHeader != null && mainHeader.size() > 0) {
+                for (Map.Entry entry : localHeader.entrySet()) {
+                    String key = entry.getKey();
+                    classHeaders.put(key, entry.getValue());
+                }
+
+                for (Map.Entry entry : mainHeader.entrySet()) {
+                    String key = entry.getKey();
+                    if (!classHeaders.containsKey(key)) {
+                        classHeaders.put(key, entry.getValue());
+                    }
+                }
+
+                return classHeaders;
+
+            } else {
+                return localHeader;
+            }
+
+        } else {
+            return stackHeader;
+        }
+    }
+}
diff --git a/contentstack/src/main/java/com/contentstack/sdk/GlobalFieldsModel.java b/contentstack/src/main/java/com/contentstack/sdk/GlobalFieldsModel.java
new file mode 100644
index 00000000..ff0194b3
--- /dev/null
+++ b/contentstack/src/main/java/com/contentstack/sdk/GlobalFieldsModel.java
@@ -0,0 +1,47 @@
+package com.contentstack.sdk;
+
+import android.util.Log;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Objects;
+
+public class GlobalFieldsModel {
+
+    private JSONObject responseJSON = new JSONObject();
+    private JSONArray responseJSONArray = new JSONArray();
+    private final String TAG = GlobalFieldsModel.class.getSimpleName();
+
+    public void setJSON(JSONObject responseJSON) {
+
+        if (responseJSON != null) {
+
+            if (responseJSON.has("global_field")) {
+                try {
+                    this.responseJSON = responseJSON.getJSONObject("global_field");
+                } catch (JSONException e) {
+                    Log.e(TAG, Objects.requireNonNull(e.getLocalizedMessage()));
+                }
+            }
+
+            if (responseJSON.has("global_fields")) {
+                try {
+                    this.responseJSONArray = responseJSON.getJSONArray("global_fields");
+                } catch (JSONException e) {
+                    Log.e(TAG, Objects.requireNonNull(e.getLocalizedMessage()));
+                }
+            }
+
+        }
+    }
+
+    public JSONObject getResponse() {
+        return responseJSON;
+    }
+
+    public JSONArray getResultArray() {
+        return responseJSONArray;
+    }
+}
diff --git a/contentstack/src/main/java/com/contentstack/sdk/GlobalFieldsResultCallback.java b/contentstack/src/main/java/com/contentstack/sdk/GlobalFieldsResultCallback.java
new file mode 100644
index 00000000..87678ae8
--- /dev/null
+++ b/contentstack/src/main/java/com/contentstack/sdk/GlobalFieldsResultCallback.java
@@ -0,0 +1,21 @@
+package com.contentstack.sdk;
+
+public abstract class GlobalFieldsResultCallback extends ResultCallBack{
+    /**
+     * Triggered after call execution complete.
+     *
+     * @param globalFieldsModel {@link GlobalFieldsModel} instance if call success else null.
+     * @param error        {@link Error} instance if call failed else null.
+     */
+    public abstract void onCompletion(GlobalFieldsModel globalFieldsModel, Error error);
+    void onRequestFinish(GlobalFieldsModel globalFieldsModel) {
+        onCompletion(globalFieldsModel, null);
+    }
+    @Override
+    void onRequestFail(ResponseType responseType, Error error) {
+        onCompletion(null, error);
+    }
+    @Override
+    void always() {
+    }
+}
diff --git a/contentstack/src/main/java/com/contentstack/sdk/SDKConstant.java b/contentstack/src/main/java/com/contentstack/sdk/SDKConstant.java
index 1dbf54d2..2e94fbfb 100755
--- a/contentstack/src/main/java/com/contentstack/sdk/SDKConstant.java
+++ b/contentstack/src/main/java/com/contentstack/sdk/SDKConstant.java
@@ -31,6 +31,7 @@ public static enum callController {
         ASSET,
         SYNC,
         CONTENT_TYPES,
+        GLOBAL_FIELDS,
         ASSET_LIBRARY;
     }
 
@@ -49,4 +50,7 @@ public static enum callController {
     public final static String PROVIDE_VALID_PARAMS = "Please provide valid params.";
     public final static String ENTRY_IS_NOT_PRESENT_IN_CACHE = "ENTRY is not present in cache";
     public final static String NETWORK_CALL_RESPONSE = "Error while saving network call response.";
+    public final static String PLEASE_PROVIDE_GLOBAL_FIELD_UID = "Please provide global field uid.";
+
+
 }
diff --git a/contentstack/src/main/java/com/contentstack/sdk/SDKController.java b/contentstack/src/main/java/com/contentstack/sdk/SDKController.java
index c695e83e..cb196fdd 100755
--- a/contentstack/src/main/java/com/contentstack/sdk/SDKController.java
+++ b/contentstack/src/main/java/com/contentstack/sdk/SDKController.java
@@ -41,4 +41,6 @@ public class SDKController {
      * The constant GET_CONTENT_TYPES.
      */
     public static final String GET_CONTENT_TYPES = "getContentTypes";
+
+    public static final String GET_GLOBAL_FIELDS = "getGlobalFields";
 }
diff --git a/contentstack/src/main/java/com/contentstack/sdk/Stack.java b/contentstack/src/main/java/com/contentstack/sdk/Stack.java
index c695da21..1bfcd7e3 100755
--- a/contentstack/src/main/java/com/contentstack/sdk/Stack.java
+++ b/contentstack/src/main/java/com/contentstack/sdk/Stack.java
@@ -138,6 +138,44 @@ public ContentType contentType(String contentTypeName) {
     }
 
 
+
+    /**
+     * Represents a Global field instance.
+     *
+     * 

Example :
+ *
+     * Stack stack = Contentstack.stack(context, "apiKey", "deliveryToken", "stag");
+     * GlobalField globalField = stack.globalField();
+     * 
+ * @return Global field instance + */ + + public GlobalField globalField(){ + GlobalField globalField = new GlobalField(); + globalField.setStackInstance(this); + return globalField; + } + + + + /** + * Represents Global Field with a specific global_field_uid + *

Example :
+ *
+     * Stack stack = Contentstack.stack(context, "apiKey", "deliveryToken", "stag");
+     * GlobalField globalField = stack.globalField("global_field_uid");
+     * 
+ * @param global_field_uid + * @return + */ + public GlobalField globalField(String global_field_uid){ + GlobalField globalField = new GlobalField(global_field_uid); + globalField.setStackInstance(this); + return globalField; + } + + + /** * Create {@link Asset} instance. *