├── LICENSE ├── README.md ├── app.yaml ├── billing_export.css ├── bootflat.css ├── chart.js ├── cloudstorage ├── __init__.py ├── api_utils.py ├── cloudstorage_api.py ├── common.py ├── errors.py ├── rest_api.py ├── storage_api.py └── test_utils.py ├── config.py.template ├── gviz_api.py ├── httplib2 ├── .svn │ ├── all-wcprops │ ├── entries │ └── text-base │ │ ├── __init__.py.svn-base │ │ ├── cacerts.txt.svn-base │ │ ├── iri2uri.py.svn-base │ │ └── socks.py.svn-base ├── __init__.py ├── cacerts.txt ├── iri2uri.py └── socks.py ├── index.html ├── loader.gif ├── main.py ├── oauth2client ├── .svn │ ├── all-wcprops │ ├── entries │ └── text-base │ │ ├── __init__.py.svn-base │ │ ├── anyjson.py.svn-base │ │ ├── appengine.py.svn-base │ │ ├── client.py.svn-base │ │ ├── clientsecrets.py.svn-base │ │ ├── crypt.py.svn-base │ │ ├── django_orm.py.svn-base │ │ ├── file.py.svn-base │ │ ├── gce.py.svn-base │ │ ├── keyring_storage.py.svn-base │ │ ├── locked_file.py.svn-base │ │ ├── multistore_file.py.svn-base │ │ ├── old_run.py.svn-base │ │ ├── tools.py.svn-base │ │ ├── util.py.svn-base │ │ └── xsrfutil.py.svn-base ├── __init__.py ├── anyjson.py ├── appengine.py ├── client.py ├── clientsecrets.py ├── crypt.py ├── django_orm.py ├── file.py ├── gce.py ├── keyring_storage.py ├── locked_file.py ├── multistore_file.py ├── old_run.py ├── tools.py ├── util.py └── xsrfutil.py ├── project_email.html └── test ├── __init__.py ├── data ├── exports │ ├── analytics-bigquery-demo-2014-01-06.json │ ├── analytics-bigquery-demo-2014-01-07.json │ ├── analytics-bigquery-demo-2014-01-08.json │ ├── analytics-bigquery-demo-2014-01-09.json │ ├── analytics-bigquery-demo-2014-01-10.json │ ├── analytics-bigquery-demo-2014-01-11.json │ ├── analytics-bigquery-demo-2014-01-12.json │ ├── analytics-bigquery-demo-2014-01-13.json │ ├── analytics-bigquery-demo-2014-01-14.json │ ├── analytics-bigquery-demo-2014-01-15.json │ ├── analytics-bigquery-demo-2014-01-16.json │ ├── analytics-bigquery-demo-2014-01-17.json │ ├── analytics-bigquery-demo-2014-01-18.json │ ├── analytics-bigquery-demo-2014-01-19.json │ ├── analytics-bigquery-demo-2014-01-20.json │ ├── analytics-bigquery-demo-2014-01-21.json │ ├── analytics-bigquery-demo-2014-01-22.json │ ├── analytics-bigquery-demo-2014-01-23.json │ ├── analytics-bigquery-demo-2014-01-24.json │ ├── analytics-bigquery-demo-2014-01-25.json │ ├── analytics-bigquery-demo-2014-01-26.json │ ├── analytics-bigquery-demo-2014-01-27.json │ ├── analytics-bigquery-demo-2014-01-28.json │ ├── analytics-bigquery-demo-2014-01-29.json │ ├── analytics-bigquery-demo-2014-01-30.json │ ├── analytics-bigquery-demo-2014-01-31.json │ ├── analytics-bigquery-demo-2014-02-01.json │ ├── analytics-bigquery-demo-2014-02-02.json │ ├── analytics-bigquery-demo-2014-02-03.json │ ├── analytics-bigquery-demo-2014-02-04.json │ ├── analytics-bigquery-demo-2014-02-05.json │ ├── analytics-bigquery-demo-2014-02-06.json │ ├── analytics-bigquery-demo-2014-02-07.json │ ├── analytics-bigquery-demo-2014-02-08.json │ ├── analytics-bigquery-demo-2014-02-09.json │ ├── analytics-bigquery-demo-2014-02-10.json │ ├── analytics-bigquery-demo-2014-02-11.json │ ├── analytics-bigquery-demo-2014-02-12.json │ ├── analytics-bigquery-demo-2014-02-13.json │ ├── analytics-bigquery-demo-2014-02-14.json │ ├── analytics-bigquery-demo-2014-02-15.json │ ├── analytics-bigquery-demo-2014-02-16.json │ ├── analytics-bigquery-demo-2014-02-17.json │ ├── analytics-bigquery-demo-2014-02-18.json │ ├── analytics-bigquery-demo-2014-02-19.json │ ├── analytics-bigquery-demo-2014-02-20.json │ ├── analytics-bigquery-demo-2014-02-21.json │ ├── analytics-bigquery-demo-2014-02-22.json │ ├── analytics-bigquery-demo-2014-02-23.json │ ├── google-platform-demo-2013-12-30.json │ ├── google-platform-demo-2013-12-31.json │ ├── google-platform-demo-2014-01-01.json │ ├── google-platform-demo-2014-01-02.json │ ├── google-platform-demo-2014-01-03.json │ ├── google-platform-demo-2014-01-04.json │ ├── google-platform-demo-2014-01-05.json │ ├── google-platform-demo-2014-01-06.json │ ├── google-platform-demo-2014-01-07.json │ ├── google-platform-demo-2014-01-08.json │ ├── google-platform-demo-2014-01-09.json │ ├── google-platform-demo-2014-01-10.json │ ├── google-platform-demo-2014-01-11.json │ ├── google-platform-demo-2014-01-12.json │ ├── google-platform-demo-2014-01-13.json │ ├── google-platform-demo-2014-01-14.json │ ├── google-platform-demo-2014-01-15.json │ ├── google-platform-demo-2014-01-16.json │ ├── google-platform-demo-2014-01-17.json │ ├── google-platform-demo-2014-01-18.json │ ├── google-platform-demo-2014-01-19.json │ ├── google-platform-demo-2014-01-20.json │ ├── google-platform-demo-2014-01-21.json │ ├── google-platform-demo-2014-01-22.json │ ├── google-platform-demo-2014-01-23.json │ ├── google-platform-demo-2014-01-24.json │ ├── google-platform-demo-2014-01-25.json │ ├── google-platform-demo-2014-01-26.json │ ├── google-platform-demo-2014-01-27.json │ ├── google-platform-demo-2014-01-28.json │ ├── google-platform-demo-2014-01-29.json │ ├── google-platform-demo-2014-01-30.json │ ├── google-platform-demo-2014-01-31.json │ ├── google-platform-demo-2014-02-01.json │ ├── google-platform-demo-2014-02-02.json │ ├── google-platform-demo-2014-02-03.json │ ├── google-platform-demo-2014-02-04.json │ ├── google-platform-demo-2014-02-05.json │ ├── google-platform-demo-2014-02-06.json │ ├── google-platform-demo-2014-02-07.json │ ├── google-platform-demo-2014-02-08.json │ ├── google-platform-demo-2014-02-09.json │ ├── google-platform-demo-2014-02-10.json │ ├── google-platform-demo-2014-02-11.json │ ├── google-platform-demo-2014-02-12.json │ ├── google-platform-demo-2014-02-13.json │ ├── google-platform-demo-2014-02-14.json │ ├── google-platform-demo-2014-02-15.json │ ├── google-platform-demo-2014-02-16.json │ ├── google-platform-demo-2014-02-17.json │ ├── google-platform-demo-2014-02-18.json │ ├── google-platform-demo-2014-02-19.json │ ├── google-platform-demo-2014-02-20.json │ ├── google-platform-demo-2014-02-21.json │ ├── google-platform-demo-2014-02-22.json │ └── google-platform-demo-2014-02-23.json └── notifications │ ├── google-platform-demo-2014-02-04.json │ └── google-platform-demo-2014-02-23.json ├── run_server_tests.py └── test.py /README.md: -------------------------------------------------------------------------------- 1 | ![status: inactive](https://img.shields.io/badge/status-inactive-red.svg) 2 | 3 | This project is no longer actively developed or maintained. 4 | 5 | For more information about App Engine, refer to our [documentation](https://cloud.google.com/appengine). 6 | 7 | # billing-export-python 8 | 9 | View Google Cloud Platform billing export files via an App Engine dashboard. 10 | 11 | Demonstrates parsing billing export files stored in a cloud storage bucket and rendering a Google Chart, triggering alerts and sending summary email. 12 | 13 | The dashboard presents a graph of the last 90 days of billing data sent by the billing export feature. A complete walkthrough of the application, and enabling billing export, is available on YouTube. 14 | 15 | 16 | 17 | ![Screenshot](https://storage.googleapis.com/platform-demo-billing-export-backup/Selection_142.png "Screenshot") 18 | 19 | 20 | 21 | ## Setup Instructions 22 | 23 | * *Setup Billing Export*. - Create a Cloud Storage bucket, and navigate to "Billing → Project → Billing Export". Enter the bucket name, a useful prefix, and select 'JSON' as the format. 24 | 25 | * *Copy config.py.template to config.py* - Enter values for the bucket to monitor, and a default email address to use when no email address exists. 26 | 27 | * *Edit app.yaml* - Supply a valid App Engine application id with access to the created bucket. 28 | 29 | * *Setup Object Change Notifications* - Configure the URL https://billing-export-dot-{appid}.appspot.com/objectChangeNofication as the object change notification URL of the bucket. Steps are described here. Please not the necessity of *using a service account with gsutil* to run the "gsutil notification" command, a personal account won't work. 30 | 31 | > gsutil notification watchbucket https://billing-export-dot-{appid}.appspot.com/objectChangeNofication gs://{bucketname>} 32 | 33 | 34 | ## Usage Tips 35 | 36 | * Clicking the "Flush all caches" button takes time if there are a large number of objects in the bucket. It should never be needed if object change notifications are working. 37 | 38 | * Select a date in the line chart by clicking a column in the body of the chart. 39 | 40 | * The TreeMap chart at the top of the file presents the charge breakdown for the selected date. 41 | 42 | * Select a product or SKU from the treemap to show charges for just the selected product or SKU in the line chart. 43 | 44 | * Right-click the treemap to go back up. 45 | 46 | * Show or hide lines in the line chart by selecting a series in the chart legend. 47 | 48 | 49 | ## Dependencies 50 | 51 | This application makes use of 52 | 53 | - *httplib2* - http://code.google.com/p/httplib2/ 54 | - *oauth2client* - http://pypi.python.org/pypi/oauth2client/1.0 55 | - *cloudstorage* - https://code.google.com/p/appengine-gcs-client/ 56 | - *gviz_api* - https://code.google.com/p/google-visualization-python/ 57 | - *google charts* - https://developers.google.com/chart/ 58 | - *bootstrap* - http://getbootstrap.com/ 59 | - *bootflat* - http://bootflat.github.io/ 60 | - *angularjs* - http://angularjs.org/ 61 | -------------------------------------------------------------------------------- /app.yaml: -------------------------------------------------------------------------------- 1 | application: 2 | module: billing-export 3 | version: 1 4 | runtime: python27 5 | api_version: 1 6 | threadsafe: true 7 | 8 | handlers: 9 | - url: /favicon\.ico 10 | static_files: favicon.ico 11 | upload: favicon\.ico 12 | - url: /loader.gif 13 | static_files: loader.gif 14 | upload: loader.gif 15 | - url: /index.html 16 | static_files: index.html 17 | upload: index.html 18 | login: admin 19 | - url: / 20 | static_files: index.html 21 | upload: index.html 22 | login: admin 23 | - url: /chart.js 24 | static_files: chart.js 25 | upload: chart.js 26 | - url: /billing_export.css 27 | static_files: billing_export.css 28 | upload: billing_export.css 29 | - url: /bootflat.css 30 | static_files: bootflat.css 31 | upload: bootflat.css 32 | - url: /objectChangeNofication 33 | script: main.app 34 | - url: /.* 35 | login: admin 36 | script: main.app 37 | 38 | libraries: 39 | - name: pycrypto 40 | version: "latest" 41 | - name: jinja2 42 | version: "latest" 43 | 44 | builtins: 45 | - remote_api: on 46 | - deferred: on 47 | -------------------------------------------------------------------------------- /billing_export.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | body { 17 | font-family: 'Arvo', serif; 18 | font-size: 14px; 19 | } 20 | 21 | main { 22 | padding-top: 60px; 23 | } 24 | 25 | .container { 26 | width: 80%; 27 | } 28 | 29 | .well { 30 | background-color: #fff; 31 | padding-top: 20px; 32 | } 33 | 34 | .nav { 35 | font-size: 14px; 36 | } 37 | 38 | h1 { 39 | font-size: 48px; 40 | margin-top: 0px; 41 | } 42 | 43 | .navbar-inverse { 44 | background-color: #f1f1f1; 45 | border-color: #f1f1f1; 46 | } 47 | 48 | .navbar-inverse .navbar-nav>li>a { 49 | color: #404040; 50 | } 51 | 52 | .navbar-inverse .navbar-nav>li>a:hover { 53 | color: #000; 54 | } 55 | 56 | #alert-actions { 57 | padding-top: 10px; 58 | padding-bottom: 20px; 59 | } 60 | 61 | .control-label { 62 | text-align:left; 63 | width: 60px; 64 | } 65 | 66 | .form { 67 | padding-top: 20px; 68 | padding-bottom: 10px; 69 | } 70 | 71 | .form-btn-offset { 72 | padding-left: 5px; 73 | } 74 | 75 | .btn-primary { 76 | background-color: #d14836; 77 | border-color: #d14836; 78 | background-image: -webkit-linear-gradient(top,#dd4b39,#d14836); 79 | background-image: linear-gradient(top,#dd4b39,#d14836); 80 | color: #fff; 81 | } 82 | 83 | .btn-primary:hover, .btn-primary:focus, .btn-primary:active, .btn-primary.active, .open .dropdown-toggle.btn-primary { 84 | color: #fff; 85 | background-color: #d14836; 86 | border-color: #d14836; 87 | background-image: none; 88 | } 89 | 90 | .loading-container { 91 | position:absolute; 92 | top:0; 93 | left:0; 94 | width:100%; 95 | height:100%; 96 | z-index:1000; 97 | background-color:#fff; 98 | opacity: .8; 99 | } 100 | 101 | .loading { 102 | position: absolute; 103 | left: 50%; 104 | top: 50%; 105 | margin-left: -32px; 106 | margin-top: -32px; 107 | display: block; 108 | } 109 | 110 | .well { 111 | background-color: white; 112 | } 113 | 114 | .unsubscribe-true { 115 | text-decoration: line-through; 116 | color: #fff; 117 | } -------------------------------------------------------------------------------- /cloudstorage/__init__.py: -------------------------------------------------------------------------------- 1 | """Client Library for Google Cloud Storage.""" 2 | 3 | 4 | 5 | 6 | from .api_utils import RetryParams 7 | from .api_utils import set_default_retry_params 8 | from cloudstorage_api import * 9 | from .common import CSFileStat 10 | from .common import GCSFileStat 11 | from .common import validate_bucket_name 12 | from .common import validate_bucket_path 13 | from .common import validate_file_path 14 | from errors import * 15 | from storage_api import * 16 | -------------------------------------------------------------------------------- /cloudstorage/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Google Inc. All Rights Reserved. 2 | 3 | """Google Cloud Storage specific Files API calls.""" 4 | 5 | 6 | 7 | 8 | 9 | __all__ = ['AuthorizationError', 10 | 'check_status', 11 | 'Error', 12 | 'FatalError', 13 | 'ForbiddenError', 14 | 'NotFoundError', 15 | 'ServerError', 16 | 'TimeoutError', 17 | 'TransientError', 18 | ] 19 | 20 | import httplib 21 | 22 | 23 | class Error(Exception): 24 | """Base error for all gcs operations. 25 | 26 | Error can happen on GAE side or GCS server side. 27 | For details on a particular GCS HTTP response code, see 28 | https://developers.google.com/storage/docs/reference-status#standardcodes 29 | """ 30 | 31 | 32 | class TransientError(Error): 33 | """TransientError could be retried.""" 34 | 35 | 36 | class TimeoutError(TransientError): 37 | """HTTP 408 timeout.""" 38 | 39 | 40 | class FatalError(Error): 41 | """FatalError shouldn't be retried.""" 42 | 43 | 44 | class NotFoundError(FatalError): 45 | """HTTP 404 resource not found.""" 46 | 47 | 48 | class ForbiddenError(FatalError): 49 | """HTTP 403 Forbidden. 50 | 51 | While GCS replies with a 403 error for many reasons, the most common one 52 | is due to bucket permission not correctly setup for your app to access. 53 | """ 54 | 55 | 56 | class AuthorizationError(FatalError): 57 | """HTTP 401 authentication required. 58 | 59 | Unauthorized request has been received by GCS. 60 | 61 | This error is mostly handled by GCS client. GCS client will request 62 | a new access token and retry the request. 63 | """ 64 | 65 | 66 | class InvalidRange(FatalError): 67 | """HTTP 416 RequestRangeNotSatifiable.""" 68 | 69 | 70 | class ServerError(TransientError): 71 | """HTTP >= 500 server side error.""" 72 | 73 | 74 | def check_status(status, expected, path, headers=None, 75 | resp_headers=None, extras=None): 76 | """Check HTTP response status is expected. 77 | 78 | Args: 79 | status: HTTP response status. int. 80 | expected: a list of expected statuses. A list of ints. 81 | path: filename or a path prefix. 82 | headers: HTTP request headers. 83 | resp_headers: HTTP response headers. 84 | extras: extra info to be logged verbatim if error occurs. 85 | 86 | Raises: 87 | AuthorizationError: if authorization failed. 88 | NotFoundError: if an object that's expected to exist doesn't. 89 | TimeoutError: if HTTP request timed out. 90 | ServerError: if server experienced some errors. 91 | FatalError: if any other unexpected errors occurred. 92 | """ 93 | if status in expected: 94 | return 95 | 96 | msg = ('Expect status %r from Google Storage. But got status %d.\n' 97 | 'Path: %r.\n' 98 | 'Request headers: %r.\n' 99 | 'Response headers: %r.\n' 100 | 'Extra info: %r.\n' % 101 | (expected, status, path, headers, resp_headers, extras)) 102 | 103 | if status == httplib.UNAUTHORIZED: 104 | raise AuthorizationError(msg) 105 | elif status == httplib.FORBIDDEN: 106 | raise ForbiddenError(msg) 107 | elif status == httplib.NOT_FOUND: 108 | raise NotFoundError(msg) 109 | elif status == httplib.REQUEST_TIMEOUT: 110 | raise TimeoutError(msg) 111 | elif status == httplib.REQUESTED_RANGE_NOT_SATISFIABLE: 112 | raise InvalidRange(msg) 113 | elif status >= 500: 114 | raise ServerError(msg) 115 | else: 116 | raise FatalError(msg) 117 | -------------------------------------------------------------------------------- /cloudstorage/rest_api.py: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Google Inc. All Rights Reserved. 2 | 3 | """Base and helper classes for Google RESTful APIs.""" 4 | 5 | 6 | 7 | 8 | 9 | __all__ = ['add_sync_methods'] 10 | 11 | import httplib 12 | import time 13 | 14 | from . import api_utils 15 | 16 | try: 17 | from google.appengine.api import app_identity 18 | from google.appengine.ext import ndb 19 | except ImportError: 20 | from google.appengine.api import app_identity 21 | from google.appengine.ext import ndb 22 | 23 | 24 | def _make_sync_method(name): 25 | """Helper to synthesize a synchronous method from an async method name. 26 | 27 | Used by the @add_sync_methods class decorator below. 28 | 29 | Args: 30 | name: The name of the synchronous method. 31 | 32 | Returns: 33 | A method (with first argument 'self') that retrieves and calls 34 | self., passing its own arguments, expects it to return a 35 | Future, and then waits for and returns that Future's result. 36 | """ 37 | 38 | def sync_wrapper(self, *args, **kwds): 39 | method = getattr(self, name) 40 | future = method(*args, **kwds) 41 | return future.get_result() 42 | 43 | return sync_wrapper 44 | 45 | 46 | def add_sync_methods(cls): 47 | """Class decorator to add synchronous methods corresponding to async methods. 48 | 49 | This modifies the class in place, adding additional methods to it. 50 | If a synchronous method of a given name already exists it is not 51 | replaced. 52 | 53 | Args: 54 | cls: A class. 55 | 56 | Returns: 57 | The same class, modified in place. 58 | """ 59 | for name in cls.__dict__.keys(): 60 | if name.endswith('_async'): 61 | sync_name = name[:-6] 62 | if not hasattr(cls, sync_name): 63 | setattr(cls, sync_name, _make_sync_method(name)) 64 | return cls 65 | 66 | 67 | class _AE_TokenStorage_(ndb.Model): 68 | """Entity to store app_identity tokens in memcache.""" 69 | 70 | token = ndb.StringProperty() 71 | expires = ndb.FloatProperty() 72 | 73 | 74 | @ndb.tasklet 75 | def _make_token_async(scopes, service_account_id): 76 | """Get a fresh authentication token. 77 | 78 | Args: 79 | scopes: A list of scopes. 80 | service_account_id: Internal-use only. 81 | 82 | Returns: 83 | An tuple (token, expiration_time) where expiration_time is 84 | seconds since the epoch. 85 | """ 86 | rpc = app_identity.create_rpc() 87 | app_identity.make_get_access_token_call(rpc, scopes, service_account_id) 88 | token, expires_at = yield rpc 89 | raise ndb.Return((token, expires_at)) 90 | 91 | 92 | class _RestApi(object): 93 | """Base class for REST-based API wrapper classes. 94 | 95 | This class manages authentication tokens and request retries. All 96 | APIs are available as synchronous and async methods; synchronous 97 | methods are synthesized from async ones by the add_sync_methods() 98 | function in this module. 99 | 100 | WARNING: Do NOT directly use this api. It's an implementation detail 101 | and is subject to change at any release. 102 | """ 103 | 104 | def __init__(self, scopes, service_account_id=None, token_maker=None, 105 | retry_params=None): 106 | """Constructor. 107 | 108 | Args: 109 | scopes: A scope or a list of scopes. 110 | token_maker: An asynchronous function of the form 111 | (scopes, service_account_id) -> (token, expires). 112 | retry_params: An instance of api_utils.RetryParams. If None, the 113 | default for current thread will be used. 114 | service_account_id: Internal use only. 115 | """ 116 | 117 | if isinstance(scopes, basestring): 118 | scopes = [scopes] 119 | self.scopes = scopes 120 | self.service_account_id = service_account_id 121 | self.make_token_async = token_maker or _make_token_async 122 | self.token = None 123 | if not retry_params: 124 | retry_params = api_utils._get_default_retry_params() 125 | self.retry_params = retry_params 126 | 127 | def __getstate__(self): 128 | """Store state as part of serialization/pickling.""" 129 | return {'token': self.token, 130 | 'scopes': self.scopes, 131 | 'id': self.service_account_id, 132 | 'a_maker': None if self.make_token_async == _make_token_async 133 | else self.make_token_async, 134 | 'retry_params': self.retry_params} 135 | 136 | def __setstate__(self, state): 137 | """Restore state as part of deserialization/unpickling.""" 138 | self.__init__(state['scopes'], 139 | service_account_id=state['id'], 140 | token_maker=state['a_maker'], 141 | retry_params=state['retry_params']) 142 | self.token = state['token'] 143 | 144 | @ndb.tasklet 145 | def do_request_async(self, url, method='GET', headers=None, payload=None, 146 | deadline=None, callback=None): 147 | """Issue one HTTP request. 148 | 149 | This is an async wrapper around urlfetch(). It adds an authentication 150 | header and retries on a 401 status code. Upon other retriable errors, 151 | it performs blocking retries. 152 | """ 153 | headers = {} if headers is None else dict(headers) 154 | if self.token is None: 155 | self.token = yield self.get_token_async() 156 | headers['authorization'] = 'OAuth ' + self.token 157 | 158 | deadline = deadline or self.retry_params.urlfetch_timeout 159 | 160 | retry = False 161 | resp = None 162 | try: 163 | resp = yield self.urlfetch_async(url, payload=payload, method=method, 164 | headers=headers, follow_redirects=False, 165 | deadline=deadline, callback=callback) 166 | if resp.status_code == httplib.UNAUTHORIZED: 167 | self.token = yield self.get_token_async(refresh=True) 168 | headers['authorization'] = 'OAuth ' + self.token 169 | resp = yield self.urlfetch_async( 170 | url, payload=payload, method=method, headers=headers, 171 | follow_redirects=False, deadline=deadline, callback=callback) 172 | except api_utils._RETRIABLE_EXCEPTIONS: 173 | retry = True 174 | else: 175 | retry = api_utils._should_retry(resp) 176 | 177 | if retry: 178 | retry_resp = api_utils._retry_fetch( 179 | url, retry_params=self.retry_params, payload=payload, method=method, 180 | headers=headers, follow_redirects=False, deadline=deadline) 181 | if retry_resp: 182 | resp = retry_resp 183 | elif not resp: 184 | raise 185 | 186 | raise ndb.Return((resp.status_code, resp.headers, resp.content)) 187 | 188 | @ndb.tasklet 189 | def get_token_async(self, refresh=False): 190 | """Get an authentication token. 191 | 192 | The token is cached in memcache, keyed by the scopes argument. 193 | 194 | Args: 195 | refresh: If True, ignore a cached token; default False. 196 | 197 | Returns: 198 | An authentication token. 199 | """ 200 | if self.token is not None and not refresh: 201 | raise ndb.Return(self.token) 202 | key = '%s,%s' % (self.service_account_id, ','.join(self.scopes)) 203 | ts = None 204 | if not refresh: 205 | ts = yield _AE_TokenStorage_.get_by_id_async( 206 | key, use_cache=True, use_memcache=True, 207 | use_datastore=self.retry_params.save_access_token) 208 | if ts is None or ts.expires < (time.time() + 60): 209 | token, expires_at = yield self.make_token_async( 210 | self.scopes, self.service_account_id) 211 | timeout = int(expires_at - time.time()) 212 | ts = _AE_TokenStorage_(id=key, token=token, expires=expires_at) 213 | if timeout > 0: 214 | yield ts.put_async(memcache_timeout=timeout, 215 | use_datastore=self.retry_params.save_access_token, 216 | use_cache=True, use_memcache=True) 217 | self.token = ts.token 218 | raise ndb.Return(self.token) 219 | 220 | def urlfetch_async(self, url, **kwds): 221 | """Make an async urlfetch() call. 222 | 223 | This just passes the url and keyword arguments to NDB's async 224 | urlfetch() wrapper in the current context. 225 | 226 | This returns a Future despite not being decorated with @ndb.tasklet! 227 | """ 228 | ctx = ndb.get_context() 229 | return ctx.urlfetch(url, **kwds) 230 | 231 | 232 | _RestApi = add_sync_methods(_RestApi) 233 | -------------------------------------------------------------------------------- /cloudstorage/test_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 Google Inc. All Rights Reserved. 2 | 3 | """Utils for testing.""" 4 | 5 | 6 | class MockUrlFetchResult(object): 7 | 8 | def __init__(self, status, headers, body): 9 | self.status_code = status 10 | self.headers = headers 11 | self.content = body 12 | self.content_was_truncated = False 13 | self.final_url = None 14 | -------------------------------------------------------------------------------- /config.py.template: -------------------------------------------------------------------------------- 1 | """Configuration file. 2 | 3 | Copy to config.py after filling in values. 4 | """ 5 | 6 | # runtime configurations 7 | bucket = 8 | default_to_email = 9 | 10 | 11 | # ** OPTIONAL** 12 | # 13 | # Enable dev_appserver.py to use remote GCS bucket 14 | # 15 | # For testing purposes it's can be useful to speak to a remote GCS bucket. If 16 | # this use_remote_gcs_when_local is set to true, additional configurations are 17 | # required when running local dev_servers. 18 | # 19 | use_remote_gcs_when_local = False 20 | # 21 | # To connect to remote GCS rather then remote, create a service account, 22 | # 23 | # similar to abc123abc123@developer.gserviceaccount.com 24 | service_account = '' 25 | # 26 | # downloading the private key and changing config.py to reference the private 27 | # key. It's necessary to change .p12 file into a pem file with the command: 28 | # 29 | # > openssl pkcs12 -in abc123abc123-privatekey.p12 -nodes -nocerts | openssl rsa > abc123abc123-privatekey.pem 30 | # 31 | # The password to the key file is "notasecret". 32 | # private key file in local filesystem like 'ABC123-privatekey.pem' 33 | private_key_pem_file = '' 34 | -------------------------------------------------------------------------------- /httplib2/.svn/all-wcprops: -------------------------------------------------------------------------------- 1 | K 25 2 | svn:wc:ra_dav:version-url 3 | V 57 4 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/httplib2 5 | END 6 | cacerts.txt 7 | K 25 8 | svn:wc:ra_dav:version-url 9 | V 69 10 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/httplib2/cacerts.txt 11 | END 12 | __init__.py 13 | K 25 14 | svn:wc:ra_dav:version-url 15 | V 69 16 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/httplib2/__init__.py 17 | END 18 | socks.py 19 | K 25 20 | svn:wc:ra_dav:version-url 21 | V 66 22 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/httplib2/socks.py 23 | END 24 | iri2uri.py 25 | K 25 26 | svn:wc:ra_dav:version-url 27 | V 68 28 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/httplib2/iri2uri.py 29 | END 30 | -------------------------------------------------------------------------------- /httplib2/.svn/entries: -------------------------------------------------------------------------------- 1 | 10 2 | 3 | dir 4 | 12 5 | https://svn.codespot.com/a/google.com/gcs-file-uploader/trunk/httplib2 6 | https://svn.codespot.com/a/google.com/gcs-file-uploader 7 | 8 | 9 | 10 | 2013-11-11T21:00:17.576267Z 11 | 2 12 | bmenasha@google.com 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 64dbcbab-f634-aa3b-7583-e74f06a72553 28 | 29 | __init__.py 30 | file 31 | 32 | 33 | 34 | 35 | 2013-11-19T23:25:39.882312Z 36 | 28c4c18495bb25aa88c90a1f2e70f5c5 37 | 2013-11-11T21:00:17.576267Z 38 | 2 39 | bmenasha@google.com 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 69621 62 | 63 | socks.py 64 | file 65 | 66 | 67 | 68 | 69 | 2013-11-19T23:25:39.882312Z 70 | 331e87ccd3d0cc6ed3033900bf4529f2 71 | 2013-11-11T21:00:17.576267Z 72 | 2 73 | bmenasha@google.com 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 18459 96 | 97 | iri2uri.py 98 | file 99 | 100 | 101 | 102 | 103 | 2013-11-19T23:25:39.886312Z 104 | 7acc8b5dcc069a0f3f17725c9d4f19f2 105 | 2013-11-11T21:00:17.576267Z 106 | 2 107 | bmenasha@google.com 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 3828 130 | 131 | cacerts.txt 132 | file 133 | 134 | 135 | 136 | 137 | 2013-11-19T23:25:39.882312Z 138 | 3cb831b2a04dc411d415ff26b2a66ee0 139 | 2013-11-11T21:00:17.576267Z 140 | 2 141 | bmenasha@google.com 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 39670 164 | 165 | -------------------------------------------------------------------------------- /httplib2/.svn/text-base/iri2uri.py.svn-base: -------------------------------------------------------------------------------- 1 | """ 2 | iri2uri 3 | 4 | Converts an IRI to a URI. 5 | 6 | """ 7 | __author__ = "Joe Gregorio (joe@bitworking.org)" 8 | __copyright__ = "Copyright 2006, Joe Gregorio" 9 | __contributors__ = [] 10 | __version__ = "1.0.0" 11 | __license__ = "MIT" 12 | __history__ = """ 13 | """ 14 | 15 | import urlparse 16 | 17 | 18 | # Convert an IRI to a URI following the rules in RFC 3987 19 | # 20 | # The characters we need to enocde and escape are defined in the spec: 21 | # 22 | # iprivate = %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD 23 | # ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF 24 | # / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD 25 | # / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD 26 | # / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD 27 | # / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD 28 | # / %xD0000-DFFFD / %xE1000-EFFFD 29 | 30 | escape_range = [ 31 | (0xA0, 0xD7FF), 32 | (0xE000, 0xF8FF), 33 | (0xF900, 0xFDCF), 34 | (0xFDF0, 0xFFEF), 35 | (0x10000, 0x1FFFD), 36 | (0x20000, 0x2FFFD), 37 | (0x30000, 0x3FFFD), 38 | (0x40000, 0x4FFFD), 39 | (0x50000, 0x5FFFD), 40 | (0x60000, 0x6FFFD), 41 | (0x70000, 0x7FFFD), 42 | (0x80000, 0x8FFFD), 43 | (0x90000, 0x9FFFD), 44 | (0xA0000, 0xAFFFD), 45 | (0xB0000, 0xBFFFD), 46 | (0xC0000, 0xCFFFD), 47 | (0xD0000, 0xDFFFD), 48 | (0xE1000, 0xEFFFD), 49 | (0xF0000, 0xFFFFD), 50 | (0x100000, 0x10FFFD), 51 | ] 52 | 53 | def encode(c): 54 | retval = c 55 | i = ord(c) 56 | for low, high in escape_range: 57 | if i < low: 58 | break 59 | if i >= low and i <= high: 60 | retval = "".join(["%%%2X" % ord(o) for o in c.encode('utf-8')]) 61 | break 62 | return retval 63 | 64 | 65 | def iri2uri(uri): 66 | """Convert an IRI to a URI. Note that IRIs must be 67 | passed in a unicode strings. That is, do not utf-8 encode 68 | the IRI before passing it into the function.""" 69 | if isinstance(uri ,unicode): 70 | (scheme, authority, path, query, fragment) = urlparse.urlsplit(uri) 71 | authority = authority.encode('idna') 72 | # For each character in 'ucschar' or 'iprivate' 73 | # 1. encode as utf-8 74 | # 2. then %-encode each octet of that utf-8 75 | uri = urlparse.urlunsplit((scheme, authority, path, query, fragment)) 76 | uri = "".join([encode(c) for c in uri]) 77 | return uri 78 | 79 | if __name__ == "__main__": 80 | import unittest 81 | 82 | class Test(unittest.TestCase): 83 | 84 | def test_uris(self): 85 | """Test that URIs are invariant under the transformation.""" 86 | invariant = [ 87 | u"ftp://ftp.is.co.za/rfc/rfc1808.txt", 88 | u"http://www.ietf.org/rfc/rfc2396.txt", 89 | u"ldap://[2001:db8::7]/c=GB?objectClass?one", 90 | u"mailto:John.Doe@example.com", 91 | u"news:comp.infosystems.www.servers.unix", 92 | u"tel:+1-816-555-1212", 93 | u"telnet://192.0.2.16:80/", 94 | u"urn:oasis:names:specification:docbook:dtd:xml:4.1.2" ] 95 | for uri in invariant: 96 | self.assertEqual(uri, iri2uri(uri)) 97 | 98 | def test_iri(self): 99 | """ Test that the right type of escaping is done for each part of the URI.""" 100 | self.assertEqual("http://xn--o3h.com/%E2%98%84", iri2uri(u"http://\N{COMET}.com/\N{COMET}")) 101 | self.assertEqual("http://bitworking.org/?fred=%E2%98%84", iri2uri(u"http://bitworking.org/?fred=\N{COMET}")) 102 | self.assertEqual("http://bitworking.org/#%E2%98%84", iri2uri(u"http://bitworking.org/#\N{COMET}")) 103 | self.assertEqual("#%E2%98%84", iri2uri(u"#\N{COMET}")) 104 | self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}")) 105 | self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}"))) 106 | self.assertNotEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}".encode('utf-8'))) 107 | 108 | unittest.main() 109 | 110 | 111 | -------------------------------------------------------------------------------- /httplib2/iri2uri.py: -------------------------------------------------------------------------------- 1 | """ 2 | iri2uri 3 | 4 | Converts an IRI to a URI. 5 | 6 | """ 7 | __author__ = "Joe Gregorio (joe@bitworking.org)" 8 | __copyright__ = "Copyright 2006, Joe Gregorio" 9 | __contributors__ = [] 10 | __version__ = "1.0.0" 11 | __license__ = "MIT" 12 | __history__ = """ 13 | """ 14 | 15 | import urlparse 16 | 17 | 18 | # Convert an IRI to a URI following the rules in RFC 3987 19 | # 20 | # The characters we need to enocde and escape are defined in the spec: 21 | # 22 | # iprivate = %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD 23 | # ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF 24 | # / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD 25 | # / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD 26 | # / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD 27 | # / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD 28 | # / %xD0000-DFFFD / %xE1000-EFFFD 29 | 30 | escape_range = [ 31 | (0xA0, 0xD7FF), 32 | (0xE000, 0xF8FF), 33 | (0xF900, 0xFDCF), 34 | (0xFDF0, 0xFFEF), 35 | (0x10000, 0x1FFFD), 36 | (0x20000, 0x2FFFD), 37 | (0x30000, 0x3FFFD), 38 | (0x40000, 0x4FFFD), 39 | (0x50000, 0x5FFFD), 40 | (0x60000, 0x6FFFD), 41 | (0x70000, 0x7FFFD), 42 | (0x80000, 0x8FFFD), 43 | (0x90000, 0x9FFFD), 44 | (0xA0000, 0xAFFFD), 45 | (0xB0000, 0xBFFFD), 46 | (0xC0000, 0xCFFFD), 47 | (0xD0000, 0xDFFFD), 48 | (0xE1000, 0xEFFFD), 49 | (0xF0000, 0xFFFFD), 50 | (0x100000, 0x10FFFD), 51 | ] 52 | 53 | def encode(c): 54 | retval = c 55 | i = ord(c) 56 | for low, high in escape_range: 57 | if i < low: 58 | break 59 | if i >= low and i <= high: 60 | retval = "".join(["%%%2X" % ord(o) for o in c.encode('utf-8')]) 61 | break 62 | return retval 63 | 64 | 65 | def iri2uri(uri): 66 | """Convert an IRI to a URI. Note that IRIs must be 67 | passed in a unicode strings. That is, do not utf-8 encode 68 | the IRI before passing it into the function.""" 69 | if isinstance(uri ,unicode): 70 | (scheme, authority, path, query, fragment) = urlparse.urlsplit(uri) 71 | authority = authority.encode('idna') 72 | # For each character in 'ucschar' or 'iprivate' 73 | # 1. encode as utf-8 74 | # 2. then %-encode each octet of that utf-8 75 | uri = urlparse.urlunsplit((scheme, authority, path, query, fragment)) 76 | uri = "".join([encode(c) for c in uri]) 77 | return uri 78 | 79 | if __name__ == "__main__": 80 | import unittest 81 | 82 | class Test(unittest.TestCase): 83 | 84 | def test_uris(self): 85 | """Test that URIs are invariant under the transformation.""" 86 | invariant = [ 87 | u"ftp://ftp.is.co.za/rfc/rfc1808.txt", 88 | u"http://www.ietf.org/rfc/rfc2396.txt", 89 | u"ldap://[2001:db8::7]/c=GB?objectClass?one", 90 | u"mailto:John.Doe@example.com", 91 | u"news:comp.infosystems.www.servers.unix", 92 | u"tel:+1-816-555-1212", 93 | u"telnet://192.0.2.16:80/", 94 | u"urn:oasis:names:specification:docbook:dtd:xml:4.1.2" ] 95 | for uri in invariant: 96 | self.assertEqual(uri, iri2uri(uri)) 97 | 98 | def test_iri(self): 99 | """ Test that the right type of escaping is done for each part of the URI.""" 100 | self.assertEqual("http://xn--o3h.com/%E2%98%84", iri2uri(u"http://\N{COMET}.com/\N{COMET}")) 101 | self.assertEqual("http://bitworking.org/?fred=%E2%98%84", iri2uri(u"http://bitworking.org/?fred=\N{COMET}")) 102 | self.assertEqual("http://bitworking.org/#%E2%98%84", iri2uri(u"http://bitworking.org/#\N{COMET}")) 103 | self.assertEqual("#%E2%98%84", iri2uri(u"#\N{COMET}")) 104 | self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}")) 105 | self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}"))) 106 | self.assertNotEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}".encode('utf-8'))) 107 | 108 | unittest.main() 109 | 110 | 111 | -------------------------------------------------------------------------------- /loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlearchive/billing-export-python/46988b491aac5d270891c4eb1dfb1e973c005133/loader.gif -------------------------------------------------------------------------------- /oauth2client/.svn/all-wcprops: -------------------------------------------------------------------------------- 1 | K 25 2 | svn:wc:ra_dav:version-url 3 | V 61 4 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client 5 | END 6 | keyring_storage.py 7 | K 25 8 | svn:wc:ra_dav:version-url 9 | V 80 10 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/keyring_storage.py 11 | END 12 | gce.py 13 | K 25 14 | svn:wc:ra_dav:version-url 15 | V 68 16 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/gce.py 17 | END 18 | __init__.py 19 | K 25 20 | svn:wc:ra_dav:version-url 21 | V 73 22 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/__init__.py 23 | END 24 | locked_file.py 25 | K 25 26 | svn:wc:ra_dav:version-url 27 | V 76 28 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/locked_file.py 29 | END 30 | tools.py 31 | K 25 32 | svn:wc:ra_dav:version-url 33 | V 70 34 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/tools.py 35 | END 36 | crypt.py 37 | K 25 38 | svn:wc:ra_dav:version-url 39 | V 70 40 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/crypt.py 41 | END 42 | old_run.py 43 | K 25 44 | svn:wc:ra_dav:version-url 45 | V 72 46 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/old_run.py 47 | END 48 | multistore_file.py 49 | K 25 50 | svn:wc:ra_dav:version-url 51 | V 80 52 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/multistore_file.py 53 | END 54 | appengine.py 55 | K 25 56 | svn:wc:ra_dav:version-url 57 | V 74 58 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/appengine.py 59 | END 60 | clientsecrets.py 61 | K 25 62 | svn:wc:ra_dav:version-url 63 | V 78 64 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/clientsecrets.py 65 | END 66 | util.py 67 | K 25 68 | svn:wc:ra_dav:version-url 69 | V 69 70 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/util.py 71 | END 72 | client.py 73 | K 25 74 | svn:wc:ra_dav:version-url 75 | V 71 76 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/client.py 77 | END 78 | django_orm.py 79 | K 25 80 | svn:wc:ra_dav:version-url 81 | V 75 82 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/django_orm.py 83 | END 84 | file.py 85 | K 25 86 | svn:wc:ra_dav:version-url 87 | V 69 88 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/file.py 89 | END 90 | xsrfutil.py 91 | K 25 92 | svn:wc:ra_dav:version-url 93 | V 73 94 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/xsrfutil.py 95 | END 96 | anyjson.py 97 | K 25 98 | svn:wc:ra_dav:version-url 99 | V 72 100 | /a/google.com/gcs-file-uploader/!svn/ver/2/trunk/oauth2client/anyjson.py 101 | END 102 | -------------------------------------------------------------------------------- /oauth2client/.svn/entries: -------------------------------------------------------------------------------- 1 | 10 2 | 3 | dir 4 | 12 5 | https://svn.codespot.com/a/google.com/gcs-file-uploader/trunk/oauth2client 6 | https://svn.codespot.com/a/google.com/gcs-file-uploader 7 | 8 | 9 | 10 | 2013-11-11T21:00:17.576267Z 11 | 2 12 | bmenasha@google.com 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 64dbcbab-f634-aa3b-7583-e74f06a72553 28 | 29 | keyring_storage.py 30 | file 31 | 32 | 33 | 34 | 35 | 2013-11-19T23:25:39.802311Z 36 | 774c54e45f91e5991f8b7791f83032f6 37 | 2013-11-11T21:00:17.576267Z 38 | 2 39 | bmenasha@google.com 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 3227 62 | 63 | gce.py 64 | file 65 | 66 | 67 | 68 | 69 | 2013-11-19T23:25:39.802311Z 70 | ab2810720f17520b5a0d17ba30c016c2 71 | 2013-11-11T21:00:17.576267Z 72 | 2 73 | bmenasha@google.com 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 3038 96 | 97 | __init__.py 98 | file 99 | 100 | 101 | 102 | 103 | 2013-11-19T23:25:39.802311Z 104 | b33f33f3851bfb17d2585598536aa70d 105 | 2013-11-11T21:00:17.576267Z 106 | 2 107 | bmenasha@google.com 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 213 130 | 131 | locked_file.py 132 | file 133 | 134 | 135 | 136 | 137 | 2013-11-19T23:25:39.806311Z 138 | 5e2c3437cce855d70349e55944efed56 139 | 2013-11-11T21:00:17.576267Z 140 | 2 141 | bmenasha@google.com 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 11379 164 | 165 | tools.py 166 | file 167 | 168 | 169 | 170 | 171 | 2013-11-19T23:25:39.806311Z 172 | f60c315a7b553012b0b4e5766ecb45dc 173 | 2013-11-11T21:00:17.576267Z 174 | 2 175 | bmenasha@google.com 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 8344 198 | 199 | crypt.py 200 | file 201 | 202 | 203 | 204 | 205 | 2013-11-19T23:25:39.806311Z 206 | ccb88d2b61ae89bc5e79925683eb2416 207 | 2013-11-11T21:00:17.576267Z 208 | 2 209 | bmenasha@google.com 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 10233 232 | 233 | old_run.py 234 | file 235 | 236 | 237 | 238 | 239 | 2013-11-19T23:25:39.806311Z 240 | 8ace7061774a0282ee126180120f6536 241 | 2013-11-11T21:00:17.576267Z 242 | 2 243 | bmenasha@google.com 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 5548 266 | 267 | multistore_file.py 268 | file 269 | 270 | 271 | 272 | 273 | 2013-11-19T23:25:39.806311Z 274 | cf0d8c399b8b89cfe750c6ccee27fba1 275 | 2013-11-11T21:00:17.576267Z 276 | 2 277 | bmenasha@google.com 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 13935 300 | 301 | appengine.py 302 | file 303 | 304 | 305 | 306 | 307 | 2013-11-19T23:25:39.806311Z 308 | f4425ba896670df72785b099b50f5d6e 309 | 2013-11-11T21:00:17.576267Z 310 | 2 311 | bmenasha@google.com 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 32524 334 | 335 | clientsecrets.py 336 | file 337 | 338 | 339 | 340 | 341 | 2013-11-19T23:25:39.806311Z 342 | 672ac17abd762104b5d43144859f8335 343 | 2013-11-11T21:00:17.576267Z 344 | 2 345 | bmenasha@google.com 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 4405 368 | 369 | util.py 370 | file 371 | 372 | 373 | 374 | 375 | 2013-11-19T23:25:39.806311Z 376 | 7f614daf45a03d638c6ca6ed614fb0ed 377 | 2013-11-11T21:00:17.576267Z 378 | 2 379 | bmenasha@google.com 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 5670 402 | 403 | client.py 404 | file 405 | 406 | 407 | 408 | 409 | 2013-11-19T23:25:39.806311Z 410 | 0c4d885518bcf80f080703e0357b2a8f 411 | 2013-11-11T21:00:17.576267Z 412 | 2 413 | bmenasha@google.com 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 44282 436 | 437 | django_orm.py 438 | file 439 | 440 | 441 | 442 | 443 | 2013-11-19T23:25:39.806311Z 444 | 3e3f8de166f09bfc2d7d43e407b275b5 445 | 2013-11-11T21:00:17.576267Z 446 | 2 447 | bmenasha@google.com 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 3833 470 | 471 | file.py 472 | file 473 | 474 | 475 | 476 | 477 | 2013-11-19T23:25:39.806311Z 478 | f2025006a2aa4e22996540888569f733 479 | 2013-11-11T21:00:17.576267Z 480 | 2 481 | bmenasha@google.com 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 3160 504 | 505 | xsrfutil.py 506 | file 507 | 508 | 509 | 510 | 511 | 2013-11-19T23:25:39.806311Z 512 | b318c98501f2996512b4db137359ecc8 513 | 2013-11-11T21:00:17.576267Z 514 | 2 515 | bmenasha@google.com 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 3368 538 | 539 | anyjson.py 540 | file 541 | 542 | 543 | 544 | 545 | 2013-11-19T23:25:39.806311Z 546 | 1146b43e7c65929b6446ee021271085e 547 | 2013-11-11T21:00:17.576267Z 548 | 2 549 | bmenasha@google.com 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 1044 572 | 573 | -------------------------------------------------------------------------------- /oauth2client/.svn/text-base/__init__.py.svn-base: -------------------------------------------------------------------------------- 1 | __version__ = "1.2" 2 | 3 | GOOGLE_AUTH_URI = 'https://accounts.google.com/o/oauth2/auth' 4 | GOOGLE_REVOKE_URI = 'https://accounts.google.com/o/oauth2/revoke' 5 | GOOGLE_TOKEN_URI = 'https://accounts.google.com/o/oauth2/token' 6 | -------------------------------------------------------------------------------- /oauth2client/.svn/text-base/anyjson.py.svn-base: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Utility module to import a JSON module 16 | 17 | Hides all the messy details of exactly where 18 | we get a simplejson module from. 19 | """ 20 | 21 | __author__ = 'jcgregorio@google.com (Joe Gregorio)' 22 | 23 | 24 | try: # pragma: no cover 25 | # Should work for Python2.6 and higher. 26 | import json as simplejson 27 | except ImportError: # pragma: no cover 28 | try: 29 | import simplejson 30 | except ImportError: 31 | # Try to import from django, should work on App Engine 32 | from django.utils import simplejson 33 | -------------------------------------------------------------------------------- /oauth2client/.svn/text-base/clientsecrets.py.svn-base: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Utilities for reading OAuth 2.0 client secret files. 16 | 17 | A client_secrets.json file contains all the information needed to interact with 18 | an OAuth 2.0 protected service. 19 | """ 20 | 21 | __author__ = 'jcgregorio@google.com (Joe Gregorio)' 22 | 23 | 24 | from anyjson import simplejson 25 | 26 | # Properties that make a client_secrets.json file valid. 27 | TYPE_WEB = 'web' 28 | TYPE_INSTALLED = 'installed' 29 | 30 | VALID_CLIENT = { 31 | TYPE_WEB: { 32 | 'required': [ 33 | 'client_id', 34 | 'client_secret', 35 | 'redirect_uris', 36 | 'auth_uri', 37 | 'token_uri', 38 | ], 39 | 'string': [ 40 | 'client_id', 41 | 'client_secret', 42 | ], 43 | }, 44 | TYPE_INSTALLED: { 45 | 'required': [ 46 | 'client_id', 47 | 'client_secret', 48 | 'redirect_uris', 49 | 'auth_uri', 50 | 'token_uri', 51 | ], 52 | 'string': [ 53 | 'client_id', 54 | 'client_secret', 55 | ], 56 | }, 57 | } 58 | 59 | 60 | class Error(Exception): 61 | """Base error for this module.""" 62 | pass 63 | 64 | 65 | class InvalidClientSecretsError(Error): 66 | """Format of ClientSecrets file is invalid.""" 67 | pass 68 | 69 | 70 | def _validate_clientsecrets(obj): 71 | if obj is None or len(obj) != 1: 72 | raise InvalidClientSecretsError('Invalid file format.') 73 | client_type = obj.keys()[0] 74 | if client_type not in VALID_CLIENT.keys(): 75 | raise InvalidClientSecretsError('Unknown client type: %s.' % client_type) 76 | client_info = obj[client_type] 77 | for prop_name in VALID_CLIENT[client_type]['required']: 78 | if prop_name not in client_info: 79 | raise InvalidClientSecretsError( 80 | 'Missing property "%s" in a client type of "%s".' % (prop_name, 81 | client_type)) 82 | for prop_name in VALID_CLIENT[client_type]['string']: 83 | if client_info[prop_name].startswith('[['): 84 | raise InvalidClientSecretsError( 85 | 'Property "%s" is not configured.' % prop_name) 86 | return client_type, client_info 87 | 88 | 89 | def load(fp): 90 | obj = simplejson.load(fp) 91 | return _validate_clientsecrets(obj) 92 | 93 | 94 | def loads(s): 95 | obj = simplejson.loads(s) 96 | return _validate_clientsecrets(obj) 97 | 98 | 99 | def _loadfile(filename): 100 | try: 101 | fp = file(filename, 'r') 102 | try: 103 | obj = simplejson.load(fp) 104 | finally: 105 | fp.close() 106 | except IOError: 107 | raise InvalidClientSecretsError('File not found: "%s"' % filename) 108 | return _validate_clientsecrets(obj) 109 | 110 | 111 | def loadfile(filename, cache=None): 112 | """Loading of client_secrets JSON file, optionally backed by a cache. 113 | 114 | Typical cache storage would be App Engine memcache service, 115 | but you can pass in any other cache client that implements 116 | these methods: 117 | - get(key, namespace=ns) 118 | - set(key, value, namespace=ns) 119 | 120 | Usage: 121 | # without caching 122 | client_type, client_info = loadfile('secrets.json') 123 | # using App Engine memcache service 124 | from google.appengine.api import memcache 125 | client_type, client_info = loadfile('secrets.json', cache=memcache) 126 | 127 | Args: 128 | filename: string, Path to a client_secrets.json file on a filesystem. 129 | cache: An optional cache service client that implements get() and set() 130 | methods. If not specified, the file is always being loaded from 131 | a filesystem. 132 | 133 | Raises: 134 | InvalidClientSecretsError: In case of a validation error or some 135 | I/O failure. Can happen only on cache miss. 136 | 137 | Returns: 138 | (client_type, client_info) tuple, as _loadfile() normally would. 139 | JSON contents is validated only during first load. Cache hits are not 140 | validated. 141 | """ 142 | _SECRET_NAMESPACE = 'oauth2client:secrets#ns' 143 | 144 | if not cache: 145 | return _loadfile(filename) 146 | 147 | obj = cache.get(filename, namespace=_SECRET_NAMESPACE) 148 | if obj is None: 149 | client_type, client_info = _loadfile(filename) 150 | obj = {client_type: client_info} 151 | cache.set(filename, obj, namespace=_SECRET_NAMESPACE) 152 | 153 | return obj.iteritems().next() 154 | -------------------------------------------------------------------------------- /oauth2client/.svn/text-base/django_orm.py.svn-base: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """OAuth 2.0 utilities for Django. 16 | 17 | Utilities for using OAuth 2.0 in conjunction with 18 | the Django datastore. 19 | """ 20 | 21 | __author__ = 'jcgregorio@google.com (Joe Gregorio)' 22 | 23 | import oauth2client 24 | import base64 25 | import pickle 26 | 27 | from django.db import models 28 | from oauth2client.client import Storage as BaseStorage 29 | 30 | class CredentialsField(models.Field): 31 | 32 | __metaclass__ = models.SubfieldBase 33 | 34 | def __init__(self, *args, **kwargs): 35 | if 'null' not in kwargs: 36 | kwargs['null'] = True 37 | super(CredentialsField, self).__init__(*args, **kwargs) 38 | 39 | def get_internal_type(self): 40 | return "TextField" 41 | 42 | def to_python(self, value): 43 | if value is None: 44 | return None 45 | if isinstance(value, oauth2client.client.Credentials): 46 | return value 47 | return pickle.loads(base64.b64decode(value)) 48 | 49 | def get_db_prep_value(self, value, connection, prepared=False): 50 | if value is None: 51 | return None 52 | return base64.b64encode(pickle.dumps(value)) 53 | 54 | 55 | class FlowField(models.Field): 56 | 57 | __metaclass__ = models.SubfieldBase 58 | 59 | def __init__(self, *args, **kwargs): 60 | if 'null' not in kwargs: 61 | kwargs['null'] = True 62 | super(FlowField, self).__init__(*args, **kwargs) 63 | 64 | def get_internal_type(self): 65 | return "TextField" 66 | 67 | def to_python(self, value): 68 | if value is None: 69 | return None 70 | if isinstance(value, oauth2client.client.Flow): 71 | return value 72 | return pickle.loads(base64.b64decode(value)) 73 | 74 | def get_db_prep_value(self, value, connection, prepared=False): 75 | if value is None: 76 | return None 77 | return base64.b64encode(pickle.dumps(value)) 78 | 79 | 80 | class Storage(BaseStorage): 81 | """Store and retrieve a single credential to and from 82 | the datastore. 83 | 84 | This Storage helper presumes the Credentials 85 | have been stored as a CredenialsField 86 | on a db model class. 87 | """ 88 | 89 | def __init__(self, model_class, key_name, key_value, property_name): 90 | """Constructor for Storage. 91 | 92 | Args: 93 | model: db.Model, model class 94 | key_name: string, key name for the entity that has the credentials 95 | key_value: string, key value for the entity that has the credentials 96 | property_name: string, name of the property that is an CredentialsProperty 97 | """ 98 | self.model_class = model_class 99 | self.key_name = key_name 100 | self.key_value = key_value 101 | self.property_name = property_name 102 | 103 | def locked_get(self): 104 | """Retrieve Credential from datastore. 105 | 106 | Returns: 107 | oauth2client.Credentials 108 | """ 109 | credential = None 110 | 111 | query = {self.key_name: self.key_value} 112 | entities = self.model_class.objects.filter(**query) 113 | if len(entities) > 0: 114 | credential = getattr(entities[0], self.property_name) 115 | if credential and hasattr(credential, 'set_store'): 116 | credential.set_store(self) 117 | return credential 118 | 119 | def locked_put(self, credentials): 120 | """Write a Credentials to the datastore. 121 | 122 | Args: 123 | credentials: Credentials, the credentials to store. 124 | """ 125 | args = {self.key_name: self.key_value} 126 | entity = self.model_class(**args) 127 | setattr(entity, self.property_name, credentials) 128 | entity.save() 129 | 130 | def locked_delete(self): 131 | """Delete Credentials from the datastore.""" 132 | 133 | query = {self.key_name: self.key_value} 134 | entities = self.model_class.objects.filter(**query).delete() 135 | -------------------------------------------------------------------------------- /oauth2client/.svn/text-base/file.py.svn-base: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Utilities for OAuth. 16 | 17 | Utilities for making it easier to work with OAuth 2.0 18 | credentials. 19 | """ 20 | 21 | __author__ = 'jcgregorio@google.com (Joe Gregorio)' 22 | 23 | import os 24 | import stat 25 | import threading 26 | 27 | from anyjson import simplejson 28 | from client import Storage as BaseStorage 29 | from client import Credentials 30 | 31 | 32 | class CredentialsFileSymbolicLinkError(Exception): 33 | """Credentials files must not be symbolic links.""" 34 | 35 | 36 | class Storage(BaseStorage): 37 | """Store and retrieve a single credential to and from a file.""" 38 | 39 | def __init__(self, filename): 40 | self._filename = filename 41 | self._lock = threading.Lock() 42 | 43 | def _validate_file(self): 44 | if os.path.islink(self._filename): 45 | raise CredentialsFileSymbolicLinkError( 46 | 'File: %s is a symbolic link.' % self._filename) 47 | 48 | def acquire_lock(self): 49 | """Acquires any lock necessary to access this Storage. 50 | 51 | This lock is not reentrant.""" 52 | self._lock.acquire() 53 | 54 | def release_lock(self): 55 | """Release the Storage lock. 56 | 57 | Trying to release a lock that isn't held will result in a 58 | RuntimeError. 59 | """ 60 | self._lock.release() 61 | 62 | def locked_get(self): 63 | """Retrieve Credential from file. 64 | 65 | Returns: 66 | oauth2client.client.Credentials 67 | 68 | Raises: 69 | CredentialsFileSymbolicLinkError if the file is a symbolic link. 70 | """ 71 | credentials = None 72 | self._validate_file() 73 | try: 74 | f = open(self._filename, 'rb') 75 | content = f.read() 76 | f.close() 77 | except IOError: 78 | return credentials 79 | 80 | try: 81 | credentials = Credentials.new_from_json(content) 82 | credentials.set_store(self) 83 | except ValueError: 84 | pass 85 | 86 | return credentials 87 | 88 | def _create_file_if_needed(self): 89 | """Create an empty file if necessary. 90 | 91 | This method will not initialize the file. Instead it implements a 92 | simple version of "touch" to ensure the file has been created. 93 | """ 94 | if not os.path.exists(self._filename): 95 | old_umask = os.umask(0177) 96 | try: 97 | open(self._filename, 'a+b').close() 98 | finally: 99 | os.umask(old_umask) 100 | 101 | def locked_put(self, credentials): 102 | """Write Credentials to file. 103 | 104 | Args: 105 | credentials: Credentials, the credentials to store. 106 | 107 | Raises: 108 | CredentialsFileSymbolicLinkError if the file is a symbolic link. 109 | """ 110 | 111 | self._create_file_if_needed() 112 | self._validate_file() 113 | f = open(self._filename, 'wb') 114 | f.write(credentials.to_json()) 115 | f.close() 116 | 117 | def locked_delete(self): 118 | """Delete Credentials file. 119 | 120 | Args: 121 | credentials: Credentials, the credentials to store. 122 | """ 123 | 124 | os.unlink(self._filename) 125 | -------------------------------------------------------------------------------- /oauth2client/.svn/text-base/gce.py.svn-base: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Utilities for Google Compute Engine 16 | 17 | Utilities for making it easier to use OAuth 2.0 on Google Compute Engine. 18 | """ 19 | 20 | __author__ = 'jcgregorio@google.com (Joe Gregorio)' 21 | 22 | import httplib2 23 | import logging 24 | import uritemplate 25 | 26 | from oauth2client import util 27 | from oauth2client.anyjson import simplejson 28 | from oauth2client.client import AccessTokenRefreshError 29 | from oauth2client.client import AssertionCredentials 30 | 31 | logger = logging.getLogger(__name__) 32 | 33 | # URI Template for the endpoint that returns access_tokens. 34 | META = ('http://metadata.google.internal/0.1/meta-data/service-accounts/' 35 | 'default/acquire{?scope}') 36 | 37 | 38 | class AppAssertionCredentials(AssertionCredentials): 39 | """Credentials object for Compute Engine Assertion Grants 40 | 41 | This object will allow a Compute Engine instance to identify itself to 42 | Google and other OAuth 2.0 servers that can verify assertions. It can be used 43 | for the purpose of accessing data stored under an account assigned to the 44 | Compute Engine instance itself. 45 | 46 | This credential does not require a flow to instantiate because it represents 47 | a two legged flow, and therefore has all of the required information to 48 | generate and refresh its own access tokens. 49 | """ 50 | 51 | @util.positional(2) 52 | def __init__(self, scope, **kwargs): 53 | """Constructor for AppAssertionCredentials 54 | 55 | Args: 56 | scope: string or iterable of strings, scope(s) of the credentials being 57 | requested. 58 | """ 59 | self.scope = util.scopes_to_string(scope) 60 | 61 | # Assertion type is no longer used, but still in the parent class signature. 62 | super(AppAssertionCredentials, self).__init__(None) 63 | 64 | @classmethod 65 | def from_json(cls, json): 66 | data = simplejson.loads(json) 67 | return AppAssertionCredentials(data['scope']) 68 | 69 | def _refresh(self, http_request): 70 | """Refreshes the access_token. 71 | 72 | Skip all the storage hoops and just refresh using the API. 73 | 74 | Args: 75 | http_request: callable, a callable that matches the method signature of 76 | httplib2.Http.request, used to make the refresh request. 77 | 78 | Raises: 79 | AccessTokenRefreshError: When the refresh fails. 80 | """ 81 | uri = uritemplate.expand(META, {'scope': self.scope}) 82 | response, content = http_request(uri) 83 | if response.status == 200: 84 | try: 85 | d = simplejson.loads(content) 86 | except StandardError, e: 87 | raise AccessTokenRefreshError(str(e)) 88 | self.access_token = d['accessToken'] 89 | else: 90 | raise AccessTokenRefreshError(content) 91 | -------------------------------------------------------------------------------- /oauth2client/.svn/text-base/keyring_storage.py.svn-base: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """A keyring based Storage. 16 | 17 | A Storage for Credentials that uses the keyring module. 18 | """ 19 | 20 | __author__ = 'jcgregorio@google.com (Joe Gregorio)' 21 | 22 | import keyring 23 | import threading 24 | 25 | from client import Storage as BaseStorage 26 | from client import Credentials 27 | 28 | 29 | class Storage(BaseStorage): 30 | """Store and retrieve a single credential to and from the keyring. 31 | 32 | To use this module you must have the keyring module installed. See 33 | . This is an optional module and is not 34 | installed with oauth2client by default because it does not work on all the 35 | platforms that oauth2client supports, such as Google App Engine. 36 | 37 | The keyring module is a cross-platform 38 | library for access the keyring capabilities of the local system. The user will 39 | be prompted for their keyring password when this module is used, and the 40 | manner in which the user is prompted will vary per platform. 41 | 42 | Usage: 43 | from oauth2client.keyring_storage import Storage 44 | 45 | s = Storage('name_of_application', 'user1') 46 | credentials = s.get() 47 | 48 | """ 49 | 50 | def __init__(self, service_name, user_name): 51 | """Constructor. 52 | 53 | Args: 54 | service_name: string, The name of the service under which the credentials 55 | are stored. 56 | user_name: string, The name of the user to store credentials for. 57 | """ 58 | self._service_name = service_name 59 | self._user_name = user_name 60 | self._lock = threading.Lock() 61 | 62 | def acquire_lock(self): 63 | """Acquires any lock necessary to access this Storage. 64 | 65 | This lock is not reentrant.""" 66 | self._lock.acquire() 67 | 68 | def release_lock(self): 69 | """Release the Storage lock. 70 | 71 | Trying to release a lock that isn't held will result in a 72 | RuntimeError. 73 | """ 74 | self._lock.release() 75 | 76 | def locked_get(self): 77 | """Retrieve Credential from file. 78 | 79 | Returns: 80 | oauth2client.client.Credentials 81 | """ 82 | credentials = None 83 | content = keyring.get_password(self._service_name, self._user_name) 84 | 85 | if content is not None: 86 | try: 87 | credentials = Credentials.new_from_json(content) 88 | credentials.set_store(self) 89 | except ValueError: 90 | pass 91 | 92 | return credentials 93 | 94 | def locked_put(self, credentials): 95 | """Write Credentials to file. 96 | 97 | Args: 98 | credentials: Credentials, the credentials to store. 99 | """ 100 | keyring.set_password(self._service_name, self._user_name, 101 | credentials.to_json()) 102 | 103 | def locked_delete(self): 104 | """Delete Credentials file. 105 | 106 | Args: 107 | credentials: Credentials, the credentials to store. 108 | """ 109 | keyring.set_password(self._service_name, self._user_name, '') 110 | -------------------------------------------------------------------------------- /oauth2client/.svn/text-base/old_run.py.svn-base: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """This module holds the old run() function which is deprecated, the 16 | tools.run_flow() function should be used in its place.""" 17 | 18 | 19 | import logging 20 | import socket 21 | import sys 22 | import webbrowser 23 | 24 | import gflags 25 | 26 | from oauth2client import client 27 | from oauth2client import util 28 | from tools import ClientRedirectHandler 29 | from tools import ClientRedirectServer 30 | 31 | 32 | FLAGS = gflags.FLAGS 33 | 34 | gflags.DEFINE_boolean('auth_local_webserver', True, 35 | ('Run a local web server to handle redirects during ' 36 | 'OAuth authorization.')) 37 | 38 | gflags.DEFINE_string('auth_host_name', 'localhost', 39 | ('Host name to use when running a local web server to ' 40 | 'handle redirects during OAuth authorization.')) 41 | 42 | gflags.DEFINE_multi_int('auth_host_port', [8080, 8090], 43 | ('Port to use when running a local web server to ' 44 | 'handle redirects during OAuth authorization.')) 45 | 46 | 47 | @util.positional(2) 48 | def run(flow, storage, http=None): 49 | """Core code for a command-line application. 50 | 51 | The run() function is called from your application and runs through all 52 | the steps to obtain credentials. It takes a Flow argument and attempts to 53 | open an authorization server page in the user's default web browser. The 54 | server asks the user to grant your application access to the user's data. 55 | If the user grants access, the run() function returns new credentials. The 56 | new credentials are also stored in the Storage argument, which updates the 57 | file associated with the Storage object. 58 | 59 | It presumes it is run from a command-line application and supports the 60 | following flags: 61 | 62 | --auth_host_name: Host name to use when running a local web server 63 | to handle redirects during OAuth authorization. 64 | (default: 'localhost') 65 | 66 | --auth_host_port: Port to use when running a local web server to handle 67 | redirects during OAuth authorization.; 68 | repeat this option to specify a list of values 69 | (default: '[8080, 8090]') 70 | (an integer) 71 | 72 | --[no]auth_local_webserver: Run a local web server to handle redirects 73 | during OAuth authorization. 74 | (default: 'true') 75 | 76 | Since it uses flags make sure to initialize the gflags module before 77 | calling run(). 78 | 79 | Args: 80 | flow: Flow, an OAuth 2.0 Flow to step through. 81 | storage: Storage, a Storage to store the credential in. 82 | http: An instance of httplib2.Http.request 83 | or something that acts like it. 84 | 85 | Returns: 86 | Credentials, the obtained credential. 87 | """ 88 | logging.warning('This function, oauth2client.tools.run(), and the use of ' 89 | 'the gflags library are deprecated and will be removed in a future ' 90 | 'version of the library.') 91 | if FLAGS.auth_local_webserver: 92 | success = False 93 | port_number = 0 94 | for port in FLAGS.auth_host_port: 95 | port_number = port 96 | try: 97 | httpd = ClientRedirectServer((FLAGS.auth_host_name, port), 98 | ClientRedirectHandler) 99 | except socket.error, e: 100 | pass 101 | else: 102 | success = True 103 | break 104 | FLAGS.auth_local_webserver = success 105 | if not success: 106 | print 'Failed to start a local webserver listening on either port 8080' 107 | print 'or port 9090. Please check your firewall settings and locally' 108 | print 'running programs that may be blocking or using those ports.' 109 | print 110 | print 'Falling back to --noauth_local_webserver and continuing with', 111 | print 'authorization.' 112 | print 113 | 114 | if FLAGS.auth_local_webserver: 115 | oauth_callback = 'http://%s:%s/' % (FLAGS.auth_host_name, port_number) 116 | else: 117 | oauth_callback = client.OOB_CALLBACK_URN 118 | flow.redirect_uri = oauth_callback 119 | authorize_url = flow.step1_get_authorize_url() 120 | 121 | if FLAGS.auth_local_webserver: 122 | webbrowser.open(authorize_url, new=1, autoraise=True) 123 | print 'Your browser has been opened to visit:' 124 | print 125 | print ' ' + authorize_url 126 | print 127 | print 'If your browser is on a different machine then exit and re-run' 128 | print 'this application with the command-line parameter ' 129 | print 130 | print ' --noauth_local_webserver' 131 | print 132 | else: 133 | print 'Go to the following link in your browser:' 134 | print 135 | print ' ' + authorize_url 136 | print 137 | 138 | code = None 139 | if FLAGS.auth_local_webserver: 140 | httpd.handle_request() 141 | if 'error' in httpd.query_params: 142 | sys.exit('Authentication request was rejected.') 143 | if 'code' in httpd.query_params: 144 | code = httpd.query_params['code'] 145 | else: 146 | print 'Failed to find "code" in the query parameters of the redirect.' 147 | sys.exit('Try running with --noauth_local_webserver.') 148 | else: 149 | code = raw_input('Enter verification code: ').strip() 150 | 151 | try: 152 | credential = flow.step2_exchange(code, http=http) 153 | except client.FlowExchangeError, e: 154 | sys.exit('Authentication has failed: %s' % e) 155 | 156 | storage.put(credential) 157 | credential.set_store(storage) 158 | print 'Authentication successful.' 159 | 160 | return credential 161 | -------------------------------------------------------------------------------- /oauth2client/.svn/text-base/util.py.svn-base: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2010 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | """Common utility library.""" 19 | 20 | __author__ = ['rafek@google.com (Rafe Kaplan)', 21 | 'guido@google.com (Guido van Rossum)', 22 | ] 23 | __all__ = [ 24 | 'positional', 25 | 'POSITIONAL_WARNING', 26 | 'POSITIONAL_EXCEPTION', 27 | 'POSITIONAL_IGNORE', 28 | ] 29 | 30 | import inspect 31 | import logging 32 | import types 33 | import urllib 34 | import urlparse 35 | 36 | try: 37 | from urlparse import parse_qsl 38 | except ImportError: 39 | from cgi import parse_qsl 40 | 41 | logger = logging.getLogger(__name__) 42 | 43 | POSITIONAL_WARNING = 'WARNING' 44 | POSITIONAL_EXCEPTION = 'EXCEPTION' 45 | POSITIONAL_IGNORE = 'IGNORE' 46 | POSITIONAL_SET = frozenset([POSITIONAL_WARNING, POSITIONAL_EXCEPTION, 47 | POSITIONAL_IGNORE]) 48 | 49 | positional_parameters_enforcement = POSITIONAL_WARNING 50 | 51 | def positional(max_positional_args): 52 | """A decorator to declare that only the first N arguments my be positional. 53 | 54 | This decorator makes it easy to support Python 3 style key-word only 55 | parameters. For example, in Python 3 it is possible to write: 56 | 57 | def fn(pos1, *, kwonly1=None, kwonly1=None): 58 | ... 59 | 60 | All named parameters after * must be a keyword: 61 | 62 | fn(10, 'kw1', 'kw2') # Raises exception. 63 | fn(10, kwonly1='kw1') # Ok. 64 | 65 | Example: 66 | To define a function like above, do: 67 | 68 | @positional(1) 69 | def fn(pos1, kwonly1=None, kwonly2=None): 70 | ... 71 | 72 | If no default value is provided to a keyword argument, it becomes a required 73 | keyword argument: 74 | 75 | @positional(0) 76 | def fn(required_kw): 77 | ... 78 | 79 | This must be called with the keyword parameter: 80 | 81 | fn() # Raises exception. 82 | fn(10) # Raises exception. 83 | fn(required_kw=10) # Ok. 84 | 85 | When defining instance or class methods always remember to account for 86 | 'self' and 'cls': 87 | 88 | class MyClass(object): 89 | 90 | @positional(2) 91 | def my_method(self, pos1, kwonly1=None): 92 | ... 93 | 94 | @classmethod 95 | @positional(2) 96 | def my_method(cls, pos1, kwonly1=None): 97 | ... 98 | 99 | The positional decorator behavior is controlled by 100 | util.positional_parameters_enforcement, which may be set to 101 | POSITIONAL_EXCEPTION, POSITIONAL_WARNING or POSITIONAL_IGNORE to raise an 102 | exception, log a warning, or do nothing, respectively, if a declaration is 103 | violated. 104 | 105 | Args: 106 | max_positional_arguments: Maximum number of positional arguments. All 107 | parameters after the this index must be keyword only. 108 | 109 | Returns: 110 | A decorator that prevents using arguments after max_positional_args from 111 | being used as positional parameters. 112 | 113 | Raises: 114 | TypeError if a key-word only argument is provided as a positional 115 | parameter, but only if util.positional_parameters_enforcement is set to 116 | POSITIONAL_EXCEPTION. 117 | """ 118 | def positional_decorator(wrapped): 119 | def positional_wrapper(*args, **kwargs): 120 | if len(args) > max_positional_args: 121 | plural_s = '' 122 | if max_positional_args != 1: 123 | plural_s = 's' 124 | message = '%s() takes at most %d positional argument%s (%d given)' % ( 125 | wrapped.__name__, max_positional_args, plural_s, len(args)) 126 | if positional_parameters_enforcement == POSITIONAL_EXCEPTION: 127 | raise TypeError(message) 128 | elif positional_parameters_enforcement == POSITIONAL_WARNING: 129 | logger.warning(message) 130 | else: # IGNORE 131 | pass 132 | return wrapped(*args, **kwargs) 133 | return positional_wrapper 134 | 135 | if isinstance(max_positional_args, (int, long)): 136 | return positional_decorator 137 | else: 138 | args, _, _, defaults = inspect.getargspec(max_positional_args) 139 | return positional(len(args) - len(defaults))(max_positional_args) 140 | 141 | 142 | def scopes_to_string(scopes): 143 | """Converts scope value to a string. 144 | 145 | If scopes is a string then it is simply passed through. If scopes is an 146 | iterable then a string is returned that is all the individual scopes 147 | concatenated with spaces. 148 | 149 | Args: 150 | scopes: string or iterable of strings, the scopes. 151 | 152 | Returns: 153 | The scopes formatted as a single string. 154 | """ 155 | if isinstance(scopes, types.StringTypes): 156 | return scopes 157 | else: 158 | return ' '.join(scopes) 159 | 160 | 161 | def dict_to_tuple_key(dictionary): 162 | """Converts a dictionary to a tuple that can be used as an immutable key. 163 | 164 | The resulting key is always sorted so that logically equivalent dictionaries 165 | always produce an identical tuple for a key. 166 | 167 | Args: 168 | dictionary: the dictionary to use as the key. 169 | 170 | Returns: 171 | A tuple representing the dictionary in it's naturally sorted ordering. 172 | """ 173 | return tuple(sorted(dictionary.items())) 174 | 175 | 176 | def _add_query_parameter(url, name, value): 177 | """Adds a query parameter to a url. 178 | 179 | Replaces the current value if it already exists in the URL. 180 | 181 | Args: 182 | url: string, url to add the query parameter to. 183 | name: string, query parameter name. 184 | value: string, query parameter value. 185 | 186 | Returns: 187 | Updated query parameter. Does not update the url if value is None. 188 | """ 189 | if value is None: 190 | return url 191 | else: 192 | parsed = list(urlparse.urlparse(url)) 193 | q = dict(parse_qsl(parsed[4])) 194 | q[name] = value 195 | parsed[4] = urllib.urlencode(q) 196 | return urlparse.urlunparse(parsed) 197 | -------------------------------------------------------------------------------- /oauth2client/.svn/text-base/xsrfutil.py.svn-base: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.5 2 | # 3 | # Copyright 2010 the Melange authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Helper methods for creating & verifying XSRF tokens.""" 18 | 19 | __authors__ = [ 20 | '"Doug Coker" ', 21 | '"Joe Gregorio" ', 22 | ] 23 | 24 | 25 | import base64 26 | import hmac 27 | import os # for urandom 28 | import time 29 | 30 | from oauth2client import util 31 | 32 | 33 | # Delimiter character 34 | DELIMITER = ':' 35 | 36 | # 1 hour in seconds 37 | DEFAULT_TIMEOUT_SECS = 1*60*60 38 | 39 | @util.positional(2) 40 | def generate_token(key, user_id, action_id="", when=None): 41 | """Generates a URL-safe token for the given user, action, time tuple. 42 | 43 | Args: 44 | key: secret key to use. 45 | user_id: the user ID of the authenticated user. 46 | action_id: a string identifier of the action they requested 47 | authorization for. 48 | when: the time in seconds since the epoch at which the user was 49 | authorized for this action. If not set the current time is used. 50 | 51 | Returns: 52 | A string XSRF protection token. 53 | """ 54 | when = when or int(time.time()) 55 | digester = hmac.new(key) 56 | digester.update(str(user_id)) 57 | digester.update(DELIMITER) 58 | digester.update(action_id) 59 | digester.update(DELIMITER) 60 | digester.update(str(when)) 61 | digest = digester.digest() 62 | 63 | token = base64.urlsafe_b64encode('%s%s%d' % (digest, 64 | DELIMITER, 65 | when)) 66 | return token 67 | 68 | 69 | @util.positional(3) 70 | def validate_token(key, token, user_id, action_id="", current_time=None): 71 | """Validates that the given token authorizes the user for the action. 72 | 73 | Tokens are invalid if the time of issue is too old or if the token 74 | does not match what generateToken outputs (i.e. the token was forged). 75 | 76 | Args: 77 | key: secret key to use. 78 | token: a string of the token generated by generateToken. 79 | user_id: the user ID of the authenticated user. 80 | action_id: a string identifier of the action they requested 81 | authorization for. 82 | 83 | Returns: 84 | A boolean - True if the user is authorized for the action, False 85 | otherwise. 86 | """ 87 | if not token: 88 | return False 89 | try: 90 | decoded = base64.urlsafe_b64decode(str(token)) 91 | token_time = long(decoded.split(DELIMITER)[-1]) 92 | except (TypeError, ValueError): 93 | return False 94 | if current_time is None: 95 | current_time = time.time() 96 | # If the token is too old it's not valid. 97 | if current_time - token_time > DEFAULT_TIMEOUT_SECS: 98 | return False 99 | 100 | # The given token should match the generated one with the same time. 101 | expected_token = generate_token(key, user_id, action_id=action_id, 102 | when=token_time) 103 | if len(token) != len(expected_token): 104 | return False 105 | 106 | # Perform constant time comparison to avoid timing attacks 107 | different = 0 108 | for x, y in zip(token, expected_token): 109 | different |= ord(x) ^ ord(y) 110 | if different: 111 | return False 112 | 113 | return True 114 | -------------------------------------------------------------------------------- /oauth2client/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "1.2" 2 | 3 | GOOGLE_AUTH_URI = 'https://accounts.google.com/o/oauth2/auth' 4 | GOOGLE_REVOKE_URI = 'https://accounts.google.com/o/oauth2/revoke' 5 | GOOGLE_TOKEN_URI = 'https://accounts.google.com/o/oauth2/token' 6 | -------------------------------------------------------------------------------- /oauth2client/anyjson.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Utility module to import a JSON module 16 | 17 | Hides all the messy details of exactly where 18 | we get a simplejson module from. 19 | """ 20 | 21 | __author__ = 'jcgregorio@google.com (Joe Gregorio)' 22 | 23 | 24 | try: # pragma: no cover 25 | # Should work for Python2.6 and higher. 26 | import json as simplejson 27 | except ImportError: # pragma: no cover 28 | try: 29 | import simplejson 30 | except ImportError: 31 | # Try to import from django, should work on App Engine 32 | from django.utils import simplejson 33 | -------------------------------------------------------------------------------- /oauth2client/clientsecrets.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Utilities for reading OAuth 2.0 client secret files. 16 | 17 | A client_secrets.json file contains all the information needed to interact with 18 | an OAuth 2.0 protected service. 19 | """ 20 | 21 | __author__ = 'jcgregorio@google.com (Joe Gregorio)' 22 | 23 | 24 | from anyjson import simplejson 25 | 26 | # Properties that make a client_secrets.json file valid. 27 | TYPE_WEB = 'web' 28 | TYPE_INSTALLED = 'installed' 29 | 30 | VALID_CLIENT = { 31 | TYPE_WEB: { 32 | 'required': [ 33 | 'client_id', 34 | 'client_secret', 35 | 'redirect_uris', 36 | 'auth_uri', 37 | 'token_uri', 38 | ], 39 | 'string': [ 40 | 'client_id', 41 | 'client_secret', 42 | ], 43 | }, 44 | TYPE_INSTALLED: { 45 | 'required': [ 46 | 'client_id', 47 | 'client_secret', 48 | 'redirect_uris', 49 | 'auth_uri', 50 | 'token_uri', 51 | ], 52 | 'string': [ 53 | 'client_id', 54 | 'client_secret', 55 | ], 56 | }, 57 | } 58 | 59 | 60 | class Error(Exception): 61 | """Base error for this module.""" 62 | pass 63 | 64 | 65 | class InvalidClientSecretsError(Error): 66 | """Format of ClientSecrets file is invalid.""" 67 | pass 68 | 69 | 70 | def _validate_clientsecrets(obj): 71 | if obj is None or len(obj) != 1: 72 | raise InvalidClientSecretsError('Invalid file format.') 73 | client_type = obj.keys()[0] 74 | if client_type not in VALID_CLIENT.keys(): 75 | raise InvalidClientSecretsError('Unknown client type: %s.' % client_type) 76 | client_info = obj[client_type] 77 | for prop_name in VALID_CLIENT[client_type]['required']: 78 | if prop_name not in client_info: 79 | raise InvalidClientSecretsError( 80 | 'Missing property "%s" in a client type of "%s".' % (prop_name, 81 | client_type)) 82 | for prop_name in VALID_CLIENT[client_type]['string']: 83 | if client_info[prop_name].startswith('[['): 84 | raise InvalidClientSecretsError( 85 | 'Property "%s" is not configured.' % prop_name) 86 | return client_type, client_info 87 | 88 | 89 | def load(fp): 90 | obj = simplejson.load(fp) 91 | return _validate_clientsecrets(obj) 92 | 93 | 94 | def loads(s): 95 | obj = simplejson.loads(s) 96 | return _validate_clientsecrets(obj) 97 | 98 | 99 | def _loadfile(filename): 100 | try: 101 | fp = file(filename, 'r') 102 | try: 103 | obj = simplejson.load(fp) 104 | finally: 105 | fp.close() 106 | except IOError: 107 | raise InvalidClientSecretsError('File not found: "%s"' % filename) 108 | return _validate_clientsecrets(obj) 109 | 110 | 111 | def loadfile(filename, cache=None): 112 | """Loading of client_secrets JSON file, optionally backed by a cache. 113 | 114 | Typical cache storage would be App Engine memcache service, 115 | but you can pass in any other cache client that implements 116 | these methods: 117 | - get(key, namespace=ns) 118 | - set(key, value, namespace=ns) 119 | 120 | Usage: 121 | # without caching 122 | client_type, client_info = loadfile('secrets.json') 123 | # using App Engine memcache service 124 | from google.appengine.api import memcache 125 | client_type, client_info = loadfile('secrets.json', cache=memcache) 126 | 127 | Args: 128 | filename: string, Path to a client_secrets.json file on a filesystem. 129 | cache: An optional cache service client that implements get() and set() 130 | methods. If not specified, the file is always being loaded from 131 | a filesystem. 132 | 133 | Raises: 134 | InvalidClientSecretsError: In case of a validation error or some 135 | I/O failure. Can happen only on cache miss. 136 | 137 | Returns: 138 | (client_type, client_info) tuple, as _loadfile() normally would. 139 | JSON contents is validated only during first load. Cache hits are not 140 | validated. 141 | """ 142 | _SECRET_NAMESPACE = 'oauth2client:secrets#ns' 143 | 144 | if not cache: 145 | return _loadfile(filename) 146 | 147 | obj = cache.get(filename, namespace=_SECRET_NAMESPACE) 148 | if obj is None: 149 | client_type, client_info = _loadfile(filename) 150 | obj = {client_type: client_info} 151 | cache.set(filename, obj, namespace=_SECRET_NAMESPACE) 152 | 153 | return obj.iteritems().next() 154 | -------------------------------------------------------------------------------- /oauth2client/django_orm.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """OAuth 2.0 utilities for Django. 16 | 17 | Utilities for using OAuth 2.0 in conjunction with 18 | the Django datastore. 19 | """ 20 | 21 | __author__ = 'jcgregorio@google.com (Joe Gregorio)' 22 | 23 | import oauth2client 24 | import base64 25 | import pickle 26 | 27 | from django.db import models 28 | from oauth2client.client import Storage as BaseStorage 29 | 30 | class CredentialsField(models.Field): 31 | 32 | __metaclass__ = models.SubfieldBase 33 | 34 | def __init__(self, *args, **kwargs): 35 | if 'null' not in kwargs: 36 | kwargs['null'] = True 37 | super(CredentialsField, self).__init__(*args, **kwargs) 38 | 39 | def get_internal_type(self): 40 | return "TextField" 41 | 42 | def to_python(self, value): 43 | if value is None: 44 | return None 45 | if isinstance(value, oauth2client.client.Credentials): 46 | return value 47 | return pickle.loads(base64.b64decode(value)) 48 | 49 | def get_db_prep_value(self, value, connection, prepared=False): 50 | if value is None: 51 | return None 52 | return base64.b64encode(pickle.dumps(value)) 53 | 54 | 55 | class FlowField(models.Field): 56 | 57 | __metaclass__ = models.SubfieldBase 58 | 59 | def __init__(self, *args, **kwargs): 60 | if 'null' not in kwargs: 61 | kwargs['null'] = True 62 | super(FlowField, self).__init__(*args, **kwargs) 63 | 64 | def get_internal_type(self): 65 | return "TextField" 66 | 67 | def to_python(self, value): 68 | if value is None: 69 | return None 70 | if isinstance(value, oauth2client.client.Flow): 71 | return value 72 | return pickle.loads(base64.b64decode(value)) 73 | 74 | def get_db_prep_value(self, value, connection, prepared=False): 75 | if value is None: 76 | return None 77 | return base64.b64encode(pickle.dumps(value)) 78 | 79 | 80 | class Storage(BaseStorage): 81 | """Store and retrieve a single credential to and from 82 | the datastore. 83 | 84 | This Storage helper presumes the Credentials 85 | have been stored as a CredenialsField 86 | on a db model class. 87 | """ 88 | 89 | def __init__(self, model_class, key_name, key_value, property_name): 90 | """Constructor for Storage. 91 | 92 | Args: 93 | model: db.Model, model class 94 | key_name: string, key name for the entity that has the credentials 95 | key_value: string, key value for the entity that has the credentials 96 | property_name: string, name of the property that is an CredentialsProperty 97 | """ 98 | self.model_class = model_class 99 | self.key_name = key_name 100 | self.key_value = key_value 101 | self.property_name = property_name 102 | 103 | def locked_get(self): 104 | """Retrieve Credential from datastore. 105 | 106 | Returns: 107 | oauth2client.Credentials 108 | """ 109 | credential = None 110 | 111 | query = {self.key_name: self.key_value} 112 | entities = self.model_class.objects.filter(**query) 113 | if len(entities) > 0: 114 | credential = getattr(entities[0], self.property_name) 115 | if credential and hasattr(credential, 'set_store'): 116 | credential.set_store(self) 117 | return credential 118 | 119 | def locked_put(self, credentials): 120 | """Write a Credentials to the datastore. 121 | 122 | Args: 123 | credentials: Credentials, the credentials to store. 124 | """ 125 | args = {self.key_name: self.key_value} 126 | entity = self.model_class(**args) 127 | setattr(entity, self.property_name, credentials) 128 | entity.save() 129 | 130 | def locked_delete(self): 131 | """Delete Credentials from the datastore.""" 132 | 133 | query = {self.key_name: self.key_value} 134 | entities = self.model_class.objects.filter(**query).delete() 135 | -------------------------------------------------------------------------------- /oauth2client/file.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Utilities for OAuth. 16 | 17 | Utilities for making it easier to work with OAuth 2.0 18 | credentials. 19 | """ 20 | 21 | __author__ = 'jcgregorio@google.com (Joe Gregorio)' 22 | 23 | import os 24 | import stat 25 | import threading 26 | 27 | from anyjson import simplejson 28 | from client import Storage as BaseStorage 29 | from client import Credentials 30 | 31 | 32 | class CredentialsFileSymbolicLinkError(Exception): 33 | """Credentials files must not be symbolic links.""" 34 | 35 | 36 | class Storage(BaseStorage): 37 | """Store and retrieve a single credential to and from a file.""" 38 | 39 | def __init__(self, filename): 40 | self._filename = filename 41 | self._lock = threading.Lock() 42 | 43 | def _validate_file(self): 44 | if os.path.islink(self._filename): 45 | raise CredentialsFileSymbolicLinkError( 46 | 'File: %s is a symbolic link.' % self._filename) 47 | 48 | def acquire_lock(self): 49 | """Acquires any lock necessary to access this Storage. 50 | 51 | This lock is not reentrant.""" 52 | self._lock.acquire() 53 | 54 | def release_lock(self): 55 | """Release the Storage lock. 56 | 57 | Trying to release a lock that isn't held will result in a 58 | RuntimeError. 59 | """ 60 | self._lock.release() 61 | 62 | def locked_get(self): 63 | """Retrieve Credential from file. 64 | 65 | Returns: 66 | oauth2client.client.Credentials 67 | 68 | Raises: 69 | CredentialsFileSymbolicLinkError if the file is a symbolic link. 70 | """ 71 | credentials = None 72 | self._validate_file() 73 | try: 74 | f = open(self._filename, 'rb') 75 | content = f.read() 76 | f.close() 77 | except IOError: 78 | return credentials 79 | 80 | try: 81 | credentials = Credentials.new_from_json(content) 82 | credentials.set_store(self) 83 | except ValueError: 84 | pass 85 | 86 | return credentials 87 | 88 | def _create_file_if_needed(self): 89 | """Create an empty file if necessary. 90 | 91 | This method will not initialize the file. Instead it implements a 92 | simple version of "touch" to ensure the file has been created. 93 | """ 94 | if not os.path.exists(self._filename): 95 | old_umask = os.umask(0177) 96 | try: 97 | open(self._filename, 'a+b').close() 98 | finally: 99 | os.umask(old_umask) 100 | 101 | def locked_put(self, credentials): 102 | """Write Credentials to file. 103 | 104 | Args: 105 | credentials: Credentials, the credentials to store. 106 | 107 | Raises: 108 | CredentialsFileSymbolicLinkError if the file is a symbolic link. 109 | """ 110 | 111 | self._create_file_if_needed() 112 | self._validate_file() 113 | f = open(self._filename, 'wb') 114 | f.write(credentials.to_json()) 115 | f.close() 116 | 117 | def locked_delete(self): 118 | """Delete Credentials file. 119 | 120 | Args: 121 | credentials: Credentials, the credentials to store. 122 | """ 123 | 124 | os.unlink(self._filename) 125 | -------------------------------------------------------------------------------- /oauth2client/gce.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Utilities for Google Compute Engine 16 | 17 | Utilities for making it easier to use OAuth 2.0 on Google Compute Engine. 18 | """ 19 | 20 | __author__ = 'jcgregorio@google.com (Joe Gregorio)' 21 | 22 | import httplib2 23 | import logging 24 | import uritemplate 25 | 26 | from oauth2client import util 27 | from oauth2client.anyjson import simplejson 28 | from oauth2client.client import AccessTokenRefreshError 29 | from oauth2client.client import AssertionCredentials 30 | 31 | logger = logging.getLogger(__name__) 32 | 33 | # URI Template for the endpoint that returns access_tokens. 34 | META = ('http://metadata.google.internal/0.1/meta-data/service-accounts/' 35 | 'default/acquire{?scope}') 36 | 37 | 38 | class AppAssertionCredentials(AssertionCredentials): 39 | """Credentials object for Compute Engine Assertion Grants 40 | 41 | This object will allow a Compute Engine instance to identify itself to 42 | Google and other OAuth 2.0 servers that can verify assertions. It can be used 43 | for the purpose of accessing data stored under an account assigned to the 44 | Compute Engine instance itself. 45 | 46 | This credential does not require a flow to instantiate because it represents 47 | a two legged flow, and therefore has all of the required information to 48 | generate and refresh its own access tokens. 49 | """ 50 | 51 | @util.positional(2) 52 | def __init__(self, scope, **kwargs): 53 | """Constructor for AppAssertionCredentials 54 | 55 | Args: 56 | scope: string or iterable of strings, scope(s) of the credentials being 57 | requested. 58 | """ 59 | self.scope = util.scopes_to_string(scope) 60 | 61 | # Assertion type is no longer used, but still in the parent class signature. 62 | super(AppAssertionCredentials, self).__init__(None) 63 | 64 | @classmethod 65 | def from_json(cls, json): 66 | data = simplejson.loads(json) 67 | return AppAssertionCredentials(data['scope']) 68 | 69 | def _refresh(self, http_request): 70 | """Refreshes the access_token. 71 | 72 | Skip all the storage hoops and just refresh using the API. 73 | 74 | Args: 75 | http_request: callable, a callable that matches the method signature of 76 | httplib2.Http.request, used to make the refresh request. 77 | 78 | Raises: 79 | AccessTokenRefreshError: When the refresh fails. 80 | """ 81 | uri = uritemplate.expand(META, {'scope': self.scope}) 82 | response, content = http_request(uri) 83 | if response.status == 200: 84 | try: 85 | d = simplejson.loads(content) 86 | except StandardError, e: 87 | raise AccessTokenRefreshError(str(e)) 88 | self.access_token = d['accessToken'] 89 | else: 90 | raise AccessTokenRefreshError(content) 91 | -------------------------------------------------------------------------------- /oauth2client/keyring_storage.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """A keyring based Storage. 16 | 17 | A Storage for Credentials that uses the keyring module. 18 | """ 19 | 20 | __author__ = 'jcgregorio@google.com (Joe Gregorio)' 21 | 22 | import keyring 23 | import threading 24 | 25 | from client import Storage as BaseStorage 26 | from client import Credentials 27 | 28 | 29 | class Storage(BaseStorage): 30 | """Store and retrieve a single credential to and from the keyring. 31 | 32 | To use this module you must have the keyring module installed. See 33 | . This is an optional module and is not 34 | installed with oauth2client by default because it does not work on all the 35 | platforms that oauth2client supports, such as Google App Engine. 36 | 37 | The keyring module is a cross-platform 38 | library for access the keyring capabilities of the local system. The user will 39 | be prompted for their keyring password when this module is used, and the 40 | manner in which the user is prompted will vary per platform. 41 | 42 | Usage: 43 | from oauth2client.keyring_storage import Storage 44 | 45 | s = Storage('name_of_application', 'user1') 46 | credentials = s.get() 47 | 48 | """ 49 | 50 | def __init__(self, service_name, user_name): 51 | """Constructor. 52 | 53 | Args: 54 | service_name: string, The name of the service under which the credentials 55 | are stored. 56 | user_name: string, The name of the user to store credentials for. 57 | """ 58 | self._service_name = service_name 59 | self._user_name = user_name 60 | self._lock = threading.Lock() 61 | 62 | def acquire_lock(self): 63 | """Acquires any lock necessary to access this Storage. 64 | 65 | This lock is not reentrant.""" 66 | self._lock.acquire() 67 | 68 | def release_lock(self): 69 | """Release the Storage lock. 70 | 71 | Trying to release a lock that isn't held will result in a 72 | RuntimeError. 73 | """ 74 | self._lock.release() 75 | 76 | def locked_get(self): 77 | """Retrieve Credential from file. 78 | 79 | Returns: 80 | oauth2client.client.Credentials 81 | """ 82 | credentials = None 83 | content = keyring.get_password(self._service_name, self._user_name) 84 | 85 | if content is not None: 86 | try: 87 | credentials = Credentials.new_from_json(content) 88 | credentials.set_store(self) 89 | except ValueError: 90 | pass 91 | 92 | return credentials 93 | 94 | def locked_put(self, credentials): 95 | """Write Credentials to file. 96 | 97 | Args: 98 | credentials: Credentials, the credentials to store. 99 | """ 100 | keyring.set_password(self._service_name, self._user_name, 101 | credentials.to_json()) 102 | 103 | def locked_delete(self): 104 | """Delete Credentials file. 105 | 106 | Args: 107 | credentials: Credentials, the credentials to store. 108 | """ 109 | keyring.set_password(self._service_name, self._user_name, '') 110 | -------------------------------------------------------------------------------- /oauth2client/old_run.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """This module holds the old run() function which is deprecated, the 16 | tools.run_flow() function should be used in its place.""" 17 | 18 | 19 | import logging 20 | import socket 21 | import sys 22 | import webbrowser 23 | 24 | import gflags 25 | 26 | from oauth2client import client 27 | from oauth2client import util 28 | from tools import ClientRedirectHandler 29 | from tools import ClientRedirectServer 30 | 31 | 32 | FLAGS = gflags.FLAGS 33 | 34 | gflags.DEFINE_boolean('auth_local_webserver', True, 35 | ('Run a local web server to handle redirects during ' 36 | 'OAuth authorization.')) 37 | 38 | gflags.DEFINE_string('auth_host_name', 'localhost', 39 | ('Host name to use when running a local web server to ' 40 | 'handle redirects during OAuth authorization.')) 41 | 42 | gflags.DEFINE_multi_int('auth_host_port', [8080, 8090], 43 | ('Port to use when running a local web server to ' 44 | 'handle redirects during OAuth authorization.')) 45 | 46 | 47 | @util.positional(2) 48 | def run(flow, storage, http=None): 49 | """Core code for a command-line application. 50 | 51 | The run() function is called from your application and runs through all 52 | the steps to obtain credentials. It takes a Flow argument and attempts to 53 | open an authorization server page in the user's default web browser. The 54 | server asks the user to grant your application access to the user's data. 55 | If the user grants access, the run() function returns new credentials. The 56 | new credentials are also stored in the Storage argument, which updates the 57 | file associated with the Storage object. 58 | 59 | It presumes it is run from a command-line application and supports the 60 | following flags: 61 | 62 | --auth_host_name: Host name to use when running a local web server 63 | to handle redirects during OAuth authorization. 64 | (default: 'localhost') 65 | 66 | --auth_host_port: Port to use when running a local web server to handle 67 | redirects during OAuth authorization.; 68 | repeat this option to specify a list of values 69 | (default: '[8080, 8090]') 70 | (an integer) 71 | 72 | --[no]auth_local_webserver: Run a local web server to handle redirects 73 | during OAuth authorization. 74 | (default: 'true') 75 | 76 | Since it uses flags make sure to initialize the gflags module before 77 | calling run(). 78 | 79 | Args: 80 | flow: Flow, an OAuth 2.0 Flow to step through. 81 | storage: Storage, a Storage to store the credential in. 82 | http: An instance of httplib2.Http.request 83 | or something that acts like it. 84 | 85 | Returns: 86 | Credentials, the obtained credential. 87 | """ 88 | logging.warning('This function, oauth2client.tools.run(), and the use of ' 89 | 'the gflags library are deprecated and will be removed in a future ' 90 | 'version of the library.') 91 | if FLAGS.auth_local_webserver: 92 | success = False 93 | port_number = 0 94 | for port in FLAGS.auth_host_port: 95 | port_number = port 96 | try: 97 | httpd = ClientRedirectServer((FLAGS.auth_host_name, port), 98 | ClientRedirectHandler) 99 | except socket.error, e: 100 | pass 101 | else: 102 | success = True 103 | break 104 | FLAGS.auth_local_webserver = success 105 | if not success: 106 | print 'Failed to start a local webserver listening on either port 8080' 107 | print 'or port 9090. Please check your firewall settings and locally' 108 | print 'running programs that may be blocking or using those ports.' 109 | print 110 | print 'Falling back to --noauth_local_webserver and continuing with', 111 | print 'authorization.' 112 | print 113 | 114 | if FLAGS.auth_local_webserver: 115 | oauth_callback = 'http://%s:%s/' % (FLAGS.auth_host_name, port_number) 116 | else: 117 | oauth_callback = client.OOB_CALLBACK_URN 118 | flow.redirect_uri = oauth_callback 119 | authorize_url = flow.step1_get_authorize_url() 120 | 121 | if FLAGS.auth_local_webserver: 122 | webbrowser.open(authorize_url, new=1, autoraise=True) 123 | print 'Your browser has been opened to visit:' 124 | print 125 | print ' ' + authorize_url 126 | print 127 | print 'If your browser is on a different machine then exit and re-run' 128 | print 'this application with the command-line parameter ' 129 | print 130 | print ' --noauth_local_webserver' 131 | print 132 | else: 133 | print 'Go to the following link in your browser:' 134 | print 135 | print ' ' + authorize_url 136 | print 137 | 138 | code = None 139 | if FLAGS.auth_local_webserver: 140 | httpd.handle_request() 141 | if 'error' in httpd.query_params: 142 | sys.exit('Authentication request was rejected.') 143 | if 'code' in httpd.query_params: 144 | code = httpd.query_params['code'] 145 | else: 146 | print 'Failed to find "code" in the query parameters of the redirect.' 147 | sys.exit('Try running with --noauth_local_webserver.') 148 | else: 149 | code = raw_input('Enter verification code: ').strip() 150 | 151 | try: 152 | credential = flow.step2_exchange(code, http=http) 153 | except client.FlowExchangeError, e: 154 | sys.exit('Authentication has failed: %s' % e) 155 | 156 | storage.put(credential) 157 | credential.set_store(storage) 158 | print 'Authentication successful.' 159 | 160 | return credential 161 | -------------------------------------------------------------------------------- /oauth2client/tools.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Command-line tools for authenticating via OAuth 2.0 16 | 17 | Do the OAuth 2.0 Web Server dance for a command line application. Stores the 18 | generated credentials in a common file that is used by other example apps in 19 | the same directory. 20 | """ 21 | 22 | __author__ = 'jcgregorio@google.com (Joe Gregorio)' 23 | __all__ = ['argparser', 'run_flow', 'run', 'message_if_missing'] 24 | 25 | 26 | import BaseHTTPServer 27 | import argparse 28 | import httplib2 29 | import logging 30 | import os 31 | import socket 32 | import sys 33 | import webbrowser 34 | 35 | from oauth2client import client 36 | from oauth2client import file 37 | from oauth2client import util 38 | 39 | try: 40 | from urlparse import parse_qsl 41 | except ImportError: 42 | from cgi import parse_qsl 43 | 44 | _CLIENT_SECRETS_MESSAGE = """WARNING: Please configure OAuth 2.0 45 | 46 | To make this sample run you will need to populate the client_secrets.json file 47 | found at: 48 | 49 | %s 50 | 51 | with information from the APIs Console . 52 | 53 | """ 54 | 55 | # run_parser is an ArgumentParser that contains command-line options expected 56 | # by tools.run(). Pass it in as part of the 'parents' argument to your own 57 | # ArgumentParser. 58 | argparser = argparse.ArgumentParser(add_help=False) 59 | argparser.add_argument('--auth_host_name', default='localhost', 60 | help='Hostname when running a local web server.') 61 | argparser.add_argument('--noauth_local_webserver', action='store_true', 62 | default=False, help='Do not run a local web server.') 63 | argparser.add_argument('--auth_host_port', default=[8080, 8090], type=int, 64 | nargs='*', help='Port web server should listen on.') 65 | argparser.add_argument('--logging_level', default='ERROR', 66 | choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 67 | 'CRITICAL'], 68 | help='Set the logging level of detail.') 69 | 70 | 71 | class ClientRedirectServer(BaseHTTPServer.HTTPServer): 72 | """A server to handle OAuth 2.0 redirects back to localhost. 73 | 74 | Waits for a single request and parses the query parameters 75 | into query_params and then stops serving. 76 | """ 77 | query_params = {} 78 | 79 | 80 | class ClientRedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler): 81 | """A handler for OAuth 2.0 redirects back to localhost. 82 | 83 | Waits for a single request and parses the query parameters 84 | into the servers query_params and then stops serving. 85 | """ 86 | 87 | def do_GET(s): 88 | """Handle a GET request. 89 | 90 | Parses the query parameters and prints a message 91 | if the flow has completed. Note that we can't detect 92 | if an error occurred. 93 | """ 94 | s.send_response(200) 95 | s.send_header("Content-type", "text/html") 96 | s.end_headers() 97 | query = s.path.split('?', 1)[-1] 98 | query = dict(parse_qsl(query)) 99 | s.server.query_params = query 100 | s.wfile.write("Authentication Status") 101 | s.wfile.write("

The authentication flow has completed.

") 102 | s.wfile.write("") 103 | 104 | def log_message(self, format, *args): 105 | """Do not log messages to stdout while running as command line program.""" 106 | pass 107 | 108 | 109 | @util.positional(3) 110 | def run_flow(flow, storage, flags, http=None): 111 | """Core code for a command-line application. 112 | 113 | The run() function is called from your application and runs through all the 114 | steps to obtain credentials. It takes a Flow argument and attempts to open an 115 | authorization server page in the user's default web browser. The server asks 116 | the user to grant your application access to the user's data. If the user 117 | grants access, the run() function returns new credentials. The new credentials 118 | are also stored in the Storage argument, which updates the file associated 119 | with the Storage object. 120 | 121 | It presumes it is run from a command-line application and supports the 122 | following flags: 123 | 124 | --auth_host_name: Host name to use when running a local web server 125 | to handle redirects during OAuth authorization. 126 | (default: 'localhost') 127 | 128 | --auth_host_port: Port to use when running a local web server to handle 129 | redirects during OAuth authorization.; 130 | repeat this option to specify a list of values 131 | (default: '[8080, 8090]') 132 | (an integer) 133 | 134 | --[no]auth_local_webserver: Run a local web server to handle redirects 135 | during OAuth authorization. 136 | (default: 'true') 137 | 138 | The tools module defines an ArgumentParser the already contains the flag 139 | definitions that run() requires. You can pass that ArgumentParser to your 140 | ArgumentParser constructor: 141 | 142 | parser = argparse.ArgumentParser(description=__doc__, 143 | formatter_class=argparse.RawDescriptionHelpFormatter, 144 | parents=[tools.run_parser]) 145 | flags = parser.parse_args(argv) 146 | 147 | Args: 148 | flow: Flow, an OAuth 2.0 Flow to step through. 149 | storage: Storage, a Storage to store the credential in. 150 | flags: argparse.ArgumentParser, the command-line flags. 151 | http: An instance of httplib2.Http.request 152 | or something that acts like it. 153 | 154 | Returns: 155 | Credentials, the obtained credential. 156 | """ 157 | logging.getLogger().setLevel(getattr(logging, flags.logging_level)) 158 | if not flags.noauth_local_webserver: 159 | success = False 160 | port_number = 0 161 | for port in flags.auth_host_port: 162 | port_number = port 163 | try: 164 | httpd = ClientRedirectServer((flags.auth_host_name, port), 165 | ClientRedirectHandler) 166 | except socket.error, e: 167 | pass 168 | else: 169 | success = True 170 | break 171 | flags.noauth_local_webserver = not success 172 | if not success: 173 | print 'Failed to start a local webserver listening on either port 8080' 174 | print 'or port 9090. Please check your firewall settings and locally' 175 | print 'running programs that may be blocking or using those ports.' 176 | print 177 | print 'Falling back to --noauth_local_webserver and continuing with', 178 | print 'authorization.' 179 | print 180 | 181 | if not flags.noauth_local_webserver: 182 | oauth_callback = 'http://%s:%s/' % (flags.auth_host_name, port_number) 183 | else: 184 | oauth_callback = client.OOB_CALLBACK_URN 185 | flow.redirect_uri = oauth_callback 186 | authorize_url = flow.step1_get_authorize_url() 187 | 188 | if not flags.noauth_local_webserver: 189 | webbrowser.open(authorize_url, new=1, autoraise=True) 190 | print 'Your browser has been opened to visit:' 191 | print 192 | print ' ' + authorize_url 193 | print 194 | print 'If your browser is on a different machine then exit and re-run this' 195 | print 'application with the command-line parameter ' 196 | print 197 | print ' --noauth_local_webserver' 198 | print 199 | else: 200 | print 'Go to the following link in your browser:' 201 | print 202 | print ' ' + authorize_url 203 | print 204 | 205 | code = None 206 | if not flags.noauth_local_webserver: 207 | httpd.handle_request() 208 | if 'error' in httpd.query_params: 209 | sys.exit('Authentication request was rejected.') 210 | if 'code' in httpd.query_params: 211 | code = httpd.query_params['code'] 212 | else: 213 | print 'Failed to find "code" in the query parameters of the redirect.' 214 | sys.exit('Try running with --noauth_local_webserver.') 215 | else: 216 | code = raw_input('Enter verification code: ').strip() 217 | 218 | try: 219 | credential = flow.step2_exchange(code, http=http) 220 | except client.FlowExchangeError, e: 221 | sys.exit('Authentication has failed: %s' % e) 222 | 223 | storage.put(credential) 224 | credential.set_store(storage) 225 | print 'Authentication successful.' 226 | 227 | return credential 228 | 229 | 230 | def message_if_missing(filename): 231 | """Helpful message to display if the CLIENT_SECRETS file is missing.""" 232 | 233 | return _CLIENT_SECRETS_MESSAGE % filename 234 | 235 | try: 236 | from old_run import run 237 | from old_run import FLAGS 238 | except ImportError: 239 | def run(*args, **kwargs): 240 | raise NotImplementedError( 241 | 'The gflags library must be installed to use tools.run(). ' 242 | 'Please install gflags or preferrably switch to using ' 243 | 'tools.run_flow().') 244 | -------------------------------------------------------------------------------- /oauth2client/util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2010 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | """Common utility library.""" 19 | 20 | __author__ = ['rafek@google.com (Rafe Kaplan)', 21 | 'guido@google.com (Guido van Rossum)', 22 | ] 23 | __all__ = [ 24 | 'positional', 25 | 'POSITIONAL_WARNING', 26 | 'POSITIONAL_EXCEPTION', 27 | 'POSITIONAL_IGNORE', 28 | ] 29 | 30 | import inspect 31 | import logging 32 | import types 33 | import urllib 34 | import urlparse 35 | 36 | try: 37 | from urlparse import parse_qsl 38 | except ImportError: 39 | from cgi import parse_qsl 40 | 41 | logger = logging.getLogger(__name__) 42 | 43 | POSITIONAL_WARNING = 'WARNING' 44 | POSITIONAL_EXCEPTION = 'EXCEPTION' 45 | POSITIONAL_IGNORE = 'IGNORE' 46 | POSITIONAL_SET = frozenset([POSITIONAL_WARNING, POSITIONAL_EXCEPTION, 47 | POSITIONAL_IGNORE]) 48 | 49 | positional_parameters_enforcement = POSITIONAL_WARNING 50 | 51 | def positional(max_positional_args): 52 | """A decorator to declare that only the first N arguments my be positional. 53 | 54 | This decorator makes it easy to support Python 3 style key-word only 55 | parameters. For example, in Python 3 it is possible to write: 56 | 57 | def fn(pos1, *, kwonly1=None, kwonly1=None): 58 | ... 59 | 60 | All named parameters after * must be a keyword: 61 | 62 | fn(10, 'kw1', 'kw2') # Raises exception. 63 | fn(10, kwonly1='kw1') # Ok. 64 | 65 | Example: 66 | To define a function like above, do: 67 | 68 | @positional(1) 69 | def fn(pos1, kwonly1=None, kwonly2=None): 70 | ... 71 | 72 | If no default value is provided to a keyword argument, it becomes a required 73 | keyword argument: 74 | 75 | @positional(0) 76 | def fn(required_kw): 77 | ... 78 | 79 | This must be called with the keyword parameter: 80 | 81 | fn() # Raises exception. 82 | fn(10) # Raises exception. 83 | fn(required_kw=10) # Ok. 84 | 85 | When defining instance or class methods always remember to account for 86 | 'self' and 'cls': 87 | 88 | class MyClass(object): 89 | 90 | @positional(2) 91 | def my_method(self, pos1, kwonly1=None): 92 | ... 93 | 94 | @classmethod 95 | @positional(2) 96 | def my_method(cls, pos1, kwonly1=None): 97 | ... 98 | 99 | The positional decorator behavior is controlled by 100 | util.positional_parameters_enforcement, which may be set to 101 | POSITIONAL_EXCEPTION, POSITIONAL_WARNING or POSITIONAL_IGNORE to raise an 102 | exception, log a warning, or do nothing, respectively, if a declaration is 103 | violated. 104 | 105 | Args: 106 | max_positional_arguments: Maximum number of positional arguments. All 107 | parameters after the this index must be keyword only. 108 | 109 | Returns: 110 | A decorator that prevents using arguments after max_positional_args from 111 | being used as positional parameters. 112 | 113 | Raises: 114 | TypeError if a key-word only argument is provided as a positional 115 | parameter, but only if util.positional_parameters_enforcement is set to 116 | POSITIONAL_EXCEPTION. 117 | """ 118 | def positional_decorator(wrapped): 119 | def positional_wrapper(*args, **kwargs): 120 | if len(args) > max_positional_args: 121 | plural_s = '' 122 | if max_positional_args != 1: 123 | plural_s = 's' 124 | message = '%s() takes at most %d positional argument%s (%d given)' % ( 125 | wrapped.__name__, max_positional_args, plural_s, len(args)) 126 | if positional_parameters_enforcement == POSITIONAL_EXCEPTION: 127 | raise TypeError(message) 128 | elif positional_parameters_enforcement == POSITIONAL_WARNING: 129 | logger.warning(message) 130 | else: # IGNORE 131 | pass 132 | return wrapped(*args, **kwargs) 133 | return positional_wrapper 134 | 135 | if isinstance(max_positional_args, (int, long)): 136 | return positional_decorator 137 | else: 138 | args, _, _, defaults = inspect.getargspec(max_positional_args) 139 | return positional(len(args) - len(defaults))(max_positional_args) 140 | 141 | 142 | def scopes_to_string(scopes): 143 | """Converts scope value to a string. 144 | 145 | If scopes is a string then it is simply passed through. If scopes is an 146 | iterable then a string is returned that is all the individual scopes 147 | concatenated with spaces. 148 | 149 | Args: 150 | scopes: string or iterable of strings, the scopes. 151 | 152 | Returns: 153 | The scopes formatted as a single string. 154 | """ 155 | if isinstance(scopes, types.StringTypes): 156 | return scopes 157 | else: 158 | return ' '.join(scopes) 159 | 160 | 161 | def dict_to_tuple_key(dictionary): 162 | """Converts a dictionary to a tuple that can be used as an immutable key. 163 | 164 | The resulting key is always sorted so that logically equivalent dictionaries 165 | always produce an identical tuple for a key. 166 | 167 | Args: 168 | dictionary: the dictionary to use as the key. 169 | 170 | Returns: 171 | A tuple representing the dictionary in it's naturally sorted ordering. 172 | """ 173 | return tuple(sorted(dictionary.items())) 174 | 175 | 176 | def _add_query_parameter(url, name, value): 177 | """Adds a query parameter to a url. 178 | 179 | Replaces the current value if it already exists in the URL. 180 | 181 | Args: 182 | url: string, url to add the query parameter to. 183 | name: string, query parameter name. 184 | value: string, query parameter value. 185 | 186 | Returns: 187 | Updated query parameter. Does not update the url if value is None. 188 | """ 189 | if value is None: 190 | return url 191 | else: 192 | parsed = list(urlparse.urlparse(url)) 193 | q = dict(parse_qsl(parsed[4])) 194 | q[name] = value 195 | parsed[4] = urllib.urlencode(q) 196 | return urlparse.urlunparse(parsed) 197 | -------------------------------------------------------------------------------- /oauth2client/xsrfutil.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.5 2 | # 3 | # Copyright 2010 the Melange authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Helper methods for creating & verifying XSRF tokens.""" 18 | 19 | __authors__ = [ 20 | '"Doug Coker" ', 21 | '"Joe Gregorio" ', 22 | ] 23 | 24 | 25 | import base64 26 | import hmac 27 | import os # for urandom 28 | import time 29 | 30 | from oauth2client import util 31 | 32 | 33 | # Delimiter character 34 | DELIMITER = ':' 35 | 36 | # 1 hour in seconds 37 | DEFAULT_TIMEOUT_SECS = 1*60*60 38 | 39 | @util.positional(2) 40 | def generate_token(key, user_id, action_id="", when=None): 41 | """Generates a URL-safe token for the given user, action, time tuple. 42 | 43 | Args: 44 | key: secret key to use. 45 | user_id: the user ID of the authenticated user. 46 | action_id: a string identifier of the action they requested 47 | authorization for. 48 | when: the time in seconds since the epoch at which the user was 49 | authorized for this action. If not set the current time is used. 50 | 51 | Returns: 52 | A string XSRF protection token. 53 | """ 54 | when = when or int(time.time()) 55 | digester = hmac.new(key) 56 | digester.update(str(user_id)) 57 | digester.update(DELIMITER) 58 | digester.update(action_id) 59 | digester.update(DELIMITER) 60 | digester.update(str(when)) 61 | digest = digester.digest() 62 | 63 | token = base64.urlsafe_b64encode('%s%s%d' % (digest, 64 | DELIMITER, 65 | when)) 66 | return token 67 | 68 | 69 | @util.positional(3) 70 | def validate_token(key, token, user_id, action_id="", current_time=None): 71 | """Validates that the given token authorizes the user for the action. 72 | 73 | Tokens are invalid if the time of issue is too old or if the token 74 | does not match what generateToken outputs (i.e. the token was forged). 75 | 76 | Args: 77 | key: secret key to use. 78 | token: a string of the token generated by generateToken. 79 | user_id: the user ID of the authenticated user. 80 | action_id: a string identifier of the action they requested 81 | authorization for. 82 | 83 | Returns: 84 | A boolean - True if the user is authorized for the action, False 85 | otherwise. 86 | """ 87 | if not token: 88 | return False 89 | try: 90 | decoded = base64.urlsafe_b64decode(str(token)) 91 | token_time = long(decoded.split(DELIMITER)[-1]) 92 | except (TypeError, ValueError): 93 | return False 94 | if current_time is None: 95 | current_time = time.time() 96 | # If the token is too old it's not valid. 97 | if current_time - token_time > DEFAULT_TIMEOUT_SECS: 98 | return False 99 | 100 | # The given token should match the generated one with the same time. 101 | expected_token = generate_token(key, user_id, action_id=action_id, 102 | when=token_time) 103 | if len(token) != len(expected_token): 104 | return False 105 | 106 | # Perform constant time comparison to avoid timing attacks 107 | different = 0 108 | for x, y in zip(token, expected_token): 109 | different |= ord(x) ^ ord(y) 110 | if different: 111 | return False 112 | 113 | return True 114 | -------------------------------------------------------------------------------- /project_email.html: -------------------------------------------------------------------------------- 1 | 21 | 22 | 23 | 24 | Billing Export Report For {{project}} 25 | 26 | 27 | 28 |

Billing Export Report for {{project}}

29 | 30 |

Don't want to receive this email? Unsubscribe here

31 | 32 | {% if triggered_alerts %} 33 |

Warning: These Alerts have Triggered!

34 |
35 |
    36 | {% for alert in triggered_alerts %} 37 |
  • {{ alert.name }}
  • 38 | {% endfor %} 39 |
40 |
41 |
42 | {% endif %} 43 |

Current Billing Data:

44 | 45 |
46 | 47 | 48 | 49 | 50 | 51 | {% for column in current_data.columns %} 52 | 53 | 54 | 55 | 56 | {% endfor %} 57 |
SkuAmount
{{column}}{{"$%.2f"|format(current_data.rows[0][loop.index])}}
58 |
59 | 60 | - The Billing Export Reporter 61 | 62 | 63 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlearchive/billing-export-python/46988b491aac5d270891c4eb1dfb1e973c005133/test/__init__.py -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-06.json: -------------------------------------------------------------------------------- 1 | [ ] 2 | -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-07.json: -------------------------------------------------------------------------------- 1 | [ ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-08.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-01-07T00:00:00-08:00", 4 | "endTime" : "2014-01-08T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 17 | "startTime" : "2014-01-07T00:00:00-08:00", 18 | "endTime" : "2014-01-08T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 22 | "sum" : "0", 23 | "unit" : "requests" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 31 | "startTime" : "2014-01-07T00:00:00-08:00", 32 | "endTime" : "2014-01-08T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 45 | "startTime" : "2014-01-07T00:00:00-08:00", 46 | "endTime" : "2014-01-08T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 50 | "sum" : "32212254720", 51 | "unit" : "byte-seconds" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-09.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-01-08T00:00:00-08:00", 4 | "endTime" : "2014-01-09T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "4194304", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-01-08T00:00:00-08:00", 18 | "endTime" : "2014-01-09T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 31 | "startTime" : "2014-01-08T00:00:00-08:00", 32 | "endTime" : "2014-01-09T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 45 | "startTime" : "2014-01-08T00:00:00-08:00", 46 | "endTime" : "2014-01-09T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 50 | "sum" : "0", 51 | "unit" : "requests" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | }, { 58 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 59 | "startTime" : "2014-01-08T00:00:00-08:00", 60 | "endTime" : "2014-01-09T00:00:00-08:00", 61 | "projectNumber" : "544906558578", 62 | "measurements" : [ { 63 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 64 | "sum" : "32212254720", 65 | "unit" : "byte-seconds" 66 | } ], 67 | "cost" : { 68 | "amount" : "0", 69 | "currency" : "USD" 70 | } 71 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-10.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-01-09T00:00:00-08:00", 4 | "endTime" : "2014-01-10T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "5242880", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-01-09T00:00:00-08:00", 18 | "endTime" : "2014-01-10T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 31 | "startTime" : "2014-01-09T00:00:00-08:00", 32 | "endTime" : "2014-01-10T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 45 | "startTime" : "2014-01-09T00:00:00-08:00", 46 | "endTime" : "2014-01-10T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 50 | "sum" : "0", 51 | "unit" : "requests" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | }, { 58 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 59 | "startTime" : "2014-01-09T00:00:00-08:00", 60 | "endTime" : "2014-01-10T00:00:00-08:00", 61 | "projectNumber" : "544906558578", 62 | "measurements" : [ { 63 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 64 | "sum" : "32212254720", 65 | "unit" : "byte-seconds" 66 | } ], 67 | "cost" : { 68 | "amount" : "0", 69 | "currency" : "USD" 70 | } 71 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-11.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-01-10T00:00:00-08:00", 4 | "endTime" : "2014-01-11T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 17 | "startTime" : "2014-01-10T00:00:00-08:00", 18 | "endTime" : "2014-01-11T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 22 | "sum" : "0", 23 | "unit" : "requests" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 31 | "startTime" : "2014-01-10T00:00:00-08:00", 32 | "endTime" : "2014-01-11T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 45 | "startTime" : "2014-01-10T00:00:00-08:00", 46 | "endTime" : "2014-01-11T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 50 | "sum" : "32212254720", 51 | "unit" : "byte-seconds" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-12.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-01-11T00:00:00-08:00", 4 | "endTime" : "2014-01-12T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 17 | "startTime" : "2014-01-11T00:00:00-08:00", 18 | "endTime" : "2014-01-12T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 22 | "sum" : "0", 23 | "unit" : "requests" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 31 | "startTime" : "2014-01-11T00:00:00-08:00", 32 | "endTime" : "2014-01-12T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 45 | "startTime" : "2014-01-11T00:00:00-08:00", 46 | "endTime" : "2014-01-12T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 50 | "sum" : "32212254720", 51 | "unit" : "byte-seconds" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-13.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-01-12T00:00:00-08:00", 4 | "endTime" : "2014-01-13T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 17 | "startTime" : "2014-01-12T00:00:00-08:00", 18 | "endTime" : "2014-01-13T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 22 | "sum" : "0", 23 | "unit" : "requests" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 31 | "startTime" : "2014-01-12T00:00:00-08:00", 32 | "endTime" : "2014-01-13T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 45 | "startTime" : "2014-01-12T00:00:00-08:00", 46 | "endTime" : "2014-01-13T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 50 | "sum" : "32212254720", 51 | "unit" : "byte-seconds" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-14.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-01-13T00:00:00-08:00", 4 | "endTime" : "2014-01-14T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "7340032", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-01-13T00:00:00-08:00", 18 | "endTime" : "2014-01-14T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 31 | "startTime" : "2014-01-13T00:00:00-08:00", 32 | "endTime" : "2014-01-14T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 45 | "startTime" : "2014-01-13T00:00:00-08:00", 46 | "endTime" : "2014-01-14T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 50 | "sum" : "0", 51 | "unit" : "requests" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | }, { 58 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 59 | "startTime" : "2014-01-13T00:00:00-08:00", 60 | "endTime" : "2014-01-14T00:00:00-08:00", 61 | "projectNumber" : "544906558578", 62 | "measurements" : [ { 63 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 64 | "sum" : "32212254720", 65 | "unit" : "byte-seconds" 66 | } ], 67 | "cost" : { 68 | "amount" : "0", 69 | "currency" : "USD" 70 | } 71 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-15.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-01-14T00:00:00-08:00", 4 | "endTime" : "2014-01-15T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "3145728", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-01-14T00:00:00-08:00", 18 | "endTime" : "2014-01-15T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 31 | "startTime" : "2014-01-14T00:00:00-08:00", 32 | "endTime" : "2014-01-15T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 45 | "startTime" : "2014-01-14T00:00:00-08:00", 46 | "endTime" : "2014-01-15T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 50 | "sum" : "0", 51 | "unit" : "requests" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | }, { 58 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 59 | "startTime" : "2014-01-14T00:00:00-08:00", 60 | "endTime" : "2014-01-15T00:00:00-08:00", 61 | "projectNumber" : "544906558578", 62 | "measurements" : [ { 63 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 64 | "sum" : "32212254720", 65 | "unit" : "byte-seconds" 66 | } ], 67 | "cost" : { 68 | "amount" : "0", 69 | "currency" : "USD" 70 | } 71 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-16.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-01-15T00:00:00-08:00", 4 | "endTime" : "2014-01-16T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "2097152", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-01-15T00:00:00-08:00", 18 | "endTime" : "2014-01-16T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 31 | "startTime" : "2014-01-15T00:00:00-08:00", 32 | "endTime" : "2014-01-16T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 45 | "startTime" : "2014-01-15T00:00:00-08:00", 46 | "endTime" : "2014-01-16T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 50 | "sum" : "0", 51 | "unit" : "requests" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | }, { 58 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 59 | "startTime" : "2014-01-15T00:00:00-08:00", 60 | "endTime" : "2014-01-16T00:00:00-08:00", 61 | "projectNumber" : "544906558578", 62 | "measurements" : [ { 63 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 64 | "sum" : "32212254720", 65 | "unit" : "byte-seconds" 66 | } ], 67 | "cost" : { 68 | "amount" : "0", 69 | "currency" : "USD" 70 | } 71 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-17.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-01-16T00:00:00-08:00", 4 | "endTime" : "2014-01-17T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "3145728", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-01-16T00:00:00-08:00", 18 | "endTime" : "2014-01-17T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 31 | "startTime" : "2014-01-16T00:00:00-08:00", 32 | "endTime" : "2014-01-17T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 45 | "startTime" : "2014-01-16T00:00:00-08:00", 46 | "endTime" : "2014-01-17T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 50 | "sum" : "0", 51 | "unit" : "requests" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | }, { 58 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 59 | "startTime" : "2014-01-16T00:00:00-08:00", 60 | "endTime" : "2014-01-17T00:00:00-08:00", 61 | "projectNumber" : "544906558578", 62 | "measurements" : [ { 63 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 64 | "sum" : "32212254720", 65 | "unit" : "byte-seconds" 66 | } ], 67 | "cost" : { 68 | "amount" : "0", 69 | "currency" : "USD" 70 | } 71 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-18.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-01-17T00:00:00-08:00", 4 | "endTime" : "2014-01-18T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "5242880", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-01-17T00:00:00-08:00", 18 | "endTime" : "2014-01-18T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 31 | "startTime" : "2014-01-17T00:00:00-08:00", 32 | "endTime" : "2014-01-18T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 45 | "startTime" : "2014-01-17T00:00:00-08:00", 46 | "endTime" : "2014-01-18T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 50 | "sum" : "0", 51 | "unit" : "requests" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | }, { 58 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 59 | "startTime" : "2014-01-17T00:00:00-08:00", 60 | "endTime" : "2014-01-18T00:00:00-08:00", 61 | "projectNumber" : "544906558578", 62 | "measurements" : [ { 63 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 64 | "sum" : "32212254720", 65 | "unit" : "byte-seconds" 66 | } ], 67 | "cost" : { 68 | "amount" : "0", 69 | "currency" : "USD" 70 | } 71 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-19.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-01-18T00:00:00-08:00", 4 | "endTime" : "2014-01-19T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 17 | "startTime" : "2014-01-18T00:00:00-08:00", 18 | "endTime" : "2014-01-19T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 22 | "sum" : "0", 23 | "unit" : "requests" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 31 | "startTime" : "2014-01-18T00:00:00-08:00", 32 | "endTime" : "2014-01-19T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 45 | "startTime" : "2014-01-18T00:00:00-08:00", 46 | "endTime" : "2014-01-19T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 50 | "sum" : "32212254720", 51 | "unit" : "byte-seconds" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-20.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-01-19T00:00:00-08:00", 4 | "endTime" : "2014-01-20T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 17 | "startTime" : "2014-01-19T00:00:00-08:00", 18 | "endTime" : "2014-01-20T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 22 | "sum" : "0", 23 | "unit" : "requests" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 31 | "startTime" : "2014-01-19T00:00:00-08:00", 32 | "endTime" : "2014-01-20T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 45 | "startTime" : "2014-01-19T00:00:00-08:00", 46 | "endTime" : "2014-01-20T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 50 | "sum" : "32212254720", 51 | "unit" : "byte-seconds" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-21.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-01-20T00:00:00-08:00", 4 | "endTime" : "2014-01-21T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "10485760", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-01-20T00:00:00-08:00", 18 | "endTime" : "2014-01-21T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 31 | "startTime" : "2014-01-20T00:00:00-08:00", 32 | "endTime" : "2014-01-21T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 45 | "startTime" : "2014-01-20T00:00:00-08:00", 46 | "endTime" : "2014-01-21T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 50 | "sum" : "0", 51 | "unit" : "requests" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | }, { 58 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 59 | "startTime" : "2014-01-20T00:00:00-08:00", 60 | "endTime" : "2014-01-21T00:00:00-08:00", 61 | "projectNumber" : "544906558578", 62 | "measurements" : [ { 63 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 64 | "sum" : "32212254720", 65 | "unit" : "byte-seconds" 66 | } ], 67 | "cost" : { 68 | "amount" : "0", 69 | "currency" : "USD" 70 | } 71 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-22.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-01-21T00:00:00-08:00", 4 | "endTime" : "2014-01-22T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 17 | "startTime" : "2014-01-21T00:00:00-08:00", 18 | "endTime" : "2014-01-22T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 22 | "sum" : "0", 23 | "unit" : "requests" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 31 | "startTime" : "2014-01-21T00:00:00-08:00", 32 | "endTime" : "2014-01-22T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 45 | "startTime" : "2014-01-21T00:00:00-08:00", 46 | "endTime" : "2014-01-22T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 50 | "sum" : "32212254720", 51 | "unit" : "byte-seconds" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-23.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-01-22T00:00:00-08:00", 4 | "endTime" : "2014-01-23T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "10485760", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-01-22T00:00:00-08:00", 18 | "endTime" : "2014-01-23T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 31 | "startTime" : "2014-01-22T00:00:00-08:00", 32 | "endTime" : "2014-01-23T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 45 | "startTime" : "2014-01-22T00:00:00-08:00", 46 | "endTime" : "2014-01-23T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 50 | "sum" : "0", 51 | "unit" : "requests" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | }, { 58 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 59 | "startTime" : "2014-01-22T00:00:00-08:00", 60 | "endTime" : "2014-01-23T00:00:00-08:00", 61 | "projectNumber" : "544906558578", 62 | "measurements" : [ { 63 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 64 | "sum" : "32212254720", 65 | "unit" : "byte-seconds" 66 | } ], 67 | "cost" : { 68 | "amount" : "0", 69 | "currency" : "USD" 70 | } 71 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-24.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-01-23T00:00:00-08:00", 4 | "endTime" : "2014-01-24T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 17 | "startTime" : "2014-01-23T00:00:00-08:00", 18 | "endTime" : "2014-01-24T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 22 | "sum" : "0", 23 | "unit" : "requests" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 31 | "startTime" : "2014-01-23T00:00:00-08:00", 32 | "endTime" : "2014-01-24T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 45 | "startTime" : "2014-01-23T00:00:00-08:00", 46 | "endTime" : "2014-01-24T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 50 | "sum" : "32212254720", 51 | "unit" : "byte-seconds" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-25.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-01-24T00:00:00-08:00", 4 | "endTime" : "2014-01-25T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "1048576", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-01-24T00:00:00-08:00", 18 | "endTime" : "2014-01-25T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 31 | "startTime" : "2014-01-24T00:00:00-08:00", 32 | "endTime" : "2014-01-25T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 45 | "startTime" : "2014-01-24T00:00:00-08:00", 46 | "endTime" : "2014-01-25T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 50 | "sum" : "0", 51 | "unit" : "requests" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | }, { 58 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 59 | "startTime" : "2014-01-24T00:00:00-08:00", 60 | "endTime" : "2014-01-25T00:00:00-08:00", 61 | "projectNumber" : "544906558578", 62 | "measurements" : [ { 63 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 64 | "sum" : "32212254720", 65 | "unit" : "byte-seconds" 66 | } ], 67 | "cost" : { 68 | "amount" : "0", 69 | "currency" : "USD" 70 | } 71 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-26.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-01-25T00:00:00-08:00", 4 | "endTime" : "2014-01-26T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 17 | "startTime" : "2014-01-25T00:00:00-08:00", 18 | "endTime" : "2014-01-26T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 22 | "sum" : "0", 23 | "unit" : "requests" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 31 | "startTime" : "2014-01-25T00:00:00-08:00", 32 | "endTime" : "2014-01-26T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 45 | "startTime" : "2014-01-25T00:00:00-08:00", 46 | "endTime" : "2014-01-26T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 50 | "sum" : "32212254720", 51 | "unit" : "byte-seconds" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-27.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-01-26T00:00:00-08:00", 4 | "endTime" : "2014-01-27T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassARequest", 17 | "startTime" : "2014-01-26T00:00:00-08:00", 18 | "endTime" : "2014-01-27T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassARequest", 22 | "sum" : "0", 23 | "unit" : "requests" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 31 | "startTime" : "2014-01-26T00:00:00-08:00", 32 | "endTime" : "2014-01-27T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/ClassBRequest", 36 | "sum" : "0", 37 | "unit" : "requests" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 45 | "startTime" : "2014-01-26T00:00:00-08:00", 46 | "endTime" : "2014-01-27T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 50 | "sum" : "32212254720", 51 | "unit" : "byte-seconds" 52 | } ], 53 | "cost" : { 54 | "amount" : "0", 55 | "currency" : "USD" 56 | } 57 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-28.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-01-27T00:00:00-08:00", 4 | "endTime" : "2014-01-28T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 17 | "startTime" : "2014-01-27T00:00:00-08:00", 18 | "endTime" : "2014-01-28T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 22 | "sum" : "32212254720", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-29.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-01-28T00:00:00-08:00", 4 | "endTime" : "2014-01-29T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "2097152", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-01-28T00:00:00-08:00", 18 | "endTime" : "2014-01-29T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 31 | "startTime" : "2014-01-28T00:00:00-08:00", 32 | "endTime" : "2014-01-29T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 36 | "sum" : "32212254720", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-30.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-01-29T00:00:00-08:00", 4 | "endTime" : "2014-01-30T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 17 | "startTime" : "2014-01-29T00:00:00-08:00", 18 | "endTime" : "2014-01-30T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 22 | "sum" : "32212254720", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-01-31.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-01-30T00:00:00-08:00", 4 | "endTime" : "2014-01-31T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "9437184", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-01-30T00:00:00-08:00", 18 | "endTime" : "2014-01-31T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 31 | "startTime" : "2014-01-30T00:00:00-08:00", 32 | "endTime" : "2014-01-31T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 36 | "sum" : "32212254720", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-01.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-01-31T00:00:00-08:00", 4 | "endTime" : "2014-02-01T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "5242880", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-01-31T00:00:00-08:00", 18 | "endTime" : "2014-02-01T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 31 | "startTime" : "2014-01-31T00:00:00-08:00", 32 | "endTime" : "2014-02-01T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 36 | "sum" : "32212254720", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-02.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-02-01T00:00:00-08:00", 4 | "endTime" : "2014-02-02T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 17 | "startTime" : "2014-02-01T00:00:00-08:00", 18 | "endTime" : "2014-02-02T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 22 | "sum" : "32212254720", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0.000001", 27 | "currency" : "USD" 28 | } 29 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-03.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-02-02T00:00:00-08:00", 4 | "endTime" : "2014-02-03T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 17 | "startTime" : "2014-02-02T00:00:00-08:00", 18 | "endTime" : "2014-02-03T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 22 | "sum" : "32212254720", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0.000001", 27 | "currency" : "USD" 28 | } 29 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-04.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-02-03T00:00:00-08:00", 4 | "endTime" : "2014-02-04T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "3145728", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-02-03T00:00:00-08:00", 18 | "endTime" : "2014-02-04T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 31 | "startTime" : "2014-02-03T00:00:00-08:00", 32 | "endTime" : "2014-02-04T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 36 | "sum" : "32212254720", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0.000001", 41 | "currency" : "USD" 42 | } 43 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-05.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-02-04T00:00:00-08:00", 4 | "endTime" : "2014-02-05T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "1048576", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-02-04T00:00:00-08:00", 18 | "endTime" : "2014-02-05T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 31 | "startTime" : "2014-02-04T00:00:00-08:00", 32 | "endTime" : "2014-02-05T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 36 | "sum" : "32212254720", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0.000001", 41 | "currency" : "USD" 42 | } 43 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-06.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-02-05T00:00:00-08:00", 4 | "endTime" : "2014-02-06T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 17 | "startTime" : "2014-02-05T00:00:00-08:00", 18 | "endTime" : "2014-02-06T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 22 | "sum" : "32212254720", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0.000001", 27 | "currency" : "USD" 28 | } 29 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-07.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-02-06T00:00:00-08:00", 4 | "endTime" : "2014-02-07T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "1048576", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-02-06T00:00:00-08:00", 18 | "endTime" : "2014-02-07T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 31 | "startTime" : "2014-02-06T00:00:00-08:00", 32 | "endTime" : "2014-02-07T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 36 | "sum" : "32212254720", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0.000001", 41 | "currency" : "USD" 42 | } 43 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-08.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-02-07T00:00:00-08:00", 4 | "endTime" : "2014-02-08T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 17 | "startTime" : "2014-02-07T00:00:00-08:00", 18 | "endTime" : "2014-02-08T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 22 | "sum" : "32212254720", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0.000001", 27 | "currency" : "USD" 28 | } 29 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-09.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-02-08T00:00:00-08:00", 4 | "endTime" : "2014-02-09T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 17 | "startTime" : "2014-02-08T00:00:00-08:00", 18 | "endTime" : "2014-02-09T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 22 | "sum" : "32212254720", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0.000001", 27 | "currency" : "USD" 28 | } 29 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-10.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-02-09T00:00:00-08:00", 4 | "endTime" : "2014-02-10T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 17 | "startTime" : "2014-02-09T00:00:00-08:00", 18 | "endTime" : "2014-02-10T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 22 | "sum" : "32212254720", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0.000001", 27 | "currency" : "USD" 28 | } 29 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-11.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-02-10T00:00:00-08:00", 4 | "endTime" : "2014-02-11T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "7340032", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-02-10T00:00:00-08:00", 18 | "endTime" : "2014-02-11T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 31 | "startTime" : "2014-02-10T00:00:00-08:00", 32 | "endTime" : "2014-02-11T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 36 | "sum" : "32212254720", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0.000001", 41 | "currency" : "USD" 42 | } 43 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-12.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-02-11T00:00:00-08:00", 4 | "endTime" : "2014-02-12T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "6291456", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-02-11T00:00:00-08:00", 18 | "endTime" : "2014-02-12T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8024832000", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 31 | "startTime" : "2014-02-11T00:00:00-08:00", 32 | "endTime" : "2014-02-12T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 36 | "sum" : "32212254720", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0.000001", 41 | "currency" : "USD" 42 | } 43 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-13.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-02-12T00:00:00-08:00", 4 | "endTime" : "2014-02-13T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "4194304", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-02-12T00:00:00-08:00", 18 | "endTime" : "2014-02-13T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 31 | "startTime" : "2014-02-12T00:00:00-08:00", 32 | "endTime" : "2014-02-13T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 36 | "sum" : "32212254720", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0.000001", 41 | "currency" : "USD" 42 | } 43 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-14.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-02-13T00:00:00-08:00", 4 | "endTime" : "2014-02-14T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "2097152", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-02-13T00:00:00-08:00", 18 | "endTime" : "2014-02-14T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 31 | "startTime" : "2014-02-13T00:00:00-08:00", 32 | "endTime" : "2014-02-14T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 36 | "sum" : "32212254720", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0.000001", 41 | "currency" : "USD" 42 | } 43 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-15.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-02-14T00:00:00-08:00", 4 | "endTime" : "2014-02-15T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "5242880", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-02-14T00:00:00-08:00", 18 | "endTime" : "2014-02-15T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 31 | "startTime" : "2014-02-14T00:00:00-08:00", 32 | "endTime" : "2014-02-15T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 36 | "sum" : "32212254720", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0.000001", 41 | "currency" : "USD" 42 | } 43 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-16.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-02-15T00:00:00-08:00", 4 | "endTime" : "2014-02-16T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 17 | "startTime" : "2014-02-15T00:00:00-08:00", 18 | "endTime" : "2014-02-16T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 22 | "sum" : "32212254720", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0.000001", 27 | "currency" : "USD" 28 | } 29 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-17.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-02-16T00:00:00-08:00", 4 | "endTime" : "2014-02-17T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 17 | "startTime" : "2014-02-16T00:00:00-08:00", 18 | "endTime" : "2014-02-17T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 22 | "sum" : "32212254720", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0.000001", 27 | "currency" : "USD" 28 | } 29 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-18.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-02-17T00:00:00-08:00", 4 | "endTime" : "2014-02-18T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 17 | "startTime" : "2014-02-17T00:00:00-08:00", 18 | "endTime" : "2014-02-18T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 22 | "sum" : "32212254720", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0.000001", 27 | "currency" : "USD" 28 | } 29 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-19.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-02-18T00:00:00-08:00", 4 | "endTime" : "2014-02-19T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "12582912", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-02-18T00:00:00-08:00", 18 | "endTime" : "2014-02-19T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 31 | "startTime" : "2014-02-18T00:00:00-08:00", 32 | "endTime" : "2014-02-19T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 36 | "sum" : "32212254720", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0.000001", 41 | "currency" : "USD" 42 | } 43 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-20.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-02-19T00:00:00-08:00", 4 | "endTime" : "2014-02-20T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "17349738496", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-02-19T00:00:00-08:00", 18 | "endTime" : "2014-02-20T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-21.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 3 | "startTime" : "2014-02-19T00:00:00-08:00", 4 | "endTime" : "2014-02-20T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 8 | "sum" : "32212254720", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0.000001", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 17 | "startTime" : "2014-02-20T00:00:00-08:00", 18 | "endTime" : "2014-02-21T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 22 | "sum" : "15728640", 23 | "unit" : "bytes" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 31 | "startTime" : "2014-02-20T00:00:00-08:00", 32 | "endTime" : "2014-02-21T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/big-query/Storage", 36 | "sum" : "8739704832", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0", 41 | "currency" : "USD" 42 | } 43 | }, { 44 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 45 | "startTime" : "2014-02-20T00:00:00-08:00", 46 | "endTime" : "2014-02-21T00:00:00-08:00", 47 | "projectNumber" : "544906558578", 48 | "measurements" : [ { 49 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 50 | "sum" : "32212254720", 51 | "unit" : "byte-seconds" 52 | } ], 53 | "cost" : { 54 | "amount" : "0.000001", 55 | "currency" : "USD" 56 | } 57 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-22.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Analysis", 3 | "startTime" : "2014-02-21T00:00:00-08:00", 4 | "endTime" : "2014-02-22T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Analysis", 8 | "sum" : "4194304", 9 | "unit" : "bytes" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 17 | "startTime" : "2014-02-21T00:00:00-08:00", 18 | "endTime" : "2014-02-22T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/big-query/Storage", 22 | "sum" : "8739704832", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0", 27 | "currency" : "USD" 28 | } 29 | }, { 30 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 31 | "startTime" : "2014-02-21T00:00:00-08:00", 32 | "endTime" : "2014-02-22T00:00:00-08:00", 33 | "projectNumber" : "544906558578", 34 | "measurements" : [ { 35 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 36 | "sum" : "32212254720", 37 | "unit" : "byte-seconds" 38 | } ], 39 | "cost" : { 40 | "amount" : "0.000001", 41 | "currency" : "USD" 42 | } 43 | } ] -------------------------------------------------------------------------------- /test/data/exports/analytics-bigquery-demo-2014-02-23.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "lineItemId" : "com.google.cloud/services/big-query/Storage", 3 | "startTime" : "2014-02-22T00:00:00-08:00", 4 | "endTime" : "2014-02-23T00:00:00-08:00", 5 | "projectNumber" : "544906558578", 6 | "measurements" : [ { 7 | "measurementId" : "com.google.cloud/services/big-query/Storage", 8 | "sum" : "8739704832", 9 | "unit" : "byte-seconds" 10 | } ], 11 | "cost" : { 12 | "amount" : "0", 13 | "currency" : "USD" 14 | } 15 | }, { 16 | "lineItemId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 17 | "startTime" : "2014-02-22T00:00:00-08:00", 18 | "endTime" : "2014-02-23T00:00:00-08:00", 19 | "projectNumber" : "544906558578", 20 | "measurements" : [ { 21 | "measurementId" : "com.google.cloud/services/cloud-storage/StorageGbsec", 22 | "sum" : "32212254720", 23 | "unit" : "byte-seconds" 24 | } ], 25 | "cost" : { 26 | "amount" : "0.000001", 27 | "currency" : "USD" 28 | } 29 | } ] -------------------------------------------------------------------------------- /test/data/notifications/google-platform-demo-2014-02-04.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "storage#object", 3 | "id": "platform-demo-billing-export/google-platform-demo-2014-02-04.json/1393932402214000", 4 | "selfLink": "https://www.googleapis.com/storage/v1beta2/b/platform-demo-billing-export/o/google-platform-demo-2014-02-04.json", 5 | "name": "google-platform-demo-2014-02-04.json", 6 | "bucket": "platform-demo-billing-export", 7 | "generation": "1393932402214000", 8 | "metageneration": "1", 9 | "contentType": "application/json", 10 | "updated": "2014-02-04T11:26:42.078Z", 11 | "timeDeleted": "2014-02-04T15:38:33.413Z", 12 | "size": "3", 13 | "md5Hash": "+pSX9azMr8w+YBlle9xesQ==", 14 | "mediaLink": "https://www.googleapis.com/storage/v1beta2/b/platform-demo-billing-export/o/google-platform-demo-2014-02-04.json?generation=1393932402214000&alt=media", 15 | "owner": { 16 | "entity": "user-00b4903a9703b365e9dfd610758eb08b857edbd47b3eb404440b5862e716e6b6", 17 | "entityId": "00b4903a9703b365e9dfd610758eb08b857edbd47b3eb404440b5862e716e6b6" 18 | }, 19 | "crc32c": "lFrVnQ==", 20 | "etag": "CPCIs+3i+LwCEAE=" 21 | } 22 | -------------------------------------------------------------------------------- /test/data/notifications/google-platform-demo-2014-02-23.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "storage#object", 3 | "id": "platform-demo-billing-export/google-platform-demo-2014-02-04.json/1393932402214000", 4 | "selfLink": "https://www.googleapis.com/storage/v1beta2/b/platform-demo-billing-export/o/google-platform-demo-2014-02-04.json", 5 | "name": "google-platform-demo-2014-02-04.json", 6 | "bucket": "platform-demo-billing-export", 7 | "generation": "1393932402214000", 8 | "metageneration": "1", 9 | "contentType": "application/json", 10 | "updated": "2014-02-04T11:26:42.078Z", 11 | "timeDeleted": "2014-02-04T15:38:33.413Z", 12 | "size": "3", 13 | "md5Hash": "+pSX9azMr8w+YBlle9xesQ==", 14 | "mediaLink": "https://www.googleapis.com/storage/v1beta2/b/platform-demo-billing-export/o/google-platform-demo-2014-02-04.json?generation=1393932402214000&alt=media", 15 | "owner": { 16 | "entity": "user-00b4903a9703b365e9dfd610758eb08b857edbd47b3eb404440b5862e716e6b6", 17 | "entityId": "00b4903a9703b365e9dfd610758eb08b857edbd47b3eb404440b5862e716e6b6" 18 | }, 19 | "crc32c": "lFrVnQ==", 20 | "etag": "CPCIs+3i+LwCEAE=" 21 | } 22 | -------------------------------------------------------------------------------- /test/run_server_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import optparse 3 | import os 4 | import sys 5 | # Install the Python unittest package before you run this script. 6 | import unittest 7 | 8 | USAGE = """%prog SDK_PATH TEST_PATH 9 | Run unit tests for App Engine apps. 10 | 11 | SDK_PATH Path to the SDK installation 12 | TEST_PATH Path to package containing test modules 13 | 14 | For example: 15 | test/run_server_tests.py ~/local/google-cloud-sdk/platform/google_appengine test 16 | """ 17 | 18 | 19 | def main(sdk_path, test_path): 20 | sys.path.insert(0, sdk_path) 21 | sys.path.insert(0, os.path.join(test_path, '../')) 22 | sys.path.insert(0, os.path.join(test_path)) 23 | import dev_appserver 24 | dev_appserver.fix_sys_path() 25 | suite = unittest.loader.TestLoader().discover(test_path) 26 | unittest.TextTestRunner(verbosity=10).run(suite) 27 | 28 | 29 | if __name__ == '__main__': 30 | parser = optparse.OptionParser(USAGE) 31 | options, args = parser.parse_args() 32 | if len(args) != 2: 33 | print 'Error: Exactly 2 arguments required.' 34 | parser.print_help() 35 | sys.exit(1) 36 | SDK_PATH = args[0] 37 | TEST_PATH = args[1] 38 | main(SDK_PATH, TEST_PATH) 39 | -------------------------------------------------------------------------------- /test/test.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | import json 3 | import logging 4 | import os 5 | import unittest 6 | 7 | import cloudstorage as gcs 8 | import main 9 | import webapp2 10 | import webtest 11 | 12 | from google.appengine.ext import testbed 13 | 14 | 15 | class TestParseData(unittest.TestCase): 16 | """Tests parsing billing export data into a datatable.""" 17 | 18 | def LoadTestData(self): 19 | data_dir = 'test/data/exports' 20 | for file_name in os.listdir(data_dir): 21 | local_data_file = open(os.sep.join([data_dir, file_name])) 22 | gcs_data_file = gcs.open(main.BUCKET + '/' + file_name, 'w') 23 | gcs_data_file.write(local_data_file.read()) 24 | gcs_data_file.close() 25 | local_data_file.close() 26 | 27 | def setUp(self): 28 | #logging.basicConfig(level=logging.DEBUG) 29 | self.testbed = testbed.Testbed() 30 | self.testbed.setup_env(app_id='_') 31 | self.testbed.activate() 32 | self.testbed.init_all_stubs() 33 | main.UseLocalGCS() 34 | self.LoadTestData() 35 | app = webapp2.WSGIApplication([('/objectChangeNotification', 36 | main.ObjectChangeNotification)]) 37 | self.testapp = webtest.TestApp(app) 38 | 39 | def testTotalRelativeDifferenceAlert(self): 40 | compute_engine_alert = main.Alert() 41 | compute_engine_alert.range = main.AlertRange.ONE_DAY 42 | compute_engine_alert.trigger = main.AlertTrigger.RELATIVE_CHANGE 43 | compute_engine_alert.target_value = 'Total' 44 | compute_engine_alert.trigger_value = 1.1 45 | v = compute_engine_alert.isAlertTriggered('google-platform-demo', 46 | date(2014, 02, 01)) 47 | assert v 48 | 49 | def testSKURelativeDifferenceAlert(self): 50 | compute_engine_alert = main.Alert() 51 | compute_engine_alert.range = main.AlertRange.ONE_WEEK 52 | compute_engine_alert.trigger = main.AlertTrigger.RELATIVE_CHANGE 53 | compute_engine_alert.target_value = 'Cloud/compute-engine' 54 | compute_engine_alert.trigger_value = 300 55 | v = compute_engine_alert.isAlertTriggered('google-platform-demo', 56 | date(2014, 02, 01)) 57 | assert v 58 | 59 | def testNotSKURelativeDifferenceAlert(self): 60 | compute_engine_alert = main.Alert() 61 | compute_engine_alert.range = main.AlertRange.ONE_WEEK 62 | compute_engine_alert.trigger = main.AlertTrigger.RELATIVE_CHANGE 63 | compute_engine_alert.target_value = 'Cloud/compute-engine' 64 | compute_engine_alert.trigger_value = 400 65 | v = compute_engine_alert.isAlertTriggered('google-platform-demo', 66 | date(2014, 02, 01)) 67 | assert not v 68 | 69 | def testNegativetSKURelativeDifferenceAlert(self): 70 | compute_engine_alert = main.Alert() 71 | compute_engine_alert.range = main.AlertRange.ONE_WEEK 72 | compute_engine_alert.trigger = main.AlertTrigger.RELATIVE_CHANGE 73 | compute_engine_alert.target_value = 'Cloud/compute-engine' 74 | compute_engine_alert.trigger_value = -300 75 | v = compute_engine_alert.isAlertTriggered('google-platform-demo', 76 | date(2014, 02, 01)) 77 | assert not v 78 | 79 | def testTotalDifferenceAlert(self): 80 | # data_table = main.GetAllBillingDataTable('google-platform-demo') 81 | compute_engine_alert = main.Alert() 82 | compute_engine_alert.range = main.AlertRange.ONE_DAY 83 | compute_engine_alert.target_value = 'Total' 84 | compute_engine_alert.trigger = main.AlertTrigger.TOTAL_CHANGE 85 | compute_engine_alert.trigger_value = 10.00 86 | v = compute_engine_alert.isAlertTriggered('google-platform-demo', 87 | date(2014, 02, 04)) 88 | self.assertTrue(v) 89 | # 167.33016600000002 2/3 90 | # 184.93568900000002 2/4 91 | 92 | def testSimpleObjectChangeNotification(self): 93 | data_dir = 'test/data/notifications' 94 | for file_name in os.listdir(data_dir): 95 | local_notification = open(os.sep.join([data_dir, file_name])).read() 96 | notification_dict = json.loads(local_notification) 97 | response = self.testapp.post_json('/objectChangeNotification', 98 | notification_dict) 99 | logging.debug(repr(response)) 100 | self.assertEqual(response.status_int, 200) 101 | 102 | def testEmptyObjectChangeNotification(self): 103 | data_dir = 'test/data/notifications' 104 | for file_name in os.listdir(data_dir): 105 | response = self.testapp.post('/objectChangeNotification') 106 | logging.debug(repr(response)) 107 | self.assertEqual(response.status_int, 200) 108 | 109 | def testDailySummaryObjectChangeNotification(self): 110 | data_dir = 'test/data/notifications' 111 | for file_name in os.listdir(data_dir): 112 | local_notification = open(os.sep.join([data_dir, file_name])).read() 113 | notification_dict = json.loads(local_notification) 114 | project_date = main.MatchProjectDate(file_name) 115 | subscription = main.Subscription.getInstance(project_date[0]) 116 | subscription.daily_summary = True 117 | response = self.testapp.post_json('/objectChangeNotification', 118 | notification_dict) 119 | logging.debug(repr(response)) 120 | self.assertEqual(response.status_int, 200) 121 | 122 | def testAlertSummaryObjectChangeNotification(self): 123 | data_dir = 'test/data/notifications' 124 | file_name = 'google-platform-demo-2014-02-04.json' 125 | project_date = main.MatchProjectDate(file_name) 126 | 127 | compute_engine_alert = main.Alert(parent=main.Alert.entity_group) 128 | compute_engine_alert.name = 'Test Compute Engine Alert Alert' 129 | compute_engine_alert.range = main.AlertRange.ONE_DAY 130 | compute_engine_alert.target_value = 'Total' 131 | compute_engine_alert.trigger = main.AlertTrigger.TOTAL_CHANGE 132 | compute_engine_alert.trigger_value = 10.00 133 | compute_engine_alert.project = project_date[0] 134 | compute_engine_alert.put() 135 | subscription = main.Subscription.getInstance(project_date[0]) 136 | subscription.daily_summary = False 137 | local_notification = open(os.sep.join([data_dir, file_name])).read() 138 | notification_dict = json.loads(local_notification) 139 | project_date = main.MatchProjectDate(file_name) 140 | subscription = main.Subscription.getInstance(project_date[0]) 141 | subscription.daily_summary = True 142 | response = self.testapp.post_json('/objectChangeNotification', 143 | notification_dict) 144 | logging.debug(repr(response)) 145 | self.assertEqual(response.status_int, 200) 146 | 147 | def tearDown(self): 148 | # for gcs_object in gcs.listbucket(main.BUCKET): 149 | # gcs.delete(gcs_object.filename) 150 | self.testbed.deactivate() 151 | --------------------------------------------------------------------------------