File indexing completed on 2024-11-10 04:22:06
0001 /**************************************************************************************** 0002 * Copyright (c) 2009 Maximilian Kossick <maximilian.kossick@googlemail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #include "TestSqlCollectionLocation.h" 0018 0019 #include "DatabaseUpdater.h" 0020 #include "core/support/Debug.h" 0021 #include "core/support/Components.h" 0022 #include "DefaultSqlQueryMakerFactory.h" 0023 #include "core/meta/Meta.h" 0024 #include "core-impl/storage/sql/mysqlestorage/MySqlEmbeddedStorage.h" 0025 #include "SqlCollection.h" 0026 #include "SqlCollectionLocation.h" 0027 #include "SqlRegistry.h" 0028 #include "SqlMountPointManagerMock.h" 0029 #include "core/collections/MockCollectionLocationDelegate.h" 0030 0031 #include "config-amarok-test.h" 0032 0033 #include <QMetaObject> 0034 #include <QProcess> 0035 #include <QTimer> 0036 0037 #include <gmock/gmock.h> 0038 #include <KConfigGroup> 0039 0040 using ::testing::AnyNumber; 0041 using ::testing::Return; 0042 using ::testing::_; 0043 0044 /** A SqlCollectionLocation that claims writing is possible even though it doesn't have 0045 * a valid directory. 0046 */ 0047 class MySqlCollectionLocation : public Collections::SqlCollectionLocation 0048 { 0049 public: 0050 MySqlCollectionLocation( Collections::SqlCollection *coll ) : Collections::SqlCollectionLocation( coll ) {} 0051 ~MySqlCollectionLocation() override {} 0052 0053 bool isWritable() const override { return true; } 0054 }; 0055 0056 class MyOrganizeCollectionDelegate : public OrganizeCollectionDelegate 0057 { 0058 public: 0059 MyOrganizeCollectionDelegate() : OrganizeCollectionDelegate(), overwrite( false ), migrate( false ) {} 0060 ~MyOrganizeCollectionDelegate() override {} 0061 0062 void setTracks( const Meta::TrackList &tracks ) override { Q_UNUSED( tracks ) } 0063 void setFolders( const QStringList &folders ) override { Q_UNUSED( folders ) } 0064 void setIsOrganizing( bool organizing ) override { Q_UNUSED( organizing ) } 0065 void setTranscodingConfiguration(const Transcoding::Configuration &configuration) override 0066 { Q_UNUSED( configuration ) } 0067 void setCaption( const QString& ) override {} 0068 0069 void show() override { emit accepted(); } 0070 0071 bool overwriteDestinations() const override { return overwrite; } 0072 QMap<Meta::TrackPtr, QString> destinations() const override { return dests; } 0073 bool migrateLabels() const { return migrate; } 0074 0075 bool overwrite; 0076 bool migrate; 0077 QMap<Meta::TrackPtr, QString> dests; 0078 }; 0079 0080 class MyOrganizeCollectionDelegateFactory : public OrganizeCollectionDelegateFactory 0081 { 0082 public: 0083 MyOrganizeCollectionDelegateFactory( OrganizeCollectionDelegate *d ) 0084 : OrganizeCollectionDelegateFactory() 0085 , delegate( d ) {} 0086 ~MyOrganizeCollectionDelegateFactory() override {} 0087 0088 //warning: SqlCollectionLocation will delete the delegate 0089 OrganizeCollectionDelegate* createDelegate() override { return delegate; } 0090 0091 OrganizeCollectionDelegate *delegate; 0092 }; 0093 0094 0095 0096 QTEST_GUILESS_MAIN( TestSqlCollectionLocation ) 0097 0098 TestSqlCollectionLocation::TestSqlCollectionLocation() 0099 : QObject() 0100 , m_collection( nullptr ) 0101 , m_storage( nullptr ) 0102 , m_tmpDir( nullptr ) 0103 { 0104 int argc = 1; 0105 char **argv = (char **) malloc(sizeof(char *)); 0106 argv[0] = strdup( QCoreApplication::applicationName().toLocal8Bit().data() ); 0107 ::testing::InitGoogleMock( &argc, argv ); 0108 } 0109 0110 void 0111 TestSqlCollectionLocation::initTestCase() 0112 { 0113 m_tmpDir = new QTemporaryDir(); 0114 m_storage = QSharedPointer<MySqlEmbeddedStorage>( new MySqlEmbeddedStorage() ); 0115 QVERIFY( m_storage->init( m_tmpDir->path() ) ); 0116 m_collection = new Collections::SqlCollection( m_storage ); 0117 SqlMountPointManagerMock *mock = new SqlMountPointManagerMock( this, m_storage ); 0118 mock->setCollectionFolders( QStringList() << m_tmpDir->path() ); // the target folder needs to have enough space and be writable 0119 m_collection->setMountPointManager( mock ); 0120 0121 // I just need the table and not the whole playlist manager 0122 m_storage->query( QString( "CREATE TABLE playlist_tracks (" 0123 " id " + m_storage->idType() + 0124 ", playlist_id INTEGER " 0125 ", track_num INTEGER " 0126 ", url " + m_storage->exactTextColumnType() + 0127 ", title " + m_storage->textColumnType() + 0128 ", album " + m_storage->textColumnType() + 0129 ", artist " + m_storage->textColumnType() + 0130 ", length INTEGER " 0131 ", uniqueid " + m_storage->textColumnType(128) + ") ENGINE = MyISAM;" ) ); 0132 } 0133 0134 void 0135 TestSqlCollectionLocation::cleanupTestCase() 0136 { 0137 delete m_collection; 0138 //m_storage is deleted by SqlCollection 0139 delete m_tmpDir; 0140 } 0141 0142 void 0143 TestSqlCollectionLocation::init() 0144 { 0145 //setup base data 0146 m_storage->query( "INSERT INTO artists(id, name) VALUES (1, 'artist1');" ); 0147 m_storage->query( "INSERT INTO artists(id, name) VALUES (2, 'artist2');" ); 0148 m_storage->query( "INSERT INTO artists(id, name) VALUES (3, 'artist3');" ); 0149 0150 m_storage->query( "INSERT INTO albums(id,name,artist) VALUES(1,'album1',1);" ); 0151 m_storage->query( "INSERT INTO albums(id,name,artist) VALUES(2,'album2',1);" ); 0152 m_storage->query( "INSERT INTO albums(id,name,artist) VALUES(3,'album3',2);" ); 0153 0154 m_storage->query( "INSERT INTO composers(id, name) VALUES (1, 'composer1');" ); 0155 m_storage->query( "INSERT INTO genres(id, name) VALUES (1, 'genre1');" ); 0156 m_storage->query( "INSERT INTO years(id, name) VALUES (1, '1');" ); 0157 0158 m_storage->query( "INSERT INTO directories(id,deviceid,dir) VALUES (1, -1, '." + m_tmpDir->path() + "/ab/')"); 0159 m_storage->query( "INSERT INTO directories(id,deviceid,dir) VALUES (2, -1, '." + m_tmpDir->path() + "/b/')"); 0160 m_storage->query( "INSERT INTO directories(id,deviceid,dir) VALUES (3, -1, '." + m_tmpDir->path() + "/c/')"); 0161 0162 m_storage->query( QString( "INSERT INTO urls(id, deviceid, rpath, uniqueid, directory ) VALUES (1, -1, '%1', 'uid://1', 1);" ).arg( setupFileInTempDir( "ab/IDoNotExist.mp3" ) ) ); 0163 m_storage->query( QString( "INSERT INTO urls(id, deviceid, rpath, uniqueid, directory ) VALUES (2, -1, '%1', 'uid://2', 2);" ).arg( setupFileInTempDir( "b/IDoNotExistAsWell.mp3") ) ); 0164 m_storage->query( QString( "INSERT INTO urls(id, deviceid, rpath, uniqueid, directory ) VALUES (3, -1, '%1', 'uid:/3', 3);" ).arg( setupFileInTempDir( "c/MeNeither.mp3" ) ) ); 0165 0166 m_storage->query( "INSERT INTO tracks(id,url,title,comment,artist,album,genre,year,composer) " 0167 "VALUES(1,1,'track1','comment1',1,1,1,1,1);" ); 0168 m_storage->query( "INSERT INTO tracks(id,url,title,comment,artist,album,genre,year,composer) " 0169 "VALUES(2,2,'track2','comment2',1,2,1,1,1);" ); 0170 m_storage->query( "INSERT INTO tracks(id,url,title,comment,artist,album,genre,year,composer) " 0171 "VALUES(3,3,'track3','comment3',2,3,1,1,1);" ); 0172 0173 m_collection->registry()->emptyCache(); 0174 } 0175 0176 void 0177 TestSqlCollectionLocation::cleanup() 0178 { 0179 delete Amarok::Components::setCollectionLocationDelegate( nullptr ); 0180 m_storage->query( "TRUNCATE TABLE years;" ); 0181 m_storage->query( "TRUNCATE TABLE genres;" ); 0182 m_storage->query( "TRUNCATE TABLE composers;" ); 0183 m_storage->query( "TRUNCATE TABLE albums;" ); 0184 m_storage->query( "TRUNCATE TABLE artists;" ); 0185 m_storage->query( "TRUNCATE TABLE tracks;" ); 0186 m_storage->query( "TRUNCATE TABLE urls;" ); 0187 m_storage->query( "TRUNCATE TABLE labels;" ); 0188 m_storage->query( "TRUNCATE TABLE urls_labels;" ); 0189 m_storage->query( "TRUNCATE TABLE directories;" ); 0190 } 0191 0192 void 0193 TestSqlCollectionLocation::testOrganizingCopiesLabels() 0194 { 0195 { 0196 Collections::MockCollectionLocationDelegate *d = new Collections::MockCollectionLocationDelegate(); 0197 EXPECT_CALL( *d, reallyMove( _, _ ) ).Times( AnyNumber() ).WillRepeatedly( Return( true ) ); 0198 EXPECT_CALL( *d, transcode( _, _, _, _, _ ) ).WillOnce( Return( 0199 Transcoding::Configuration( Transcoding::INVALID ) ) ); 0200 Amarok::Components::setCollectionLocationDelegate( d ); 0201 } 0202 0203 { 0204 Meta::TrackPtr track = m_collection->registry()->getTrackFromUid( "uid://1" ); 0205 QVERIFY( track ); 0206 QVERIFY( track->playableUrl().path().endsWith( "ab/IDoNotExist.mp3" ) ); 0207 0208 track->addLabel( "test" ); 0209 0210 QCOMPARE( track->labels().count(), 1 ); 0211 0212 Collections::SqlCollectionLocation *source = new MySqlCollectionLocation( m_collection ); 0213 Collections::SqlCollectionLocation *dest = new MySqlCollectionLocation( m_collection ); 0214 QSignalSpy spy( source, &Collections::SqlCollectionLocation::destroyed ); 0215 0216 { 0217 MyOrganizeCollectionDelegate *delegate = new MyOrganizeCollectionDelegate(); 0218 delegate->overwrite = true; 0219 delegate->migrate = true; 0220 delegate->dests.insert( track, m_tmpDir->path() + "b/IDoNotExist.mp3" ); 0221 dest->setOrganizeCollectionDelegateFactory( new MyOrganizeCollectionDelegateFactory( delegate ) ); 0222 } 0223 0224 source->prepareMove( track, dest ); 0225 0226 spy.wait( 1000 ); 0227 0228 QCOMPARE( track->labels().count(), 1 ); 0229 QVERIFY( track->playableUrl().path().endsWith( "b/IDoNotExist.mp3" ) ); 0230 } 0231 0232 //force a reload from the database 0233 m_collection->registry()->emptyCache(); 0234 0235 { 0236 // Meta::TrackPtr track = m_collection->registry()->getTrack( m_tmpDir->path() + "/b/IDoNotExist.mp3" ); 0237 Meta::TrackPtr track = m_collection->registry()->getTrack(1); 0238 QVERIFY( track ); 0239 QVERIFY( track->playableUrl().path().endsWith( "b/IDoNotExist.mp3" ) ); 0240 // TODO: check that the db urls entry really specifies the exiting directories entry 0241 QCOMPARE( track->labels().count(), 1 ); 0242 } 0243 } 0244 0245 void 0246 TestSqlCollectionLocation::testCopiesLabelFromExternalTracks() 0247 { 0248 0249 } 0250 0251 void 0252 TestSqlCollectionLocation::testCopyTrackToDirectoryWithExistingTracks() 0253 { 0254 0255 } 0256 0257 QString 0258 TestSqlCollectionLocation::setupFileInTempDir( const QString &relativeName ) 0259 { 0260 QString absoluteName = m_tmpDir->path() + '/' + relativeName; 0261 0262 //TODO: unix specific 0263 //create directory where necessary 0264 int index = absoluteName.lastIndexOf( '/' ); 0265 if(index > 0 ) 0266 { 0267 QString dir = absoluteName.left( index ); 0268 QProcess::execute( "mkdir", QStringList() << "-p" << dir ); 0269 } 0270 else 0271 { 0272 qDebug() << "huh? index was " << index << " relative name was " << relativeName << " tmpDir " << m_tmpDir->path(); 0273 } 0274 0275 QProcess::execute( "touch", QStringList() << absoluteName ); 0276 return '.' + absoluteName; 0277 }