From 37db8b47b0a0395c97d1a71b13b4148fe6e721d0 Mon Sep 17 00:00:00 2001 From: Waheed Ahmed Date: Wed, 2 Oct 2019 15:52:28 +0500 Subject: [PATCH 1/2] Upgrade to python 3. Updated travis.yml to run tests on both python 2 and 3, added openedx.yaml. PROD-773 --- .travis.yml | 26 ++++++------ google_drive/google_calendar.py | 3 +- google_drive/google_docs.py | 9 ++-- google_drive/tests/integration/base_test.py | 1 + google_drive/tests/integration/test_studio.py | 3 +- google_drive/tests/test_const.py | 2 +- google_drive/tests/unit/test_calendar.py | 30 ++++++++----- google_drive/tests/unit/test_docs.py | 42 ++++++++++++------- google_drive/tests/unit/test_utils.py | 2 +- openedx.yaml | 13 ++++++ requirements/base.in | 2 +- requirements/dev.in | 2 +- requirements/dev.txt | 8 ++-- requirements/quality.txt | 8 ++-- requirements/test.in | 2 +- requirements/test.txt | 8 ++-- setup.py | 2 + tox.ini | 7 +--- 18 files changed, 101 insertions(+), 69 deletions(-) create mode 100644 openedx.yaml diff --git a/.travis.yml b/.travis.yml index 9d5548e..fec16da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,26 +1,24 @@ language: python sudo: false -python: - - "2.7" - -env: - - TOXENV=django18 - - TOXENV=django110 - - TOXENV=django111 - - TOXENV=quality +matrix: + include: + - python: '2.7' + env: 'TOXENV=django111' + - python: '3.5' + env: 'TOXENV=django111' + - python: '3.5' + env: 'TOXENV=quality' before_install: - - export DISPLAY=:99.0 - - sh -e /etc/init.d/xvfb start - - sleep 3 # give xvfb some time to start - - wget https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz + - wget https://github.com/mozilla/geckodriver/releases/download/v0.25.0/geckodriver-v0.25.0-linux64.tar.gz - mkdir geckodriver - - tar -xzf geckodriver-v0.19.1-linux64.tar.gz -C geckodriver + - tar -xzf geckodriver-v0.25.0-linux64.tar.gz -C geckodriver - export PATH=$PATH:$PWD/geckodriver + - export BOKCHOY_HEADLESS=true addons: - firefox: '58.0.2' + firefox: latest install: - pip install -r requirements/travis.txt diff --git a/google_drive/google_calendar.py b/google_drive/google_calendar.py index 5a7ac0b..2e1fe5f 100644 --- a/google_drive/google_calendar.py +++ b/google_drive/google_calendar.py @@ -3,11 +3,12 @@ # # Imports ########################################################### +from __future__ import absolute_import import logging from django import utils from xblock.core import XBlock -from xblock.fields import Scope, String, Integer +from xblock.fields import Integer, Scope, String from xblock.fragment import Fragment from xblockutils.publish_event import PublishEventMixin from xblockutils.resources import ResourceLoader diff --git a/google_drive/google_docs.py b/google_drive/google_docs.py index 32532fc..b429cdc 100644 --- a/google_drive/google_docs.py +++ b/google_drive/google_docs.py @@ -3,16 +3,17 @@ # # Imports ########################################################### +from __future__ import absolute_import import logging import textwrap -import requests +import requests from xblock.core import XBlock from xblock.fields import Scope, String from xblock.fragment import Fragment - from xblockutils.publish_event import PublishEventMixin from xblockutils.resources import ResourceLoader +import six LOG = logging.getLogger(__name__) RESOURCE_LOADER = ResourceLoader(__name__) @@ -143,7 +144,7 @@ def check_url(self, data, suffix=''): # pylint: disable=unused-argument,no-self try: test_url = data['url'] except KeyError as ex: - LOG.debug("URL not provided - %s", unicode(ex)) + LOG.debug("URL not provided - %s", six.text_type(ex)) return { 'status_code': 400, } @@ -152,7 +153,7 @@ def check_url(self, data, suffix=''): # pylint: disable=unused-argument,no-self url_response = requests.head(test_url) # Catch wide range of request exceptions except requests.exceptions.RequestException as ex: - LOG.debug("Unable to connect to %s - %s", test_url, unicode(ex)) + LOG.debug("Unable to connect to %s - %s", test_url, six.text_type(ex)) return { 'status_code': 400, } diff --git a/google_drive/tests/integration/base_test.py b/google_drive/tests/integration/base_test.py index aef313f..a5c781f 100644 --- a/google_drive/tests/integration/base_test.py +++ b/google_drive/tests/integration/base_test.py @@ -3,6 +3,7 @@ # # Imports ########################################################### +from __future__ import absolute_import from xblockutils.base_test import SeleniumBaseTest diff --git a/google_drive/tests/integration/test_studio.py b/google_drive/tests/integration/test_studio.py index 2857a0b..f99fbb1 100644 --- a/google_drive/tests/integration/test_studio.py +++ b/google_drive/tests/integration/test_studio.py @@ -3,7 +3,8 @@ # # Imports ########################################################### -from ddt import ddt, unpack, data +from __future__ import absolute_import +from ddt import data, ddt, unpack from google_drive.google_calendar import DEFAULT_CALENDAR_URL from google_drive.google_docs import DEFAULT_DOCUMENT_URL diff --git a/google_drive/tests/test_const.py b/google_drive/tests/test_const.py index 60ddcde..9f6bedf 100644 --- a/google_drive/tests/test_const.py +++ b/google_drive/tests/test_const.py @@ -15,4 +15,4 @@ STATUS_CODE_400 = {'status_code': 400} STATUS_CODE_404 = {'status_code': 404} -TEST_IMAGE_URL = 'https://docs.google.com/drawings/d/1lmmxboBM5c_0WCTjhAxBdkpqQb3T8VSwtuG0TRR1ODQ/pub?w=960&h=720' +TEST_IMAGE_URL = 'https://docs.google.com/drawings/d/1C1hw4pLKLDAhGDD4Etd20Y1BpFeGy0rTlMfoczNZXx4/edit?usp=sharing' diff --git a/google_drive/tests/unit/test_calendar.py b/google_drive/tests/unit/test_calendar.py index 2c53f6a..fec5bf8 100644 --- a/google_drive/tests/unit/test_calendar.py +++ b/google_drive/tests/unit/test_calendar.py @@ -2,23 +2,31 @@ # -*- coding: utf-8 -*- # +from __future__ import absolute_import # Imports ########################################################### import json import unittest -import cgi -import ddt -from mock import Mock +import ddt +from django.utils.html import escape from django.utils.translation import override as override_language +from mock import Mock from nose.tools import assert_equals, assert_in from workbench.runtime import WorkbenchRuntime -from xblock.runtime import KvsFieldData, DictKeyValueStore +from xblock.runtime import DictKeyValueStore, KvsFieldData from google_drive import GoogleCalendarBlock from google_drive.google_calendar import DEFAULT_CALENDAR_ID +from google_drive.tests.test_const import ( + BUTTONS_WRAPPER, + RESULT_ERROR, + RESULT_MISSING_EVENT_TYPE, + RESULT_SUCCESS, + STUDIO_EDIT_WRAPPER, + USER_INPUTS_WRAPPER, + VALIDATION_WRAPPER +) from google_drive.tests.unit.test_utils import generate_scope_ids, make_request -from google_drive.tests.test_const import STUDIO_EDIT_WRAPPER, VALIDATION_WRAPPER, USER_INPUTS_WRAPPER, BUTTONS_WRAPPER -from google_drive.tests.test_const import RESULT_SUCCESS, RESULT_ERROR, RESULT_MISSING_EVENT_TYPE # Constants ########################################################### TEST_SUBMIT_DATA = { @@ -101,7 +109,7 @@ def test_calendar_template_content(self, override, activate_lang, expected_lang) ) assert_in('
', student_fragment.content) - assert_in(cgi.escape(src_url), student_fragment.content) + assert_in(escape(src_url), student_fragment.content) assert_in('Google Calendar', student_fragment.content) assert_in(STUDIO_EDIT_WRAPPER, studio_fragment.content) @@ -116,7 +124,7 @@ def test_calendar_document_submit(self): # pylint: disable=no-self-use body = json.dumps(TEST_SUBMIT_DATA) res = block.handle('studio_submit', make_request(body)) # pylint: disable=no-value-for-parameter - assert_equals(json.loads(res.body), RESULT_SUCCESS) + assert_equals(json.loads(res.body.decode('utf8')), RESULT_SUCCESS) assert_equals(block.display_name, TEST_SUBMIT_DATA['display_name']) assert_equals(block.calendar_id, TEST_SUBMIT_DATA['calendar_id']) @@ -125,7 +133,7 @@ def test_calendar_document_submit(self): # pylint: disable=no-self-use body = json.dumps('') res = block.handle('studio_submit', make_request(body)) # pylint: disable=no-value-for-parameter - assert_equals(json.loads(res.body), RESULT_ERROR) + assert_equals(json.loads(res.body.decode('utf8')), RESULT_ERROR) def test_calendar_publish_event(self): # pylint: disable=no-self-use """ Test event publishing in GoogleCalendarBlock""" @@ -134,9 +142,9 @@ def test_calendar_publish_event(self): # pylint: disable=no-self-use body = json.dumps(TEST_COMPLETE_PUBLISH_DATA) res = block.handle('publish_event', make_request(body)) # pylint: disable=no-value-for-parameter - assert_equals(json.loads(res.body), RESULT_SUCCESS) + assert_equals(json.loads(res.body.decode('utf8')), RESULT_SUCCESS) body = json.dumps(TEST_INCOMPLETE_PUBLISH_DATA) res = block.handle('publish_event', make_request(body)) - assert_equals(json.loads(res.body), RESULT_MISSING_EVENT_TYPE) + assert_equals(json.loads(res.body.decode('utf8')), RESULT_MISSING_EVENT_TYPE) diff --git a/google_drive/tests/unit/test_docs.py b/google_drive/tests/unit/test_docs.py index 9a824ae..ffe1ddf 100644 --- a/google_drive/tests/unit/test_docs.py +++ b/google_drive/tests/unit/test_docs.py @@ -3,21 +3,31 @@ # # Imports ########################################################### +from __future__ import absolute_import import json import unittest -from mock import Mock +from mock import Mock from nose.tools import assert_equals, assert_in from workbench.runtime import WorkbenchRuntime -from xblock.runtime import KvsFieldData, DictKeyValueStore +from xblock.runtime import DictKeyValueStore, KvsFieldData from google_drive import GoogleDocumentBlock -from google_drive.google_docs import DEFAULT_EMBED_CODE, DEFAULT_DOCUMENT_URL +from google_drive.google_docs import DEFAULT_DOCUMENT_URL, DEFAULT_EMBED_CODE +from google_drive.tests.test_const import ( + BUTTONS_WRAPPER, + RESULT_ERROR, + RESULT_MISSING_EVENT_TYPE, + RESULT_SUCCESS, + STATUS_CODE_200, + STATUS_CODE_400, + STATUS_CODE_404, + STUDIO_EDIT_WRAPPER, + TEST_IMAGE_URL, + USER_INPUTS_WRAPPER, + VALIDATION_WRAPPER +) from google_drive.tests.unit.test_utils import generate_scope_ids, make_request -from google_drive.tests.test_const import STUDIO_EDIT_WRAPPER, VALIDATION_WRAPPER, USER_INPUTS_WRAPPER, BUTTONS_WRAPPER -from google_drive.tests.test_const import RESULT_SUCCESS, RESULT_ERROR, RESULT_MISSING_EVENT_TYPE -from google_drive.tests.test_const import STATUS_CODE_200, STATUS_CODE_400, STATUS_CODE_404 -from google_drive.tests.test_const import TEST_IMAGE_URL # Constants ########################################################### TEST_SUBMIT_DATA = { @@ -90,7 +100,7 @@ def test_studio_document_submit(self): # pylint: disable=no-self-use body = json.dumps(TEST_SUBMIT_DATA) res = block.handle('studio_submit', make_request(body)) # pylint: disable=no-value-for-parameter - assert_equals(json.loads(res.body), RESULT_SUCCESS) + assert_equals(json.loads(res.body.decode('utf8')), RESULT_SUCCESS) assert_equals(block.display_name, TEST_SUBMIT_DATA['display_name']) assert_equals(block.embed_code, TEST_SUBMIT_DATA['embed_code']) @@ -98,7 +108,7 @@ def test_studio_document_submit(self): # pylint: disable=no-self-use body = json.dumps('') res = block.handle('studio_submit', make_request(body)) - assert_equals(json.loads(res.body), RESULT_ERROR) + assert_equals(json.loads(res.body.decode('utf8')), RESULT_ERROR) def test_check_document_url(self): # pylint: disable=no-self-use """ Test verification of the provided Google Document URL""" @@ -107,22 +117,22 @@ def test_check_document_url(self): # pylint: disable=no-self-use data = json.dumps(TEST_VALIDATE_URL_DATA) res = block.handle('check_url', make_request(data)) # pylint: disable=no-value-for-parameter - assert_equals(json.loads(res.body), STATUS_CODE_200) + assert_equals(json.loads(res.body.decode('utf8')), STATUS_CODE_200) data = json.dumps(TEST_VALIDATE_UNDEFINED_DATA) res = block.handle('check_url', make_request(data)) - assert_equals(json.loads(res.body), STATUS_CODE_400) + assert_equals(json.loads(res.body.decode('utf8')), STATUS_CODE_400) data = json.dumps(TEST_VALIDATE_NONEXISTENT_URL_DATA) res = block.handle('check_url', make_request(data)) - assert_equals(json.loads(res.body), STATUS_CODE_404) + assert_equals(json.loads(res.body.decode('utf8')), STATUS_CODE_404) data = json.dumps({}) res = block.handle('check_url', make_request(data)) - assert_equals(json.loads(res.body), STATUS_CODE_400) + assert_equals(json.loads(res.body.decode('utf8')), STATUS_CODE_400) def test_document_publish_event(self): # pylint: disable=no-self-use """ Test event publishing in GoogleDocumentBlock""" @@ -131,14 +141,14 @@ def test_document_publish_event(self): # pylint: disable=no-self-use body = json.dumps(TEST_COMPLETE_PUBLISH_DOCUMENT_DATA) res = block.handle('publish_event', make_request(body)) # pylint: disable=no-value-for-parameter - assert_equals(json.loads(res.body), RESULT_SUCCESS) + assert_equals(json.loads(res.body.decode('utf8')), RESULT_SUCCESS) body = json.dumps(TEST_COMPLETE_PUBLISH_IMAGE_DATA) res = block.handle('publish_event', make_request(body)) - assert_equals(json.loads(res.body), RESULT_SUCCESS) + assert_equals(json.loads(res.body.decode('utf8')), RESULT_SUCCESS) body = json.dumps(TEST_INCOMPLETE_PUBLISH_DATA) res = block.handle('publish_event', make_request(body)) - assert_equals(json.loads(res.body), RESULT_MISSING_EVENT_TYPE) + assert_equals(json.loads(res.body.decode('utf8')), RESULT_MISSING_EVENT_TYPE) diff --git a/google_drive/tests/unit/test_utils.py b/google_drive/tests/unit/test_utils.py index 367f602..ce70f40 100644 --- a/google_drive/tests/unit/test_utils.py +++ b/google_drive/tests/unit/test_utils.py @@ -3,8 +3,8 @@ # # Imports ########################################################### +from __future__ import absolute_import from webob import Request - from xblock.fields import ScopeIds diff --git a/openedx.yaml b/openedx.yaml new file mode 100644 index 0000000..ac3aebf --- /dev/null +++ b/openedx.yaml @@ -0,0 +1,13 @@ +# This file describes this Open edX repo, as described in OEP-2: +# https://open-edx-proposals.readthedocs.io/en/latest/oep-0002-bp-repo-metadata.html#specification + +nick: xblock-google-drive +owner: unknown + +oeps: + oep-2: true + oep-7: true + oep-18: true +tags: + - xblock + - library diff --git a/requirements/base.in b/requirements/base.in index 0af2bb6..719f957 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -3,4 +3,4 @@ Django>=1.8,<2 # Web application framework mako # Used by xblock-utils.resources, but not declared as a requirement for it XBlock[django] # Courseware component architecture --e git+https://github.com/edx/xblock-utils.git@v1.1.1#egg=xblock-utils==1.1.1 # Utility functions shared by many XBlocks +-e git+https://github.com/edx/xblock-utils.git@v1.2.2#egg=xblock-utils==1.2.2 # Utility functions shared by many XBlocks diff --git a/requirements/dev.in b/requirements/dev.in index 0a4e412..1c0387d 100644 --- a/requirements/dev.in +++ b/requirements/dev.in @@ -3,4 +3,4 @@ diff-cover # Changeset diff test coverage pip-tools # Requirements file management transifex-client # Client for Transifex.com to push and pull translation files --e git://github.com/edx/xblock-sdk.git@v0.1.4#egg=xblock-sdk==v0.1.4 # XBlock SDK to render Django templates properly +-e git+https://github.com/edx/xblock-sdk.git#egg=xblock-sdk # XBlock SDK to render Django templates properly diff --git a/requirements/dev.txt b/requirements/dev.txt index de187bc..6c3960d 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -4,8 +4,8 @@ # # pip-compile --output-file requirements/dev.txt requirements/base.in requirements/dev.in requirements/quality.in requirements/test.in requirements/travis.in # --e git+https://github.com/edx/xblock-sdk.git@v0.1.4#egg=xblock-sdk==0.1.4 --e git+https://github.com/edx/xblock-utils.git@v1.1.1#egg=xblock-utils==1.1.1 +-e git+https://github.com/edx/xblock-sdk.git#egg=xblock-sdk +-e git+https://github.com/edx/xblock-utils.git@v1.2.2#egg=xblock-utils==1.2.2 appdirs==1.4.3 # via fs argparse==1.4.0 # via caniusepython3 asn1crypto==0.24.0 # via cryptography @@ -45,7 +45,7 @@ fs-s3fs==1.0.0 # via django-pyfs fs==2.1.0 # via django-pyfs, fs-s3fs, xblock funcsigs==1.0.2 # via mock, pytest future==0.16.0 # via backports.os -futures==3.2.0 # via caniusepython3, isort, s3transfer +futures==3.2.0; python_version == "2.7" idna==2.7 # via cryptography, requests, urllib3 importlib-metadata==0.5 # via path.py inflect==1.0.1 # via jinja2-pluralize @@ -108,4 +108,4 @@ virtualenv==16.0.0 # via tox web-fragments==0.2.2 # via xblock webob==1.8.2 # via xblock wrapt==1.10.11 # via astroid -xblock[django]==1.2.2 +xblock[django]==1.2.6 diff --git a/requirements/quality.txt b/requirements/quality.txt index 13ac252..ac536b0 100644 --- a/requirements/quality.txt +++ b/requirements/quality.txt @@ -4,8 +4,8 @@ # # pip-compile --output-file requirements/quality.txt requirements/base.in requirements/quality.in requirements/test.in # --e git+https://github.com/edx/xblock-sdk.git@v0.1.4#egg=xblock-sdk==0.1.4 --e git+https://github.com/edx/xblock-utils.git@v1.1.1#egg=xblock-utils==1.1.1 +-e git+https://github.com/edx/xblock-sdk.git#egg=xblock-sdk +-e git+https://github.com/edx/xblock-utils.git@v1.2.2#egg=xblock-utils==1.2.2 appdirs==1.4.3 # via fs argparse==1.4.0 # via caniusepython3 astroid==1.5.2 # via edx-lint, pylint, pylint-celery @@ -37,7 +37,7 @@ fs-s3fs==1.0.0 # via django-pyfs fs==2.1.0 # via django-pyfs, fs-s3fs, xblock funcsigs==1.0.2 # via mock, pytest future==0.16.0 # via backports.os -futures==3.2.0 # via caniusepython3, isort, s3transfer +futures==3.2.0; python_version == "2.7" idna==2.7 # via requests isort==4.3.4 jinja2==2.10 # via cookiecutter @@ -83,4 +83,4 @@ urllib3==1.23 # via botocore, requests, selenium web-fragments==0.2.2 # via xblock webob==1.8.2 # via xblock wrapt==1.10.11 # via astroid -xblock[django]==1.2.2 +xblock[django]==1.2.6 diff --git a/requirements/test.in b/requirements/test.in index 3f9df24..04bcb37 100644 --- a/requirements/test.in +++ b/requirements/test.in @@ -6,4 +6,4 @@ mock pytest pytest-cov pytest-django --e git+https://github.com/edx/xblock-sdk.git@v0.1.4#egg=xblock-sdk==0.1.4 +-e git+https://github.com/edx/xblock-sdk.git#egg=xblock-sdk diff --git a/requirements/test.txt b/requirements/test.txt index 11f692d..1730218 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -4,8 +4,8 @@ # # pip-compile --output-file requirements/test.txt requirements/base.in requirements/test.in # --e git+https://github.com/edx/xblock-sdk.git@v0.1.4#egg=xblock-sdk==0.1.4 --e git+https://github.com/edx/xblock-utils.git@v1.1.1#egg=xblock-utils==1.1.1 +-e git+https://github.com/edx/xblock-sdk.git#egg=xblock-sdk +-e git+https://github.com/edx/xblock-utils.git@v1.2.2#egg=xblock-utils==1.2.2 appdirs==1.4.3 # via fs atomicwrites==1.2.1 # via pytest attrs==18.2.0 # via pytest @@ -27,7 +27,7 @@ fs-s3fs==1.0.0 # via django-pyfs fs==2.1.0 # via django-pyfs, fs-s3fs, xblock funcsigs==1.0.2 # via mock, pytest future==0.16.0 # via backports.os -futures==3.2.0 # via s3transfer +futures==3.2.0; python_version == "2.7" idna==2.7 # via requests jinja2==2.10 # via cookiecutter jmespath==0.9.3 # via boto3, botocore @@ -59,4 +59,4 @@ typing==3.6.6 # via fs urllib3==1.23 # via botocore, requests, selenium web-fragments==0.2.2 # via xblock webob==1.8.2 # via xblock -xblock[django]==1.2.2 +xblock[django]==1.2.6 diff --git a/setup.py b/setup.py index 543c9b2..97e7b96 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,8 @@ """Setup for my_google_drive XBlock.""" +from __future__ import absolute_import import os + from setuptools import setup diff --git a/tox.ini b/tox.ini index 997acd8..28ab28a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27-django{18,19,110,111} +envlist = py{27,35}-django111 [pycodestyle] exclude = .git,.tox @@ -18,13 +18,10 @@ whitelist_externals = mkdir rm deps = - django18: Django>=1.8,<1.9 - django19: Django>=1.9,<1.10 - django110: Django>=1.10,<1.11 django111: Django>=1.11,<2 -r{toxinidir}/requirements/test.txt passenv = - DISPLAY + BOKCHOY_HEADLESS setenv = SCREENSHOT_DIR={toxinidir}/var/logs SELENIUM_DRIVER_LOG_DIR={toxinidir}/var/logs From 0d214938dff4935079bc653a065e0af0f2e5667a Mon Sep 17 00:00:00 2001 From: Waheed Ahmed Date: Thu, 3 Oct 2019 15:08:39 +0500 Subject: [PATCH 2/2] Tests fixed. Image url used to test Image rendering was returing 404 (Gone) --- google_drive/tests/integration/xml/image.xml | 2 +- google_drive/tests/test_const.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/google_drive/tests/integration/xml/image.xml b/google_drive/tests/integration/xml/image.xml index 54b5652..ca8478d 100644 --- a/google_drive/tests/integration/xml/image.xml +++ b/google_drive/tests/integration/xml/image.xml @@ -1 +1 @@ - + diff --git a/google_drive/tests/test_const.py b/google_drive/tests/test_const.py index 9f6bedf..c7b9554 100644 --- a/google_drive/tests/test_const.py +++ b/google_drive/tests/test_const.py @@ -15,4 +15,5 @@ STATUS_CODE_400 = {'status_code': 400} STATUS_CODE_404 = {'status_code': 404} -TEST_IMAGE_URL = 'https://docs.google.com/drawings/d/1C1hw4pLKLDAhGDD4Etd20Y1BpFeGy0rTlMfoczNZXx4/edit?usp=sharing' +TEST_IMAGE_URL = 'https://docs.google.com/drawings/d/e/2PACX-1vR5IEdW9QtEDQG8Kr0ZyigIVJNE8PTpet3H1AcLH0LsCBIVlN' \ + '-onsTnmP5cfD44cwzrAS3jacvPP6q6/pub?w=960&h=720'