Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix r2016b tests #234

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 29 additions & 24 deletions +dj/+store_plugins/S3.m
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,8 @@ function remove_object(self, external_filepath)
credential_scope ', ' 'SignedHeaders=' signed_headers ', ' ...
'Signature=' signature];
url = [protocol host canonical_uri '?' canonical_querystring];
if ~strcmpi(method, 'head')

try
headers = {...
'content_type', content_type; ...
'host', host; ...
Expand All @@ -207,6 +207,7 @@ function remove_object(self, external_filepath)
'HeaderFields', headers, ...
'RequestMethod', lower(method), ...
'Timeout', 60, ...
'CertificateFilename', 'default', ...
'ContentType', 'binary', ...
'MediaType', content_type, ...
'CharacterEncoding', 'ISO-8859-1'...
Expand All @@ -217,30 +218,34 @@ function remove_object(self, external_filepath)
else
data = webwrite(url, char(payload_bin'), options);
end
else
headers = [...
matlab.net.http.HeaderField('content_type', content_type), ...
matlab.net.http.HeaderField('host', host), ...
matlab.net.http.HeaderField('X-Amz-Date', amzdate), ...
matlab.net.http.HeaderField('X-Amz-Content-Sha256', payload_hash), ...
matlab.net.http.HeaderField('Authorization', authorization_header), ...
matlab.net.http.field.AcceptField(...
[matlab.net.http.MediaType(content_type)]) ...
];

request = matlab.net.http.RequestMessage(lower(method), headers, ...
matlab.net.http.MessageBody(payload_bin));
response = request.send(url, matlab.net.http.HTTPOptions(...
'ConnectTimeout', 60));
if response.StatusCode ~= matlab.net.http.StatusCode.OK && ...
response.StatusCode ~= matlab.net.http.StatusCode.NoContent
error(['DataJoint:RequestError:' char(response.StatusCode)], ...
'Request failed on route `%s` with status `%s`.', canonical_uri, ...
response.StatusLine);
catch ME
if strcmp(ME.identifier,'MATLAB:weboptions:unrecognizedStringChoice')
headers = [...
matlab.net.http.HeaderField('content_type', content_type), ...
matlab.net.http.HeaderField('host', host), ...
matlab.net.http.HeaderField('X-Amz-Date', amzdate), ...
matlab.net.http.HeaderField('X-Amz-Content-Sha256', payload_hash), ...
matlab.net.http.HeaderField('Authorization', authorization_header), ...
matlab.net.http.field.AcceptField(...
[matlab.net.http.MediaType(content_type)]) ...
];

request = matlab.net.http.RequestMessage(lower(method), headers, ...
matlab.net.http.MessageBody(payload_bin));
response = request.send(url, matlab.net.http.HTTPOptions(...
'ConnectTimeout', 60, 'CertificateFilename', 'default'));
if response.StatusCode ~= matlab.net.http.StatusCode.OK && ...
response.StatusCode ~= matlab.net.http.StatusCode.NoContent
error(['DataJoint:RequestError:' char(response.StatusCode)], ...
'Request failed on route `%s` with status `%s`.', canonical_uri,...
response.StatusLine);
else
data = response.Body.Data;
end
else
data = response.Body.Data;
rethrow(ME);
end
end
end
end
end
end
Expand Down
11 changes: 0 additions & 11 deletions +tests/Main.m

This file was deleted.

16 changes: 6 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,21 @@ jobs:
include:
- <<: *slim
env:
- MATLAB_VERSION: R2018b
- MATLAB_VERSION: R2019a
- MYSQL_TAG: 8.0
- <<: *slim
env:
- MATLAB_VERSION: R2018b
- MATLAB_VERSION: R2019a
- MYSQL_TAG: 5.7
- <<: *slim
env:
- MATLAB_VERSION: R2018b
- MYSQL_TAG: 5.6
- <<: *slim
env:
- MATLAB_VERSION: R2019a
- MYSQL_TAG: 8.0
- MYSQL_TAG: 5.6
- <<: *slim
env:
- MATLAB_VERSION: R2019a
- MATLAB_VERSION: R2018b
- MYSQL_TAG: 5.7
- <<: *slim
env:
- MATLAB_VERSION: R2019a
- MYSQL_TAG: 5.6
- MATLAB_VERSION: R2016b
- MYSQL_TAG: 5.7
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ MYSQL_TAG=5.7
* `cp local-docker-compose.yml docker-compose.yml`
* `docker-compose up` (Note configured `JUPYTER_PASSWORD`)
* Select a means of running MATLAB e.g. Jupyter Notebook, GUI, or Terminal (see bottom)
* Add `tests` directory to path e.g. in MATLAB, `addpath('tests')`
* Run desired tests. Some examples are as follows:

| Use Case | MATLAB Code |
| ---------------------------- | ------------------------------------------------------------------------------ |
| Run all tests | `run(tests.Main)` |
| Run one class of tests | `run(tests.TestTls)` |
| Run one specific test | `runtests('tests.TestTls/testInsecureConn')` |
| Run tests based on test name | `import matlab.unittest.TestSuite;`<br>`import matlab.unittest.selectors.HasName;`<br>`import matlab.unittest.constraints.ContainsSubstring;`<br>`suite = TestSuite.fromClass(?tests.Main, ... `<br><code>&nbsp;&nbsp;&nbsp;&nbsp;</code>`HasName(ContainsSubstring('Conn')));`<br>`run(suite)`|
| Run all tests | `run(Main)` |
| Run one class of tests | `run(TestTls)` |
| Run one specific test | `runtests('TestTls/testInsecureConn')` |
| Run tests based on test name | `import matlab.unittest.TestSuite;`<br>`import matlab.unittest.selectors.HasName;`<br>`import matlab.unittest.constraints.ContainsSubstring;`<br>`suite = TestSuite.fromClass(?Main, ... `<br><code>&nbsp;&nbsp;&nbsp;&nbsp;</code>`HasName(ContainsSubstring('Conn')));`<br>`run(suite)`|


Launch Jupyter Notebook
Expand Down
File renamed without changes.
11 changes: 11 additions & 0 deletions tests/Main.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
classdef Main < ...
TestConfig & ...
TestConnection & ...
TestERD & ...
TestExternalFile & ...
TestExternalS3 & ...
TestFetch & ...
TestProjection & ...
TestTls & ...
TestUuid
end
8 changes: 5 additions & 3 deletions +tests/Prep.m → tests/Prep.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
methods
function obj = Prep()
% Initialize test_root
test_pkg_details = what('tests');
test_pkg_details = what('dj');
[test_root, ~, ~] = fileparts(test_pkg_details.path);
obj.test_root = [test_root '/+tests'];
obj.test_root = [test_root '/tests'];
if ispc
obj.external_file_store_root = [getenv('TEMP') '\root'];
else
Expand All @@ -37,13 +37,14 @@
function init(testCase)
disp('---------------INIT---------------');
clear functions;
addpath(testCase.test_root);
addpath([testCase.test_root '/test_schemas']);

curr_conn = dj.conn(testCase.CONN_INFO_ROOT.host, ...
testCase.CONN_INFO_ROOT.user, testCase.CONN_INFO_ROOT.password,'',true);
% create test users
ver = curr_conn.query('select @@version as version').version;
if tests.lib.compareVersions(ver,'5.8')
if lib.compareVersions(ver,'5.8')
cmd = {...
'CREATE USER IF NOT EXISTS ''datajoint''@''%%'' '
'IDENTIFIED BY ''datajoint'';'
Expand Down Expand Up @@ -154,6 +155,7 @@ function dispose(testCase)
% delete(['test_schemas/+University/getSchema.m'])
end
rmpath([testCase.test_root '/test_schemas']);
% rmpath(testCase.test_root);
warning('on','MATLAB:RMDIR:RemovedFromPath');
end
end
Expand Down
46 changes: 26 additions & 20 deletions +tests/TestConfig.m → tests/TestConfig.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
classdef TestConfig < tests.Prep
classdef TestConfig < Prep
% TestConfig tests scenarios related to initializing DJ config.
methods (Static)
function obj = TestConfig_configRemoveEnvVars(obj, type)
Expand Down Expand Up @@ -49,7 +49,7 @@ function TestConfig_configSingleFileTest(test_instance, type, fname, base)
end
% load raw
read_data = fileread(fname);
obj1 = tests.TestConfig.TestConfig_configRemoveEnvVars(jsondecode(read_data), 'file');
obj1 = TestConfig.TestConfig_configRemoveEnvVars(jsondecode(read_data), 'file');
% optional merge from base
if strcmpi(type, 'load-custom')
tmp = rmfield(base, intersect(fieldnames(base), fieldnames(obj1)));
Expand All @@ -60,7 +60,7 @@ function TestConfig_configSingleFileTest(test_instance, type, fname, base)
% stringify
file = jsonencode(obj1);
% load config
obj2 = tests.TestConfig.TestConfig_configRemoveEnvVars(dj.config(), 'config');
obj2 = TestConfig.TestConfig_configRemoveEnvVars(dj.config(), 'config');
curr = jsonencode(obj2);
curr = regexprep(curr,'[a-z0-9][A-Z]','${$0(1)}_${lower($0(2))}');
% checks
Expand Down Expand Up @@ -142,15 +142,20 @@ function TestConfig_testConfigChecks(testCase)
disp(['---------------' st(1).name '---------------']);
testCase.verifyError(@() dj.config(9), ...
'DataJoint:Config:InvalidType');
d = testCase.verifyError(@() dj.config('none'), ...
'DataJoint:Config:InvalidKey');
try
d = dj.config('none');
catch ME
if ~strcmp(ME.identifier,'DataJoint:Config:InvalidKey')
rethrow(ME);
end
end
end
function TestConfig_testRestore(testCase)
st = dbstack;
disp(['---------------' st(1).name '---------------']);
dj.config.restore;
obj1 = tests.TestConfig.TestConfig_configRemoveEnvVars(dj.config(), 'config');
obj2 = tests.TestConfig.TestConfig_configRemoveEnvVars( ...
obj1 = TestConfig.TestConfig_configRemoveEnvVars(dj.config(), 'config');
obj2 = TestConfig.TestConfig_configRemoveEnvVars( ...
orderfields(dj.internal.Settings.DEFAULTS), 'config');
testCase.verifyEqual(jsonencode(obj1), jsonencode(obj2));
end
Expand All @@ -161,36 +166,37 @@ function TestConfig_testSave(testCase)

% local
dj.config('font', 10);
tests.TestConfig.TestConfig_configSingleFileTest(testCase, 'save-local');
TestConfig.TestConfig_configSingleFileTest(testCase, 'save-local');
% global
dj.config('font', 12);
tests.TestConfig.TestConfig_configSingleFileTest(testCase, 'save-global');
TestConfig.TestConfig_configSingleFileTest(testCase, 'save-global');
% custom
dj.config('font', 16);
tests.TestConfig.TestConfig_configSingleFileTest(testCase, 'save-custom', './config.json');
TestConfig.TestConfig_configSingleFileTest(...
testCase, 'save-custom', './config.json');

dj.config.restore;
end
function TestConfig_testLoad(testCase)
st = dbstack;
disp(['---------------' st(1).name '---------------']);
pkg = what('tests');
pkg_path = testCase.test_root;
% generate default base
default_file = [pkg.path '/test_schemas/default.json'];
default_file = [pkg_path '/test_schemas/default.json'];
dj.config.restore;
dj.config.save(default_file);
defaults = tests.TestConfig.TestConfig_configRemoveEnvVars( ...
defaults = TestConfig.TestConfig_configRemoveEnvVars( ...
jsondecode(fileread(default_file)), 'file');
delete(default_file);
% load test config
tests.TestConfig.TestConfig_configSingleFileTest(testCase, 'load-custom', ...
[pkg.path '/test_schemas/config.json'], defaults);
TestConfig.TestConfig_configSingleFileTest(testCase, 'load-custom', ...
[pkg_path '/test_schemas/config.json'], defaults);
% load new config on top of existing
base = tests.TestConfig.TestConfig_configRemoveEnvVars(dj.config, 'config');
base = TestConfig.TestConfig_configRemoveEnvVars(dj.config, 'config');
base = jsonencode(base);
base = regexprep(base,'[a-z0-9][A-Z]','${$0(1)}_${lower($0(2))}');
tests.TestConfig.TestConfig_configSingleFileTest(testCase, 'load-custom', ...
[pkg.path '/test_schemas/config_lite.json'], jsondecode(base));
TestConfig.TestConfig_configSingleFileTest(testCase, 'load-custom', ...
[pkg_path '/test_schemas/config_lite.json'], jsondecode(base));
% cleanup
dj.config.restore;
end
Expand All @@ -210,14 +216,14 @@ function validateEnvVarConfig(type, values)
testCase.verifyEqual(dj.config('databasePassword'), values{3});
testCase.verifyEqual(dj.config('connectionInit_function'), values{4});
end
pkg = what('tests');
pkg_path = testCase.test_root;
setenv('DJ_INIT', 'select @@version;');
dj.config.restore;
% check pulling from env vars
env = {getenv('DJ_HOST'), getenv('DJ_USER'), getenv('DJ_PASS'), getenv('DJ_INIT')};
validateEnvVarConfig('env', env);
% check after load if env vars take precedence
dj.config.load([pkg.path '/test_schemas/config.json']);
dj.config.load([pkg_path '/test_schemas/config.json']);
validateEnvVarConfig('env', env);
% check if overriding env vars is persisted
validateEnvVarConfig('set', ...
Expand Down
36 changes: 35 additions & 1 deletion +tests/TestConnection.m → tests/TestConnection.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
classdef TestConnection < tests.Prep
classdef TestConnection < Prep
% TestConnection tests typical connection scenarios.
methods (Test)
function TestConnection_testConnection(testCase)
Expand Down Expand Up @@ -39,5 +39,39 @@ function TestConnection_testPort(testCase)
testCase.CONN_INFO.password,'',true), ...
'MySQL:Error');
end
function TestConnection_testTransactionRollback(testCase)
st = dbstack;
disp(['---------------' st(1).name '---------------']);
package = 'University';

c1 = dj.conn(...
testCase.CONN_INFO.host,...
testCase.CONN_INFO.user,...
testCase.CONN_INFO.password,'',true);
dj.createSchema(package,[testCase.test_root '/test_schemas'], ...
[testCase.PREFIX '_university']);
schema = University.getSchema;
tmp = {
20 'Henry' 'Jupyter' '2020-11-25 12:34:56'
21 'Lacy' 'Mars' '2017-11-25 12:34:56'
};

insert(University.Student, tmp(1, :));

schema.conn.startTransaction
try
insert(University.Student, tmp(2, :));
assert(false, 'Customer:Error', 'Message')
catch ME
schema.conn.cancelTransaction
if ~strcmp(ME.identifier,'Customer:Error')
rethrow(ME);
end
end

q = University.Student & 'student_id in (20,21)';
testCase.verifyEqual(q.count, 1);
testCase.verifyEqual(q.fetch1('student_id'), 20);
end
end
end
2 changes: 1 addition & 1 deletion +tests/TestERD.m → tests/TestERD.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
classdef TestERD < tests.Prep
classdef TestERD < Prep
% TestERD tests unusual ERD scenarios.
methods (Test)
function TestERD_testDraw(testCase)
Expand Down
Loading